[theano] 01/02: use full source for the embedded Javascript modules

Rebecca Palmer rnpalmer-guest at moszumanska.debian.org
Thu Sep 28 22:24:05 UTC 2017


This is an automated email from the git hooks/post-receive script.

rnpalmer-guest pushed a commit to branch master
in repository theano.

commit 815035b6722c6612b70de00f1fcb5ef2fb7686f3
Author: Rebecca N. Palmer <rebecca_palmer at zoho.com>
Date:   Thu Sep 28 23:05:07 2017 +0100

    use full source for the embedded Javascript modules
---
 debian/control                                     |    10 +-
 debian/copyright                                   |    26 +-
 debian/missing-source/README.txt                   |    24 -
 debian/missing-source/dagre-d3.js                  | 25569 -------------------
 debian/missing-source/dagre-d3/.gitignore          |     6 +
 debian/missing-source/dagre-d3/.jscsrc             |     6 +
 debian/missing-source/dagre-d3/.jshintrc           |    13 +
 debian/missing-source/dagre-d3/.npmignore          |     7 +
 debian/missing-source/dagre-d3/LICENSE             |    19 +
 debian/missing-source/dagre-d3/README.md           |    15 +
 debian/missing-source/dagre-d3/bower.json          |    31 +
 debian/missing-source/dagre-d3/demo/arrows.html    |    76 +
 debian/missing-source/dagre-d3/demo/clusters.html  |   102 +
 debian/missing-source/dagre-d3/demo/demo.css       |    35 +
 debian/missing-source/dagre-d3/demo/demo.js        |    25 +
 debian/missing-source/dagre-d3/demo/dom.html       |    99 +
 .../missing-source/dagre-d3/demo/etl-status.html   |   284 +
 .../dagre-d3/demo/graph-story-board.html           |   424 +
 debian/missing-source/dagre-d3/demo/hover.html     |   197 +
 .../dagre-d3/demo/interactive-demo.html            |   173 +
 .../dagre-d3/demo/sentence-tokenization.html       |   105 +
 debian/missing-source/dagre-d3/demo/shapes.html    |    73 +
 .../missing-source/dagre-d3/demo/style-attrs.html  |   106 +
 .../missing-source/dagre-d3/demo/svg-labels.html   |   103 +
 .../dagre-d3/demo/tcp-state-diagram.html           |   105 +
 debian/missing-source/dagre-d3/demo/tipsy.css      |    25 +
 debian/missing-source/dagre-d3/demo/tipsy.js       |   288 +
 .../missing-source/dagre-d3/demo/user-defined.html |   115 +
 debian/missing-source/dagre-d3/gulpfile.js         |   228 +
 debian/missing-source/dagre-d3/index.js            |    30 +
 debian/missing-source/dagre-d3/karma.conf.js       |    71 +
 debian/missing-source/dagre-d3/karma.core.conf.js  |    82 +
 debian/missing-source/dagre-d3/lib/arrows.js       |    71 +
 .../missing-source/dagre-d3/lib/create-clusters.js |    43 +
 .../dagre-d3/lib/create-edge-labels.js             |    35 +
 .../dagre-d3/lib/create-edge-paths.js              |   136 +
 debian/missing-source/dagre-d3/lib/create-nodes.js |    58 +
 debian/missing-source/dagre-d3/lib/d3.js           |     2 +
 debian/missing-source/dagre-d3/lib/dagre.js        |    15 +
 debian/missing-source/dagre-d3/lib/graphlib.js     |    15 +
 .../missing-source/dagre-d3/lib/intersect/index.js |     7 +
 .../dagre-d3/lib/intersect/intersect-circle.js     |     7 +
 .../dagre-d3/lib/intersect/intersect-ellipse.js    |    25 +
 .../dagre-d3/lib/intersect/intersect-line.js       |    70 +
 .../dagre-d3/lib/intersect/intersect-node.js       |     5 +
 .../dagre-d3/lib/intersect/intersect-polygon.js    |    55 +
 .../dagre-d3/lib/intersect/intersect-rect.js       |    32 +
 .../dagre-d3/lib/label/add-html-label.js           |    37 +
 .../missing-source/dagre-d3/lib/label/add-label.js |    37 +
 .../dagre-d3/lib/label/add-svg-label.js            |    13 +
 .../dagre-d3/lib/label/add-text-label.js           |    45 +
 debian/missing-source/dagre-d3/lib/lodash.js       |    15 +
 .../dagre-d3/lib/position-clusters.js              |    34 +
 .../dagre-d3/lib/position-edge-labels.js           |    22 +
 .../missing-source/dagre-d3/lib/position-nodes.js  |    21 +
 debian/missing-source/dagre-d3/lib/render.js       |   167 +
 debian/missing-source/dagre-d3/lib/shapes.js       |    81 +
 debian/missing-source/dagre-d3/lib/util.js         |    54 +
 debian/missing-source/dagre-d3/lib/version.js      |     1 +
 debian/missing-source/dagre-d3/package.json        |    57 +
 debian/missing-source/dagre-d3/src/bower.json.tmpl |    26 +
 .../dagre-d3/src/release/bump-version.js           |    24 +
 .../dagre-d3/src/release/check-version.js          |    29 +
 .../missing-source/dagre-d3/src/release/release.sh |    66 +
 debian/missing-source/dagre-d3/src/version.js.tmpl |     1 +
 .../missing-source/dagre-d3/test/bundle-test.css   |    29 +
 debian/missing-source/dagre-d3/test/bundle-test.js |   325 +
 debian/missing-source/dagre-d3/test/demo-test.js   |    76 +
 debian/missing-source/dagre/.gitignore             |     3 +
 debian/missing-source/dagre/.jscsrc                |     6 +
 debian/missing-source/dagre/.jshintrc              |    24 +
 debian/missing-source/dagre/.npmignore             |     7 +
 debian/missing-source/dagre/.travis.yml            |     7 +
 debian/missing-source/dagre/LICENSE                |    19 +
 debian/missing-source/dagre/Makefile               |    83 +
 debian/missing-source/dagre/README.md              |    16 +
 debian/missing-source/dagre/bower.json             |    26 +
 debian/missing-source/dagre/index.js               |    33 +
 debian/missing-source/dagre/karma.conf.js          |    68 +
 debian/missing-source/dagre/karma.core.conf.js     |    70 +
 debian/missing-source/dagre/lib/acyclic.js         |    67 +
 .../dagre/lib/add-border-segments.js               |    38 +
 .../missing-source/dagre/lib/coordinate-system.js  |    72 +
 debian/missing-source/dagre/lib/data/list.js       |    56 +
 debian/missing-source/dagre/lib/debug.js           |    34 +
 debian/missing-source/dagre/lib/graphlib.js        |    15 +
 debian/missing-source/dagre/lib/greedy-fas.js      |   118 +
 debian/missing-source/dagre/lib/layout.js          |   392 +
 debian/missing-source/dagre/lib/lodash.js          |    15 +
 debian/missing-source/dagre/lib/nesting-graph.js   |   132 +
 debian/missing-source/dagre/lib/normalize.js       |    90 +
 .../dagre/lib/order/add-subgraph-constraints.js    |    53 +
 .../missing-source/dagre/lib/order/barycenter.js   |    28 +
 .../dagre/lib/order/build-layer-graph.js           |    73 +
 .../missing-source/dagre/lib/order/cross-count.js  |    70 +
 debian/missing-source/dagre/lib/order/index.js     |    79 +
 .../missing-source/dagre/lib/order/init-order.js   |    38 +
 .../dagre/lib/order/resolve-conflicts.js           |   123 +
 .../dagre/lib/order/sort-subgraph.js               |    76 +
 debian/missing-source/dagre/lib/order/sort.js      |    57 +
 .../dagre/lib/parent-dummy-chains.js               |    86 +
 debian/missing-source/dagre/lib/position/bk.js     |   398 +
 debian/missing-source/dagre/lib/position/index.js  |    30 +
 .../missing-source/dagre/lib/rank/feasible-tree.js |    89 +
 debian/missing-source/dagre/lib/rank/index.js      |    48 +
 .../dagre/lib/rank/network-simplex.js              |   234 +
 debian/missing-source/dagre/lib/rank/util.js       |    61 +
 debian/missing-source/dagre/lib/util.js            |   236 +
 debian/missing-source/dagre/lib/version.js         |     1 +
 debian/missing-source/dagre/package.json           |    40 +
 debian/missing-source/dagre/src/bench.js           |    63 +
 .../dagre/src/release/bump-version.js              |    26 +
 .../dagre/src/release/check-version.js             |    32 +
 .../dagre/src/release/make-bower.json.js           |    28 +
 .../dagre/src/release/make-version.js              |     4 +
 debian/missing-source/dagre/src/release/release.sh |    67 +
 debian/missing-source/dagre/test/acyclic-test.js   |    98 +
 .../dagre/test/add-border-segments-test.js         |    92 +
 debian/missing-source/dagre/test/bundle-test.js    |    34 +
 debian/missing-source/dagre/test/chai.js           |    13 +
 debian/missing-source/dagre/test/console.html      |   244 +
 .../dagre/test/coordinate-system-test.js           |    71 +
 debian/missing-source/dagre/test/data/list-test.js |    60 +
 .../missing-source/dagre/test/greedy-fas-test.js   |   109 +
 debian/missing-source/dagre/test/layout-test.js    |   298 +
 .../dagre/test/nesting-graph-test.js               |   199 +
 debian/missing-source/dagre/test/normalize-test.js |   219 +
 .../test/order/add-subgraph-constraints-test.js    |    59 +
 .../dagre/test/order/barycenter-test.js            |    69 +
 .../dagre/test/order/build-layer-graph-test.js     |   117 +
 .../dagre/test/order/cross-count-test.js           |    49 +
 .../dagre/test/order/init-order-test.js            |    49 +
 .../missing-source/dagre/test/order/order-test.js  |    47 +
 .../dagre/test/order/resolve-conflicts-test.js     |   150 +
 .../dagre/test/order/sort-subgraph-test.js         |   126 +
 .../missing-source/dagre/test/order/sort-test.js   |    86 +
 .../dagre/test/parent-dummy-chains-test.js         |   147 +
 debian/missing-source/dagre/test/position-test.js  |    54 +
 .../missing-source/dagre/test/position/bk-test.js  |   667 +
 .../dagre/test/rank/feasible-tree-test.js          |    52 +
 .../dagre/test/rank/network-simplex-test.js        |   499 +
 debian/missing-source/dagre/test/rank/rank-test.js |    42 +
 debian/missing-source/dagre/test/rank/util-test.js |    65 +
 debian/missing-source/dagre/test/util-test.js      |   245 +
 debian/missing-source/dagre/test/version-test.js   |     8 +
 debian/missing-source/graphlib-dot.js              | 10701 --------
 debian/missing-source/graphlib-dot/.gitignore      |     2 +
 debian/missing-source/graphlib-dot/.jscsrc         |     6 +
 debian/missing-source/graphlib-dot/.jshintrc       |    25 +
 debian/missing-source/graphlib-dot/.npmignore      |     7 +
 debian/missing-source/graphlib-dot/.travis.yml     |     7 +
 debian/missing-source/graphlib-dot/LICENSE         |    19 +
 debian/missing-source/graphlib-dot/Makefile        |    83 +
 debian/missing-source/graphlib-dot/README.md       |    14 +
 debian/missing-source/graphlib-dot/browser.js      |    22 +
 debian/missing-source/graphlib-dot/index.js        |    22 +
 debian/missing-source/graphlib-dot/karma.conf.js   |    68 +
 .../missing-source/graphlib-dot/karma.core.conf.js |    70 +
 .../missing-source/graphlib-dot/lib/build-graph.js |   129 +
 debian/missing-source/graphlib-dot/lib/graphlib.js |    15 +
 debian/missing-source/graphlib-dot/lib/index.js    |     9 +
 debian/missing-source/graphlib-dot/lib/lodash.js   |    15 +
 .../missing-source/graphlib-dot/lib/read-many.js   |     8 +
 debian/missing-source/graphlib-dot/lib/read-one.js |     8 +
 .../missing-source/graphlib-dot/lib/write-one.js   |   127 +
 debian/missing-source/graphlib-dot/package.json    |    43 +
 .../graphlib-dot/src/dot-grammar.pegjs             |   153 +
 .../graphlib-dot/src/release/bump-version.js       |    26 +
 .../graphlib-dot/src/release/check-version.js      |    32 +
 .../graphlib-dot/src/release/make-bower.json.js    |    29 +
 .../graphlib-dot/src/release/make-version.js       |     4 +
 .../graphlib-dot/src/release/release.sh            |    67 +
 .../graphlib-dot/test/bundle-test.js               |    32 +
 debian/missing-source/graphlib-dot/test/chai.js    |     5 +
 .../graphlib-dot/test/read-many-test.js            |    12 +
 .../graphlib-dot/test/read-one-test.js             |   375 +
 .../graphlib-dot/test/version-test.js              |     8 +
 .../missing-source/graphlib-dot/test/write-test.js |   137 +
 debian/missing-source/graphlib/.gitignore          |     2 +
 debian/missing-source/graphlib/.jscsrc             |     6 +
 debian/missing-source/graphlib/.jshintrc           |    25 +
 debian/missing-source/graphlib/.npmignore          |     8 +
 debian/missing-source/graphlib/.travis.yml         |     7 +
 debian/missing-source/graphlib/LICENSE             |    19 +
 debian/missing-source/graphlib/Makefile            |    83 +
 debian/missing-source/graphlib/README.md           |    16 +
 debian/missing-source/graphlib/bower.json          |    25 +
 debian/missing-source/graphlib/browser.js          |    31 +
 debian/missing-source/graphlib/index.js            |    38 +
 debian/missing-source/graphlib/karma.conf.js       |    68 +
 debian/missing-source/graphlib/karma.core.conf.js  |    69 +
 .../missing-source/graphlib/lib/alg/components.js  |    27 +
 debian/missing-source/graphlib/lib/alg/dfs.js      |    39 +
 .../graphlib/lib/alg/dijkstra-all.js               |    10 +
 debian/missing-source/graphlib/lib/alg/dijkstra.js |    54 +
 .../missing-source/graphlib/lib/alg/find-cycles.js |    10 +
 .../graphlib/lib/alg/floyd-warshall.js             |    50 +
 debian/missing-source/graphlib/lib/alg/index.js    |    13 +
 .../missing-source/graphlib/lib/alg/is-acyclic.js  |    15 +
 .../missing-source/graphlib/lib/alg/postorder.js   |     7 +
 debian/missing-source/graphlib/lib/alg/preorder.js |     7 +
 debian/missing-source/graphlib/lib/alg/prim.js     |    52 +
 debian/missing-source/graphlib/lib/alg/tarjan.js   |    47 +
 debian/missing-source/graphlib/lib/alg/topsort.js  |    34 +
 .../graphlib/lib/data/priority-queue.js            |   152 +
 debian/missing-source/graphlib/lib/graph.js        |   519 +
 debian/missing-source/graphlib/lib/index.js        |     5 +
 debian/missing-source/graphlib/lib/json.js         |    66 +
 debian/missing-source/graphlib/lib/lodash.js       |    15 +
 debian/missing-source/graphlib/lib/version.js      |     1 +
 debian/missing-source/graphlib/package.json        |    40 +
 debian/missing-source/graphlib/src/bench.js        |   170 +
 .../graphlib/src/release/bump-version.js           |    26 +
 .../graphlib/src/release/check-version.js          |    32 +
 .../graphlib/src/release/make-bower.json.js        |    29 +
 .../graphlib/src/release/make-version.js           |     4 +
 .../missing-source/graphlib/src/release/release.sh |    67 +
 .../graphlib/test/alg/all-shortest-paths-test.js   |   126 +
 .../graphlib/test/alg/components-test.js           |    39 +
 .../graphlib/test/alg/dijkstra-all-test.js         |    24 +
 .../graphlib/test/alg/dijkstra-test.js             |    90 +
 .../graphlib/test/alg/find-cycles-test.js          |    50 +
 .../graphlib/test/alg/floyd-warshall-test.js       |    62 +
 .../graphlib/test/alg/is-acyclic-test.js           |    27 +
 .../graphlib/test/alg/postorder-test.js            |    54 +
 .../graphlib/test/alg/preorder-test.js             |    54 +
 .../missing-source/graphlib/test/alg/prim-test.js  |    56 +
 .../graphlib/test/alg/tarjan-test.js               |    44 +
 .../graphlib/test/alg/topsort-test.js              |    49 +
 debian/missing-source/graphlib/test/bundle-test.js |    39 +
 debian/missing-source/graphlib/test/chai.js        |     5 +
 .../graphlib/test/data/priority-queue-test.js      |   131 +
 debian/missing-source/graphlib/test/graph-test.js  |   945 +
 debian/missing-source/graphlib/test/json-test.js   |    64 +
 .../missing-source/graphlib/test/version-test.js   |     8 +
 debian/missing-source/js_fixes.diff                |    80 +
 debian/rules                                       |    17 +-
 debian/source.lintian-overrides                    |     7 -
 238 files changed, 17421 insertions(+), 36325 deletions(-)

diff --git a/debian/control b/debian/control
index cbef564..3f557ff 100644
--- a/debian/control
+++ b/debian/control
@@ -26,11 +26,14 @@ Build-Depends:
  python3-sphinx,
  python3-sphinx-rtd-theme,
  python3-pygments,
- uglifyjs,
  dvipng,
  texlive-latex-extra,
  rdfind,
- symlinks
+ symlinks,
+ node-browserify-lite,
+ node-uglify,
+ node-pegjs,
+ node-lodash-compat
 Standards-Version: 4.1.0
 Homepage: http://www.deeplearning.net/software/theano/
 Vcs-Git: https://anonscm.debian.org/git/debian-science/packages/theano.git
@@ -60,6 +63,7 @@ Recommends:
 Suggests:
  nvidia-cuda-toolkit,
  python-pycuda
+Built-Using: ${javascriptBU}
 Description: CPU/GPU math expression compiler for Python
  Theano is a Python library that allows one to define and evaluate mathematical
  expressions involving multi-dimensional arrays efficiently. It provides a
@@ -92,6 +96,7 @@ Recommends:
 Suggests:
  nvidia-cuda-toolkit,
  python3-pycuda
+Built-Using: ${javascriptBU}
 Description: CPU/GPU math expression compiler for Python 3
  Theano is a Python library that allows one to define and evaluate mathematical
  expressions involving multi-dimensional arrays efficiently. It provides a
@@ -112,6 +117,7 @@ Depends:
 Recommends:
  python-theano,
  python3-theano
+Built-Using: ${javascriptBU}
 Description: CPU/GPU math expression compiler for Python (docs)
  Theano is a Python library that allows one to define and evaluate mathematical
  expressions involving multi-dimensional arrays efficiently. It provides a
diff --git a/debian/copyright b/debian/copyright
index cc24fc8..08504bd 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -18,29 +18,17 @@ Copyright: 2016 Daniel Stender <stender at debian.org>
            2017 Rebecca N. Palmer <rebecca_palmer at zoho.com>
 License: BSD-3-Clause
 
-Files: theano/compat/six.py
-Copyright: 2010-2015 Benjamin Peterson
+Files: debian/missing-source/*
+Copyright: 2012-2016 Chris Pettitt <cpettitt at gmail.com> and contributors
+Comment: from https://github.com/cpettitt with some changes (see debian/missing-source/js_fixes.diff)
 License: Expat
 
-Files: theano/d3viz/js/d3.v3.min.js
-       doc/library/d3viz/examples/d3viz/js/d3.v3.min.js
-       debian/missing-source/d3.js
-Copyright: 2010-2016 Mike Bostock <mike at ocks.org>
-Comment: https://github.com/d3/d3
-License: BSD-3-Clause
-
-Files: theano/d3viz/js/dagre-d3.min.js
-       doc/library/d3viz/examples/d3viz/js/dagre-d3.min.js
-       debian/missing-source/dagre-d3.js
-Copyright: 2013-2015 Chris Pettitt <cpettitt at gmail.com>
-Comment: https://github.com/cpettitt/dagre-d3
+Files: debian/missing-source/dagre-d3/demo/tipsy.js
+Copyright: 2008-2010 jason frame <jason at onehackoranother.com>
 License: Expat
 
-Files: theano/d3viz/js/graphlib-dot.min.js
-       doc/library/d3viz/examples/d3viz/js/graphlib-dot.min.js
-       debian/missing-source/graphlib-dot.js
-Copyright: 2012-2015 Chris Pettitt <cpettitt at gmail.com>
-Comment: https://github.com/cpettitt/graphlib-dot
+Files: theano/compat/six.py
+Copyright: 2010-2015 Benjamin Peterson
 License: Expat
 
 Files: theano/gof/sched.py
diff --git a/debian/missing-source/README.txt b/debian/missing-source/README.txt
deleted file mode 100644
index 0235876..0000000
--- a/debian/missing-source/README.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Non-minified sources of minified Javascript files in the source tarball:
-
-1) d3.js
-
-origin: https://github.com/d3/d3 (release 3.5.6)
-
-theano/d3viz/js/d3.v3.min.js
-doc/library/d3viz/examples/d3viz/js/d3.v3.min.js
-
-2) dagre-d3.js
-
-origin: https://github.com/cpettitt/dagre-d3 (supposingly release 0.4.5)
-
-theano/d3viz/js/dagre-d3.min.js
-doc/library/d3viz/examples/d3viz/js/dagre-d3.min.js
-
-3) graphlib-dot.js
-
-origin: https://github.com/cpettitt/graphlib-dot/tree/master/dist (20150728.b3192e8)
-
-theano/d3viz/js/graphlib-dot.min.js
-doc/library/d3viz/examples/d3viz/js/graphlib-dot.min.js
-
-Daniel Stender <stender at debian.org> 2015-07-11
diff --git a/debian/missing-source/dagre-d3.js b/debian/missing-source/dagre-d3.js
deleted file mode 100644
index c427486..0000000
--- a/debian/missing-source/dagre-d3.js
+++ /dev/null
@@ -1,25569 +0,0 @@
-!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.dagreD3=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot fi [...]
-/**
- * @license
- * Copyright (c) 2012-2013 Chris Pettitt
- *
- * 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.
- */
-module.exports =  {
-  graphlib: require("./lib/graphlib"),
-  dagre: require("./lib/dagre"),
-  intersect: require("./lib/intersect"),
-  render: require("./lib/render"),
-  util: require("./lib/util"),
-  version: require("./lib/version")
-};
-
-},{"./lib/dagre":8,"./lib/graphlib":9,"./lib/intersect":10,"./lib/render":25,"./lib/util":27,"./lib/version":28}],2:[function(require,module,exports){
-var util = require("./util");
-
-module.exports = {
-  "default": normal,
-  "normal": normal,
-  "vee": vee,
-  "undirected": undirected
-};
-
-function normal(parent, id, edge, type) {
-  var marker = parent.append("marker")
-    .attr("id", id)
-    .attr("viewBox", "0 0 10 10")
-    .attr("refX", 9)
-    .attr("refY", 5)
-    .attr("markerUnits", "strokeWidth")
-    .attr("markerWidth", 8)
-    .attr("markerHeight", 6)
-    .attr("orient", "auto");
-
-  var path = marker.append("path")
-    .attr("d", "M 0 0 L 10 5 L 0 10 z")
-    .style("stroke-width", 1)
-    .style("stroke-dasharray", "1,0");
-  util.applyStyle(path, edge[type + "Style"]);
-}
-
-function vee(parent, id, edge, type) {
-  var marker = parent.append("marker")
-    .attr("id", id)
-    .attr("viewBox", "0 0 10 10")
-    .attr("refX", 9)
-    .attr("refY", 5)
-    .attr("markerUnits", "strokeWidth")
-    .attr("markerWidth", 8)
-    .attr("markerHeight", 6)
-    .attr("orient", "auto");
-
-  var path = marker.append("path")
-    .attr("d", "M 0 0 L 10 5 L 0 10 L 4 5 z")
-    .style("stroke-width", 1)
-    .style("stroke-dasharray", "1,0");
-  util.applyStyle(path, edge[type + "Style"]);
-}
-
-function undirected(parent, id, edge, type) {
-  var marker = parent.append("marker")
-    .attr("id", id)
-    .attr("viewBox", "0 0 10 10")
-    .attr("refX", 9)
-    .attr("refY", 5)
-    .attr("markerUnits", "strokeWidth")
-    .attr("markerWidth", 8)
-    .attr("markerHeight", 6)
-    .attr("orient", "auto");
-
-  var path = marker.append("path")
-    .attr("d", "M 0 5 L 10 5")
-    .style("stroke-width", 1)
-    .style("stroke-dasharray", "1,0");
-  util.applyStyle(path, edge[type + "Style"]);
-}
-
-},{"./util":27}],3:[function(require,module,exports){
-var util = require("./util"),
-    addLabel = require("./label/add-label");
-
-module.exports = createClusters;
-
-function createClusters(selection, g) {
-  var clusters = g.nodes().filter(function(v) { return util.isSubgraph(g, v); }),
-      svgClusters = selection.selectAll("g.cluster")
-        .data(clusters, function(v) { return v; });
-
-  svgClusters.selectAll("*").remove();
-  svgClusters.enter()
-    .append("g")
-      .attr("class", "cluster")
-      .style("opacity", 0)
-      .append("rect");
-  util.applyTransition(svgClusters.exit(), g)
-    .style("opacity", 0)
-    .remove();
-
-  util.applyTransition(svgClusters, g)
-    .style("opacity", 1);
-
-  svgClusters.each(function(v) {
-    var node = g.node(v),
-        thisGroup = d3.select(this),
-        labelGroup = thisGroup.append("g").attr("class", "label");
-    addLabel(labelGroup, node, node.clusterLabelPos);
-  });
-
-  svgClusters.selectAll("rect").each(function(c) {
-    var node = g.node(c);
-    var domCluster = d3.select(this);
-    util.applyStyle(domCluster, node.style);
-  });
-}
-
-},{"./label/add-label":18,"./util":27}],4:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash"),
-    addLabel = require("./label/add-label"),
-    util = require("./util"),
-    d3 = require("./d3");
-
-module.exports = createEdgeLabels;
-
-function createEdgeLabels(selection, g) {
-  var svgEdgeLabels = selection.selectAll("g.edgeLabel")
-    .data(g.edges(), function(e) { return util.edgeToId(e); })
-    .classed("update", true);
-
-  svgEdgeLabels.selectAll("*").remove();
-  svgEdgeLabels.enter()
-    .append("g")
-      .classed("edgeLabel", true)
-      .style("opacity", 0);
-  svgEdgeLabels.each(function(e) {
-    var edge = g.edge(e),
-        label = addLabel(d3.select(this), g.edge(e), 0, 0).classed("label", true),
-        bbox = label.node().getBBox();
-
-    if (edge.labelId) { label.attr("id", edge.labelId); }
-    if (!_.has(edge, "width")) { edge.width = bbox.width; }
-    if (!_.has(edge, "height")) { edge.height = bbox.height; }
-  });
-
-  util.applyTransition(svgEdgeLabels.exit(), g)
-    .style("opacity", 0)
-    .remove();
-
-  return svgEdgeLabels;
-}
-
-},{"./d3":7,"./label/add-label":18,"./lodash":21,"./util":27}],5:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash"),
-    intersectNode = require("./intersect/intersect-node"),
-    util = require("./util"),
-    d3 = require("./d3");
-
-module.exports = createEdgePaths;
-
-function createEdgePaths(selection, g, arrows) {
-  var svgPaths = selection.selectAll("g.edgePath")
-    .data(g.edges(), function(e) { return util.edgeToId(e); })
-    .classed("update", true);
-
-  enter(svgPaths, g);
-  exit(svgPaths, g);
-
-  util.applyTransition(svgPaths, g)
-    .style("opacity", 1);
-
-  // Save DOM element in the path group, and set ID and class
-  svgPaths.each(function(e) {
-    var domEdge = d3.select(this);
-    var edge = g.edge(e);
-    edge.elem = this;
-
-    if (edge.id) {
-      domEdge.attr("id", edge.id);
-    }
-
-    util.applyClass(domEdge, edge["class"],
-      (domEdge.classed("update") ? "update " : "") + "edgePath");
-  });
-
-  svgPaths.selectAll("path.path")
-    .each(function(e) {
-      var edge = g.edge(e);
-      edge.arrowheadId = _.uniqueId("arrowhead");
-
-      var domEdge = d3.select(this)
-        .attr("marker-end", function() {
-          return "url(#" + edge.arrowheadId + ")";
-        })
-        .style("fill", "none");
-
-      util.applyTransition(domEdge, g)
-        .attr("d", function(e) { return calcPoints(g, e); });
-
-      util.applyStyle(domEdge, edge.style);
-    });
-
-  svgPaths.selectAll("defs *").remove();
-  svgPaths.selectAll("defs")
-    .each(function(e) {
-      var edge = g.edge(e),
-          arrowhead = arrows[edge.arrowhead];
-      arrowhead(d3.select(this), edge.arrowheadId, edge, "arrowhead");
-    });
-
-  return svgPaths;
-}
-
-function calcPoints(g, e) {
-  var edge = g.edge(e),
-      tail = g.node(e.v),
-      head = g.node(e.w),
-      points = edge.points.slice(1, edge.points.length - 1);
-  points.unshift(intersectNode(tail, points[0]));
-  points.push(intersectNode(head, points[points.length - 1]));
-
-  return createLine(edge, points);
-}
-
-function createLine(edge, points) {
-  var line = d3.svg.line()
-    .x(function(d) { return d.x; })
-    .y(function(d) { return d.y; });
-
-  if (_.has(edge, "lineInterpolate")) {
-    line.interpolate(edge.lineInterpolate);
-  }
-
-  if (_.has(edge, "lineTension")) {
-    line.tension(Number(edge.lineTension));
-  }
-
-  return line(points);
-}
-
-function getCoords(elem) {
-  var bbox = elem.getBBox(),
-      matrix = elem.getTransformToElement(elem.ownerSVGElement)
-        .translate(bbox.width / 2, bbox.height / 2);
-  return { x: matrix.e, y: matrix.f };
-}
-
-function enter(svgPaths, g) {
-  var svgPathsEnter = svgPaths.enter()
-    .append("g")
-      .attr("class", "edgePath")
-      .style("opacity", 0);
-  svgPathsEnter.append("path")
-    .attr("class", "path")
-    .attr("d", function(e) {
-      var edge = g.edge(e),
-          sourceElem = g.node(e.v).elem,
-          points = _.range(edge.points.length).map(function() { return getCoords(sourceElem); });
-      return createLine(edge, points);
-    });
-  svgPathsEnter.append("defs");
-}
-
-function exit(svgPaths, g) {
-  var svgPathExit = svgPaths.exit();
-  util.applyTransition(svgPathExit, g)
-    .style("opacity", 0)
-    .remove();
-
-  util.applyTransition(svgPathExit.select("path.path"), g)
-    .attr("d", function(e) {
-      var source = g.node(e.v);
-
-      if (source) {
-        var points = _.range(this.pathSegList.length).map(function() { return source; });
-        return createLine({}, points);
-      } else {
-        return d3.select(this).attr("d");
-      }
-    });
-}
-
-},{"./d3":7,"./intersect/intersect-node":14,"./lodash":21,"./util":27}],6:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash"),
-    addLabel = require("./label/add-label"),
-    util = require("./util"),
-    d3 = require("./d3");
-
-module.exports = createNodes;
-
-function createNodes(selection, g, shapes) {
-  var simpleNodes = g.nodes().filter(function(v) { return !util.isSubgraph(g, v); });
-  var svgNodes = selection.selectAll("g.node")
-    .data(simpleNodes, function(v) { return v; })
-    .classed("update", true);
-
-  svgNodes.selectAll("*").remove();
-  svgNodes.enter()
-    .append("g")
-      .attr("class", "node")
-      .style("opacity", 0);
-  svgNodes.each(function(v) {
-    var node = g.node(v),
-        thisGroup = d3.select(this),
-        labelGroup = thisGroup.append("g").attr("class", "label"),
-        labelDom = addLabel(labelGroup, node),
-        shape = shapes[node.shape],
-        bbox = _.pick(labelDom.node().getBBox(), "width", "height");
-
-    node.elem = this;
-
-    if (node.id) { thisGroup.attr("id", node.id); }
-    if (node.labelId) { labelGroup.attr("id", node.labelId); }
-    util.applyClass(thisGroup, node["class"],
-      (thisGroup.classed("update") ? "update " : "") + "node");
-
-    if (_.has(node, "width")) { bbox.width = node.width; }
-    if (_.has(node, "height")) { bbox.height = node.height; }
-
-    bbox.width += node.paddingLeft + node.paddingRight;
-    bbox.height += node.paddingTop + node.paddingBottom;
-    labelGroup.attr("transform", "translate(" +
-      ((node.paddingLeft - node.paddingRight) / 2) + "," +
-      ((node.paddingTop - node.paddingBottom) / 2) + ")");
-
-    var shapeSvg = shape(d3.select(this), bbox, node);
-    util.applyStyle(shapeSvg, node.style);
-
-    var shapeBBox = shapeSvg.node().getBBox();
-    node.width = shapeBBox.width;
-    node.height = shapeBBox.height;
-  });
-
-  util.applyTransition(svgNodes.exit(), g)
-    .style("opacity", 0)
-    .remove();
-
-  return svgNodes;
-}
-
-},{"./d3":7,"./label/add-label":18,"./lodash":21,"./util":27}],7:[function(require,module,exports){
-// Stub to get D3 either via NPM or from the global object
-module.exports = window.d3;
-
-},{}],8:[function(require,module,exports){
-/* global window */
-
-var dagre;
-
-if (require) {
-  try {
-    dagre = require("dagre");
-  } catch (e) {}
-}
-
-if (!dagre) {
-  dagre = window.dagre;
-}
-
-module.exports = dagre;
-
-},{"dagre":29}],9:[function(require,module,exports){
-/* global window */
-
-var graphlib;
-
-if (require) {
-  try {
-    graphlib = require("graphlib");
-  } catch (e) {}
-}
-
-if (!graphlib) {
-  graphlib = window.graphlib;
-}
-
-module.exports = graphlib;
-
-},{"graphlib":60}],10:[function(require,module,exports){
-module.exports = {
-  node: require("./intersect-node"),
-  circle: require("./intersect-circle"),
-  ellipse: require("./intersect-ellipse"),
-  polygon: require("./intersect-polygon"),
-  rect: require("./intersect-rect")
-};
-
-},{"./intersect-circle":11,"./intersect-ellipse":12,"./intersect-node":14,"./intersect-polygon":15,"./intersect-rect":16}],11:[function(require,module,exports){
-var intersectEllipse = require("./intersect-ellipse");
-
-module.exports = intersectCircle;
-
-function intersectCircle(node, rx, point) {
-  return intersectEllipse(node, rx, rx, point);
-}
-
-},{"./intersect-ellipse":12}],12:[function(require,module,exports){
-module.exports = intersectEllipse;
-
-function intersectEllipse(node, rx, ry, point) {
-  // Formulae from: http://mathworld.wolfram.com/Ellipse-LineIntersection.html
-
-  var cx = node.x;
-  var cy = node.y;
-
-  var px = cx - point.x;
-  var py = cy - point.y;
-
-  var det = Math.sqrt(rx * rx * py * py + ry * ry * px * px);
-
-  var dx = Math.abs(rx * ry * px / det);
-  if (point.x < cx) {
-    dx = -dx;
-  }
-  var dy = Math.abs(rx * ry * py / det);
-  if (point.y < cy) {
-    dy = -dy;
-  }
-
-  return {x: cx + dx, y: cy + dy};
-}
-
-
-},{}],13:[function(require,module,exports){
-module.exports = intersectLine;
-
-/*
- * Returns the point at which two lines, p and q, intersect or returns
- * undefined if they do not intersect.
- */
-function intersectLine(p1, p2, q1, q2) {
-  // Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
-  // p7 and p473.
-
-  var a1, a2, b1, b2, c1, c2;
-  var r1, r2 , r3, r4;
-  var denom, offset, num;
-  var x, y;
-
-  // Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
-  // b1 y + c1 = 0.
-  a1 = p2.y - p1.y;
-  b1 = p1.x - p2.x;
-  c1 = (p2.x * p1.y) - (p1.x * p2.y);
-
-  // Compute r3 and r4.
-  r3 = ((a1 * q1.x) + (b1 * q1.y) + c1);
-  r4 = ((a1 * q2.x) + (b1 * q2.y) + c1);
-
-  // Check signs of r3 and r4. If both point 3 and point 4 lie on
-  // same side of line 1, the line segments do not intersect.
-  if ((r3 !== 0) && (r4 !== 0) && sameSign(r3, r4)) {
-    return /*DONT_INTERSECT*/;
-  }
-
-  // Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
-  a2 = q2.y - q1.y;
-  b2 = q1.x - q2.x;
-  c2 = (q2.x * q1.y) - (q1.x * q2.y);
-
-  // Compute r1 and r2
-  r1 = (a2 * p1.x) + (b2 * p1.yy) + c2;
-  r2 = (a2 * p2.x) + (b2 * p2.y) + c2;
-
-  // Check signs of r1 and r2. If both point 1 and point 2 lie
-  // on same side of second line segment, the line segments do
-  // not intersect.
-  if ((r1 !== 0) && (r2 !== 0) && (sameSign(r1, r2))) {
-    return /*DONT_INTERSECT*/;
-  }
-
-  // Line segments intersect: compute intersection point.
-  denom = (a1 * b2) - (a2 * b1);
-  if (denom === 0) {
-    return /*COLLINEAR*/;
-  }
-
-  offset = Math.abs(denom / 2);
-
-  // The denom/2 is to get rounding instead of truncating. It
-  // is added or subtracted to the numerator, depending upon the
-  // sign of the numerator.
-  num = (b1 * c2) - (b2 * c1);
-  x = (num < 0) ? ((num - offset) / denom) : ((num + offset) / denom);
-
-  num = (a2 * c1) - (a1 * c2);
-  y = (num < 0) ? ((num - offset) / denom) : ((num + offset) / denom);
-
-  return { x: x, y: y };
-}
-
-function sameSign(r1, r2) {
-  return r1 * r2 > 0;
-}
-
-},{}],14:[function(require,module,exports){
-module.exports = intersectNode;
-
-function intersectNode(node, point) {
-  return node.intersect(point);
-}
-
-},{}],15:[function(require,module,exports){
-var intersectLine = require("./intersect-line");
-
-module.exports = intersectPolygon;
-
-/*
- * Returns the point ({x, y}) at which the point argument intersects with the
- * node argument assuming that it has the shape specified by polygon.
- */
-function intersectPolygon(node, polyPoints, point) {
-  var x1 = node.x;
-  var y1 = node.y;
-
-  var intersections = [];
-
-  var minX = Number.POSITIVE_INFINITY,
-      minY = Number.POSITIVE_INFINITY;
-  polyPoints.forEach(function(entry) {
-    minX = Math.min(minX, entry.x);
-    minY = Math.min(minY, entry.y);
-  });
-
-  var left = x1 - node.width / 2 - minX;
-  var top =  y1 - node.height / 2 - minY;
-
-  for (var i = 0; i < polyPoints.length; i++) {
-    var p1 = polyPoints[i];
-    var p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
-    var intersect = intersectLine(node, point,
-      {x: left + p1.x, y: top + p1.y}, {x: left + p2.x, y: top + p2.y});
-    if (intersect) {
-      intersections.push(intersect);
-    }
-  }
-
-  if (!intersections.length) {
-    console.log("NO INTERSECTION FOUND, RETURN NODE CENTER", node);
-    return node;
-  }
-
-  if (intersections.length > 1) {
-    // More intersections, find the one nearest to edge end point
-    intersections.sort(function(p, q) {
-      var pdx = p.x - point.x,
-          pdy = p.y - point.y,
-          distp = Math.sqrt(pdx * pdx + pdy * pdy),
-
-          qdx = q.x - point.x,
-          qdy = q.y - point.y,
-          distq = Math.sqrt(qdx * qdx + qdy * qdy);
-
-      return (distp < distq) ? -1 : (distp === distq ? 0 : 1);
-    });
-  }
-  return intersections[0];
-}
-
-},{"./intersect-line":13}],16:[function(require,module,exports){
-module.exports = intersectRect;
-
-function intersectRect(node, point) {
-  var x = node.x;
-  var y = node.y;
-
-  // Rectangle intersection algorithm from:
-  // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
-  var dx = point.x - x;
-  var dy = point.y - y;
-  var w = node.width / 2;
-  var h = node.height / 2;
-
-  var sx, sy;
-  if (Math.abs(dy) * w > Math.abs(dx) * h) {
-    // Intersection is top or bottom of rect.
-    if (dy < 0) {
-      h = -h;
-    }
-    sx = dy === 0 ? 0 : h * dx / dy;
-    sy = h;
-  } else {
-    // Intersection is left or right of rect.
-    if (dx < 0) {
-      w = -w;
-    }
-    sx = w;
-    sy = dx === 0 ? 0 : w * dy / dx;
-  }
-
-  return {x: x + sx, y: y + sy};
-}
-
-},{}],17:[function(require,module,exports){
-var util = require("../util");
-
-module.exports = addHtmlLabel;
-
-function addHtmlLabel(root, node) {
-  var fo = root
-    .append("foreignObject")
-      .attr("width", "100000");
-
-  var div = fo
-    .append("xhtml:div");
-
-  var label = node.label;
-  switch(typeof label) {
-    case "function":
-      div.insert(label);
-      break;
-    case "object":
-      // Currently we assume this is a DOM object.
-      div.insert(function() { return label; });
-      break;
-    default: div.html(label);
-  }
-
-  util.applyStyle(div, node.labelStyle);
-  div.style("display", "inline-block");
-  // Fix for firefox
-  div.style("white-space", "nowrap");
-
-  // TODO find a better way to get dimensions for foreignObjects...
-  var w, h;
-  div
-    .each(function() {
-      w = this.clientWidth;
-      h = this.clientHeight;
-    });
-
-  fo
-    .attr("width", w)
-    .attr("height", h);
-
-  return fo;
-}
-
-},{"../util":27}],18:[function(require,module,exports){
-var addTextLabel = require("./add-text-label"),
-    addHtmlLabel = require("./add-html-label"),
-    addSVGLabel  = require("./add-svg-label");
-
-module.exports = addLabel;
-
-function addLabel(root, node, location) {
-  var label = node.label;
-  var labelSvg = root.append("g");
-
-  // Allow the label to be a string, a function that returns a DOM element, or
-  // a DOM element itself.
-  if (node.labelType === "svg") {
-    addSVGLabel(labelSvg, node);
-  } else if (typeof label !== "string" || node.labelType === "html") {
-    addHtmlLabel(labelSvg, node);
-  } else {
-    addTextLabel(labelSvg, node);
-  }
-
-  var labelBBox = labelSvg.node().getBBox();
-  switch(location) {
-    case "top":
-      y = (-node.height / 2);
-      break;
-    case "bottom":
-      y = (node.height / 2) - labelBBox.height;
-      break;
-    default:
-      y = (-labelBBox.height / 2);
-  }
-  labelSvg.attr("transform",
-                "translate(" + (-labelBBox.width / 2) + "," + y + ")");
-
-  return labelSvg;
-}
-
-},{"./add-html-label":17,"./add-svg-label":19,"./add-text-label":20}],19:[function(require,module,exports){
-var util = require("../util");
-
-module.exports = addSVGLabel;
-
-function addSVGLabel(root, node) {
-  var domNode = root;
-
-  domNode.node().appendChild(node.label);
-
-  util.applyStyle(domNode, node.labelStyle);
-
-  return domNode;
-}
-
-},{"../util":27}],20:[function(require,module,exports){
-var util = require("../util");
-
-module.exports = addTextLabel;
-
-/*
- * Attaches a text label to the specified root. Handles escape sequences.
- */
-function addTextLabel(root, node) {
-  var domNode = root.append("text");
-
-  var lines = processEscapeSequences(node.label).split("\n");
-  for (var i = 0; i < lines.length; i++) {
-    domNode
-      .append("tspan")
-        .attr("xml:space", "preserve")
-        .attr("dy", "1em")
-        .attr("x", "1")
-        .text(lines[i]);
-  }
-
-  util.applyStyle(domNode, node.labelStyle);
-
-  return domNode;
-}
-
-function processEscapeSequences(text) {
-  var newText = "",
-      escaped = false,
-      ch;
-  for (var i = 0; i < text.length; ++i) {
-    ch = text[i];
-    if (escaped) {
-      switch(ch) {
-        case "n": newText += "\n"; break;
-        default: newText += ch;
-      }
-      escaped = false;
-    } else if (ch === "\\") {
-      escaped = true;
-    } else {
-      newText += ch;
-    }
-  }
-  return newText;
-}
-
-},{"../util":27}],21:[function(require,module,exports){
-/* global window */
-
-var lodash;
-
-if (require) {
-  try {
-    lodash = require("lodash");
-  } catch (e) {}
-}
-
-if (!lodash) {
-  lodash = window._;
-}
-
-module.exports = lodash;
-
-},{"lodash":81}],22:[function(require,module,exports){
-"use strict";
-
-var util = require("./util"),
-    d3 = require("./d3");
-
-module.exports = positionClusters;
-
-function positionClusters(selection, g) {
-  var created = selection.filter(function() { return !d3.select(this).classed("update"); });
-
-  function translate(v) {
-    var node = g.node(v);
-    return "translate(" + node.x + "," + node.y + ")";
-  }
-
-  created.attr("transform", translate);
-
-  util.applyTransition(selection, g)
-      .style("opacity", 1)
-      .attr("transform", translate);
-
-  util.applyTransition(created.selectAll("rect"), g)
-      .attr("width", function(v) { return g.node(v).width; })
-      .attr("height", function(v) { return g.node(v).height; })
-      .attr("x", function(v) {
-        var node = g.node(v);
-        return -node.width / 2;
-      })
-      .attr("y", function(v) {
-        var node = g.node(v);
-        return -node.height / 2;
-      });
-
-}
-
-},{"./d3":7,"./util":27}],23:[function(require,module,exports){
-"use strict";
-
-var util = require("./util"),
-    d3 = require("./d3"),
-    _ = require("./lodash");
-
-module.exports = positionEdgeLabels;
-
-function positionEdgeLabels(selection, g) {
-  var created = selection.filter(function() { return !d3.select(this).classed("update"); });
-
-  function translate(e) {
-    var edge = g.edge(e);
-    return _.has(edge, "x") ? "translate(" + edge.x + "," + edge.y + ")" : "";
-  }
-
-  created.attr("transform", translate);
-
-  util.applyTransition(selection, g)
-    .style("opacity", 1)
-    .attr("transform", translate);
-}
-
-},{"./d3":7,"./lodash":21,"./util":27}],24:[function(require,module,exports){
-"use strict";
-
-var util = require("./util"),
-    d3 = require("./d3");
-
-module.exports = positionNodes;
-
-function positionNodes(selection, g) {
-  var created = selection.filter(function() { return !d3.select(this).classed("update"); });
-
-  function translate(v) {
-    var node = g.node(v);
-    return "translate(" + node.x + "," + node.y + ")";
-  }
-
-  created.attr("transform", translate);
-
-  util.applyTransition(selection, g)
-    .style("opacity", 1)
-    .attr("transform", translate);
-}
-
-},{"./d3":7,"./util":27}],25:[function(require,module,exports){
-var _ = require("./lodash"),
-    layout = require("./dagre").layout;
-
-module.exports = render;
-
-// This design is based on http://bost.ocks.org/mike/chart/.
-function render() {
-  var createNodes = require("./create-nodes"),
-      createClusters = require("./create-clusters"),
-      createEdgeLabels = require("./create-edge-labels"),
-      createEdgePaths = require("./create-edge-paths"),
-      positionNodes = require("./position-nodes"),
-      positionEdgeLabels = require("./position-edge-labels"),
-      positionClusters = require("./position-clusters"),
-      shapes = require("./shapes"),
-      arrows = require("./arrows");
-
-  var fn = function(svg, g) {
-    preProcessGraph(g);
-
-    var outputGroup = createOrSelectGroup(svg, "output"),
-        clustersGroup = createOrSelectGroup(outputGroup, "clusters"),
-        edgePathsGroup = createOrSelectGroup(outputGroup, "edgePaths"),
-        edgeLabels = createEdgeLabels(createOrSelectGroup(outputGroup, "edgeLabels"), g),
-        nodes = createNodes(createOrSelectGroup(outputGroup, "nodes"), g, shapes);
-
-    layout(g);
-
-    positionNodes(nodes, g);
-    positionEdgeLabels(edgeLabels, g);
-    createEdgePaths(edgePathsGroup, g, arrows);
-    createClusters(clustersGroup, g);
-    positionClusters(clustersGroup.selectAll("g.cluster"), g);
-
-    postProcessGraph(g);
-  };
-
-  fn.createNodes = function(value) {
-    if (!arguments.length) return createNodes;
-    createNodes = value;
-    return fn;
-  };
-
-  fn.createClusters = function(value) {
-    if (!arguments.length) return createClusters;
-    createClusters = value;
-    return fn;
-  };
-
-  fn.createEdgeLabels = function(value) {
-    if (!arguments.length) return createEdgeLabels;
-    createEdgeLabels = value;
-    return fn;
-  };
-
-  fn.createEdgePaths = function(value) {
-    if (!arguments.length) return createEdgePaths;
-    createEdgePaths = value;
-    return fn;
-  };
-
-  fn.shapes = function(value) {
-    if (!arguments.length) return shapes;
-    shapes = value;
-    return fn;
-  };
-
-  fn.arrows = function(value) {
-    if (!arguments.length) return arrows;
-    arrows = value;
-    return fn;
-  };
-
-  return fn;
-}
-
-var NODE_DEFAULT_ATTRS = {
-  paddingLeft: 10,
-  paddingRight: 10,
-  paddingTop: 10,
-  paddingBottom: 10,
-  rx: 0,
-  ry: 0,
-  shape: "rect"
-};
-
-var EDGE_DEFAULT_ATTRS = {
-  arrowhead: "normal",
-  lineInterpolate: "linear"
-};
-
-function preProcessGraph(g) {
-  g.nodes().forEach(function(v) {
-    var node = g.node(v);
-    if (!_.has(node, "label")) { node.label = v; }
-
-    if (_.has(node, "paddingX")) {
-      _.defaults(node, {
-        paddingLeft: node.paddingX,
-        paddingRight: node.paddingX
-      });
-    }
-
-    if (_.has(node, "paddingY")) {
-      _.defaults(node, {
-        paddingTop: node.paddingY,
-        paddingBottom: node.paddingY
-      });
-    }
-
-    if (_.has(node, "padding")) {
-      _.defaults(node, {
-        paddingLeft: node.padding,
-        paddingRight: node.padding,
-        paddingTop: node.padding,
-        paddingBottom: node.padding
-      });
-    }
-
-    _.defaults(node, NODE_DEFAULT_ATTRS);
-
-    _.each(["paddingLeft", "paddingRight", "paddingTop", "paddingBottom"], function(k) {
-      node[k] = Number(node[k]);
-    });
-
-    // Save dimensions for restore during post-processing
-    if (_.has(node, "width")) { node._prevWidth = node.width; }
-    if (_.has(node, "height")) { node._prevHeight = node.height; }
-  });
-
-  g.edges().forEach(function(e) {
-    var edge = g.edge(e);
-    if (!_.has(edge, "label")) { edge.label = ""; }
-    _.defaults(edge, EDGE_DEFAULT_ATTRS);
-  });
-}
-
-function postProcessGraph(g) {
-  _.each(g.nodes(), function(v) {
-    var node = g.node(v);
-
-    // Restore original dimensions
-    if (_.has(node, "_prevWidth")) {
-      node.width = node._prevWidth;
-    } else {
-      delete node.width;
-    }
-
-    if (_.has(node, "_prevHeight")) {
-      node.height = node._prevHeight;
-    } else {
-      delete node.height;
-    }
-
-    delete node._prevWidth;
-    delete node._prevHeight;
-  });
-}
-
-function createOrSelectGroup(root, name) {
-  var selection = root.select("g." + name);
-  if (selection.empty()) {
-    selection = root.append("g").attr("class", name);
-  }
-  return selection;
-}
-
-},{"./arrows":2,"./create-clusters":3,"./create-edge-labels":4,"./create-edge-paths":5,"./create-nodes":6,"./dagre":8,"./lodash":21,"./position-clusters":22,"./position-edge-labels":23,"./position-nodes":24,"./shapes":26}],26:[function(require,module,exports){
-"use strict";
-
-var intersectRect = require("./intersect/intersect-rect"),
-    intersectEllipse = require("./intersect/intersect-ellipse"),
-    intersectCircle = require("./intersect/intersect-circle"),
-    intersectPolygon = require("./intersect/intersect-polygon");
-
-module.exports = {
-  rect: rect,
-  ellipse: ellipse,
-  circle: circle,
-  diamond: diamond
-};
-
-function rect(parent, bbox, node) {
-  var shapeSvg = parent.insert("rect", ":first-child")
-        .attr("rx", node.rx)
-        .attr("ry", node.ry)
-        .attr("x", -bbox.width / 2)
-        .attr("y", -bbox.height / 2)
-        .attr("width", bbox.width)
-        .attr("height", bbox.height);
-
-  node.intersect = function(point) {
-    return intersectRect(node, point);
-  };
-
-  return shapeSvg;
-}
-
-function ellipse(parent, bbox, node) {
-  var rx = bbox.width / 2,
-      ry = bbox.height / 2,
-      shapeSvg = parent.insert("ellipse", ":first-child")
-        .attr("x", -bbox.width / 2)
-        .attr("y", -bbox.height / 2)
-        .attr("rx", rx)
-        .attr("ry", ry);
-
-  node.intersect = function(point) {
-    return intersectEllipse(node, rx, ry, point);
-  };
-
-  return shapeSvg;
-}
-
-function circle(parent, bbox, node) {
-  var r = Math.max(bbox.width, bbox.height) / 2,
-      shapeSvg = parent.insert("circle", ":first-child")
-        .attr("x", -bbox.width / 2)
-        .attr("y", -bbox.height / 2)
-        .attr("r", r);
-
-  node.intersect = function(point) {
-    return intersectCircle(node, r, point);
-  };
-
-  return shapeSvg;
-}
-
-// Circumscribe an ellipse for the bounding box with a diamond shape. I derived
-// the function to calculate the diamond shape from:
-// http://mathforum.org/kb/message.jspa?messageID=3750236
-function diamond(parent, bbox, node) {
-  var w = (bbox.width * Math.SQRT2) / 2,
-      h = (bbox.height * Math.SQRT2) / 2,
-      points = [
-        { x:  0, y: -h },
-        { x: -w, y:  0 },
-        { x:  0, y:  h },
-        { x:  w, y:  0 }
-      ],
-      shapeSvg = parent.insert("polygon", ":first-child")
-        .attr("points", points.map(function(p) { return p.x + "," + p.y; }).join(" "));
-
-  node.intersect = function(p) {
-    return intersectPolygon(node, points, p);
-  };
-
-  return shapeSvg;
-}
-
-},{"./intersect/intersect-circle":11,"./intersect/intersect-ellipse":12,"./intersect/intersect-polygon":15,"./intersect/intersect-rect":16}],27:[function(require,module,exports){
-var _ = require("./lodash");
-
-// Public utility functions
-module.exports = {
-  isSubgraph: isSubgraph,
-  edgeToId: edgeToId,
-  applyStyle: applyStyle,
-  applyClass: applyClass,
-  applyTransition: applyTransition
-};
-
-/*
- * Returns true if the specified node in the graph is a subgraph node. A
- * subgraph node is one that contains other nodes.
- */
-function isSubgraph(g, v) {
-  return !!g.children(v).length;
-}
-
-function edgeToId(e) {
-  return escapeId(e.v) + ":" + escapeId(e.w) + ":" + escapeId(e.name);
-}
-
-var ID_DELIM = /:/g;
-function escapeId(str) {
-  return str ? String(str).replace(ID_DELIM, "\\:") : "";
-}
-
-function applyStyle(dom, styleFn) {
-  if (styleFn) {
-    dom.attr("style", styleFn);
-  }
-}
-
-function applyClass(dom, classFn, otherClasses) {
-  if (classFn) {
-    dom
-      .attr("class", classFn)
-      .attr("class", otherClasses + " " + dom.attr("class"));
-  }
-}
-
-function applyTransition(selection, g) {
-  var graph = g.graph();
-
-  if (_.isPlainObject(graph)) {
-    var transition = graph.transition;
-    if (_.isFunction(transition)) {
-      return transition(selection);
-    }
-  }
-
-  return selection;
-}
-
-},{"./lodash":21}],28:[function(require,module,exports){
-module.exports = "0.4.5";
-
-},{}],29:[function(require,module,exports){
-/*
-Copyright (c) 2012-2014 Chris Pettitt
-
-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.
-*/
-
-module.exports = {
-  graphlib: require("./lib/graphlib"),
-
-  layout: require("./lib/layout"),
-  debug: require("./lib/debug"),
-  util: {
-    time: require("./lib/util").time,
-    notime: require("./lib/util").notime
-  },
-  version: require("./lib/version")
-};
-
-},{"./lib/debug":34,"./lib/graphlib":35,"./lib/layout":37,"./lib/util":57,"./lib/version":58}],30:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash"),
-    greedyFAS = require("./greedy-fas");
-
-module.exports = {
-  run: run,
-  undo: undo
-};
-
-function run(g) {
-  var fas = (g.graph().acyclicer === "greedy"
-                ? greedyFAS(g, weightFn(g))
-                : dfsFAS(g));
-  _.each(fas, function(e) {
-    var label = g.edge(e);
-    g.removeEdge(e);
-    label.forwardName = e.name;
-    label.reversed = true;
-    g.setEdge(e.w, e.v, label, _.uniqueId("rev"));
-  });
-
-  function weightFn(g) {
-    return function(e) {
-      return g.edge(e).weight;
-    };
-  }
-}
-
-function dfsFAS(g) {
-  var fas = [],
-      stack = {},
-      visited = {};
-
-  function dfs(v) {
-    if (_.has(visited, v)) {
-      return;
-    }
-    visited[v] = true;
-    stack[v] = true;
-    _.each(g.outEdges(v), function(e) {
-      if (_.has(stack, e.w)) {
-        fas.push(e);
-      } else {
-        dfs(e.w);
-      }
-    });
-    delete stack[v];
-  }
-
-  _.each(g.nodes(), dfs);
-  return fas;
-}
-
-function undo(g) {
-  _.each(g.edges(), function(e) {
-    var label = g.edge(e);
-    if (label.reversed) {
-      g.removeEdge(e);
-
-      var forwardName = label.forwardName;
-      delete label.reversed;
-      delete label.forwardName;
-      g.setEdge(e.w, e.v, label, forwardName);
-    }
-  });
-}
-
-},{"./greedy-fas":36,"./lodash":38}],31:[function(require,module,exports){
-var _ = require("./lodash"),
-    util = require("./util");
-
-module.exports = addBorderSegments;
-
-function addBorderSegments(g) {
-  function dfs(v) {
-    var children = g.children(v),
-        node = g.node(v);
-    if (children.length) {
-      _.each(children, dfs);
-    }
-
-    if (_.has(node, "minRank")) {
-      node.borderLeft = [];
-      node.borderRight = [];
-      for (var rank = node.minRank, maxRank = node.maxRank + 1;
-           rank < maxRank;
-           ++rank) {
-        addBorderNode(g, "borderLeft", "_bl", v, node, rank);
-        addBorderNode(g, "borderRight", "_br", v, node, rank);
-      }
-    }
-  }
-
-  _.each(g.children(), dfs);
-}
-
-function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
-  var label = { width: 0, height: 0, rank: rank, borderType: prop },
-      prev = sgNode[prop][rank - 1],
-      curr = util.addDummyNode(g, "border", label, prefix);
-  sgNode[prop][rank] = curr;
-  g.setParent(curr, sg);
-  if (prev) {
-    g.setEdge(prev, curr, { weight: 1 });
-  }
-}
-
-},{"./lodash":38,"./util":57}],32:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash");
-
-module.exports = {
-  adjust: adjust,
-  undo: undo
-};
-
-function adjust(g) {
-  var rankDir = g.graph().rankdir.toLowerCase();
-  if (rankDir === "lr" || rankDir === "rl") {
-    swapWidthHeight(g);
-  }
-}
-
-function undo(g) {
-  var rankDir = g.graph().rankdir.toLowerCase();
-  if (rankDir === "bt" || rankDir === "rl") {
-    reverseY(g);
-  }
-
-  if (rankDir === "lr" || rankDir === "rl") {
-    swapXY(g);
-    swapWidthHeight(g);
-  }
-}
-
-function swapWidthHeight(g) {
-  _.each(g.nodes(), function(v) { swapWidthHeightOne(g.node(v)); });
-  _.each(g.edges(), function(e) { swapWidthHeightOne(g.edge(e)); });
-}
-
-function swapWidthHeightOne(attrs) {
-  var w = attrs.width;
-  attrs.width = attrs.height;
-  attrs.height = w;
-}
-
-function reverseY(g) {
-  _.each(g.nodes(), function(v) { reverseYOne(g.node(v)); });
-
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    _.each(edge.points, reverseYOne);
-    if (_.has(edge, "y")) {
-      reverseYOne(edge);
-    }
-  });
-}
-
-function reverseYOne(attrs) {
-  attrs.y = -attrs.y;
-}
-
-function swapXY(g) {
-  _.each(g.nodes(), function(v) { swapXYOne(g.node(v)); });
-
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    _.each(edge.points, swapXYOne);
-    if (_.has(edge, "x")) {
-      swapXYOne(edge);
-    }
-  });
-}
-
-function swapXYOne(attrs) {
-  var x = attrs.x;
-  attrs.x = attrs.y;
-  attrs.y = x;
-}
-
-},{"./lodash":38}],33:[function(require,module,exports){
-/*
- * Simple doubly linked list implementation derived from Cormen, et al.,
- * "Introduction to Algorithms".
- */
-
-module.exports = List;
-
-function List() {
-  var sentinel = {};
-  sentinel._next = sentinel._prev = sentinel;
-  this._sentinel = sentinel;
-}
-
-List.prototype.dequeue = function() {
-  var sentinel = this._sentinel,
-      entry = sentinel._prev;
-  if (entry !== sentinel) {
-    unlink(entry);
-    return entry;
-  }
-};
-
-List.prototype.enqueue = function(entry) {
-  var sentinel = this._sentinel;
-  if (entry._prev && entry._next) {
-    unlink(entry);
-  }
-  entry._next = sentinel._next;
-  sentinel._next._prev = entry;
-  sentinel._next = entry;
-  entry._prev = sentinel;
-};
-
-List.prototype.toString = function() {
-  var strs = [],
-      sentinel = this._sentinel,
-      curr = sentinel._prev;
-  while (curr !== sentinel) {
-    strs.push(JSON.stringify(curr, filterOutLinks));
-    curr = curr._prev;
-  }
-  return "[" + strs.join(", ") + "]";
-};
-
-function unlink(entry) {
-  entry._prev._next = entry._next;
-  entry._next._prev = entry._prev;
-  delete entry._next;
-  delete entry._prev;
-}
-
-function filterOutLinks(k, v) {
-  if (k !== "_next" && k !== "_prev") {
-    return v;
-  }
-}
-
-},{}],34:[function(require,module,exports){
-var _ = require("./lodash"),
-    util = require("./util"),
-    Graph = require("./graphlib").Graph;
-
-module.exports = {
-  debugOrdering: debugOrdering
-};
-
-/* istanbul ignore next */
-function debugOrdering(g) {
-  var layerMatrix = util.buildLayerMatrix(g);
-
-  var h = new Graph({ compound: true, multigraph: true }).setGraph({});
-
-  _.each(g.nodes(), function(v) {
-    h.setNode(v, { label: v });
-    h.setParent(v, "layer" + g.node(v).rank);
-  });
-
-  _.each(g.edges(), function(e) {
-    h.setEdge(e.v, e.w, {}, e.name);
-  });
-
-  _.each(layerMatrix, function(layer, i) {
-    var layerV = "layer" + i;
-    h.setNode(layerV, { rank: "same" });
-    _.reduce(layer, function(u, v) {
-      h.setEdge(u, v, { style: "invis" });
-      return v;
-    });
-  });
-
-  return h;
-}
-
-},{"./graphlib":35,"./lodash":38,"./util":57}],35:[function(require,module,exports){
-module.exports=require(9)
-},{"/Users/cpettitt/projects/dagre-d3/lib/graphlib.js":9,"graphlib":60}],36:[function(require,module,exports){
-var _ = require("./lodash"),
-    Graph = require("./graphlib").Graph,
-    List = require("./data/list");
-
-/*
- * A greedy heuristic for finding a feedback arc set for a graph. A feedback
- * arc set is a set of edges that can be removed to make a graph acyclic.
- * The algorithm comes from: P. Eades, X. Lin, and W. F. Smyth, "A fast and
- * effective heuristic for the feedback arc set problem." This implementation
- * adjusts that from the paper to allow for weighted edges.
- */
-module.exports = greedyFAS;
-
-var DEFAULT_WEIGHT_FN = _.constant(1);
-
-function greedyFAS(g, weightFn) {
-  if (g.nodeCount() <= 1) {
-    return [];
-  }
-  var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
-  var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
-
-  // Expand multi-edges
-  return _.flatten(_.map(results, function(e) {
-    return g.outEdges(e.v, e.w);
-  }), true);
-}
-
-function doGreedyFAS(g, buckets, zeroIdx) {
-  var results = [],
-      sources = buckets[buckets.length - 1],
-      sinks = buckets[0];
-
-  var entry;
-  while (g.nodeCount()) {
-    while ((entry = sinks.dequeue()))   { removeNode(g, buckets, zeroIdx, entry); }
-    while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
-    if (g.nodeCount()) {
-      for (var i = buckets.length - 2; i > 0; --i) {
-        entry = buckets[i].dequeue();
-        if (entry) {
-          results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
-          break;
-        }
-      }
-    }
-  }
-
-  return results;
-}
-
-function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
-  var results = collectPredecessors ? [] : undefined;
-
-  _.each(g.inEdges(entry.v), function(edge) {
-    var weight = g.edge(edge),
-        uEntry = g.node(edge.v);
-
-    if (collectPredecessors) {
-      results.push({ v: edge.v, w: edge.w });
-    }
-
-    uEntry.out -= weight;
-    assignBucket(buckets, zeroIdx, uEntry);
-  });
-
-  _.each(g.outEdges(entry.v), function(edge) {
-    var weight = g.edge(edge),
-        w = edge.w,
-        wEntry = g.node(w);
-    wEntry["in"] -= weight;
-    assignBucket(buckets, zeroIdx, wEntry);
-  });
-
-  g.removeNode(entry.v);
-
-  return results;
-}
-
-function buildState(g, weightFn) {
-  var fasGraph = new Graph(),
-      maxIn = 0,
-      maxOut = 0;
-
-  _.each(g.nodes(), function(v) {
-    fasGraph.setNode(v, { v: v, "in": 0, out: 0 });
-  });
-
-  // Aggregate weights on nodes, but also sum the weights across multi-edges
-  // into a single edge for the fasGraph.
-  _.each(g.edges(), function(e) {
-    var prevWeight = fasGraph.edge(e.v, e.w) || 0,
-        weight = weightFn(e),
-        edgeWeight = prevWeight + weight;
-    fasGraph.setEdge(e.v, e.w, edgeWeight);
-    maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
-    maxIn  = Math.max(maxIn,  fasGraph.node(e.w)["in"]  += weight);
-  });
-
-  var buckets = _.range(maxOut + maxIn + 3).map(function() { return new List(); });
-  var zeroIdx = maxIn + 1;
-
-  _.each(fasGraph.nodes(), function(v) {
-    assignBucket(buckets, zeroIdx, fasGraph.node(v));
-  });
-
-  return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
-}
-
-function assignBucket(buckets, zeroIdx, entry) {
-  if (!entry.out) {
-    buckets[0].enqueue(entry);
-  } else if (!entry["in"]) {
-    buckets[buckets.length - 1].enqueue(entry);
-  } else {
-    buckets[entry.out - entry["in"] + zeroIdx].enqueue(entry);
-  }
-}
-
-},{"./data/list":33,"./graphlib":35,"./lodash":38}],37:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash"),
-    acyclic = require("./acyclic"),
-    normalize = require("./normalize"),
-    rank = require("./rank"),
-    normalizeRanks = require("./util").normalizeRanks,
-    parentDummyChains = require("./parent-dummy-chains"),
-    removeEmptyRanks = require("./util").removeEmptyRanks,
-    nestingGraph = require("./nesting-graph"),
-    addBorderSegments = require("./add-border-segments"),
-    coordinateSystem = require("./coordinate-system"),
-    order = require("./order"),
-    position = require("./position"),
-    util = require("./util"),
-    Graph = require("./graphlib").Graph;
-
-module.exports = layout;
-
-function layout(g, opts) {
-  var time = opts && opts.debugTiming ? util.time : util.notime;
-  time("layout", function() {
-    var layoutGraph = time("  buildLayoutGraph",
-                               function() { return buildLayoutGraph(g); });
-    time("  runLayout",        function() { runLayout(layoutGraph, time); });
-    time("  updateInputGraph", function() { updateInputGraph(g, layoutGraph); });
-  });
-}
-
-function runLayout(g, time) {
-  time("    makeSpaceForEdgeLabels", function() { makeSpaceForEdgeLabels(g); });
-  time("    removeSelfEdges",        function() { removeSelfEdges(g); });
-  time("    acyclic",                function() { acyclic.run(g); });
-  time("    nestingGraph.run",       function() { nestingGraph.run(g); });
-  time("    rank",                   function() { rank(util.asNonCompoundGraph(g)); });
-  time("    injectEdgeLabelProxies", function() { injectEdgeLabelProxies(g); });
-  time("    removeEmptyRanks",       function() { removeEmptyRanks(g); });
-  time("    nestingGraph.cleanup",   function() { nestingGraph.cleanup(g); });
-  time("    normalizeRanks",         function() { normalizeRanks(g); });
-  time("    assignRankMinMax",       function() { assignRankMinMax(g); });
-  time("    removeEdgeLabelProxies", function() { removeEdgeLabelProxies(g); });
-  time("    normalize.run",          function() { normalize.run(g); });
-  time("    parentDummyChains",      function() { parentDummyChains(g); });
-  time("    addBorderSegments",      function() { addBorderSegments(g); });
-  time("    order",                  function() { order(g); });
-  time("    insertSelfEdges",        function() { insertSelfEdges(g); });
-  time("    adjustCoordinateSystem", function() { coordinateSystem.adjust(g); });
-  time("    position",               function() { position(g); });
-  time("    positionSelfEdges",      function() { positionSelfEdges(g); });
-  time("    removeBorderNodes",      function() { removeBorderNodes(g); });
-  time("    normalize.undo",         function() { normalize.undo(g); });
-  time("    fixupEdgeLabelCoords",   function() { fixupEdgeLabelCoords(g); });
-  time("    undoCoordinateSystem",   function() { coordinateSystem.undo(g); });
-  time("    translateGraph",         function() { translateGraph(g); });
-  time("    assignNodeIntersects",   function() { assignNodeIntersects(g); });
-  time("    reversePoints",          function() { reversePointsForReversedEdges(g); });
-  time("    acyclic.undo",           function() { acyclic.undo(g); });
-}
-
-/*
- * Copies final layout information from the layout graph back to the input
- * graph. This process only copies whitelisted attributes from the layout graph
- * to the input graph, so it serves as a good place to determine what
- * attributes can influence layout.
- */
-function updateInputGraph(inputGraph, layoutGraph) {
-  _.each(inputGraph.nodes(), function(v) {
-    var inputLabel = inputGraph.node(v),
-        layoutLabel = layoutGraph.node(v);
-
-    if (inputLabel) {
-      inputLabel.x = layoutLabel.x;
-      inputLabel.y = layoutLabel.y;
-
-      if (layoutGraph.children(v).length) {
-        inputLabel.width = layoutLabel.width;
-        inputLabel.height = layoutLabel.height;
-      }
-    }
-  });
-
-  _.each(inputGraph.edges(), function(e) {
-    var inputLabel = inputGraph.edge(e),
-        layoutLabel = layoutGraph.edge(e);
-
-    inputLabel.points = layoutLabel.points;
-    if (_.has(layoutLabel, "x")) {
-      inputLabel.x = layoutLabel.x;
-      inputLabel.y = layoutLabel.y;
-    }
-  });
-
-  inputGraph.graph().width = layoutGraph.graph().width;
-  inputGraph.graph().height = layoutGraph.graph().height;
-}
-
-var graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"],
-    graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" },
-    graphAttrs = ["acyclicer", "ranker", "rankdir", "align"],
-    nodeNumAttrs = ["width", "height"],
-    nodeDefaults = { width: 0, height: 0 },
-    edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"],
-    edgeDefaults = {
-      minlen: 1, weight: 1, width: 0, height: 0,
-      labeloffset: 10, labelpos: "r"
-    },
-    edgeAttrs = ["labelpos"];
-
-/*
- * Constructs a new graph from the input graph, which can be used for layout.
- * This process copies only whitelisted attributes from the input graph to the
- * layout graph. Thus this function serves as a good place to determine what
- * attributes can influence layout.
- */
-function buildLayoutGraph(inputGraph) {
-  var g = new Graph({ multigraph: true, compound: true }),
-      graph = canonicalize(inputGraph.graph());
-
-  g.setGraph(_.merge({},
-    graphDefaults,
-    selectNumberAttrs(graph, graphNumAttrs),
-    _.pick(graph, graphAttrs)));
-
-  _.each(inputGraph.nodes(), function(v) {
-    var node = canonicalize(inputGraph.node(v));
-    g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults));
-    g.setParent(v, inputGraph.parent(v));
-  });
-
-  _.each(inputGraph.edges(), function(e) {
-    var edge = canonicalize(inputGraph.edge(e));
-    g.setEdge(e, _.merge({},
-      edgeDefaults,
-      selectNumberAttrs(edge, edgeNumAttrs),
-      _.pick(edge, edgeAttrs)));
-  });
-
-  return g;
-}
-
-/*
- * This idea comes from the Gansner paper: to account for edge labels in our
- * layout we split each rank in half by doubling minlen and halving ranksep.
- * Then we can place labels at these mid-points between nodes.
- *
- * We also add some minimal padding to the width to push the label for the edge
- * away from the edge itself a bit.
- */
-function makeSpaceForEdgeLabels(g) {
-  var graph = g.graph();
-  graph.ranksep /= 2;
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    edge.minlen *= 2;
-    if (edge.labelpos.toLowerCase() !== "c") {
-      if (graph.rankdir === "TB" || graph.rankdir === "BT") {
-        edge.width += edge.labeloffset;
-      } else {
-        edge.height += edge.labeloffset;
-      }
-    }
-  });
-}
-
-/*
- * Creates temporary dummy nodes that capture the rank in which each edge's
- * label is going to, if it has one of non-zero width and height. We do this
- * so that we can safely remove empty ranks while preserving balance for the
- * label's position.
- */
-function injectEdgeLabelProxies(g) {
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    if (edge.width && edge.height) {
-      var v = g.node(e.v),
-          w = g.node(e.w),
-          label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e };
-      util.addDummyNode(g, "edge-proxy", label, "_ep");
-    }
-  });
-}
-
-function assignRankMinMax(g) {
-  var maxRank = 0;
-  _.each(g.nodes(), function(v) {
-    var node = g.node(v);
-    if (node.borderTop) {
-      node.minRank = g.node(node.borderTop).rank;
-      node.maxRank = g.node(node.borderBottom).rank;
-      maxRank = _.max(maxRank, node.maxRank);
-    }
-  });
-  g.graph().maxRank = maxRank;
-}
-
-function removeEdgeLabelProxies(g) {
-  _.each(g.nodes(), function(v) {
-    var node = g.node(v);
-    if (node.dummy === "edge-proxy") {
-      g.edge(node.e).labelRank = node.rank;
-      g.removeNode(v);
-    }
-  });
-}
-
-function translateGraph(g) {
-  var minX = Number.POSITIVE_INFINITY,
-      maxX = 0,
-      minY = Number.POSITIVE_INFINITY,
-      maxY = 0,
-      graphLabel = g.graph(),
-      marginX = graphLabel.marginx || 0,
-      marginY = graphLabel.marginy || 0;
-
-  function getExtremes(attrs) {
-    var x = attrs.x,
-        y = attrs.y,
-        w = attrs.width,
-        h = attrs.height;
-    minX = Math.min(minX, x - w / 2);
-    maxX = Math.max(maxX, x + w / 2);
-    minY = Math.min(minY, y - h / 2);
-    maxY = Math.max(maxY, y + h / 2);
-  }
-
-  _.each(g.nodes(), function(v) { getExtremes(g.node(v)); });
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    if (_.has(edge, "x")) {
-      getExtremes(edge);
-    }
-  });
-
-  minX -= marginX;
-  minY -= marginY;
-
-  _.each(g.nodes(), function(v) {
-    var node = g.node(v);
-    node.x -= minX;
-    node.y -= minY;
-  });
-
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    _.each(edge.points, function(p) {
-      p.x -= minX;
-      p.y -= minY;
-    });
-    if (_.has(edge, "x")) { edge.x -= minX; }
-    if (_.has(edge, "y")) { edge.y -= minY; }
-  });
-
-  graphLabel.width = maxX - minX + marginX;
-  graphLabel.height = maxY - minY + marginY;
-}
-
-function assignNodeIntersects(g) {
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e),
-        nodeV = g.node(e.v),
-        nodeW = g.node(e.w),
-        p1, p2;
-    if (!edge.points) {
-      edge.points = [];
-      p1 = nodeW;
-      p2 = nodeV;
-    } else {
-      p1 = edge.points[0];
-      p2 = edge.points[edge.points.length - 1];
-    }
-    edge.points.unshift(util.intersectRect(nodeV, p1));
-    edge.points.push(util.intersectRect(nodeW, p2));
-  });
-}
-
-function fixupEdgeLabelCoords(g) {
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    if (_.has(edge, "x")) {
-      if (edge.labelpos === "l" || edge.labelpos === "r") {
-        edge.width -= edge.labeloffset;
-      }
-      switch (edge.labelpos) {
-        case "l": edge.x -= edge.width / 2 + edge.labeloffset; break;
-        case "r": edge.x += edge.width / 2 + edge.labeloffset; break;
-      }
-    }
-  });
-}
-
-function reversePointsForReversedEdges(g) {
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    if (edge.reversed) {
-      edge.points.reverse();
-    }
-  });
-}
-
-function removeBorderNodes(g) {
-  _.each(g.nodes(), function(v) {
-    if (g.children(v).length) {
-      var node = g.node(v),
-          t = g.node(node.borderTop),
-          b = g.node(node.borderBottom),
-          l = g.node(_.last(node.borderLeft)),
-          r = g.node(_.last(node.borderRight));
-
-      node.width = Math.abs(r.x - l.x);
-      node.height = Math.abs(b.y - t.y);
-      node.x = l.x + node.width / 2;
-      node.y = t.y + node.height / 2;
-    }
-  });
-
-  _.each(g.nodes(), function(v) {
-    if (g.node(v).dummy === "border") {
-      g.removeNode(v);
-    }
-  });
-}
-
-function removeSelfEdges(g) {
-  _.each(g.edges(), function(e) {
-    if (e.v === e.w) {
-      var node = g.node(e.v);
-      if (!node.selfEdges) {
-        node.selfEdges = [];
-      }
-      node.selfEdges.push({ e: e, label: g.edge(e) });
-      g.removeEdge(e);
-    }
-  });
-}
-
-function insertSelfEdges(g) {
-  var layers = util.buildLayerMatrix(g);
-  _.each(layers, function(layer) {
-    var orderShift = 0;
-    _.each(layer, function(v, i) {
-      var node = g.node(v);
-      node.order = i + orderShift;
-      _.each(node.selfEdges, function(selfEdge) {
-        util.addDummyNode(g, "selfedge", {
-          width: selfEdge.label.width,
-          height: selfEdge.label.height,
-          rank: node.rank,
-          order: i + (++orderShift),
-          e: selfEdge.e,
-          label: selfEdge.label
-        }, "_se");
-      });
-      delete node.selfEdges;
-    });
-  });
-}
-
-function positionSelfEdges(g) {
-  _.each(g.nodes(), function(v) {
-    var node = g.node(v);
-    if (node.dummy === "selfedge") {
-      var selfNode = g.node(node.e.v),
-          x = selfNode.x + selfNode.width / 2,
-          y = selfNode.y,
-          dx = node.x - x,
-          dy = selfNode.height / 2;
-      g.setEdge(node.e, node.label);
-      g.removeNode(v);
-      node.label.points = [
-        { x: x + 2 * dx / 3, y: y - dy },
-        { x: x + 5 * dx / 6, y: y - dy },
-        { x: x +     dx    , y: y },
-        { x: x + 5 * dx / 6, y: y + dy },
-        { x: x + 2 * dx / 3, y: y + dy },
-      ];
-      node.label.x = node.x;
-      node.label.y = node.y;
-    }
-  });
-}
-
-function selectNumberAttrs(obj, attrs) {
-  return _.mapValues(_.pick(obj, attrs), Number);
-}
-
-function canonicalize(attrs) {
-  var newAttrs = {};
-  _.each(attrs, function(v, k) {
-    newAttrs[k.toLowerCase()] = v;
-  });
-  return newAttrs;
-}
-
-},{"./acyclic":30,"./add-border-segments":31,"./coordinate-system":32,"./graphlib":35,"./lodash":38,"./nesting-graph":39,"./normalize":40,"./order":45,"./parent-dummy-chains":50,"./position":52,"./rank":54,"./util":57}],38:[function(require,module,exports){
-arguments[4][21][0].apply(exports,arguments)
-},{"/Users/cpettitt/projects/dagre-d3/lib/lodash.js":21,"lodash":59}],39:[function(require,module,exports){
-var _ = require("./lodash"),
-    util = require("./util");
-
-module.exports = {
-  run: run,
-  cleanup: cleanup
-};
-
-/*
- * A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
- * adds appropriate edges to ensure that all cluster nodes are placed between
- * these boundries, and ensures that the graph is connected.
- *
- * In addition we ensure, through the use of the minlen property, that nodes
- * and subgraph border nodes to not end up on the same rank.
- *
- * Preconditions:
- *
- *    1. Input graph is a DAG
- *    2. Nodes in the input graph has a minlen attribute
- *
- * Postconditions:
- *
- *    1. Input graph is connected.
- *    2. Dummy nodes are added for the tops and bottoms of subgraphs.
- *    3. The minlen attribute for nodes is adjusted to ensure nodes do not
- *       get placed on the same rank as subgraph border nodes.
- *
- * The nesting graph idea comes from Sander, "Layout of Compound Directed
- * Graphs."
- */
-function run(g) {
-  var root = util.addDummyNode(g, "root", {}, "_root"),
-      depths = treeDepths(g),
-      height = _.max(depths) - 1,
-      nodeSep = 2 * height + 1;
-
-  g.graph().nestingRoot = root;
-
-  // Multiply minlen by nodeSep to align nodes on non-border ranks.
-  _.each(g.edges(), function(e) { g.edge(e).minlen *= nodeSep; });
-
-  // Calculate a weight that is sufficient to keep subgraphs vertically compact
-  var weight = sumWeights(g) + 1;
-
-  // Create border nodes and link them up
-  _.each(g.children(), function(child) {
-    dfs(g, root, nodeSep, weight, height, depths, child);
-  });
-
-  // Save the multiplier for node layers for later removal of empty border
-  // layers.
-  g.graph().nodeRankFactor = nodeSep;
-}
-
-function dfs(g, root, nodeSep, weight, height, depths, v) {
-  var children = g.children(v);
-  if (!children.length) {
-    if (v !== root) {
-      g.setEdge(root, v, { weight: 0, minlen: nodeSep });
-    }
-    return;
-  }
-
-  var top = util.addBorderNode(g, "_bt"),
-      bottom = util.addBorderNode(g, "_bb"),
-      label = g.node(v);
-
-  g.setParent(top, v);
-  label.borderTop = top;
-  g.setParent(bottom, v);
-  label.borderBottom = bottom;
-
-  _.each(children, function(child) {
-    dfs(g, root, nodeSep, weight, height, depths, child);
-
-    var childNode = g.node(child),
-        childTop = childNode.borderTop ? childNode.borderTop : child,
-        childBottom = childNode.borderBottom ? childNode.borderBottom : child,
-        thisWeight = childNode.borderTop ? weight : 2 * weight,
-        minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
-
-    g.setEdge(top, childTop, {
-      weight: thisWeight,
-      minlen: minlen,
-      nestingEdge: true
-    });
-
-    g.setEdge(childBottom, bottom, {
-      weight: thisWeight,
-      minlen: minlen,
-      nestingEdge: true
-    });
-  });
-
-  if (!g.parent(v)) {
-    g.setEdge(root, top, { weight: 0, minlen: height + depths[v] });
-  }
-}
-
-function treeDepths(g) {
-  var depths = {};
-  function dfs(v, depth) {
-    var children = g.children(v);
-    if (children && children.length) {
-      _.each(children, function(child) {
-        dfs(child, depth + 1);
-      });
-    }
-    depths[v] = depth;
-  }
-  _.each(g.children(), function(v) { dfs(v, 1); });
-  return depths;
-}
-
-function sumWeights(g) {
-  return _.reduce(g.edges(), function(acc, e) {
-    return acc + g.edge(e).weight;
-  }, 0);
-}
-
-function cleanup(g) {
-  var graphLabel = g.graph();
-  g.removeNode(graphLabel.nestingRoot);
-  delete graphLabel.nestingRoot;
-  _.each(g.edges(), function(e) {
-    var edge = g.edge(e);
-    if (edge.nestingEdge) {
-      g.removeEdge(e);
-    }
-  });
-}
-
-},{"./lodash":38,"./util":57}],40:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash"),
-    util = require("./util");
-
-module.exports = {
-  run: run,
-  undo: undo
-};
-
-/*
- * Breaks any long edges in the graph into short segments that span 1 layer
- * each. This operation is undoable with the denormalize function.
- *
- * Pre-conditions:
- *
- *    1. The input graph is a DAG.
- *    2. Each node in the graph has a "rank" property.
- *
- * Post-condition:
- *
- *    1. All edges in the graph have a length of 1.
- *    2. Dummy nodes are added where edges have been split into segments.
- *    3. The graph is augmented with a "dummyChains" attribute which contains
- *       the first dummy in each chain of dummy nodes produced.
- */
-function run(g) {
-  g.graph().dummyChains = [];
-  _.each(g.edges(), function(edge) { normalizeEdge(g, edge); });
-}
-
-function normalizeEdge(g, e) {
-  var v = e.v,
-      vRank = g.node(v).rank,
-      w = e.w,
-      wRank = g.node(w).rank,
-      name = e.name,
-      edgeLabel = g.edge(e),
-      labelRank = edgeLabel.labelRank;
-
-  if (wRank === vRank + 1) return;
-
-  g.removeEdge(e);
-
-  var dummy, attrs, i;
-  for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
-    edgeLabel.points = [];
-    attrs = {
-      width: 0, height: 0,
-      edgeLabel: edgeLabel, edgeObj: e,
-      rank: vRank
-    };
-    dummy = util.addDummyNode(g, "edge", attrs, "_d");
-    if (vRank === labelRank) {
-      attrs.width = edgeLabel.width;
-      attrs.height = edgeLabel.height;
-      attrs.dummy = "edge-label";
-      attrs.labelpos = edgeLabel.labelpos;
-    }
-    g.setEdge(v, dummy, { weight: edgeLabel.weight }, name);
-    if (i === 0) {
-      g.graph().dummyChains.push(dummy);
-    }
-    v = dummy;
-  }
-
-  g.setEdge(v, w, { weight: edgeLabel.weight }, name);
-}
-
-function undo(g) {
-  _.each(g.graph().dummyChains, function(v) {
-    var node = g.node(v),
-        origLabel = node.edgeLabel,
-        w;
-    g.setEdge(node.edgeObj, origLabel);
-    while (node.dummy) {
-      w = g.successors(v)[0];
-      g.removeNode(v);
-      origLabel.points.push({ x: node.x, y: node.y });
-      if (node.dummy === "edge-label") {
-        origLabel.x = node.x;
-        origLabel.y = node.y;
-        origLabel.width = node.width;
-        origLabel.height = node.height;
-      }
-      v = w;
-      node = g.node(v);
-    }
-  });
-}
-
-},{"./lodash":38,"./util":57}],41:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = addSubgraphConstraints;
-
-function addSubgraphConstraints(g, cg, vs) {
-  var prev = {},
-      rootPrev;
-
-  _.each(vs, function(v) {
-    var child = g.parent(v),
-        parent,
-        prevChild;
-    while (child) {
-      parent = g.parent(child);
-      if (parent) {
-        prevChild = prev[parent];
-        prev[parent] = child;
-      } else {
-        prevChild = rootPrev;
-        rootPrev = child;
-      }
-      if (prevChild && prevChild !== child) {
-        cg.setEdge(prevChild, child);
-        return;
-      }
-      child = parent;
-    }
-  });
-
-  /*
-  function dfs(v) {
-    var children = v ? g.children(v) : g.children();
-    if (children.length) {
-      var min = Number.POSITIVE_INFINITY,
-          subgraphs = [];
-      _.each(children, function(child) {
-        var childMin = dfs(child);
-        if (g.children(child).length) {
-          subgraphs.push({ v: child, order: childMin });
-        }
-        min = Math.min(min, childMin);
-      });
-      _.reduce(_.sortBy(subgraphs, "order"), function(prev, curr) {
-        cg.setEdge(prev.v, curr.v);
-        return curr;
-      });
-      return min;
-    }
-    return g.node(v).order;
-  }
-  dfs(undefined);
-  */
-}
-
-},{"../lodash":38}],42:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = barycenter;
-
-function barycenter(g, movable) {
-  return _.map(movable, function(v) {
-    var inV = g.inEdges(v);
-    if (!inV.length) {
-      return { v: v };
-    } else {
-      var result = _.reduce(inV, function(acc, e) {
-        var edge = g.edge(e),
-            nodeU = g.node(e.v);
-        return {
-          sum: acc.sum + (edge.weight * nodeU.order),
-          weight: acc.weight + edge.weight
-        };
-      }, { sum: 0, weight: 0 });
-
-      return {
-        v: v,
-        barycenter: result.sum / result.weight,
-        weight: result.weight
-      };
-    }
-  });
-}
-
-
-},{"../lodash":38}],43:[function(require,module,exports){
-var _ = require("../lodash"),
-    Graph = require("../graphlib").Graph;
-
-module.exports = buildLayerGraph;
-
-/*
- * Constructs a graph that can be used to sort a layer of nodes. The graph will
- * contain all base and subgraph nodes from the request layer in their original
- * hierarchy and any edges that are incident on these nodes and are of the type
- * requested by the "relationship" parameter.
- *
- * Nodes from the requested rank that do not have parents are assigned a root
- * node in the output graph, which is set in the root graph attribute. This
- * makes it easy to walk the hierarchy of movable nodes during ordering.
- *
- * Pre-conditions:
- *
- *    1. Input graph is a DAG
- *    2. Base nodes in the input graph have a rank attribute
- *    3. Subgraph nodes in the input graph has minRank and maxRank attributes
- *    4. Edges have an assigned weight
- *
- * Post-conditions:
- *
- *    1. Output graph has all nodes in the movable rank with preserved
- *       hierarchy.
- *    2. Root nodes in the movable layer are made children of the node
- *       indicated by the root attribute of the graph.
- *    3. Non-movable nodes incident on movable nodes, selected by the
- *       relationship parameter, are included in the graph (without hierarchy).
- *    4. Edges incident on movable nodes, selected by the relationship
- *       parameter, are added to the output graph.
- *    5. The weights for copied edges are aggregated as need, since the output
- *       graph is not a multi-graph.
- */
-function buildLayerGraph(g, rank, relationship) {
-  var root = createRootNode(g),
-      result = new Graph({ compound: true }).setGraph({ root: root })
-                  .setDefaultNodeLabel(function(v) { return g.node(v); });
-
-  _.each(g.nodes(), function(v) {
-    var node = g.node(v),
-        parent = g.parent(v);
-
-    if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
-      result.setNode(v);
-      result.setParent(v, parent || root);
-
-      // This assumes we have only short edges!
-      _.each(g[relationship](v), function(e) {
-        var u = e.v === v ? e.w : e.v,
-            edge = result.edge(u, v),
-            weight = !_.isUndefined(edge) ? edge.weight : 0;
-        result.setEdge(u, v, { weight: g.edge(e).weight + weight });
-      });
-
-      if (_.has(node, "minRank")) {
-        result.setNode(v, {
-          borderLeft: node.borderLeft[rank],
-          borderRight: node.borderRight[rank]
-        });
-      }
-    }
-  });
-
-  return result;
-}
-
-function createRootNode(g) {
-  var v;
-  while (g.hasNode((v = _.uniqueId("_root"))));
-  return v;
-}
-
-},{"../graphlib":35,"../lodash":38}],44:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash");
-
-module.exports = crossCount;
-
-/*
- * A function that takes a layering (an array of layers, each with an array of
- * ordererd nodes) and a graph and returns a weighted crossing count.
- *
- * Pre-conditions:
- *
- *    1. Input graph must be simple (not a multigraph), directed, and include
- *       only simple edges.
- *    2. Edges in the input graph must have assigned weights.
- *
- * Post-conditions:
- *
- *    1. The graph and layering matrix are left unchanged.
- *
- * This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
- */
-function crossCount(g, layering) {
-  var cc = 0;
-  for (var i = 1; i < layering.length; ++i) {
-    cc += twoLayerCrossCount(g, layering[i-1], layering[i]);
-  }
-  return cc;
-}
-
-function twoLayerCrossCount(g, northLayer, southLayer) {
-  // Sort all of the edges between the north and south layers by their position
-  // in the north layer and then the south. Map these edges to the position of
-  // their head in the south layer.
-  var southPos = _.zipObject(southLayer,
-                             _.map(southLayer, function (v, i) { return i; }));
-  var southEntries = _.flatten(_.map(northLayer, function(v) {
-    return _.chain(g.outEdges(v))
-            .map(function(e) {
-              return { pos: southPos[e.w], weight: g.edge(e).weight };
-            })
-            .sortBy("pos")
-            .value();
-  }), true);
-
-  // Build the accumulator tree
-  var firstIndex = 1;
-  while (firstIndex < southLayer.length) firstIndex <<= 1;
-  var treeSize = 2 * firstIndex - 1;
-  firstIndex -= 1;
-  var tree = _.map(new Array(treeSize), function() { return 0; });
-
-  // Calculate the weighted crossings
-  var cc = 0;
-  _.each(southEntries.forEach(function(entry) {
-    var index = entry.pos + firstIndex;
-    tree[index] += entry.weight;
-    var weightSum = 0;
-    while (index > 0) {
-      if (index % 2) {
-        weightSum += tree[index + 1];
-      }
-      index = (index - 1) >> 1;
-      tree[index] += entry.weight;
-    }
-    cc += entry.weight * weightSum;
-  }));
-
-  return cc;
-}
-
-},{"../lodash":38}],45:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash"),
-    initOrder = require("./init-order"),
-    crossCount = require("./cross-count"),
-    sortSubgraph = require("./sort-subgraph"),
-    buildLayerGraph = require("./build-layer-graph"),
-    addSubgraphConstraints = require("./add-subgraph-constraints"),
-    Graph = require("../graphlib").Graph,
-    util = require("../util");
-
-module.exports = order;
-
-/*
- * Applies heuristics to minimize edge crossings in the graph and sets the best
- * order solution as an order attribute on each node.
- *
- * Pre-conditions:
- *
- *    1. Graph must be DAG
- *    2. Graph nodes must be objects with a "rank" attribute
- *    3. Graph edges must have the "weight" attribute
- *
- * Post-conditions:
- *
- *    1. Graph nodes will have an "order" attribute based on the results of the
- *       algorithm.
- */
-function order(g) {
-  var maxRank = util.maxRank(g),
-      downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank + 1), "inEdges"),
-      upLayerGraphs = buildLayerGraphs(g, _.range(maxRank - 1, -1, -1), "outEdges");
-
-  var layering = initOrder(g);
-  assignOrder(g, layering);
-
-  var bestCC = Number.POSITIVE_INFINITY,
-      best;
-
-  for (var i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
-    sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
-
-    layering = util.buildLayerMatrix(g);
-    var cc = crossCount(g, layering);
-    if (cc < bestCC) {
-      lastBest = 0;
-      best = _.cloneDeep(layering);
-      bestCC = cc;
-    }
-  }
-
-  assignOrder(g, best);
-}
-
-function buildLayerGraphs(g, ranks, relationship) {
-  return _.map(ranks, function(rank) {
-    return buildLayerGraph(g, rank, relationship);
-  });
-}
-
-function sweepLayerGraphs(layerGraphs, biasRight) {
-  var cg = new Graph();
-  _.each(layerGraphs, function(lg) {
-    var root = lg.graph().root;
-    var sorted = sortSubgraph(lg, root, cg, biasRight);
-    _.each(sorted.vs, function(v, i) {
-      lg.node(v).order = i;
-    });
-    addSubgraphConstraints(lg, cg, sorted.vs);
-  });
-}
-
-function assignOrder(g, layering) {
-  _.each(layering, function(layer) {
-    _.each(layer, function(v, i) {
-      g.node(v).order = i;
-    });
-  });
-}
-
-},{"../graphlib":35,"../lodash":38,"../util":57,"./add-subgraph-constraints":41,"./build-layer-graph":43,"./cross-count":44,"./init-order":46,"./sort-subgraph":48}],46:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash");
-
-module.exports = initOrder;
-
-/*
- * Assigns an initial order value for each node by performing a DFS search
- * starting from nodes in the first rank. Nodes are assigned an order in their
- * rank as they are first visited.
- *
- * This approach comes from Gansner, et al., "A Technique for Drawing Directed
- * Graphs."
- *
- * Returns a layering matrix with an array per layer and each layer sorted by
- * the order of its nodes.
- */
-function initOrder(g) {
-  var visited = {},
-      simpleNodes = _.filter(g.nodes(), function(v) {
-        return !g.children(v).length;
-      }),
-      maxRank = _.max(_.map(simpleNodes, function(v) { return g.node(v).rank; })),
-      layers = _.map(_.range(maxRank + 1), function() { return []; });
-
-  function dfs(v) {
-    if (_.has(visited, v)) return;
-    visited[v] = true;
-    var node = g.node(v);
-    layers[node.rank].push(v);
-    _.each(g.successors(v), dfs);
-  }
-
-  var orderedVs = _.sortBy(simpleNodes, function(v) { return g.node(v).rank; });
-  _.each(orderedVs, dfs);
-
-  return layers;
-}
-
-},{"../lodash":38}],47:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash");
-
-module.exports = resolveConflicts;
-
-/*
- * Given a list of entries of the form {v, barycenter, weight} and a
- * constraint graph this function will resolve any conflicts between the
- * constraint graph and the barycenters for the entries. If the barycenters for
- * an entry would violate a constraint in the constraint graph then we coalesce
- * the nodes in the conflict into a new node that respects the contraint and
- * aggregates barycenter and weight information.
- *
- * This implementation is based on the description in Forster, "A Fast and
- * Simple Hueristic for Constrained Two-Level Crossing Reduction," thought it
- * differs in some specific details.
- *
- * Pre-conditions:
- *
- *    1. Each entry has the form {v, barycenter, weight}, or if the node has
- *       no barycenter, then {v}.
- *
- * Returns:
- *
- *    A new list of entries of the form {vs, i, barycenter, weight}. The list
- *    `vs` may either be a singleton or it may be an aggregation of nodes
- *    ordered such that they do not violate constraints from the constraint
- *    graph. The property `i` is the lowest original index of any of the
- *    elements in `vs`.
- */
-function resolveConflicts(entries, cg) {
-  var mappedEntries = {};
-  _.each(entries, function(entry, i) {
-    var tmp = mappedEntries[entry.v] = {
-      indegree: 0,
-      "in": [],
-      out: [],
-      vs: [entry.v],
-      i: i
-    };
-    if (!_.isUndefined(entry.barycenter)) {
-      tmp.barycenter = entry.barycenter;
-      tmp.weight = entry.weight;
-    }
-  });
-
-  _.each(cg.edges(), function(e) {
-    var entryV = mappedEntries[e.v],
-        entryW = mappedEntries[e.w];
-    if (!_.isUndefined(entryV) && !_.isUndefined(entryW)) {
-      entryW.indegree++;
-      entryV.out.push(mappedEntries[e.w]);
-    }
-  });
-
-  var sourceSet = _.filter(mappedEntries, function(entry) {
-    return !entry.indegree;
-  });
-
-  return doResolveConflicts(sourceSet);
-}
-
-function doResolveConflicts(sourceSet) {
-  var entries = [];
-
-  function handleIn(vEntry) {
-    return function(uEntry) {
-      if (uEntry.merged) {
-        return;
-      }
-      if (_.isUndefined(uEntry.barycenter) ||
-          _.isUndefined(vEntry.barycenter) ||
-          uEntry.barycenter >= vEntry.barycenter) {
-        mergeEntries(vEntry, uEntry);
-      }
-    };
-  }
-
-  function handleOut(vEntry) {
-    return function(wEntry) {
-      wEntry["in"].push(vEntry);
-      if (--wEntry.indegree === 0) {
-        sourceSet.push(wEntry);
-      }
-    };
-  }
-
-  while (sourceSet.length) {
-    var entry = sourceSet.pop();
-    entries.push(entry);
-    _.each(entry["in"].reverse(), handleIn(entry));
-    _.each(entry.out, handleOut(entry));
-  }
-
-  return _.chain(entries)
-          .filter(function(entry) { return !entry.merged; })
-          .map(function(entry) {
-            return _.pick(entry, ["vs", "i", "barycenter", "weight"]);
-          })
-          .value();
-}
-
-function mergeEntries(target, source) {
-  var sum = 0,
-      weight = 0;
-
-  if (target.weight) {
-    sum += target.barycenter * target.weight;
-    weight += target.weight;
-  }
-
-  if (source.weight) {
-    sum += source.barycenter * source.weight;
-    weight += source.weight;
-  }
-
-  target.vs = source.vs.concat(target.vs);
-  target.barycenter = sum / weight;
-  target.weight = weight;
-  target.i = Math.min(source.i, target.i);
-  source.merged = true;
-}
-
-},{"../lodash":38}],48:[function(require,module,exports){
-var _ = require("../lodash"),
-    barycenter = require("./barycenter"),
-    resolveConflicts = require("./resolve-conflicts"),
-    sort = require("./sort");
-
-module.exports = sortSubgraph;
-
-function sortSubgraph(g, v, cg, biasRight) {
-  var movable = g.children(v),
-      node = g.node(v),
-      bl = node ? node.borderLeft : undefined,
-      br = node ? node.borderRight: undefined,
-      subgraphs = {};
-
-  if (bl) {
-    movable = _.filter(movable, function(w) {
-      return w !== bl && w !== br;
-    });
-  }
-
-  var barycenters = barycenter(g, movable);
-  _.each(barycenters, function(entry) {
-    if (g.children(entry.v).length) {
-      var subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
-      subgraphs[entry.v] = subgraphResult;
-      if (_.has(subgraphResult, "barycenter")) {
-        mergeBarycenters(entry, subgraphResult);
-      }
-    }
-  });
-
-  var entries = resolveConflicts(barycenters, cg);
-  expandSubgraphs(entries, subgraphs);
-
-  var result = sort(entries, biasRight);
-
-  if (bl) {
-    result.vs = _.flatten([bl, result.vs, br], true);
-    if (g.predecessors(bl).length) {
-      var blPred = g.node(g.predecessors(bl)[0]),
-          brPred = g.node(g.predecessors(br)[0]);
-      if (!_.has(result, "barycenter")) {
-        result.barycenter = 0;
-        result.weight = 0;
-      }
-      result.barycenter = (result.barycenter * result.weight +
-                           blPred.order + brPred.order) / (result.weight + 2);
-      result.weight += 2;
-    }
-  }
-
-  return result;
-}
-
-function expandSubgraphs(entries, subgraphs) {
-  _.each(entries, function(entry) {
-    entry.vs = _.flatten(entry.vs.map(function(v) {
-      if (subgraphs[v]) {
-        return subgraphs[v].vs;
-      }
-      return v;
-    }), true);
-  });
-}
-
-function mergeBarycenters(target, other) {
-  if (!_.isUndefined(target.barycenter)) {
-    target.barycenter = (target.barycenter * target.weight +
-                         other.barycenter * other.weight) /
-                        (target.weight + other.weight);
-    target.weight += other.weight;
-  } else {
-    target.barycenter = other.barycenter;
-    target.weight = other.weight;
-  }
-}
-
-},{"../lodash":38,"./barycenter":42,"./resolve-conflicts":47,"./sort":49}],49:[function(require,module,exports){
-var _ = require("../lodash"),
-    util = require("../util");
-
-module.exports = sort;
-
-function sort(entries, biasRight) {
-  var parts = util.partition(entries, function(entry) {
-    return _.has(entry, "barycenter");
-  });
-  var sortable = parts.lhs,
-      unsortable = _.sortBy(parts.rhs, function(entry) { return -entry.i; }),
-      vs = [],
-      sum = 0,
-      weight = 0,
-      vsIndex = 0;
-
-  sortable.sort(compareWithBias(!!biasRight));
-
-  vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
-
-  _.each(sortable, function (entry) {
-    vsIndex += entry.vs.length;
-    vs.push(entry.vs);
-    sum += entry.barycenter * entry.weight;
-    weight += entry.weight;
-    vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
-  });
-
-  var result = { vs: _.flatten(vs, true) };
-  if (weight) {
-    result.barycenter = sum / weight;
-    result.weight = weight;
-  }
-  return result;
-}
-
-function consumeUnsortable(vs, unsortable, index) {
-  var last;
-  while (unsortable.length && (last = _.last(unsortable)).i <= index) {
-    unsortable.pop();
-    vs.push(last.vs);
-    index++;
-  }
-  return index;
-}
-
-function compareWithBias(bias) {
-  return function(entryV, entryW) {
-    if (entryV.barycenter < entryW.barycenter) {
-      return -1;
-    } else if (entryV.barycenter > entryW.barycenter) {
-      return 1;
-    }
-
-    return !bias ? entryV.i - entryW.i : entryW.i - entryV.i;
-  };
-}
-
-},{"../lodash":38,"../util":57}],50:[function(require,module,exports){
-var _ = require("./lodash");
-
-module.exports = parentDummyChains;
-
-function parentDummyChains(g) {
-  var postorderNums = postorder(g);
-
-  _.each(g.graph().dummyChains, function(v) {
-    var node = g.node(v),
-        edgeObj = node.edgeObj,
-        pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w),
-        path = pathData.path,
-        lca = pathData.lca,
-        pathIdx = 0,
-        pathV = path[pathIdx],
-        ascending = true;
-
-    while (v !== edgeObj.w) {
-      node = g.node(v);
-
-      if (ascending) {
-        while ((pathV = path[pathIdx]) !== lca &&
-               g.node(pathV).maxRank < node.rank) {
-          pathIdx++;
-        }
-
-        if (pathV === lca) {
-          ascending = false;
-        }
-      }
-
-      if (!ascending) {
-        while (pathIdx < path.length - 1 &&
-               g.node(pathV = path[pathIdx + 1]).minRank <= node.rank) {
-          pathIdx++;
-        }
-        pathV = path[pathIdx];
-      }
-
-      g.setParent(v, pathV);
-      v = g.successors(v)[0];
-    }
-  });
-}
-
-// Find a path from v to w through the lowest common ancestor (LCA). Return the
-// full path and the LCA.
-function findPath(g, postorderNums, v, w) {
-  var vPath = [],
-      wPath = [],
-      low = Math.min(postorderNums[v].low, postorderNums[w].low),
-      lim = Math.max(postorderNums[v].lim, postorderNums[w].lim),
-      parent,
-      lca;
-
-  // Traverse up from v to find the LCA
-  parent = v;
-  do {
-    parent = g.parent(parent);
-    vPath.push(parent);
-  } while (parent &&
-           (postorderNums[parent].low > low || lim > postorderNums[parent].lim));
-  lca = parent;
-
-  // Traverse from w to LCA
-  parent = w;
-  while ((parent = g.parent(parent)) !== lca) {
-    wPath.push(parent);
-  }
-
-  return { path: vPath.concat(wPath.reverse()), lca: lca };
-}
-
-function postorder(g) {
-  var result = {},
-      lim = 0;
-
-  function dfs(v) {
-    var low = lim;
-    _.each(g.children(v), dfs);
-    result[v] = { low: low, lim: lim++ };
-  }
-  _.each(g.children(), dfs);
-
-  return result;
-}
-
-},{"./lodash":38}],51:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash"),
-    Graph = require("../graphlib").Graph,
-    util = require("../util");
-
-/*
- * This module provides coordinate assignment based on Brandes and Köpf, "Fast
- * and Simple Horizontal Coordinate Assignment."
- */
-
-module.exports = {
-  positionX: positionX,
-  findType1Conflicts: findType1Conflicts,
-  findType2Conflicts: findType2Conflicts,
-  addConflict: addConflict,
-  hasConflict: hasConflict,
-  verticalAlignment: verticalAlignment,
-  horizontalCompaction: horizontalCompaction,
-  alignCoordinates: alignCoordinates,
-  findSmallestWidthAlignment: findSmallestWidthAlignment,
-  balance: balance
-};
-
-/*
- * Marks all edges in the graph with a type-1 conflict with the "type1Conflict"
- * property. A type-1 conflict is one where a non-inner segment crosses an
- * inner segment. An inner segment is an edge with both incident nodes marked
- * with the "dummy" property.
- *
- * This algorithm scans layer by layer, starting with the second, for type-1
- * conflicts between the current layer and the previous layer. For each layer
- * it scans the nodes from left to right until it reaches one that is incident
- * on an inner segment. It then scans predecessors to determine if they have
- * edges that cross that inner segment. At the end a final scan is done for all
- * nodes on the current rank to see if they cross the last visited inner
- * segment.
- *
- * This algorithm (safely) assumes that a dummy node will only be incident on a
- * single node in the layers being scanned.
- */
-function findType1Conflicts(g, layering) {
-  var conflicts = {};
-
-  function visitLayer(prevLayer, layer) {
-    var
-      // last visited node in the previous layer that is incident on an inner
-      // segment.
-      k0 = 0,
-      // Tracks the last node in this layer scanned for crossings with a type-1
-      // segment.
-      scanPos = 0,
-      prevLayerLength = prevLayer.length,
-      lastNode = _.last(layer);
-
-    _.each(layer, function(v, i) {
-      var w = findOtherInnerSegmentNode(g, v),
-          k1 = w ? g.node(w).order : prevLayerLength;
-
-      if (w || v === lastNode) {
-        _.each(layer.slice(scanPos, i +1), function(scanNode) {
-          _.each(g.predecessors(scanNode), function(u) {
-            var uLabel = g.node(u),
-                uPos = uLabel.order;
-            if ((uPos < k0 || k1 < uPos) &&
-                !(uLabel.dummy && g.node(scanNode).dummy)) {
-              addConflict(conflicts, u, scanNode);
-            }
-          });
-        });
-        scanPos = i + 1;
-        k0 = k1;
-      }
-    });
-
-    return layer;
-  }
-
-  _.reduce(layering, visitLayer);
-  return conflicts;
-}
-
-function findType2Conflicts(g, layering) {
-  var conflicts = {};
-
-  function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
-    var v;
-    _.each(_.range(southPos, southEnd), function(i) {
-      v = south[i];
-      if (g.node(v).dummy) {
-        _.each(g.predecessors(v), function(u) {
-          var uNode = g.node(u);
-          if (uNode.dummy &&
-              (uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
-            addConflict(conflicts, u, v);
-          }
-        });
-      }
-    });
-  }
-
-
-  function visitLayer(north, south) {
-    var prevNorthPos = -1,
-        nextNorthPos,
-        southPos = 0;
-
-    _.each(south, function(v, southLookahead) {
-      if (g.node(v).dummy === "border") {
-        var predecessors = g.predecessors(v);
-        if (predecessors.length) {
-          nextNorthPos = g.node(predecessors[0]).order;
-          scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
-          southPos = southLookahead;
-          prevNorthPos = nextNorthPos;
-        }
-      }
-      scan(south, southPos, south.length, nextNorthPos, north.length);
-    });
-
-    return south;
-  }
-
-  _.reduce(layering, visitLayer);
-  return conflicts;
-}
-
-function findOtherInnerSegmentNode(g, v) {
-  if (g.node(v).dummy) {
-    return _.find(g.predecessors(v), function(u) {
-      return g.node(u).dummy;
-    });
-  }
-}
-
-function addConflict(conflicts, v, w) {
-  if (v > w) {
-    var tmp = v;
-    v = w;
-    w = tmp;
-  }
-
-  var conflictsV = conflicts[v];
-  if (!conflictsV) {
-    conflicts[v] = conflictsV = {};
-  }
-  conflictsV[w] = true;
-}
-
-function hasConflict(conflicts, v, w) {
-  if (v > w) {
-    var tmp = v;
-    v = w;
-    w = tmp;
-  }
-  return _.has(conflicts[v], w);
-}
-
-/*
- * Try to align nodes into vertical "blocks" where possible. This algorithm
- * attempts to align a node with one of its median neighbors. If the edge
- * connecting a neighbor is a type-1 conflict then we ignore that possibility.
- * If a previous node has already formed a block with a node after the node
- * we're trying to form a block with, we also ignore that possibility - our
- * blocks would be split in that scenario.
- */
-function verticalAlignment(g, layering, conflicts, neighborFn) {
-  var root = {},
-      align = {},
-      pos = {};
-
-  // We cache the position here based on the layering because the graph and
-  // layering may be out of sync. The layering matrix is manipulated to
-  // generate different extreme alignments.
-  _.each(layering, function(layer) {
-    _.each(layer, function(v, order) {
-      root[v] = v;
-      align[v] = v;
-      pos[v] = order;
-    });
-  });
-
-  _.each(layering, function(layer) {
-    var prevIdx = -1;
-    _.each(layer, function(v) {
-      var ws = neighborFn(v);
-      if (ws.length) {
-        ws = _.sortBy(ws, function(w) { return pos[w]; });
-        var mp = (ws.length - 1) / 2;
-        for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
-          var w = ws[i];
-          if (align[v] === v &&
-              prevIdx < pos[w] &&
-              !hasConflict(conflicts, v, w)) {
-            align[w] = v;
-            align[v] = root[v] = root[w];
-            prevIdx = pos[w];
-          }
-        }
-      }
-    });
-  });
-
-  return { root: root, align: align };
-}
-
-function horizontalCompaction(g, layering, root, align, reverseSep) {
-  // This portion of the algorithm differs from BK due to a number of problems.
-  // Instead of their algorithm we construct a new block graph and do two
-  // sweeps. The first sweep places blocks with the smallest possible
-  // coordinates. The second sweep removes unused space by moving blocks to the
-  // greatest coordinates without violating separation.
-  var xs = {},
-      blockG = buildBlockGraph(g, layering, root, reverseSep);
-
-  // First pass, assign smallest coordinates via DFS
-  var visited = {};
-  function pass1(v) {
-    if (!_.has(visited, v)) {
-      visited[v] = true;
-      xs[v] = _.reduce(blockG.inEdges(v), function(max, e) {
-        pass1(e.v);
-        return Math.max(max, xs[e.v] + blockG.edge(e));
-      }, 0);
-    }
-  }
-  _.each(blockG.nodes(), pass1);
-
-  var borderType = reverseSep ? "borderLeft" : "borderRight";
-  function pass2(v) {
-    if (visited[v] !== 2) {
-      visited[v]++;
-      var node = g.node(v);
-      var min = _.reduce(blockG.outEdges(v), function(min, e) {
-        pass2(e.w);
-        return Math.min(min, xs[e.w] - blockG.edge(e));
-      }, Number.POSITIVE_INFINITY);
-      if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
-        xs[v] = Math.max(xs[v], min);
-      }
-    }
-  }
-  _.each(blockG.nodes(), pass2);
-
-  // Assign x coordinates to all nodes
-  _.each(align, function(v) {
-    xs[v] = xs[root[v]];
-  });
-
-  return xs;
-}
-
-
-function buildBlockGraph(g, layering, root, reverseSep) {
-  var blockGraph = new Graph(),
-      graphLabel = g.graph(),
-      sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
-
-  _.each(layering, function(layer) {
-    var u;
-    _.each(layer, function(v) {
-      var vRoot = root[v];
-      blockGraph.setNode(vRoot);
-      if (u) {
-        var uRoot = root[u],
-            prevMax = blockGraph.edge(uRoot, vRoot);
-        blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
-      }
-      u = v;
-    });
-  });
-
-  return blockGraph;
-}
-
-/*
- * Returns the alignment that has the smallest width of the given alignments.
- */
-function findSmallestWidthAlignment(g, xss) {
-  return _.min(xss, function(xs) {
-    var min = _.min(xs, function(x, v) { return x - width(g, v) / 2; }),
-        max = _.max(xs, function(x, v) { return x + width(g, v) / 2; });
-    return max - min;
-  });
-}
-
-/*
- * Align the coordinates of each of the layout alignments such that
- * left-biased alignments have their minimum coordinate at the same point as
- * the minimum coordinate of the smallest width alignment and right-biased
- * alignments have their maximum coordinate at the same point as the maximum
- * coordinate of the smallest width alignment.
- */
-function alignCoordinates(xss, alignTo) {
-  var alignToMin = _.min(alignTo),
-      alignToMax = _.max(alignTo);
-
-  _.each(["u", "d"], function(vert) {
-    _.each(["l", "r"], function(horiz) {
-      var alignment = vert + horiz,
-          xs = xss[alignment],
-          delta;
-      if (xs === alignTo) return;
-
-      delta = horiz === "l" ? alignToMin - _.min(xs) : alignToMax - _.max(xs);
-
-      if (delta) {
-        xss[alignment] = _.mapValues(xs, function(x) { return x + delta; });
-      }
-    });
-  });
-}
-
-function balance(xss, align) {
-  return _.mapValues(xss.ul, function(ignore, v) {
-    if (align) {
-      return xss[align.toLowerCase()][v];
-    } else {
-      var xs = _.sortBy(_.pluck(xss, v));
-      return (xs[1] + xs[2]) / 2;
-    }
-  });
-}
-
-function positionX(g) {
-  var layering = util.buildLayerMatrix(g),
-      conflicts = _.merge(findType1Conflicts(g, layering),
-                          findType2Conflicts(g, layering));
-
-  var xss = {},
-      adjustedLayering;
-  _.each(["u", "d"], function(vert) {
-    adjustedLayering = vert === "u" ? layering : _.values(layering).reverse();
-    _.each(["l", "r"], function(horiz) {
-      if (horiz === "r") {
-        adjustedLayering = _.map(adjustedLayering, function(inner) {
-          return _.values(inner).reverse();
-        });
-      }
-
-      var neighborFn = _.bind(vert === "u" ? g.predecessors : g.successors, g);
-      var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
-      var xs = horizontalCompaction(g, adjustedLayering,
-                                    align.root, align.align,
-                                    horiz === "r");
-      if (horiz === "r") {
-        xs = _.mapValues(xs, function(x) { return -x; });
-      }
-      xss[vert + horiz] = xs;
-    });
-  });
-
-  var smallestWidth = findSmallestWidthAlignment(g, xss);
-  alignCoordinates(xss, smallestWidth);
-  return balance(xss, g.graph().align);
-}
-
-function sep(nodeSep, edgeSep, reverseSep) {
-  return function(g, v, w) {
-    var vLabel = g.node(v),
-        wLabel = g.node(w),
-        sum = 0,
-        delta;
-
-    sum += vLabel.width / 2;
-    if (_.has(vLabel, "labelpos")) {
-      switch (vLabel.labelpos.toLowerCase()) {
-        case "l": delta = -vLabel.width / 2; break;
-        case "r": delta = vLabel.width / 2; break;
-      }
-    }
-    if (delta) {
-      sum += reverseSep ? delta : -delta;
-    }
-    delta = 0;
-
-    sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
-    sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
-
-    sum += wLabel.width / 2;
-    if (_.has(wLabel, "labelpos")) {
-      switch (wLabel.labelpos.toLowerCase()) {
-        case "l": delta = wLabel.width / 2; break;
-        case "r": delta = -wLabel.width / 2; break;
-      }
-    }
-    if (delta) {
-      sum += reverseSep ? delta : -delta;
-    }
-    delta = 0;
-
-    return sum;
-  };
-}
-
-function width(g, v) {
-  return g.node(v).width;
-}
-
-},{"../graphlib":35,"../lodash":38,"../util":57}],52:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash"),
-    util = require("../util"),
-    positionX = require("./bk").positionX;
-
-module.exports = position;
-
-function position(g) {
-  g = util.asNonCompoundGraph(g);
-
-  positionY(g);
-  _.each(positionX(g), function(x, v) {
-    g.node(v).x = x;
-  });
-}
-
-function positionY(g) {
-  var layering = util.buildLayerMatrix(g),
-      rankSep = g.graph().ranksep,
-      prevY = 0;
-  _.each(layering, function(layer) {
-    var maxHeight = _.max(_.map(layer, function(v) { return g.node(v).height; }));
-    _.each(layer, function(v) {
-      g.node(v).y = prevY + maxHeight / 2;
-    });
-    prevY += maxHeight + rankSep;
-  });
-}
-
-
-},{"../lodash":38,"../util":57,"./bk":51}],53:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash"),
-    Graph = require("../graphlib").Graph,
-    slack = require("./util").slack;
-
-module.exports = feasibleTree;
-
-/*
- * Constructs a spanning tree with tight edges and adjusted the input node's
- * ranks to achieve this. A tight edge is one that is has a length that matches
- * its "minlen" attribute.
- *
- * The basic structure for this function is derived from Gansner, et al., "A
- * Technique for Drawing Directed Graphs."
- *
- * Pre-conditions:
- *
- *    1. Graph must be a DAG.
- *    2. Graph must be connected.
- *    3. Graph must have at least one node.
- *    5. Graph nodes must have been previously assigned a "rank" property that
- *       respects the "minlen" property of incident edges.
- *    6. Graph edges must have a "minlen" property.
- *
- * Post-conditions:
- *
- *    - Graph nodes will have their rank adjusted to ensure that all edges are
- *      tight.
- *
- * Returns a tree (undirected graph) that is constructed using only "tight"
- * edges.
- */
-function feasibleTree(g) {
-  var t = new Graph({ directed: false });
-
-  // Choose arbitrary node from which to start our tree
-  var start = g.nodes()[0],
-      size = g.nodeCount();
-  t.setNode(start, {});
-
-  var edge, delta;
-  while (tightTree(t, g) < size) {
-    edge = findMinSlackEdge(t, g);
-    delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
-    shiftRanks(t, g, delta);
-  }
-
-  return t;
-}
-
-/*
- * Finds a maximal tree of tight edges and returns the number of nodes in the
- * tree.
- */
-function tightTree(t, g) {
-  function dfs(v) {
-    _.each(g.nodeEdges(v), function(e) {
-      var edgeV = e.v,
-          w = (v === edgeV) ? e.w : edgeV;
-      if (!t.hasNode(w) && !slack(g, e)) {
-        t.setNode(w, {});
-        t.setEdge(v, w, {});
-        dfs(w);
-      }
-    });
-  }
-
-  _.each(t.nodes(), dfs);
-  return t.nodeCount();
-}
-
-/*
- * Finds the edge with the smallest slack that is incident on tree and returns
- * it.
- */
-function findMinSlackEdge(t, g) {
-  return _.min(g.edges(), function(e) {
-    if (t.hasNode(e.v) !== t.hasNode(e.w)) {
-      return slack(g, e);
-    }
-  });
-}
-
-function shiftRanks(t, g, delta) {
-  _.each(t.nodes(), function(v) {
-    g.node(v).rank += delta;
-  });
-}
-
-},{"../graphlib":35,"../lodash":38,"./util":56}],54:[function(require,module,exports){
-"use strict";
-
-var rankUtil = require("./util"),
-    longestPath = rankUtil.longestPath,
-    feasibleTree = require("./feasible-tree"),
-    networkSimplex = require("./network-simplex");
-
-module.exports = rank;
-
-/*
- * Assigns a rank to each node in the input graph that respects the "minlen"
- * constraint specified on edges between nodes.
- *
- * This basic structure is derived from Gansner, et al., "A Technique for
- * Drawing Directed Graphs."
- *
- * Pre-conditions:
- *
- *    1. Graph must be a connected DAG
- *    2. Graph nodes must be objects
- *    3. Graph edges must have "weight" and "minlen" attributes
- *
- * Post-conditions:
- *
- *    1. Graph nodes will have a "rank" attribute based on the results of the
- *       algorithm. Ranks can start at any index (including negative), we'll
- *       fix them up later.
- */
-function rank(g) {
-  switch(g.graph().ranker) {
-    case "network-simplex": networkSimplexRanker(g); break;
-    case "tight-tree": tightTreeRanker(g); break;
-    case "longest-path": longestPathRanker(g); break;
-    default: networkSimplexRanker(g);
-  }
-}
-
-// A fast and simple ranker, but results are far from optimal.
-var longestPathRanker = longestPath;
-
-function tightTreeRanker(g) {
-  longestPath(g);
-  feasibleTree(g);
-}
-
-function networkSimplexRanker(g) {
-  networkSimplex(g);
-}
-
-},{"./feasible-tree":53,"./network-simplex":55,"./util":56}],55:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash"),
-    feasibleTree = require("./feasible-tree"),
-    slack = require("./util").slack,
-    initRank = require("./util").longestPath,
-    preorder = require("../graphlib").alg.preorder,
-    postorder = require("../graphlib").alg.postorder,
-    simplify = require("../util").simplify;
-
-module.exports = networkSimplex;
-
-// Expose some internals for testing purposes
-networkSimplex.initLowLimValues = initLowLimValues;
-networkSimplex.initCutValues = initCutValues;
-networkSimplex.calcCutValue = calcCutValue;
-networkSimplex.leaveEdge = leaveEdge;
-networkSimplex.enterEdge = enterEdge;
-networkSimplex.exchangeEdges = exchangeEdges;
-
-/*
- * The network simplex algorithm assigns ranks to each node in the input graph
- * and iteratively improves the ranking to reduce the length of edges.
- *
- * Preconditions:
- *
- *    1. The input graph must be a DAG.
- *    2. All nodes in the graph must have an object value.
- *    3. All edges in the graph must have "minlen" and "weight" attributes.
- *
- * Postconditions:
- *
- *    1. All nodes in the graph will have an assigned "rank" attribute that has
- *       been optimized by the network simplex algorithm. Ranks start at 0.
- *
- *
- * A rough sketch of the algorithm is as follows:
- *
- *    1. Assign initial ranks to each node. We use the longest path algorithm,
- *       which assigns ranks to the lowest position possible. In general this
- *       leads to very wide bottom ranks and unnecessarily long edges.
- *    2. Construct a feasible tight tree. A tight tree is one such that all
- *       edges in the tree have no slack (difference between length of edge
- *       and minlen for the edge). This by itself greatly improves the assigned
- *       rankings by shorting edges.
- *    3. Iteratively find edges that have negative cut values. Generally a
- *       negative cut value indicates that the edge could be removed and a new
- *       tree edge could be added to produce a more compact graph.
- *
- * Much of the algorithms here are derived from Gansner, et al., "A Technique
- * for Drawing Directed Graphs." The structure of the file roughly follows the
- * structure of the overall algorithm.
- */
-function networkSimplex(g) {
-  g = simplify(g);
-  initRank(g);
-  var t = feasibleTree(g);
-  initLowLimValues(t);
-  initCutValues(t, g);
-
-  var e, f;
-  while ((e = leaveEdge(t))) {
-    f = enterEdge(t, g, e);
-    exchangeEdges(t, g, e, f);
-  }
-}
-
-/*
- * Initializes cut values for all edges in the tree.
- */
-function initCutValues(t, g) {
-  var vs = postorder(t, t.nodes());
-  vs = vs.slice(0, vs.length - 1);
-  _.each(vs, function(v) {
-    assignCutValue(t, g, v);
-  });
-}
-
-function assignCutValue(t, g, child) {
-  var childLab = t.node(child),
-      parent = childLab.parent;
-  t.edge(child, parent).cutvalue = calcCutValue(t, g, child);
-}
-
-/*
- * Given the tight tree, its graph, and a child in the graph calculate and
- * return the cut value for the edge between the child and its parent.
- */
-function calcCutValue(t, g, child) {
-  var childLab = t.node(child),
-      parent = childLab.parent,
-      // True if the child is on the tail end of the edge in the directed graph
-      childIsTail = true,
-      // The graph's view of the tree edge we're inspecting
-      graphEdge = g.edge(child, parent),
-      // The accumulated cut value for the edge between this node and its parent
-      cutValue = 0;
-
-  if (!graphEdge) {
-    childIsTail = false;
-    graphEdge = g.edge(parent, child);
-  }
-
-  cutValue = graphEdge.weight;
-
-  _.each(g.nodeEdges(child), function(e) {
-    var isOutEdge = e.v === child,
-        other = isOutEdge ? e.w : e.v;
-
-    if (other !== parent) {
-      var pointsToHead = isOutEdge === childIsTail,
-          otherWeight = g.edge(e).weight;
-
-      cutValue += pointsToHead ? otherWeight : -otherWeight;
-      if (isTreeEdge(t, child, other)) {
-        var otherCutValue = t.edge(child, other).cutvalue;
-        cutValue += pointsToHead ? -otherCutValue : otherCutValue;
-      }
-    }
-  });
-
-  return cutValue;
-}
-
-function initLowLimValues(tree, root) {
-  if (arguments.length < 2) {
-    root = tree.nodes()[0];
-  }
-  dfsAssignLowLim(tree, {}, 1, root);
-}
-
-function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
-  var low = nextLim,
-      label = tree.node(v);
-
-  visited[v] = true;
-  _.each(tree.neighbors(v), function(w) {
-    if (!_.has(visited, w)) {
-      nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
-    }
-  });
-
-  label.low = low;
-  label.lim = nextLim++;
-  if (parent) {
-    label.parent = parent;
-  } else {
-    // TODO should be able to remove this when we incrementally update low lim
-    delete label.parent;
-  }
-
-  return nextLim;
-}
-
-function leaveEdge(tree) {
-  return _.find(tree.edges(), function(e) {
-    return tree.edge(e).cutvalue < 0;
-  });
-}
-
-function enterEdge(t, g, edge) {
-  var v = edge.v,
-      w = edge.w;
-
-  // For the rest of this function we assume that v is the tail and w is the
-  // head, so if we don't have this edge in the graph we should flip it to
-  // match the correct orientation.
-  if (!g.hasEdge(v, w)) {
-    v = edge.w;
-    w = edge.v;
-  }
-
-  var vLabel = t.node(v),
-      wLabel = t.node(w),
-      tailLabel = vLabel,
-      flip = false;
-
-  // If the root is in the tail of the edge then we need to flip the logic that
-  // checks for the head and tail nodes in the candidates function below.
-  if (vLabel.lim > wLabel.lim) {
-    tailLabel = wLabel;
-    flip = true;
-  }
-
-  var candidates = _.filter(g.edges(), function(edge) {
-    return flip === isDescendant(t, t.node(edge.v), tailLabel) &&
-           flip !== isDescendant(t, t.node(edge.w), tailLabel);
-  });
-
-  return _.min(candidates, function(edge) { return slack(g, edge); });
-}
-
-function exchangeEdges(t, g, e, f) {
-  var v = e.v,
-      w = e.w;
-  t.removeEdge(v, w);
-  t.setEdge(f.v, f.w, {});
-  initLowLimValues(t);
-  initCutValues(t, g);
-  updateRanks(t, g);
-}
-
-function updateRanks(t, g) {
-  var root = _.find(t.nodes(), function(v) { return !g.node(v).parent; }),
-      vs = preorder(t, root);
-  vs = vs.slice(1);
-  _.each(vs, function(v) {
-    var parent = t.node(v).parent,
-        edge = g.edge(v, parent),
-        flipped = false;
-
-    if (!edge) {
-      edge = g.edge(parent, v);
-      flipped = true;
-    }
-
-    g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen);
-  });
-}
-
-/*
- * Returns true if the edge is in the tree.
- */
-function isTreeEdge(tree, u, v) {
-  return tree.hasEdge(u, v);
-}
-
-/*
- * Returns true if the specified node is descendant of the root node per the
- * assigned low and lim attributes in the tree.
- */
-function isDescendant(tree, vLabel, rootLabel) {
-  return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim;
-}
-
-},{"../graphlib":35,"../lodash":38,"../util":57,"./feasible-tree":53,"./util":56}],56:[function(require,module,exports){
-"use strict";
-
-var _ = require("../lodash");
-
-module.exports = {
-  longestPath: longestPath,
-  slack: slack
-};
-
-/*
- * Initializes ranks for the input graph using the longest path algorithm. This
- * algorithm scales well and is fast in practice, it yields rather poor
- * solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
- * ranks wide and leaving edges longer than necessary. However, due to its
- * speed, this algorithm is good for getting an initial ranking that can be fed
- * into other algorithms.
- *
- * This algorithm does not normalize layers because it will be used by other
- * algorithms in most cases. If using this algorithm directly, be sure to
- * run normalize at the end.
- *
- * Pre-conditions:
- *
- *    1. Input graph is a DAG.
- *    2. Input graph node labels can be assigned properties.
- *
- * Post-conditions:
- *
- *    1. Each node will be assign an (unnormalized) "rank" property.
- */
-function longestPath(g) {
-  var visited = {};
-
-  function dfs(v) {
-    var label = g.node(v);
-    if (_.has(visited, v)) {
-      return label.rank;
-    }
-    visited[v] = true;
-
-    var rank = _.min(_.map(g.outEdges(v), function(e) {
-      return dfs(e.w) - g.edge(e).minlen;
-    }));
-
-    if (rank === Number.POSITIVE_INFINITY) {
-      rank = 0;
-    }
-
-    return (label.rank = rank);
-  }
-
-  _.each(g.sources(), dfs);
-}
-
-/*
- * Returns the amount of slack for the given edge. The slack is defined as the
- * difference between the length of the edge and its minimum length.
- */
-function slack(g, e) {
-  return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
-}
-
-},{"../lodash":38}],57:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash"),
-    Graph = require("./graphlib").Graph;
-
-module.exports = {
-  addDummyNode: addDummyNode,
-  simplify: simplify,
-  asNonCompoundGraph: asNonCompoundGraph,
-  successorWeights: successorWeights,
-  predecessorWeights: predecessorWeights,
-  intersectRect: intersectRect,
-  buildLayerMatrix: buildLayerMatrix,
-  normalizeRanks: normalizeRanks,
-  removeEmptyRanks: removeEmptyRanks,
-  addBorderNode: addBorderNode,
-  maxRank: maxRank,
-  partition: partition,
-  time: time,
-  notime: notime
-};
-
-/*
- * Adds a dummy node to the graph and return v.
- */
-function addDummyNode(g, type, attrs, name) {
-  var v;
-  do {
-    v = _.uniqueId(name);
-  } while (g.hasNode(v));
-
-  attrs.dummy = type;
-  g.setNode(v, attrs);
-  return v;
-}
-
-/*
- * Returns a new graph with only simple edges. Handles aggregation of data
- * associated with multi-edges.
- */
-function simplify(g) {
-  var simplified = new Graph().setGraph(g.graph());
-  _.each(g.nodes(), function(v) { simplified.setNode(v, g.node(v)); });
-  _.each(g.edges(), function(e) {
-    var simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 },
-        label = g.edge(e);
-    simplified.setEdge(e.v, e.w, {
-      weight: simpleLabel.weight + label.weight,
-      minlen: Math.max(simpleLabel.minlen, label.minlen)
-    });
-  });
-  return simplified;
-}
-
-function asNonCompoundGraph(g) {
-  var simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
-  _.each(g.nodes(), function(v) {
-    if (!g.children(v).length) {
-      simplified.setNode(v, g.node(v));
-    }
-  });
-  _.each(g.edges(), function(e) {
-    simplified.setEdge(e, g.edge(e));
-  });
-  return simplified;
-}
-
-function successorWeights(g) {
-  var weightMap = _.map(g.nodes(), function(v) {
-    var sucs = {};
-    _.each(g.outEdges(v), function(e) {
-      sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight;
-    });
-    return sucs;
-  });
-  return _.zipObject(g.nodes(), weightMap);
-}
-
-function predecessorWeights(g) {
-  var weightMap = _.map(g.nodes(), function(v) {
-    var preds = {};
-    _.each(g.inEdges(v), function(e) {
-      preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight;
-    });
-    return preds;
-  });
-  return _.zipObject(g.nodes(), weightMap);
-}
-
-/*
- * Finds where a line starting at point ({x, y}) would intersect a rectangle
- * ({x, y, width, height}) if it were pointing at the rectangle's center.
- */
-function intersectRect(rect, point) {
-  var x = rect.x;
-  var y = rect.y;
-
-  // Rectangle intersection algorithm from:
-  // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
-  var dx = point.x - x;
-  var dy = point.y - y;
-  var w = rect.width / 2;
-  var h = rect.height / 2;
-
-  if (!dx && !dy) {
-    throw new Error("Not possible to find intersection inside of the rectangle");
-  }
-
-  var sx, sy;
-  if (Math.abs(dy) * w > Math.abs(dx) * h) {
-    // Intersection is top or bottom of rect.
-    if (dy < 0) {
-      h = -h;
-    }
-    sx = h * dx / dy;
-    sy = h;
-  } else {
-    // Intersection is left or right of rect.
-    if (dx < 0) {
-      w = -w;
-    }
-    sx = w;
-    sy = w * dy / dx;
-  }
-
-  return { x: x + sx, y: y + sy };
-}
-
-/*
- * Given a DAG with each node assigned "rank" and "order" properties, this
- * function will produce a matrix with the ids of each node.
- */
-function buildLayerMatrix(g) {
-  var layering = _.map(_.range(maxRank(g) + 1), function() { return []; });
-  _.each(g.nodes(), function(v) {
-    var node = g.node(v),
-        rank = node.rank;
-    if (!_.isUndefined(rank)) {
-      layering[rank][node.order] = v;
-    }
-  });
-  return layering;
-}
-
-/*
- * Adjusts the ranks for all nodes in the graph such that all nodes v have
- * rank(v) >= 0 and at least one node w has rank(w) = 0.
- */
-function normalizeRanks(g) {
-  var min = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
-  _.each(g.nodes(), function(v) {
-    var node = g.node(v);
-    if (_.has(node, "rank")) {
-      node.rank -= min;
-    }
-  });
-}
-
-function removeEmptyRanks(g) {
-  // Ranks may not start at 0, so we need to offset them
-  var offset = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
-
-  var layers = [];
-  _.each(g.nodes(), function(v) {
-    var rank = g.node(v).rank - offset;
-    if (!_.has(layers, rank)) {
-      layers[rank] = [];
-    }
-    layers[rank].push(v);
-  });
-
-  var delta = 0,
-      nodeRankFactor = g.graph().nodeRankFactor;
-  _.each(layers, function(vs, i) {
-    if (_.isUndefined(vs) && i % nodeRankFactor !== 0) {
-      --delta;
-    } else if (delta) {
-      _.each(vs, function(v) { g.node(v).rank += delta; });
-    }
-  });
-}
-
-function addBorderNode(g, prefix, rank, order) {
-  var node = {
-    width: 0,
-    height: 0
-  };
-  if (arguments.length >= 4) {
-    node.rank = rank;
-    node.order = order;
-  }
-  return addDummyNode(g, "border", node, prefix);
-}
-
-function maxRank(g) {
-  return _.max(_.map(g.nodes(), function(v) {
-    var rank = g.node(v).rank;
-    if (!_.isUndefined(rank)) {
-      return rank;
-    }
-  }));
-}
-
-/*
- * Partition a collection into two groups: `lhs` and `rhs`. If the supplied
- * function returns true for an entry it goes into `lhs`. Otherwise it goes
- * into `rhs.
- */
-function partition(collection, fn) {
-  var result = { lhs: [], rhs: [] };
-  _.each(collection, function(value) {
-    if (fn(value)) {
-      result.lhs.push(value);
-    } else {
-      result.rhs.push(value);
-    }
-  });
-  return result;
-}
-
-/*
- * Returns a new function that wraps `fn` with a timer. The wrapper logs the
- * time it takes to execute the function.
- */
-function time(name, fn) {
-  var start = _.now();
-  try {
-    return fn();
-  } finally {
-    console.log(name + " time: " + (_.now() - start) + "ms");
-  }
-}
-
-function notime(name, fn) {
-  return fn();
-}
-
-},{"./graphlib":35,"./lodash":38}],58:[function(require,module,exports){
-module.exports = "0.7.2";
-
-},{}],59:[function(require,module,exports){
-(function (global){
-/**
- * @license
- * Lo-Dash 2.4.2 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern -o ./dist/lodash.js`
- * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-;(function() {
-
-  /** Used as a safe reference for `undefined` in pre ES5 environments */
-  var undefined;
-
-  /** Used to pool arrays and objects used internally */
-  var arrayPool = [],
-      objectPool = [];
-
-  /** Used to generate unique IDs */
-  var idCounter = 0;
-
-  /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
-  var keyPrefix = +new Date + '';
-
-  /** Used as the size when optimizations are enabled for large arrays */
-  var largeArraySize = 75;
-
-  /** Used as the max size of the `arrayPool` and `objectPool` */
-  var maxPoolSize = 40;
-
-  /** Used to detect and test whitespace */
-  var whitespace = (
-    // whitespace
-    ' \t\x0B\f\xA0\ufeff' +
-
-    // line terminators
-    '\n\r\u2028\u2029' +
-
-    // unicode category "Zs" space separators
-    '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
-  );
-
-  /** Used to match empty string literals in compiled template source */
-  var reEmptyStringLeading = /\b__p \+= '';/g,
-      reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
-      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
-
-  /**
-   * Used to match ES6 template delimiters
-   * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
-   */
-  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
-
-  /** Used to match regexp flags from their coerced string values */
-  var reFlags = /\w*$/;
-
-  /** Used to detected named functions */
-  var reFuncName = /^\s*function[ \n\r\t]+\w/;
-
-  /** Used to match "interpolate" template delimiters */
-  var reInterpolate = /<%=([\s\S]+?)%>/g;
-
-  /** Used to match leading whitespace and zeros to be removed */
-  var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
-
-  /** Used to ensure capturing order of template delimiters */
-  var reNoMatch = /($^)/;
-
-  /** Used to detect functions containing a `this` reference */
-  var reThis = /\bthis\b/;
-
-  /** Used to match unescaped characters in compiled string literals */
-  var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
-
-  /** Used to assign default `context` object properties */
-  var contextProps = [
-    'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
-    'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
-    'parseInt', 'setTimeout'
-  ];
-
-  /** Used to make template sourceURLs easier to identify */
-  var templateCounter = 0;
-
-  /** `Object#toString` result shortcuts */
-  var argsClass = '[object Arguments]',
-      arrayClass = '[object Array]',
-      boolClass = '[object Boolean]',
-      dateClass = '[object Date]',
-      funcClass = '[object Function]',
-      numberClass = '[object Number]',
-      objectClass = '[object Object]',
-      regexpClass = '[object RegExp]',
-      stringClass = '[object String]';
-
-  /** Used to identify object classifications that `_.clone` supports */
-  var cloneableClasses = {};
-  cloneableClasses[funcClass] = false;
-  cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
-  cloneableClasses[boolClass] = cloneableClasses[dateClass] =
-  cloneableClasses[numberClass] = cloneableClasses[objectClass] =
-  cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
-
-  /** Used as an internal `_.debounce` options object */
-  var debounceOptions = {
-    'leading': false,
-    'maxWait': 0,
-    'trailing': false
-  };
-
-  /** Used as the property descriptor for `__bindData__` */
-  var descriptor = {
-    'configurable': false,
-    'enumerable': false,
-    'value': null,
-    'writable': false
-  };
-
-  /** Used to determine if values are of the language type Object */
-  var objectTypes = {
-    'boolean': false,
-    'function': true,
-    'object': true,
-    'number': false,
-    'string': false,
-    'undefined': false
-  };
-
-  /** Used to escape characters for inclusion in compiled string literals */
-  var stringEscapes = {
-    '\\': '\\',
-    "'": "'",
-    '\n': 'n',
-    '\r': 'r',
-    '\t': 't',
-    '\u2028': 'u2028',
-    '\u2029': 'u2029'
-  };
-
-  /** Used as a reference to the global object */
-  var root = (objectTypes[typeof window] && window) || this;
-
-  /** Detect free variable `exports` */
-  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
-
-  /** Detect free variable `module` */
-  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
-
-  /** Detect the popular CommonJS extension `module.exports` */
-  var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
-
-  /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
-  var freeGlobal = objectTypes[typeof global] && global;
-  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
-    root = freeGlobal;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * The base implementation of `_.indexOf` without support for binary searches
-   * or `fromIndex` constraints.
-   *
-   * @private
-   * @param {Array} array The array to search.
-   * @param {*} value The value to search for.
-   * @param {number} [fromIndex=0] The index to search from.
-   * @returns {number} Returns the index of the matched value or `-1`.
-   */
-  function baseIndexOf(array, value, fromIndex) {
-    var index = (fromIndex || 0) - 1,
-        length = array ? array.length : 0;
-
-    while (++index < length) {
-      if (array[index] === value) {
-        return index;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * An implementation of `_.contains` for cache objects that mimics the return
-   * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
-   *
-   * @private
-   * @param {Object} cache The cache object to inspect.
-   * @param {*} value The value to search for.
-   * @returns {number} Returns `0` if `value` is found, else `-1`.
-   */
-  function cacheIndexOf(cache, value) {
-    var type = typeof value;
-    cache = cache.cache;
-
-    if (type == 'boolean' || value == null) {
-      return cache[value] ? 0 : -1;
-    }
-    if (type != 'number' && type != 'string') {
-      type = 'object';
-    }
-    var key = type == 'number' ? value : keyPrefix + value;
-    cache = (cache = cache[type]) && cache[key];
-
-    return type == 'object'
-      ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
-      : (cache ? 0 : -1);
-  }
-
-  /**
-   * Adds a given value to the corresponding cache object.
-   *
-   * @private
-   * @param {*} value The value to add to the cache.
-   */
-  function cachePush(value) {
-    var cache = this.cache,
-        type = typeof value;
-
-    if (type == 'boolean' || value == null) {
-      cache[value] = true;
-    } else {
-      if (type != 'number' && type != 'string') {
-        type = 'object';
-      }
-      var key = type == 'number' ? value : keyPrefix + value,
-          typeCache = cache[type] || (cache[type] = {});
-
-      if (type == 'object') {
-        (typeCache[key] || (typeCache[key] = [])).push(value);
-      } else {
-        typeCache[key] = true;
-      }
-    }
-  }
-
-  /**
-   * Used by `_.max` and `_.min` as the default callback when a given
-   * collection is a string value.
-   *
-   * @private
-   * @param {string} value The character to inspect.
-   * @returns {number} Returns the code unit of given character.
-   */
-  function charAtCallback(value) {
-    return value.charCodeAt(0);
-  }
-
-  /**
-   * Used by `sortBy` to compare transformed `collection` elements, stable sorting
-   * them in ascending order.
-   *
-   * @private
-   * @param {Object} a The object to compare to `b`.
-   * @param {Object} b The object to compare to `a`.
-   * @returns {number} Returns the sort order indicator of `1` or `-1`.
-   */
-  function compareAscending(a, b) {
-    var ac = a.criteria,
-        bc = b.criteria,
-        index = -1,
-        length = ac.length;
-
-    while (++index < length) {
-      var value = ac[index],
-          other = bc[index];
-
-      if (value !== other) {
-        if (value > other || typeof value == 'undefined') {
-          return 1;
-        }
-        if (value < other || typeof other == 'undefined') {
-          return -1;
-        }
-      }
-    }
-    // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
-    // that causes it, under certain circumstances, to return the same value for
-    // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
-    //
-    // This also ensures a stable sort in V8 and other engines.
-    // See http://code.google.com/p/v8/issues/detail?id=90
-    return a.index - b.index;
-  }
-
-  /**
-   * Creates a cache object to optimize linear searches of large arrays.
-   *
-   * @private
-   * @param {Array} [array=[]] The array to search.
-   * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
-   */
-  function createCache(array) {
-    var index = -1,
-        length = array.length,
-        first = array[0],
-        mid = array[(length / 2) | 0],
-        last = array[length - 1];
-
-    if (first && typeof first == 'object' &&
-        mid && typeof mid == 'object' && last && typeof last == 'object') {
-      return false;
-    }
-    var cache = getObject();
-    cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
-
-    var result = getObject();
-    result.array = array;
-    result.cache = cache;
-    result.push = cachePush;
-
-    while (++index < length) {
-      result.push(array[index]);
-    }
-    return result;
-  }
-
-  /**
-   * Used by `template` to escape characters for inclusion in compiled
-   * string literals.
-   *
-   * @private
-   * @param {string} match The matched character to escape.
-   * @returns {string} Returns the escaped character.
-   */
-  function escapeStringChar(match) {
-    return '\\' + stringEscapes[match];
-  }
-
-  /**
-   * Gets an array from the array pool or creates a new one if the pool is empty.
-   *
-   * @private
-   * @returns {Array} The array from the pool.
-   */
-  function getArray() {
-    return arrayPool.pop() || [];
-  }
-
-  /**
-   * Gets an object from the object pool or creates a new one if the pool is empty.
-   *
-   * @private
-   * @returns {Object} The object from the pool.
-   */
-  function getObject() {
-    return objectPool.pop() || {
-      'array': null,
-      'cache': null,
-      'criteria': null,
-      'false': false,
-      'index': 0,
-      'null': false,
-      'number': null,
-      'object': null,
-      'push': null,
-      'string': null,
-      'true': false,
-      'undefined': false,
-      'value': null
-    };
-  }
-
-  /**
-   * Releases the given array back to the array pool.
-   *
-   * @private
-   * @param {Array} [array] The array to release.
-   */
-  function releaseArray(array) {
-    array.length = 0;
-    if (arrayPool.length < maxPoolSize) {
-      arrayPool.push(array);
-    }
-  }
-
-  /**
-   * Releases the given object back to the object pool.
-   *
-   * @private
-   * @param {Object} [object] The object to release.
-   */
-  function releaseObject(object) {
-    var cache = object.cache;
-    if (cache) {
-      releaseObject(cache);
-    }
-    object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
-    if (objectPool.length < maxPoolSize) {
-      objectPool.push(object);
-    }
-  }
-
-  /**
-   * Slices the `collection` from the `start` index up to, but not including,
-   * the `end` index.
-   *
-   * Note: This function is used instead of `Array#slice` to support node lists
-   * in IE < 9 and to ensure dense arrays are returned.
-   *
-   * @private
-   * @param {Array|Object|string} collection The collection to slice.
-   * @param {number} start The start index.
-   * @param {number} end The end index.
-   * @returns {Array} Returns the new array.
-   */
-  function slice(array, start, end) {
-    start || (start = 0);
-    if (typeof end == 'undefined') {
-      end = array ? array.length : 0;
-    }
-    var index = -1,
-        length = end - start || 0,
-        result = Array(length < 0 ? 0 : length);
-
-    while (++index < length) {
-      result[index] = array[start + index];
-    }
-    return result;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * Create a new `lodash` function using the given context object.
-   *
-   * @static
-   * @memberOf _
-   * @category Utilities
-   * @param {Object} [context=root] The context object.
-   * @returns {Function} Returns the `lodash` function.
-   */
-  function runInContext(context) {
-    // Avoid issues with some ES3 environments that attempt to use values, named
-    // after built-in constructors like `Object`, for the creation of literals.
-    // ES5 clears this up by stating that literals must use built-in constructors.
-    // See http://es5.github.io/#x11.1.5.
-    context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
-
-    /** Native constructor references */
-    var Array = context.Array,
-        Boolean = context.Boolean,
-        Date = context.Date,
-        Function = context.Function,
-        Math = context.Math,
-        Number = context.Number,
-        Object = context.Object,
-        RegExp = context.RegExp,
-        String = context.String,
-        TypeError = context.TypeError;
-
-    /**
-     * Used for `Array` method references.
-     *
-     * Normally `Array.prototype` would suffice, however, using an array literal
-     * avoids issues in Narwhal.
-     */
-    var arrayRef = [];
-
-    /** Used for native method references */
-    var objectProto = Object.prototype;
-
-    /** Used to restore the original `_` reference in `noConflict` */
-    var oldDash = context._;
-
-    /** Used to resolve the internal [[Class]] of values */
-    var toString = objectProto.toString;
-
-    /** Used to detect if a method is native */
-    var reNative = RegExp('^' +
-      String(toString)
-        .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
-        .replace(/toString| for [^\]]+/g, '.*?') + '$'
-    );
-
-    /** Native method shortcuts */
-    var ceil = Math.ceil,
-        clearTimeout = context.clearTimeout,
-        floor = Math.floor,
-        fnToString = Function.prototype.toString,
-        getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
-        hasOwnProperty = objectProto.hasOwnProperty,
-        push = arrayRef.push,
-        setTimeout = context.setTimeout,
-        splice = arrayRef.splice,
-        unshift = arrayRef.unshift;
-
-    /** Used to set meta data on functions */
-    var defineProperty = (function() {
-      // IE 8 only accepts DOM elements
-      try {
-        var o = {},
-            func = isNative(func = Object.defineProperty) && func,
-            result = func(o, o, o) && func;
-      } catch(e) { }
-      return result;
-    }());
-
-    /* Native method shortcuts for methods with the same name as other `lodash` methods */
-    var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
-        nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
-        nativeIsFinite = context.isFinite,
-        nativeIsNaN = context.isNaN,
-        nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
-        nativeMax = Math.max,
-        nativeMin = Math.min,
-        nativeParseInt = context.parseInt,
-        nativeRandom = Math.random;
-
-    /** Used to lookup a built-in constructor by [[Class]] */
-    var ctorByClass = {};
-    ctorByClass[arrayClass] = Array;
-    ctorByClass[boolClass] = Boolean;
-    ctorByClass[dateClass] = Date;
-    ctorByClass[funcClass] = Function;
-    ctorByClass[objectClass] = Object;
-    ctorByClass[numberClass] = Number;
-    ctorByClass[regexpClass] = RegExp;
-    ctorByClass[stringClass] = String;
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a `lodash` object which wraps the given value to enable intuitive
-     * method chaining.
-     *
-     * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
-     * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
-     * and `unshift`
-     *
-     * Chaining is supported in custom builds as long as the `value` method is
-     * implicitly or explicitly included in the build.
-     *
-     * The chainable wrapper functions are:
-     * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
-     * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
-     * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
-     * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
-     * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
-     * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
-     * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
-     * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
-     * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
-     * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
-     * and `zip`
-     *
-     * The non-chainable wrapper functions are:
-     * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
-     * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
-     * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
-     * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
-     * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
-     * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
-     * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
-     * `template`, `unescape`, `uniqueId`, and `value`
-     *
-     * The wrapper functions `first` and `last` return wrapped values when `n` is
-     * provided, otherwise they return unwrapped values.
-     *
-     * Explicit chaining can be enabled by using the `_.chain` method.
-     *
-     * @name _
-     * @constructor
-     * @category Chaining
-     * @param {*} value The value to wrap in a `lodash` instance.
-     * @returns {Object} Returns a `lodash` instance.
-     * @example
-     *
-     * var wrapped = _([1, 2, 3]);
-     *
-     * // returns an unwrapped value
-     * wrapped.reduce(function(sum, num) {
-     *   return sum + num;
-     * });
-     * // => 6
-     *
-     * // returns a wrapped value
-     * var squares = wrapped.map(function(num) {
-     *   return num * num;
-     * });
-     *
-     * _.isArray(squares);
-     * // => false
-     *
-     * _.isArray(squares.value());
-     * // => true
-     */
-    function lodash(value) {
-      // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
-      return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
-       ? value
-       : new lodashWrapper(value);
-    }
-
-    /**
-     * A fast path for creating `lodash` wrapper objects.
-     *
-     * @private
-     * @param {*} value The value to wrap in a `lodash` instance.
-     * @param {boolean} chainAll A flag to enable chaining for all methods
-     * @returns {Object} Returns a `lodash` instance.
-     */
-    function lodashWrapper(value, chainAll) {
-      this.__chain__ = !!chainAll;
-      this.__wrapped__ = value;
-    }
-    // ensure `new lodashWrapper` is an instance of `lodash`
-    lodashWrapper.prototype = lodash.prototype;
-
-    /**
-     * An object used to flag environments features.
-     *
-     * @static
-     * @memberOf _
-     * @type Object
-     */
-    var support = lodash.support = {};
-
-    /**
-     * Detect if functions can be decompiled by `Function#toString`
-     * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
-     *
-     * @memberOf _.support
-     * @type boolean
-     */
-    support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
-
-    /**
-     * Detect if `Function#name` is supported (all but IE).
-     *
-     * @memberOf _.support
-     * @type boolean
-     */
-    support.funcNames = typeof Function.name == 'string';
-
-    /**
-     * By default, the template delimiters used by Lo-Dash are similar to those in
-     * embedded Ruby (ERB). Change the following template settings to use alternative
-     * delimiters.
-     *
-     * @static
-     * @memberOf _
-     * @type Object
-     */
-    lodash.templateSettings = {
-
-      /**
-       * Used to detect `data` property values to be HTML-escaped.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'escape': /<%-([\s\S]+?)%>/g,
-
-      /**
-       * Used to detect code to be evaluated.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'evaluate': /<%([\s\S]+?)%>/g,
-
-      /**
-       * Used to detect `data` property values to inject.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'interpolate': reInterpolate,
-
-      /**
-       * Used to reference the data object in the template text.
-       *
-       * @memberOf _.templateSettings
-       * @type string
-       */
-      'variable': '',
-
-      /**
-       * Used to import variables into the compiled template.
-       *
-       * @memberOf _.templateSettings
-       * @type Object
-       */
-      'imports': {
-
-        /**
-         * A reference to the `lodash` function.
-         *
-         * @memberOf _.templateSettings.imports
-         * @type Function
-         */
-        '_': lodash
-      }
-    };
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * The base implementation of `_.bind` that creates the bound function and
-     * sets its meta data.
-     *
-     * @private
-     * @param {Array} bindData The bind data array.
-     * @returns {Function} Returns the new bound function.
-     */
-    function baseBind(bindData) {
-      var func = bindData[0],
-          partialArgs = bindData[2],
-          thisArg = bindData[4];
-
-      function bound() {
-        // `Function#bind` spec
-        // http://es5.github.io/#x15.3.4.5
-        if (partialArgs) {
-          // avoid `arguments` object deoptimizations by using `slice` instead
-          // of `Array.prototype.slice.call` and not assigning `arguments` to a
-          // variable as a ternary expression
-          var args = slice(partialArgs);
-          push.apply(args, arguments);
-        }
-        // mimic the constructor's `return` behavior
-        // http://es5.github.io/#x13.2.2
-        if (this instanceof bound) {
-          // ensure `new bound` is an instance of `func`
-          var thisBinding = baseCreate(func.prototype),
-              result = func.apply(thisBinding, args || arguments);
-          return isObject(result) ? result : thisBinding;
-        }
-        return func.apply(thisArg, args || arguments);
-      }
-      setBindData(bound, bindData);
-      return bound;
-    }
-
-    /**
-     * The base implementation of `_.clone` without argument juggling or support
-     * for `thisArg` binding.
-     *
-     * @private
-     * @param {*} value The value to clone.
-     * @param {boolean} [isDeep=false] Specify a deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {Array} [stackA=[]] Tracks traversed source objects.
-     * @param {Array} [stackB=[]] Associates clones with source counterparts.
-     * @returns {*} Returns the cloned value.
-     */
-    function baseClone(value, isDeep, callback, stackA, stackB) {
-      if (callback) {
-        var result = callback(value);
-        if (typeof result != 'undefined') {
-          return result;
-        }
-      }
-      // inspect [[Class]]
-      var isObj = isObject(value);
-      if (isObj) {
-        var className = toString.call(value);
-        if (!cloneableClasses[className]) {
-          return value;
-        }
-        var ctor = ctorByClass[className];
-        switch (className) {
-          case boolClass:
-          case dateClass:
-            return new ctor(+value);
-
-          case numberClass:
-          case stringClass:
-            return new ctor(value);
-
-          case regexpClass:
-            result = ctor(value.source, reFlags.exec(value));
-            result.lastIndex = value.lastIndex;
-            return result;
-        }
-      } else {
-        return value;
-      }
-      var isArr = isArray(value);
-      if (isDeep) {
-        // check for circular references and return corresponding clone
-        var initedStack = !stackA;
-        stackA || (stackA = getArray());
-        stackB || (stackB = getArray());
-
-        var length = stackA.length;
-        while (length--) {
-          if (stackA[length] == value) {
-            return stackB[length];
-          }
-        }
-        result = isArr ? ctor(value.length) : {};
-      }
-      else {
-        result = isArr ? slice(value) : assign({}, value);
-      }
-      // add array properties assigned by `RegExp#exec`
-      if (isArr) {
-        if (hasOwnProperty.call(value, 'index')) {
-          result.index = value.index;
-        }
-        if (hasOwnProperty.call(value, 'input')) {
-          result.input = value.input;
-        }
-      }
-      // exit for shallow clone
-      if (!isDeep) {
-        return result;
-      }
-      // add the source value to the stack of traversed objects
-      // and associate it with its clone
-      stackA.push(value);
-      stackB.push(result);
-
-      // recursively populate clone (susceptible to call stack limits)
-      (isArr ? forEach : forOwn)(value, function(objValue, key) {
-        result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
-      });
-
-      if (initedStack) {
-        releaseArray(stackA);
-        releaseArray(stackB);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.create` without support for assigning
-     * properties to the created object.
-     *
-     * @private
-     * @param {Object} prototype The object to inherit from.
-     * @returns {Object} Returns the new object.
-     */
-    function baseCreate(prototype, properties) {
-      return isObject(prototype) ? nativeCreate(prototype) : {};
-    }
-    // fallback for browsers without `Object.create`
-    if (!nativeCreate) {
-      baseCreate = (function() {
-        function Object() {}
-        return function(prototype) {
-          if (isObject(prototype)) {
-            Object.prototype = prototype;
-            var result = new Object;
-            Object.prototype = null;
-          }
-          return result || context.Object();
-        };
-      }());
-    }
-
-    /**
-     * The base implementation of `_.createCallback` without support for creating
-     * "_.pluck" or "_.where" style callbacks.
-     *
-     * @private
-     * @param {*} [func=identity] The value to convert to a callback.
-     * @param {*} [thisArg] The `this` binding of the created callback.
-     * @param {number} [argCount] The number of arguments the callback accepts.
-     * @returns {Function} Returns a callback function.
-     */
-    function baseCreateCallback(func, thisArg, argCount) {
-      if (typeof func != 'function') {
-        return identity;
-      }
-      // exit early for no `thisArg` or already bound by `Function#bind`
-      if (typeof thisArg == 'undefined' || !('prototype' in func)) {
-        return func;
-      }
-      var bindData = func.__bindData__;
-      if (typeof bindData == 'undefined') {
-        if (support.funcNames) {
-          bindData = !func.name;
-        }
-        bindData = bindData || !support.funcDecomp;
-        if (!bindData) {
-          var source = fnToString.call(func);
-          if (!support.funcNames) {
-            bindData = !reFuncName.test(source);
-          }
-          if (!bindData) {
-            // checks if `func` references the `this` keyword and stores the result
-            bindData = reThis.test(source);
-            setBindData(func, bindData);
-          }
-        }
-      }
-      // exit early if there are no `this` references or `func` is bound
-      if (bindData === false || (bindData !== true && bindData[1] & 1)) {
-        return func;
-      }
-      switch (argCount) {
-        case 1: return function(value) {
-          return func.call(thisArg, value);
-        };
-        case 2: return function(a, b) {
-          return func.call(thisArg, a, b);
-        };
-        case 3: return function(value, index, collection) {
-          return func.call(thisArg, value, index, collection);
-        };
-        case 4: return function(accumulator, value, index, collection) {
-          return func.call(thisArg, accumulator, value, index, collection);
-        };
-      }
-      return bind(func, thisArg);
-    }
-
-    /**
-     * The base implementation of `createWrapper` that creates the wrapper and
-     * sets its meta data.
-     *
-     * @private
-     * @param {Array} bindData The bind data array.
-     * @returns {Function} Returns the new function.
-     */
-    function baseCreateWrapper(bindData) {
-      var func = bindData[0],
-          bitmask = bindData[1],
-          partialArgs = bindData[2],
-          partialRightArgs = bindData[3],
-          thisArg = bindData[4],
-          arity = bindData[5];
-
-      var isBind = bitmask & 1,
-          isBindKey = bitmask & 2,
-          isCurry = bitmask & 4,
-          isCurryBound = bitmask & 8,
-          key = func;
-
-      function bound() {
-        var thisBinding = isBind ? thisArg : this;
-        if (partialArgs) {
-          var args = slice(partialArgs);
-          push.apply(args, arguments);
-        }
-        if (partialRightArgs || isCurry) {
-          args || (args = slice(arguments));
-          if (partialRightArgs) {
-            push.apply(args, partialRightArgs);
-          }
-          if (isCurry && args.length < arity) {
-            bitmask |= 16 & ~32;
-            return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
-          }
-        }
-        args || (args = arguments);
-        if (isBindKey) {
-          func = thisBinding[key];
-        }
-        if (this instanceof bound) {
-          thisBinding = baseCreate(func.prototype);
-          var result = func.apply(thisBinding, args);
-          return isObject(result) ? result : thisBinding;
-        }
-        return func.apply(thisBinding, args);
-      }
-      setBindData(bound, bindData);
-      return bound;
-    }
-
-    /**
-     * The base implementation of `_.difference` that accepts a single array
-     * of values to exclude.
-     *
-     * @private
-     * @param {Array} array The array to process.
-     * @param {Array} [values] The array of values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     */
-    function baseDifference(array, values) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = array ? array.length : 0,
-          isLarge = length >= largeArraySize && indexOf === baseIndexOf,
-          result = [];
-
-      if (isLarge) {
-        var cache = createCache(values);
-        if (cache) {
-          indexOf = cacheIndexOf;
-          values = cache;
-        } else {
-          isLarge = false;
-        }
-      }
-      while (++index < length) {
-        var value = array[index];
-        if (indexOf(values, value) < 0) {
-          result.push(value);
-        }
-      }
-      if (isLarge) {
-        releaseObject(values);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.flatten` without support for callback
-     * shorthands or `thisArg` binding.
-     *
-     * @private
-     * @param {Array} array The array to flatten.
-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
-     * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
-     * @param {number} [fromIndex=0] The index to start from.
-     * @returns {Array} Returns a new flattened array.
-     */
-    function baseFlatten(array, isShallow, isStrict, fromIndex) {
-      var index = (fromIndex || 0) - 1,
-          length = array ? array.length : 0,
-          result = [];
-
-      while (++index < length) {
-        var value = array[index];
-
-        if (value && typeof value == 'object' && typeof value.length == 'number'
-            && (isArray(value) || isArguments(value))) {
-          // recursively flatten arrays (susceptible to call stack limits)
-          if (!isShallow) {
-            value = baseFlatten(value, isShallow, isStrict);
-          }
-          var valIndex = -1,
-              valLength = value.length,
-              resIndex = result.length;
-
-          result.length += valLength;
-          while (++valIndex < valLength) {
-            result[resIndex++] = value[valIndex];
-          }
-        } else if (!isStrict) {
-          result.push(value);
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.isEqual`, without support for `thisArg` binding,
-     * that allows partial "_.where" style comparisons.
-     *
-     * @private
-     * @param {*} a The value to compare.
-     * @param {*} b The other value to compare.
-     * @param {Function} [callback] The function to customize comparing values.
-     * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
-     * @param {Array} [stackA=[]] Tracks traversed `a` objects.
-     * @param {Array} [stackB=[]] Tracks traversed `b` objects.
-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-     */
-    function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
-      // used to indicate that when comparing objects, `a` has at least the properties of `b`
-      if (callback) {
-        var result = callback(a, b);
-        if (typeof result != 'undefined') {
-          return !!result;
-        }
-      }
-      // exit early for identical values
-      if (a === b) {
-        // treat `+0` vs. `-0` as not equal
-        return a !== 0 || (1 / a == 1 / b);
-      }
-      var type = typeof a,
-          otherType = typeof b;
-
-      // exit early for unlike primitive values
-      if (a === a &&
-          !(a && objectTypes[type]) &&
-          !(b && objectTypes[otherType])) {
-        return false;
-      }
-      // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
-      // http://es5.github.io/#x15.3.4.4
-      if (a == null || b == null) {
-        return a === b;
-      }
-      // compare [[Class]] names
-      var className = toString.call(a),
-          otherClass = toString.call(b);
-
-      if (className == argsClass) {
-        className = objectClass;
-      }
-      if (otherClass == argsClass) {
-        otherClass = objectClass;
-      }
-      if (className != otherClass) {
-        return false;
-      }
-      switch (className) {
-        case boolClass:
-        case dateClass:
-          // coerce dates and booleans to numbers, dates to milliseconds and booleans
-          // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
-          return +a == +b;
-
-        case numberClass:
-          // treat `NaN` vs. `NaN` as equal
-          return (a != +a)
-            ? b != +b
-            // but treat `+0` vs. `-0` as not equal
-            : (a == 0 ? (1 / a == 1 / b) : a == +b);
-
-        case regexpClass:
-        case stringClass:
-          // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
-          // treat string primitives and their corresponding object instances as equal
-          return a == String(b);
-      }
-      var isArr = className == arrayClass;
-      if (!isArr) {
-        // unwrap any `lodash` wrapped values
-        var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
-            bWrapped = hasOwnProperty.call(b, '__wrapped__');
-
-        if (aWrapped || bWrapped) {
-          return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
-        }
-        // exit for functions and DOM nodes
-        if (className != objectClass) {
-          return false;
-        }
-        // in older versions of Opera, `arguments` objects have `Array` constructors
-        var ctorA = a.constructor,
-            ctorB = b.constructor;
-
-        // non `Object` object instances with different constructors are not equal
-        if (ctorA != ctorB &&
-              !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
-              ('constructor' in a && 'constructor' in b)
-            ) {
-          return false;
-        }
-      }
-      // assume cyclic structures are equal
-      // the algorithm for detecting cyclic structures is adapted from ES 5.1
-      // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
-      var initedStack = !stackA;
-      stackA || (stackA = getArray());
-      stackB || (stackB = getArray());
-
-      var length = stackA.length;
-      while (length--) {
-        if (stackA[length] == a) {
-          return stackB[length] == b;
-        }
-      }
-      var size = 0;
-      result = true;
-
-      // add `a` and `b` to the stack of traversed objects
-      stackA.push(a);
-      stackB.push(b);
-
-      // recursively compare objects and arrays (susceptible to call stack limits)
-      if (isArr) {
-        // compare lengths to determine if a deep comparison is necessary
-        length = a.length;
-        size = b.length;
-        result = size == length;
-
-        if (result || isWhere) {
-          // deep compare the contents, ignoring non-numeric properties
-          while (size--) {
-            var index = length,
-                value = b[size];
-
-            if (isWhere) {
-              while (index--) {
-                if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
-                  break;
-                }
-              }
-            } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
-              break;
-            }
-          }
-        }
-      }
-      else {
-        // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
-        // which, in this case, is more costly
-        forIn(b, function(value, key, b) {
-          if (hasOwnProperty.call(b, key)) {
-            // count the number of properties.
-            size++;
-            // deep compare each property value.
-            return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
-          }
-        });
-
-        if (result && !isWhere) {
-          // ensure both objects have the same number of properties
-          forIn(a, function(value, key, a) {
-            if (hasOwnProperty.call(a, key)) {
-              // `size` will be `-1` if `a` has more properties than `b`
-              return (result = --size > -1);
-            }
-          });
-        }
-      }
-      stackA.pop();
-      stackB.pop();
-
-      if (initedStack) {
-        releaseArray(stackA);
-        releaseArray(stackB);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.merge` without argument juggling or support
-     * for `thisArg` binding.
-     *
-     * @private
-     * @param {Object} object The destination object.
-     * @param {Object} source The source object.
-     * @param {Function} [callback] The function to customize merging properties.
-     * @param {Array} [stackA=[]] Tracks traversed source objects.
-     * @param {Array} [stackB=[]] Associates values with source counterparts.
-     */
-    function baseMerge(object, source, callback, stackA, stackB) {
-      (isArray(source) ? forEach : forOwn)(source, function(source, key) {
-        var found,
-            isArr,
-            result = source,
-            value = object[key];
-
-        if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
-          // avoid merging previously merged cyclic sources
-          var stackLength = stackA.length;
-          while (stackLength--) {
-            if ((found = stackA[stackLength] == source)) {
-              value = stackB[stackLength];
-              break;
-            }
-          }
-          if (!found) {
-            var isShallow;
-            if (callback) {
-              result = callback(value, source);
-              if ((isShallow = typeof result != 'undefined')) {
-                value = result;
-              }
-            }
-            if (!isShallow) {
-              value = isArr
-                ? (isArray(value) ? value : [])
-                : (isPlainObject(value) ? value : {});
-            }
-            // add `source` and associated `value` to the stack of traversed objects
-            stackA.push(source);
-            stackB.push(value);
-
-            // recursively merge objects and arrays (susceptible to call stack limits)
-            if (!isShallow) {
-              baseMerge(value, source, callback, stackA, stackB);
-            }
-          }
-        }
-        else {
-          if (callback) {
-            result = callback(value, source);
-            if (typeof result == 'undefined') {
-              result = source;
-            }
-          }
-          if (typeof result != 'undefined') {
-            value = result;
-          }
-        }
-        object[key] = value;
-      });
-    }
-
-    /**
-     * The base implementation of `_.random` without argument juggling or support
-     * for returning floating-point numbers.
-     *
-     * @private
-     * @param {number} min The minimum possible value.
-     * @param {number} max The maximum possible value.
-     * @returns {number} Returns a random number.
-     */
-    function baseRandom(min, max) {
-      return min + floor(nativeRandom() * (max - min + 1));
-    }
-
-    /**
-     * The base implementation of `_.uniq` without support for callback shorthands
-     * or `thisArg` binding.
-     *
-     * @private
-     * @param {Array} array The array to process.
-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
-     * @param {Function} [callback] The function called per iteration.
-     * @returns {Array} Returns a duplicate-value-free array.
-     */
-    function baseUniq(array, isSorted, callback) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = array ? array.length : 0,
-          result = [];
-
-      var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
-          seen = (callback || isLarge) ? getArray() : result;
-
-      if (isLarge) {
-        var cache = createCache(seen);
-        indexOf = cacheIndexOf;
-        seen = cache;
-      }
-      while (++index < length) {
-        var value = array[index],
-            computed = callback ? callback(value, index, array) : value;
-
-        if (isSorted
-              ? !index || seen[seen.length - 1] !== computed
-              : indexOf(seen, computed) < 0
-            ) {
-          if (callback || isLarge) {
-            seen.push(computed);
-          }
-          result.push(value);
-        }
-      }
-      if (isLarge) {
-        releaseArray(seen.array);
-        releaseObject(seen);
-      } else if (callback) {
-        releaseArray(seen);
-      }
-      return result;
-    }
-
-    /**
-     * Creates a function that aggregates a collection, creating an object composed
-     * of keys generated from the results of running each element of the collection
-     * through a callback. The given `setter` function sets the keys and values
-     * of the composed object.
-     *
-     * @private
-     * @param {Function} setter The setter function.
-     * @returns {Function} Returns the new aggregator function.
-     */
-    function createAggregator(setter) {
-      return function(collection, callback, thisArg) {
-        var result = {};
-        callback = lodash.createCallback(callback, thisArg, 3);
-
-        var index = -1,
-            length = collection ? collection.length : 0;
-
-        if (typeof length == 'number') {
-          while (++index < length) {
-            var value = collection[index];
-            setter(result, value, callback(value, index, collection), collection);
-          }
-        } else {
-          forOwn(collection, function(value, key, collection) {
-            setter(result, value, callback(value, key, collection), collection);
-          });
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Creates a function that, when called, either curries or invokes `func`
-     * with an optional `this` binding and partially applied arguments.
-     *
-     * @private
-     * @param {Function|string} func The function or method name to reference.
-     * @param {number} bitmask The bitmask of method flags to compose.
-     *  The bitmask may be composed of the following flags:
-     *  1 - `_.bind`
-     *  2 - `_.bindKey`
-     *  4 - `_.curry`
-     *  8 - `_.curry` (bound)
-     *  16 - `_.partial`
-     *  32 - `_.partialRight`
-     * @param {Array} [partialArgs] An array of arguments to prepend to those
-     *  provided to the new function.
-     * @param {Array} [partialRightArgs] An array of arguments to append to those
-     *  provided to the new function.
-     * @param {*} [thisArg] The `this` binding of `func`.
-     * @param {number} [arity] The arity of `func`.
-     * @returns {Function} Returns the new function.
-     */
-    function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
-      var isBind = bitmask & 1,
-          isBindKey = bitmask & 2,
-          isCurry = bitmask & 4,
-          isCurryBound = bitmask & 8,
-          isPartial = bitmask & 16,
-          isPartialRight = bitmask & 32;
-
-      if (!isBindKey && !isFunction(func)) {
-        throw new TypeError;
-      }
-      if (isPartial && !partialArgs.length) {
-        bitmask &= ~16;
-        isPartial = partialArgs = false;
-      }
-      if (isPartialRight && !partialRightArgs.length) {
-        bitmask &= ~32;
-        isPartialRight = partialRightArgs = false;
-      }
-      var bindData = func && func.__bindData__;
-      if (bindData && bindData !== true) {
-        // clone `bindData`
-        bindData = slice(bindData);
-        if (bindData[2]) {
-          bindData[2] = slice(bindData[2]);
-        }
-        if (bindData[3]) {
-          bindData[3] = slice(bindData[3]);
-        }
-        // set `thisBinding` is not previously bound
-        if (isBind && !(bindData[1] & 1)) {
-          bindData[4] = thisArg;
-        }
-        // set if previously bound but not currently (subsequent curried functions)
-        if (!isBind && bindData[1] & 1) {
-          bitmask |= 8;
-        }
-        // set curried arity if not yet set
-        if (isCurry && !(bindData[1] & 4)) {
-          bindData[5] = arity;
-        }
-        // append partial left arguments
-        if (isPartial) {
-          push.apply(bindData[2] || (bindData[2] = []), partialArgs);
-        }
-        // append partial right arguments
-        if (isPartialRight) {
-          unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
-        }
-        // merge flags
-        bindData[1] |= bitmask;
-        return createWrapper.apply(null, bindData);
-      }
-      // fast path for `_.bind`
-      var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
-      return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
-    }
-
-    /**
-     * Used by `escape` to convert characters to HTML entities.
-     *
-     * @private
-     * @param {string} match The matched character to escape.
-     * @returns {string} Returns the escaped character.
-     */
-    function escapeHtmlChar(match) {
-      return htmlEscapes[match];
-    }
-
-    /**
-     * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
-     * customized, this method returns the custom method, otherwise it returns
-     * the `baseIndexOf` function.
-     *
-     * @private
-     * @returns {Function} Returns the "indexOf" function.
-     */
-    function getIndexOf() {
-      var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
-      return result;
-    }
-
-    /**
-     * Checks if `value` is a native function.
-     *
-     * @private
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
-     */
-    function isNative(value) {
-      return typeof value == 'function' && reNative.test(value);
-    }
-
-    /**
-     * Sets `this` binding data on a given function.
-     *
-     * @private
-     * @param {Function} func The function to set data on.
-     * @param {Array} value The data array to set.
-     */
-    var setBindData = !defineProperty ? noop : function(func, value) {
-      descriptor.value = value;
-      defineProperty(func, '__bindData__', descriptor);
-      descriptor.value = null;
-    };
-
-    /**
-     * A fallback implementation of `isPlainObject` which checks if a given value
-     * is an object created by the `Object` constructor, assuming objects created
-     * by the `Object` constructor have no inherited enumerable properties and that
-     * there are no `Object.prototype` extensions.
-     *
-     * @private
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-     */
-    function shimIsPlainObject(value) {
-      var ctor,
-          result;
-
-      // avoid non Object objects, `arguments` objects, and DOM elements
-      if (!(value && toString.call(value) == objectClass) ||
-          (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
-        return false;
-      }
-      // In most environments an object's own properties are iterated before
-      // its inherited properties. If the last iterated property is an object's
-      // own property then there are no inherited enumerable properties.
-      forIn(value, function(value, key) {
-        result = key;
-      });
-      return typeof result == 'undefined' || hasOwnProperty.call(value, result);
-    }
-
-    /**
-     * Used by `unescape` to convert HTML entities to characters.
-     *
-     * @private
-     * @param {string} match The matched character to unescape.
-     * @returns {string} Returns the unescaped character.
-     */
-    function unescapeHtmlChar(match) {
-      return htmlUnescapes[match];
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Checks if `value` is an `arguments` object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
-     * @example
-     *
-     * (function() { return _.isArguments(arguments); })(1, 2, 3);
-     * // => true
-     *
-     * _.isArguments([1, 2, 3]);
-     * // => false
-     */
-    function isArguments(value) {
-      return value && typeof value == 'object' && typeof value.length == 'number' &&
-        toString.call(value) == argsClass || false;
-    }
-
-    /**
-     * Checks if `value` is an array.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
-     * @example
-     *
-     * (function() { return _.isArray(arguments); })();
-     * // => false
-     *
-     * _.isArray([1, 2, 3]);
-     * // => true
-     */
-    var isArray = nativeIsArray || function(value) {
-      return value && typeof value == 'object' && typeof value.length == 'number' &&
-        toString.call(value) == arrayClass || false;
-    };
-
-    /**
-     * A fallback implementation of `Object.keys` which produces an array of the
-     * given object's own enumerable property names.
-     *
-     * @private
-     * @type Function
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names.
-     */
-    var shimKeys = function(object) {
-      var index, iterable = object, result = [];
-      if (!iterable) return result;
-      if (!(objectTypes[typeof object])) return result;
-        for (index in iterable) {
-          if (hasOwnProperty.call(iterable, index)) {
-            result.push(index);
-          }
-        }
-      return result
-    };
-
-    /**
-     * Creates an array composed of the own enumerable property names of an object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names.
-     * @example
-     *
-     * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
-     */
-    var keys = !nativeKeys ? shimKeys : function(object) {
-      if (!isObject(object)) {
-        return [];
-      }
-      return nativeKeys(object);
-    };
-
-    /**
-     * Used to convert characters to HTML entities:
-     *
-     * Though the `>` character is escaped for symmetry, characters like `>` and `/`
-     * don't require escaping in HTML and have no special meaning unless they're part
-     * of a tag or an unquoted attribute value.
-     * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
-     */
-    var htmlEscapes = {
-      '&': '&',
-      '<': '<',
-      '>': '>',
-      '"': '"',
-      "'": '''
-    };
-
-    /** Used to convert HTML entities to characters */
-    var htmlUnescapes = invert(htmlEscapes);
-
-    /** Used to match HTML entities and HTML characters */
-    var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
-        reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Assigns own enumerable properties of source object(s) to the destination
-     * object. Subsequent sources will overwrite property assignments of previous
-     * sources. If a callback is provided it will be executed to produce the
-     * assigned values. The callback is bound to `thisArg` and invoked with two
-     * arguments; (objectValue, sourceValue).
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @alias extend
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param {Function} [callback] The function to customize assigning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
-     * // => { 'name': 'fred', 'employer': 'slate' }
-     *
-     * var defaults = _.partialRight(_.assign, function(a, b) {
-     *   return typeof a == 'undefined' ? b : a;
-     * });
-     *
-     * var object = { 'name': 'barney' };
-     * defaults(object, { 'name': 'fred', 'employer': 'slate' });
-     * // => { 'name': 'barney', 'employer': 'slate' }
-     */
-    var assign = function(object, source, guard) {
-      var index, iterable = object, result = iterable;
-      if (!iterable) return result;
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = typeof guard == 'number' ? 2 : args.length;
-      if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
-        var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
-      } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
-        callback = args[--argsLength];
-      }
-      while (++argsIndex < argsLength) {
-        iterable = args[argsIndex];
-        if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
-        }
-        }
-      }
-      return result
-    };
-
-    /**
-     * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
-     * be cloned, otherwise they will be assigned by reference. If a callback
-     * is provided it will be executed to produce the cloned values. If the
-     * callback returns `undefined` cloning will be handled by the method instead.
-     * The callback is bound to `thisArg` and invoked with one argument; (value).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to clone.
-     * @param {boolean} [isDeep=false] Specify a deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the cloned value.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * var shallow = _.clone(characters);
-     * shallow[0] === characters[0];
-     * // => true
-     *
-     * var deep = _.clone(characters, true);
-     * deep[0] === characters[0];
-     * // => false
-     *
-     * _.mixin({
-     *   'clone': _.partialRight(_.clone, function(value) {
-     *     return _.isElement(value) ? value.cloneNode(false) : undefined;
-     *   })
-     * });
-     *
-     * var clone = _.clone(document.body);
-     * clone.childNodes.length;
-     * // => 0
-     */
-    function clone(value, isDeep, callback, thisArg) {
-      // allows working with "Collections" methods without using their `index`
-      // and `collection` arguments for `isDeep` and `callback`
-      if (typeof isDeep != 'boolean' && isDeep != null) {
-        thisArg = callback;
-        callback = isDeep;
-        isDeep = false;
-      }
-      return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
-    }
-
-    /**
-     * Creates a deep clone of `value`. If a callback is provided it will be
-     * executed to produce the cloned values. If the callback returns `undefined`
-     * cloning will be handled by the method instead. The callback is bound to
-     * `thisArg` and invoked with one argument; (value).
-     *
-     * Note: This method is loosely based on the structured clone algorithm. Functions
-     * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
-     * objects created by constructors other than `Object` are cloned to plain `Object` objects.
-     * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the deep cloned value.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * var deep = _.cloneDeep(characters);
-     * deep[0] === characters[0];
-     * // => false
-     *
-     * var view = {
-     *   'label': 'docs',
-     *   'node': element
-     * };
-     *
-     * var clone = _.cloneDeep(view, function(value) {
-     *   return _.isElement(value) ? value.cloneNode(true) : undefined;
-     * });
-     *
-     * clone.node == view.node;
-     * // => false
-     */
-    function cloneDeep(value, callback, thisArg) {
-      return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
-    }
-
-    /**
-     * Creates an object that inherits from the given `prototype` object. If a
-     * `properties` object is provided its own enumerable properties are assigned
-     * to the created object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} prototype The object to inherit from.
-     * @param {Object} [properties] The properties to assign to the object.
-     * @returns {Object} Returns the new object.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * function Circle() {
-     *   Shape.call(this);
-     * }
-     *
-     * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
-     *
-     * var circle = new Circle;
-     * circle instanceof Circle;
-     * // => true
-     *
-     * circle instanceof Shape;
-     * // => true
-     */
-    function create(prototype, properties) {
-      var result = baseCreate(prototype);
-      return properties ? assign(result, properties) : result;
-    }
-
-    /**
-     * Assigns own enumerable properties of source object(s) to the destination
-     * object for all destination properties that resolve to `undefined`. Once a
-     * property is set, additional defaults of the same property will be ignored.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param- {Object} [guard] Allows working with `_.reduce` without using its
-     *  `key` and `object` arguments as sources.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * var object = { 'name': 'barney' };
-     * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
-     * // => { 'name': 'barney', 'employer': 'slate' }
-     */
-    var defaults = function(object, source, guard) {
-      var index, iterable = object, result = iterable;
-      if (!iterable) return result;
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = typeof guard == 'number' ? 2 : args.length;
-      while (++argsIndex < argsLength) {
-        iterable = args[argsIndex];
-        if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (typeof result[index] == 'undefined') result[index] = iterable[index];
-        }
-        }
-      }
-      return result
-    };
-
-    /**
-     * This method is like `_.findIndex` except that it returns the key of the
-     * first element that passes the callback check, instead of the element itself.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to search.
-     * @param {Function|Object|string} [callback=identity] The function called per
-     *  iteration. If a property name or object is provided it will be used to
-     *  create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
-     * @example
-     *
-     * var characters = {
-     *   'barney': {  'age': 36, 'blocked': false },
-     *   'fred': {    'age': 40, 'blocked': true },
-     *   'pebbles': { 'age': 1,  'blocked': false }
-     * };
-     *
-     * _.findKey(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => 'barney' (property order is not guaranteed across environments)
-     *
-     * // using "_.where" callback shorthand
-     * _.findKey(characters, { 'age': 1 });
-     * // => 'pebbles'
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findKey(characters, 'blocked');
-     * // => 'fred'
-     */
-    function findKey(object, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forOwn(object, function(value, key, object) {
-        if (callback(value, key, object)) {
-          result = key;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * This method is like `_.findKey` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to search.
-     * @param {Function|Object|string} [callback=identity] The function called per
-     *  iteration. If a property name or object is provided it will be used to
-     *  create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
-     * @example
-     *
-     * var characters = {
-     *   'barney': {  'age': 36, 'blocked': true },
-     *   'fred': {    'age': 40, 'blocked': false },
-     *   'pebbles': { 'age': 1,  'blocked': true }
-     * };
-     *
-     * _.findLastKey(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => returns `pebbles`, assuming `_.findKey` returns `barney`
-     *
-     * // using "_.where" callback shorthand
-     * _.findLastKey(characters, { 'age': 40 });
-     * // => 'fred'
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findLastKey(characters, 'blocked');
-     * // => 'pebbles'
-     */
-    function findLastKey(object, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forOwnRight(object, function(value, key, object) {
-        if (callback(value, key, object)) {
-          result = key;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * Iterates over own and inherited enumerable properties of an object,
-     * executing the callback for each property. The callback is bound to `thisArg`
-     * and invoked with three arguments; (value, key, object). Callbacks may exit
-     * iteration early by explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * Shape.prototype.move = function(x, y) {
-     *   this.x += x;
-     *   this.y += y;
-     * };
-     *
-     * _.forIn(new Shape, function(value, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
-     */
-    var forIn = function(collection, callback, thisArg) {
-      var index, iterable = collection, result = iterable;
-      if (!iterable) return result;
-      if (!objectTypes[typeof iterable]) return result;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-        for (index in iterable) {
-          if (callback(iterable[index], index, collection) === false) return result;
-        }
-      return result
-    };
-
-    /**
-     * This method is like `_.forIn` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * Shape.prototype.move = function(x, y) {
-     *   this.x += x;
-     *   this.y += y;
-     * };
-     *
-     * _.forInRight(new Shape, function(value, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
-     */
-    function forInRight(object, callback, thisArg) {
-      var pairs = [];
-
-      forIn(object, function(value, key) {
-        pairs.push(key, value);
-      });
-
-      var length = pairs.length;
-      callback = baseCreateCallback(callback, thisArg, 3);
-      while (length--) {
-        if (callback(pairs[length--], pairs[length], object) === false) {
-          break;
-        }
-      }
-      return object;
-    }
-
-    /**
-     * Iterates over own enumerable properties of an object, executing the callback
-     * for each property. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, key, object). Callbacks may exit iteration early by
-     * explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
-     *   console.log(key);
-     * });
-     * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
-     */
-    var forOwn = function(collection, callback, thisArg) {
-      var index, iterable = collection, result = iterable;
-      if (!iterable) return result;
-      if (!objectTypes[typeof iterable]) return result;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (callback(iterable[index], index, collection) === false) return result;
-        }
-      return result
-    };
-
-    /**
-     * This method is like `_.forOwn` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
-     */
-    function forOwnRight(object, callback, thisArg) {
-      var props = keys(object),
-          length = props.length;
-
-      callback = baseCreateCallback(callback, thisArg, 3);
-      while (length--) {
-        var key = props[length];
-        if (callback(object[key], key, object) === false) {
-          break;
-        }
-      }
-      return object;
-    }
-
-    /**
-     * Creates a sorted array of property names of all enumerable properties,
-     * own and inherited, of `object` that have function values.
-     *
-     * @static
-     * @memberOf _
-     * @alias methods
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names that have function values.
-     * @example
-     *
-     * _.functions(_);
-     * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
-     */
-    function functions(object) {
-      var result = [];
-      forIn(object, function(value, key) {
-        if (isFunction(value)) {
-          result.push(key);
-        }
-      });
-      return result.sort();
-    }
-
-    /**
-     * Checks if the specified property name exists as a direct property of `object`,
-     * instead of an inherited property.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @param {string} key The name of the property to check.
-     * @returns {boolean} Returns `true` if key is a direct property, else `false`.
-     * @example
-     *
-     * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
-     * // => true
-     */
-    function has(object, key) {
-      return object ? hasOwnProperty.call(object, key) : false;
-    }
-
-    /**
-     * Creates an object composed of the inverted keys and values of the given object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to invert.
-     * @returns {Object} Returns the created inverted object.
-     * @example
-     *
-     * _.invert({ 'first': 'fred', 'second': 'barney' });
-     * // => { 'fred': 'first', 'barney': 'second' }
-     */
-    function invert(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = {};
-
-      while (++index < length) {
-        var key = props[index];
-        result[object[key]] = key;
-      }
-      return result;
-    }
-
-    /**
-     * Checks if `value` is a boolean value.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
-     * @example
-     *
-     * _.isBoolean(null);
-     * // => false
-     */
-    function isBoolean(value) {
-      return value === true || value === false ||
-        value && typeof value == 'object' && toString.call(value) == boolClass || false;
-    }
-
-    /**
-     * Checks if `value` is a date.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
-     * @example
-     *
-     * _.isDate(new Date);
-     * // => true
-     */
-    function isDate(value) {
-      return value && typeof value == 'object' && toString.call(value) == dateClass || false;
-    }
-
-    /**
-     * Checks if `value` is a DOM element.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
-     * @example
-     *
-     * _.isElement(document.body);
-     * // => true
-     */
-    function isElement(value) {
-      return value && value.nodeType === 1 || false;
-    }
-
-    /**
-     * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
-     * length of `0` and objects with no own enumerable properties are considered
-     * "empty".
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Array|Object|string} value The value to inspect.
-     * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
-     * @example
-     *
-     * _.isEmpty([1, 2, 3]);
-     * // => false
-     *
-     * _.isEmpty({});
-     * // => true
-     *
-     * _.isEmpty('');
-     * // => true
-     */
-    function isEmpty(value) {
-      var result = true;
-      if (!value) {
-        return result;
-      }
-      var className = toString.call(value),
-          length = value.length;
-
-      if ((className == arrayClass || className == stringClass || className == argsClass ) ||
-          (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
-        return !length;
-      }
-      forOwn(value, function() {
-        return (result = false);
-      });
-      return result;
-    }
-
-    /**
-     * Performs a deep comparison between two values to determine if they are
-     * equivalent to each other. If a callback is provided it will be executed
-     * to compare values. If the callback returns `undefined` comparisons will
-     * be handled by the method instead. The callback is bound to `thisArg` and
-     * invoked with two arguments; (a, b).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} a The value to compare.
-     * @param {*} b The other value to compare.
-     * @param {Function} [callback] The function to customize comparing values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * var copy = { 'name': 'fred' };
-     *
-     * object == copy;
-     * // => false
-     *
-     * _.isEqual(object, copy);
-     * // => true
-     *
-     * var words = ['hello', 'goodbye'];
-     * var otherWords = ['hi', 'goodbye'];
-     *
-     * _.isEqual(words, otherWords, function(a, b) {
-     *   var reGreet = /^(?:hello|hi)$/i,
-     *       aGreet = _.isString(a) && reGreet.test(a),
-     *       bGreet = _.isString(b) && reGreet.test(b);
-     *
-     *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
-     * });
-     * // => true
-     */
-    function isEqual(a, b, callback, thisArg) {
-      return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
-    }
-
-    /**
-     * Checks if `value` is, or can be coerced to, a finite number.
-     *
-     * Note: This is not the same as native `isFinite` which will return true for
-     * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
-     * @example
-     *
-     * _.isFinite(-101);
-     * // => true
-     *
-     * _.isFinite('10');
-     * // => true
-     *
-     * _.isFinite(true);
-     * // => false
-     *
-     * _.isFinite('');
-     * // => false
-     *
-     * _.isFinite(Infinity);
-     * // => false
-     */
-    function isFinite(value) {
-      return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
-    }
-
-    /**
-     * Checks if `value` is a function.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
-     * @example
-     *
-     * _.isFunction(_);
-     * // => true
-     */
-    function isFunction(value) {
-      return typeof value == 'function';
-    }
-
-    /**
-     * Checks if `value` is the language type of Object.
-     * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
-     * @example
-     *
-     * _.isObject({});
-     * // => true
-     *
-     * _.isObject([1, 2, 3]);
-     * // => true
-     *
-     * _.isObject(1);
-     * // => false
-     */
-    function isObject(value) {
-      // check if the value is the ECMAScript language type of Object
-      // http://es5.github.io/#x8
-      // and avoid a V8 bug
-      // http://code.google.com/p/v8/issues/detail?id=2291
-      return !!(value && objectTypes[typeof value]);
-    }
-
-    /**
-     * Checks if `value` is `NaN`.
-     *
-     * Note: This is not the same as native `isNaN` which will return `true` for
-     * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
-     * @example
-     *
-     * _.isNaN(NaN);
-     * // => true
-     *
-     * _.isNaN(new Number(NaN));
-     * // => true
-     *
-     * isNaN(undefined);
-     * // => true
-     *
-     * _.isNaN(undefined);
-     * // => false
-     */
-    function isNaN(value) {
-      // `NaN` as a primitive is the only value that is not equal to itself
-      // (perform the [[Class]] check first to avoid errors with some host objects in IE)
-      return isNumber(value) && value != +value;
-    }
-
-    /**
-     * Checks if `value` is `null`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
-     * @example
-     *
-     * _.isNull(null);
-     * // => true
-     *
-     * _.isNull(undefined);
-     * // => false
-     */
-    function isNull(value) {
-      return value === null;
-    }
-
-    /**
-     * Checks if `value` is a number.
-     *
-     * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
-     * @example
-     *
-     * _.isNumber(8.4 * 5);
-     * // => true
-     */
-    function isNumber(value) {
-      return typeof value == 'number' ||
-        value && typeof value == 'object' && toString.call(value) == numberClass || false;
-    }
-
-    /**
-     * Checks if `value` is an object created by the `Object` constructor.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * _.isPlainObject(new Shape);
-     * // => false
-     *
-     * _.isPlainObject([1, 2, 3]);
-     * // => false
-     *
-     * _.isPlainObject({ 'x': 0, 'y': 0 });
-     * // => true
-     */
-    var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
-      if (!(value && toString.call(value) == objectClass)) {
-        return false;
-      }
-      var valueOf = value.valueOf,
-          objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
-
-      return objProto
-        ? (value == objProto || getPrototypeOf(value) == objProto)
-        : shimIsPlainObject(value);
-    };
-
-    /**
-     * Checks if `value` is a regular expression.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
-     * @example
-     *
-     * _.isRegExp(/fred/);
-     * // => true
-     */
-    function isRegExp(value) {
-      return value && typeof value == 'object' && toString.call(value) == regexpClass || false;
-    }
-
-    /**
-     * Checks if `value` is a string.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
-     * @example
-     *
-     * _.isString('fred');
-     * // => true
-     */
-    function isString(value) {
-      return typeof value == 'string' ||
-        value && typeof value == 'object' && toString.call(value) == stringClass || false;
-    }
-
-    /**
-     * Checks if `value` is `undefined`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
-     * @example
-     *
-     * _.isUndefined(void 0);
-     * // => true
-     */
-    function isUndefined(value) {
-      return typeof value == 'undefined';
-    }
-
-    /**
-     * Creates an object with the same keys as `object` and values generated by
-     * running each own enumerable property of `object` through the callback.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new object with values of the results of each `callback` execution.
-     * @example
-     *
-     * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     *
-     * var characters = {
-     *   'fred': { 'name': 'fred', 'age': 40 },
-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
-     * };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.mapValues(characters, 'age');
-     * // => { 'fred': 40, 'pebbles': 1 }
-     */
-    function mapValues(object, callback, thisArg) {
-      var result = {};
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      forOwn(object, function(value, key, object) {
-        result[key] = callback(value, key, object);
-      });
-      return result;
-    }
-
-    /**
-     * Recursively merges own enumerable properties of the source object(s), that
-     * don't resolve to `undefined` into the destination object. Subsequent sources
-     * will overwrite property assignments of previous sources. If a callback is
-     * provided it will be executed to produce the merged values of the destination
-     * and source properties. If the callback returns `undefined` merging will
-     * be handled by the method instead. The callback is bound to `thisArg` and
-     * invoked with two arguments; (objectValue, sourceValue).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param {Function} [callback] The function to customize merging properties.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * var names = {
-     *   'characters': [
-     *     { 'name': 'barney' },
-     *     { 'name': 'fred' }
-     *   ]
-     * };
-     *
-     * var ages = {
-     *   'characters': [
-     *     { 'age': 36 },
-     *     { 'age': 40 }
-     *   ]
-     * };
-     *
-     * _.merge(names, ages);
-     * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
-     *
-     * var food = {
-     *   'fruits': ['apple'],
-     *   'vegetables': ['beet']
-     * };
-     *
-     * var otherFood = {
-     *   'fruits': ['banana'],
-     *   'vegetables': ['carrot']
-     * };
-     *
-     * _.merge(food, otherFood, function(a, b) {
-     *   return _.isArray(a) ? a.concat(b) : undefined;
-     * });
-     * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
-     */
-    function merge(object) {
-      var args = arguments,
-          length = 2;
-
-      if (!isObject(object)) {
-        return object;
-      }
-      // allows working with `_.reduce` and `_.reduceRight` without using
-      // their `index` and `collection` arguments
-      if (typeof args[2] != 'number') {
-        length = args.length;
-      }
-      if (length > 3 && typeof args[length - 2] == 'function') {
-        var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
-      } else if (length > 2 && typeof args[length - 1] == 'function') {
-        callback = args[--length];
-      }
-      var sources = slice(arguments, 1, length),
-          index = -1,
-          stackA = getArray(),
-          stackB = getArray();
-
-      while (++index < length) {
-        baseMerge(object, sources[index], callback, stackA, stackB);
-      }
-      releaseArray(stackA);
-      releaseArray(stackB);
-      return object;
-    }
-
-    /**
-     * Creates a shallow clone of `object` excluding the specified properties.
-     * Property names may be specified as individual arguments or as arrays of
-     * property names. If a callback is provided it will be executed for each
-     * property of `object` omitting the properties the callback returns truey
-     * for. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The source object.
-     * @param {Function|...string|string[]} [callback] The properties to omit or the
-     *  function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns an object without the omitted properties.
-     * @example
-     *
-     * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
-     * // => { 'name': 'fred' }
-     *
-     * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
-     *   return typeof value == 'number';
-     * });
-     * // => { 'name': 'fred' }
-     */
-    function omit(object, callback, thisArg) {
-      var result = {};
-      if (typeof callback != 'function') {
-        var props = [];
-        forIn(object, function(value, key) {
-          props.push(key);
-        });
-        props = baseDifference(props, baseFlatten(arguments, true, false, 1));
-
-        var index = -1,
-            length = props.length;
-
-        while (++index < length) {
-          var key = props[index];
-          result[key] = object[key];
-        }
-      } else {
-        callback = lodash.createCallback(callback, thisArg, 3);
-        forIn(object, function(value, key, object) {
-          if (!callback(value, key, object)) {
-            result[key] = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Creates a two dimensional array of an object's key-value pairs,
-     * i.e. `[[key1, value1], [key2, value2]]`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns new array of key-value pairs.
-     * @example
-     *
-     * _.pairs({ 'barney': 36, 'fred': 40 });
-     * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
-     */
-    function pairs(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = Array(length);
-
-      while (++index < length) {
-        var key = props[index];
-        result[index] = [key, object[key]];
-      }
-      return result;
-    }
-
-    /**
-     * Creates a shallow clone of `object` composed of the specified properties.
-     * Property names may be specified as individual arguments or as arrays of
-     * property names. If a callback is provided it will be executed for each
-     * property of `object` picking the properties the callback returns truey
-     * for. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The source object.
-     * @param {Function|...string|string[]} [callback] The function called per
-     *  iteration or property names to pick, specified as individual property
-     *  names or arrays of property names.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns an object composed of the picked properties.
-     * @example
-     *
-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
-     * // => { 'name': 'fred' }
-     *
-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
-     *   return key.charAt(0) != '_';
-     * });
-     * // => { 'name': 'fred' }
-     */
-    function pick(object, callback, thisArg) {
-      var result = {};
-      if (typeof callback != 'function') {
-        var index = -1,
-            props = baseFlatten(arguments, true, false, 1),
-            length = isObject(object) ? props.length : 0;
-
-        while (++index < length) {
-          var key = props[index];
-          if (key in object) {
-            result[key] = object[key];
-          }
-        }
-      } else {
-        callback = lodash.createCallback(callback, thisArg, 3);
-        forIn(object, function(value, key, object) {
-          if (callback(value, key, object)) {
-            result[key] = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * An alternative to `_.reduce` this method transforms `object` to a new
-     * `accumulator` object which is the result of running each of its own
-     * enumerable properties through a callback, with each callback execution
-     * potentially mutating the `accumulator` object. The callback is bound to
-     * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
-     * Callbacks may exit iteration early by explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Array|Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] The custom accumulator value.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
-     *   num *= num;
-     *   if (num % 2) {
-     *     return result.push(num) < 3;
-     *   }
-     * });
-     * // => [1, 9, 25]
-     *
-     * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
-     *   result[key] = num * 3;
-     * });
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     */
-    function transform(object, callback, accumulator, thisArg) {
-      var isArr = isArray(object);
-      if (accumulator == null) {
-        if (isArr) {
-          accumulator = [];
-        } else {
-          var ctor = object && object.constructor,
-              proto = ctor && ctor.prototype;
-
-          accumulator = baseCreate(proto);
-        }
-      }
-      if (callback) {
-        callback = lodash.createCallback(callback, thisArg, 4);
-        (isArr ? forEach : forOwn)(object, function(value, index, object) {
-          return callback(accumulator, value, index, object);
-        });
-      }
-      return accumulator;
-    }
-
-    /**
-     * Creates an array composed of the own enumerable property values of `object`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property values.
-     * @example
-     *
-     * _.values({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => [1, 2, 3] (property order is not guaranteed across environments)
-     */
-    function values(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = Array(length);
-
-      while (++index < length) {
-        result[index] = object[props[index]];
-      }
-      return result;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates an array of elements from the specified indexes, or keys, of the
-     * `collection`. Indexes may be specified as individual arguments or as arrays
-     * of indexes.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
-     *   to retrieve, specified as individual indexes or arrays of indexes.
-     * @returns {Array} Returns a new array of elements corresponding to the
-     *  provided indexes.
-     * @example
-     *
-     * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
-     * // => ['a', 'c', 'e']
-     *
-     * _.at(['fred', 'barney', 'pebbles'], 0, 2);
-     * // => ['fred', 'pebbles']
-     */
-    function at(collection) {
-      var args = arguments,
-          index = -1,
-          props = baseFlatten(args, true, false, 1),
-          length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
-          result = Array(length);
-
-      while(++index < length) {
-        result[index] = collection[props[index]];
-      }
-      return result;
-    }
-
-    /**
-     * Checks if a given value is present in a collection using strict equality
-     * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
-     * offset from the end of the collection.
-     *
-     * @static
-     * @memberOf _
-     * @alias include
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {*} target The value to check for.
-     * @param {number} [fromIndex=0] The index to search from.
-     * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
-     * @example
-     *
-     * _.contains([1, 2, 3], 1);
-     * // => true
-     *
-     * _.contains([1, 2, 3], 1, 2);
-     * // => false
-     *
-     * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
-     * // => true
-     *
-     * _.contains('pebbles', 'eb');
-     * // => true
-     */
-    function contains(collection, target, fromIndex) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = collection ? collection.length : 0,
-          result = false;
-
-      fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
-      if (isArray(collection)) {
-        result = indexOf(collection, target, fromIndex) > -1;
-      } else if (typeof length == 'number') {
-        result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
-      } else {
-        forOwn(collection, function(value) {
-          if (++index >= fromIndex) {
-            return !(result = value === target);
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of `collection` through the callback. The corresponding value
-     * of each key is the number of times the key was returned by the callback.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
-     * // => { '4': 1, '6': 2 }
-     *
-     * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-     * // => { '4': 1, '6': 2 }
-     *
-     * _.countBy(['one', 'two', 'three'], 'length');
-     * // => { '3': 2, '5': 1 }
-     */
-    var countBy = createAggregator(function(result, value, key) {
-      (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
-    });
-
-    /**
-     * Checks if the given callback returns truey value for **all** elements of
-     * a collection. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias all
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if all elements passed the callback check,
-     *  else `false`.
-     * @example
-     *
-     * _.every([true, 1, null, 'yes']);
-     * // => false
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.every(characters, 'age');
-     * // => true
-     *
-     * // using "_.where" callback shorthand
-     * _.every(characters, { 'age': 36 });
-     * // => false
-     */
-    function every(collection, callback, thisArg) {
-      var result = true;
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if (!(result = !!callback(collection[index], index, collection))) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          return (result = !!callback(value, index, collection));
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, returning an array of all elements
-     * the callback returns truey for. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias select
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of elements that passed the callback check.
-     * @example
-     *
-     * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-     * // => [2, 4, 6]
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.filter(characters, 'blocked');
-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
-     *
-     * // using "_.where" callback shorthand
-     * _.filter(characters, { 'age': 36 });
-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-     */
-    function filter(collection, callback, thisArg) {
-      var result = [];
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          var value = collection[index];
-          if (callback(value, index, collection)) {
-            result.push(value);
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          if (callback(value, index, collection)) {
-            result.push(value);
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, returning the first element that
-     * the callback returns truey for. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias detect, findWhere
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the found element, else `undefined`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
-     * ];
-     *
-     * _.find(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => { 'name': 'barney', 'age': 36, 'blocked': false }
-     *
-     * // using "_.where" callback shorthand
-     * _.find(characters, { 'age': 1 });
-     * // =>  { 'name': 'pebbles', 'age': 1, 'blocked': false }
-     *
-     * // using "_.pluck" callback shorthand
-     * _.find(characters, 'blocked');
-     * // => { 'name': 'fred', 'age': 40, 'blocked': true }
-     */
-    function find(collection, callback, thisArg) {
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          var value = collection[index];
-          if (callback(value, index, collection)) {
-            return value;
-          }
-        }
-      } else {
-        var result;
-        forOwn(collection, function(value, index, collection) {
-          if (callback(value, index, collection)) {
-            result = value;
-            return false;
-          }
-        });
-        return result;
-      }
-    }
-
-    /**
-     * This method is like `_.find` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the found element, else `undefined`.
-     * @example
-     *
-     * _.findLast([1, 2, 3, 4], function(num) {
-     *   return num % 2 == 1;
-     * });
-     * // => 3
-     */
-    function findLast(collection, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forEachRight(collection, function(value, index, collection) {
-        if (callback(value, index, collection)) {
-          result = value;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, executing the callback for each
-     * element. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection). Callbacks may exit iteration early by
-     * explicitly returning `false`.
-     *
-     * Note: As with other "Collections" methods, objects with a `length` property
-     * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
-     * may be used for object iteration.
-     *
-     * @static
-     * @memberOf _
-     * @alias each
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array|Object|string} Returns `collection`.
-     * @example
-     *
-     * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
-     * // => logs each number and returns '1,2,3'
-     *
-     * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
-     * // => logs each number and returns the object (property order is not guaranteed across environments)
-     */
-    function forEach(collection, callback, thisArg) {
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if (callback(collection[index], index, collection) === false) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, callback);
-      }
-      return collection;
-    }
-
-    /**
-     * This method is like `_.forEach` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @alias eachRight
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array|Object|string} Returns `collection`.
-     * @example
-     *
-     * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
-     * // => logs each number from right to left and returns '3,2,1'
-     */
-    function forEachRight(collection, callback, thisArg) {
-      var length = collection ? collection.length : 0;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        while (length--) {
-          if (callback(collection[length], length, collection) === false) {
-            break;
-          }
-        }
-      } else {
-        var props = keys(collection);
-        length = props.length;
-        forOwn(collection, function(value, key, collection) {
-          key = props ? props[--length] : --length;
-          return callback(collection[key], key, collection);
-        });
-      }
-      return collection;
-    }
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of a collection through the callback. The corresponding value
-     * of each key is an array of the elements responsible for generating the key.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
-     * // => { '4': [4.2], '6': [6.1, 6.4] }
-     *
-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-     * // => { '4': [4.2], '6': [6.1, 6.4] }
-     *
-     * // using "_.pluck" callback shorthand
-     * _.groupBy(['one', 'two', 'three'], 'length');
-     * // => { '3': ['one', 'two'], '5': ['three'] }
-     */
-    var groupBy = createAggregator(function(result, value, key) {
-      (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
-    });
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of the collection through the given callback. The corresponding
-     * value of each key is the last element responsible for generating the key.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * var keys = [
-     *   { 'dir': 'left', 'code': 97 },
-     *   { 'dir': 'right', 'code': 100 }
-     * ];
-     *
-     * _.indexBy(keys, 'dir');
-     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
-     *
-     * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
-     *
-     * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
-     */
-    var indexBy = createAggregator(function(result, value, key) {
-      result[key] = value;
-    });
-
-    /**
-     * Invokes the method named by `methodName` on each element in the `collection`
-     * returning an array of the results of each invoked method. Additional arguments
-     * will be provided to each invoked method. If `methodName` is a function it
-     * will be invoked for, and `this` bound to, each element in the `collection`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|string} methodName The name of the method to invoke or
-     *  the function invoked per iteration.
-     * @param {...*} [arg] Arguments to invoke the method with.
-     * @returns {Array} Returns a new array of the results of each invoked method.
-     * @example
-     *
-     * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
-     * // => [[1, 5, 7], [1, 2, 3]]
-     *
-     * _.invoke([123, 456], String.prototype.split, '');
-     * // => [['1', '2', '3'], ['4', '5', '6']]
-     */
-    function invoke(collection, methodName) {
-      var args = slice(arguments, 2),
-          index = -1,
-          isFunc = typeof methodName == 'function',
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      forEach(collection, function(value) {
-        result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
-      });
-      return result;
-    }
-
-    /**
-     * Creates an array of values by running each element in the collection
-     * through the callback. The callback is bound to `thisArg` and invoked with
-     * three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias collect
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of the results of each `callback` execution.
-     * @example
-     *
-     * _.map([1, 2, 3], function(num) { return num * 3; });
-     * // => [3, 6, 9]
-     *
-     * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
-     * // => [3, 6, 9] (property order is not guaranteed across environments)
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.map(characters, 'name');
-     * // => ['barney', 'fred']
-     */
-    function map(collection, callback, thisArg) {
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        var result = Array(length);
-        while (++index < length) {
-          result[index] = callback(collection[index], index, collection);
-        }
-      } else {
-        result = [];
-        forOwn(collection, function(value, key, collection) {
-          result[++index] = callback(value, key, collection);
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the maximum value of a collection. If the collection is empty or
-     * falsey `-Infinity` is returned. If a callback is provided it will be executed
-     * for each value in the collection to generate the criterion by which the value
-     * is ranked. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the maximum value.
-     * @example
-     *
-     * _.max([4, 2, 8, 6]);
-     * // => 8
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.max(characters, function(chr) { return chr.age; });
-     * // => { 'name': 'fred', 'age': 40 };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.max(characters, 'age');
-     * // => { 'name': 'fred', 'age': 40 };
-     */
-    function max(collection, callback, thisArg) {
-      var computed = -Infinity,
-          result = computed;
-
-      // allows working with functions like `_.map` without using
-      // their `index` argument as a callback
-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
-        callback = null;
-      }
-      if (callback == null && isArray(collection)) {
-        var index = -1,
-            length = collection.length;
-
-        while (++index < length) {
-          var value = collection[index];
-          if (value > result) {
-            result = value;
-          }
-        }
-      } else {
-        callback = (callback == null && isString(collection))
-          ? charAtCallback
-          : lodash.createCallback(callback, thisArg, 3);
-
-        forEach(collection, function(value, index, collection) {
-          var current = callback(value, index, collection);
-          if (current > computed) {
-            computed = current;
-            result = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the minimum value of a collection. If the collection is empty or
-     * falsey `Infinity` is returned. If a callback is provided it will be executed
-     * for each value in the collection to generate the criterion by which the value
-     * is ranked. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the minimum value.
-     * @example
-     *
-     * _.min([4, 2, 8, 6]);
-     * // => 2
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.min(characters, function(chr) { return chr.age; });
-     * // => { 'name': 'barney', 'age': 36 };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.min(characters, 'age');
-     * // => { 'name': 'barney', 'age': 36 };
-     */
-    function min(collection, callback, thisArg) {
-      var computed = Infinity,
-          result = computed;
-
-      // allows working with functions like `_.map` without using
-      // their `index` argument as a callback
-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
-        callback = null;
-      }
-      if (callback == null && isArray(collection)) {
-        var index = -1,
-            length = collection.length;
-
-        while (++index < length) {
-          var value = collection[index];
-          if (value < result) {
-            result = value;
-          }
-        }
-      } else {
-        callback = (callback == null && isString(collection))
-          ? charAtCallback
-          : lodash.createCallback(callback, thisArg, 3);
-
-        forEach(collection, function(value, index, collection) {
-          var current = callback(value, index, collection);
-          if (current < computed) {
-            computed = current;
-            result = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the value of a specified property from all elements in the collection.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {string} property The name of the property to pluck.
-     * @returns {Array} Returns a new array of property values.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.pluck(characters, 'name');
-     * // => ['barney', 'fred']
-     */
-    var pluck = map;
-
-    /**
-     * Reduces a collection to a value which is the accumulated result of running
-     * each element in the collection through the callback, where each successive
-     * callback execution consumes the return value of the previous execution. If
-     * `accumulator` is not provided the first element of the collection will be
-     * used as the initial `accumulator` value. The callback is bound to `thisArg`
-     * and invoked with four arguments; (accumulator, value, index|key, collection).
-     *
-     * @static
-     * @memberOf _
-     * @alias foldl, inject
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] Initial value of the accumulator.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var sum = _.reduce([1, 2, 3], function(sum, num) {
-     *   return sum + num;
-     * });
-     * // => 6
-     *
-     * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
-     *   result[key] = num * 3;
-     *   return result;
-     * }, {});
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     */
-    function reduce(collection, callback, accumulator, thisArg) {
-      if (!collection) return accumulator;
-      var noaccum = arguments.length < 3;
-      callback = lodash.createCallback(callback, thisArg, 4);
-
-      var index = -1,
-          length = collection.length;
-
-      if (typeof length == 'number') {
-        if (noaccum) {
-          accumulator = collection[++index];
-        }
-        while (++index < length) {
-          accumulator = callback(accumulator, collection[index], index, collection);
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          accumulator = noaccum
-            ? (noaccum = false, value)
-            : callback(accumulator, value, index, collection)
-        });
-      }
-      return accumulator;
-    }
-
-    /**
-     * This method is like `_.reduce` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @alias foldr
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] Initial value of the accumulator.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var list = [[0, 1], [2, 3], [4, 5]];
-     * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
-     * // => [4, 5, 2, 3, 0, 1]
-     */
-    function reduceRight(collection, callback, accumulator, thisArg) {
-      var noaccum = arguments.length < 3;
-      callback = lodash.createCallback(callback, thisArg, 4);
-      forEachRight(collection, function(value, index, collection) {
-        accumulator = noaccum
-          ? (noaccum = false, value)
-          : callback(accumulator, value, index, collection);
-      });
-      return accumulator;
-    }
-
-    /**
-     * The opposite of `_.filter` this method returns the elements of a
-     * collection that the callback does **not** return truey for.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of elements that failed the callback check.
-     * @example
-     *
-     * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-     * // => [1, 3, 5]
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.reject(characters, 'blocked');
-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-     *
-     * // using "_.where" callback shorthand
-     * _.reject(characters, { 'age': 36 });
-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
-     */
-    function reject(collection, callback, thisArg) {
-      callback = lodash.createCallback(callback, thisArg, 3);
-      return filter(collection, function(value, index, collection) {
-        return !callback(value, index, collection);
-      });
-    }
-
-    /**
-     * Retrieves a random element or `n` random elements from a collection.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to sample.
-     * @param {number} [n] The number of elements to sample.
-     * @param- {Object} [guard] Allows working with functions like `_.map`
-     *  without using their `index` arguments as `n`.
-     * @returns {Array} Returns the random sample(s) of `collection`.
-     * @example
-     *
-     * _.sample([1, 2, 3, 4]);
-     * // => 2
-     *
-     * _.sample([1, 2, 3, 4], 2);
-     * // => [3, 1]
-     */
-    function sample(collection, n, guard) {
-      if (collection && typeof collection.length != 'number') {
-        collection = values(collection);
-      }
-      if (n == null || guard) {
-        return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
-      }
-      var result = shuffle(collection);
-      result.length = nativeMin(nativeMax(0, n), result.length);
-      return result;
-    }
-
-    /**
-     * Creates an array of shuffled values, using a version of the Fisher-Yates
-     * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to shuffle.
-     * @returns {Array} Returns a new shuffled collection.
-     * @example
-     *
-     * _.shuffle([1, 2, 3, 4, 5, 6]);
-     * // => [4, 1, 6, 3, 5, 2]
-     */
-    function shuffle(collection) {
-      var index = -1,
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      forEach(collection, function(value) {
-        var rand = baseRandom(0, ++index);
-        result[index] = result[rand];
-        result[rand] = value;
-      });
-      return result;
-    }
-
-    /**
-     * Gets the size of the `collection` by returning `collection.length` for arrays
-     * and array-like objects or the number of own enumerable properties for objects.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to inspect.
-     * @returns {number} Returns `collection.length` or number of own enumerable properties.
-     * @example
-     *
-     * _.size([1, 2]);
-     * // => 2
-     *
-     * _.size({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => 3
-     *
-     * _.size('pebbles');
-     * // => 7
-     */
-    function size(collection) {
-      var length = collection ? collection.length : 0;
-      return typeof length == 'number' ? length : keys(collection).length;
-    }
-
-    /**
-     * Checks if the callback returns a truey value for **any** element of a
-     * collection. The function returns as soon as it finds a passing value and
-     * does not iterate over the entire collection. The callback is bound to
-     * `thisArg` and invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias any
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if any element passed the callback check,
-     *  else `false`.
-     * @example
-     *
-     * _.some([null, 0, 'yes', false], Boolean);
-     * // => true
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.some(characters, 'blocked');
-     * // => true
-     *
-     * // using "_.where" callback shorthand
-     * _.some(characters, { 'age': 1 });
-     * // => false
-     */
-    function some(collection, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if ((result = callback(collection[index], index, collection))) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          return !(result = callback(value, index, collection));
-        });
-      }
-      return !!result;
-    }
-
-    /**
-     * Creates an array of elements, sorted in ascending order by the results of
-     * running each element in a collection through the callback. This method
-     * performs a stable sort, that is, it will preserve the original sort order
-     * of equal elements. The callback is bound to `thisArg` and invoked with
-     * three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an array of property names is provided for `callback` the collection
-     * will be sorted by each property value.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Array|Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of sorted elements.
-     * @example
-     *
-     * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
-     * // => [3, 1, 2]
-     *
-     * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
-     * // => [3, 1, 2]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36 },
-     *   { 'name': 'fred',    'age': 40 },
-     *   { 'name': 'barney',  'age': 26 },
-     *   { 'name': 'fred',    'age': 30 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.map(_.sortBy(characters, 'age'), _.values);
-     * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
-     *
-     * // sorting by multiple properties
-     * _.map(_.sortBy(characters, ['name', 'age']), _.values);
-     * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
-     */
-    function sortBy(collection, callback, thisArg) {
-      var index = -1,
-          isArr = isArray(callback),
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      if (!isArr) {
-        callback = lodash.createCallback(callback, thisArg, 3);
-      }
-      forEach(collection, function(value, key, collection) {
-        var object = result[++index] = getObject();
-        if (isArr) {
-          object.criteria = map(callback, function(key) { return value[key]; });
-        } else {
-          (object.criteria = getArray())[0] = callback(value, key, collection);
-        }
-        object.index = index;
-        object.value = value;
-      });
-
-      length = result.length;
-      result.sort(compareAscending);
-      while (length--) {
-        var object = result[length];
-        result[length] = object.value;
-        if (!isArr) {
-          releaseArray(object.criteria);
-        }
-        releaseObject(object);
-      }
-      return result;
-    }
-
-    /**
-     * Converts the `collection` to an array.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to convert.
-     * @returns {Array} Returns the new converted array.
-     * @example
-     *
-     * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
-     * // => [2, 3, 4]
-     */
-    function toArray(collection) {
-      if (collection && typeof collection.length == 'number') {
-        return slice(collection);
-      }
-      return values(collection);
-    }
-
-    /**
-     * Performs a deep comparison of each element in a `collection` to the given
-     * `properties` object, returning an array of all elements that have equivalent
-     * property values.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Object} props The object of property values to filter by.
-     * @returns {Array} Returns a new array of elements that have the given properties.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
-     * ];
-     *
-     * _.where(characters, { 'age': 36 });
-     * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
-     *
-     * _.where(characters, { 'pets': ['dino'] });
-     * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
-     */
-    var where = filter;
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates an array with all falsey values removed. The values `false`, `null`,
-     * `0`, `""`, `undefined`, and `NaN` are all falsey.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to compact.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.compact([0, 1, false, 2, '', 3]);
-     * // => [1, 2, 3]
-     */
-    function compact(array) {
-      var index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      while (++index < length) {
-        var value = array[index];
-        if (value) {
-          result.push(value);
-        }
-      }
-      return result;
-    }
-
-    /**
-     * Creates an array excluding all values of the provided arrays using strict
-     * equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to process.
-     * @param {...Array} [values] The arrays of values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
-     * // => [1, 3, 4]
-     */
-    function difference(array) {
-      return baseDifference(array, baseFlatten(arguments, true, true, 1));
-    }
-
-    /**
-     * This method is like `_.find` except that it returns the index of the first
-     * element that passes the callback check, instead of the element itself.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index of the found element, else `-1`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
-     * ];
-     *
-     * _.findIndex(characters, function(chr) {
-     *   return chr.age < 20;
-     * });
-     * // => 2
-     *
-     * // using "_.where" callback shorthand
-     * _.findIndex(characters, { 'age': 36 });
-     * // => 0
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findIndex(characters, 'blocked');
-     * // => 1
-     */
-    function findIndex(array, callback, thisArg) {
-      var index = -1,
-          length = array ? array.length : 0;
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (++index < length) {
-        if (callback(array[index], index, array)) {
-          return index;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * This method is like `_.findIndex` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index of the found element, else `-1`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': true },
-     *   { 'name': 'fred',    'age': 40, 'blocked': false },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': true }
-     * ];
-     *
-     * _.findLastIndex(characters, function(chr) {
-     *   return chr.age > 30;
-     * });
-     * // => 1
-     *
-     * // using "_.where" callback shorthand
-     * _.findLastIndex(characters, { 'age': 36 });
-     * // => 0
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findLastIndex(characters, 'blocked');
-     * // => 2
-     */
-    function findLastIndex(array, callback, thisArg) {
-      var length = array ? array.length : 0;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (length--) {
-        if (callback(array[length], length, array)) {
-          return length;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * Gets the first element or first `n` elements of an array. If a callback
-     * is provided elements at the beginning of the array are returned as long
-     * as the callback returns truey. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias head, take
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback] The function called
-     *  per element or the number of elements to return. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the first element(s) of `array`.
-     * @example
-     *
-     * _.first([1, 2, 3]);
-     * // => 1
-     *
-     * _.first([1, 2, 3], 2);
-     * // => [1, 2]
-     *
-     * _.first([1, 2, 3], function(num) {
-     *   return num < 3;
-     * });
-     * // => [1, 2]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.first(characters, 'blocked');
-     * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
-     *
-     * // using "_.where" callback shorthand
-     * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
-     * // => ['barney', 'fred']
-     */
-    function first(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = -1;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (++index < length && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = callback;
-        if (n == null || thisArg) {
-          return array ? array[0] : undefined;
-        }
-      }
-      return slice(array, 0, nativeMin(nativeMax(0, n), length));
-    }
-
-    /**
-     * Flattens a nested array (the nesting can be to any depth). If `isShallow`
-     * is truey, the array will only be flattened a single level. If a callback
-     * is provided each element of the array is passed through the callback before
-     * flattening. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to flatten.
-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new flattened array.
-     * @example
-     *
-     * _.flatten([1, [2], [3, [[4]]]]);
-     * // => [1, 2, 3, 4];
-     *
-     * _.flatten([1, [2], [3, [[4]]]], true);
-     * // => [1, 2, 3, [[4]]];
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.flatten(characters, 'pets');
-     * // => ['hoppy', 'baby puss', 'dino']
-     */
-    function flatten(array, isShallow, callback, thisArg) {
-      // juggle arguments
-      if (typeof isShallow != 'boolean' && isShallow != null) {
-        thisArg = callback;
-        callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
-        isShallow = false;
-      }
-      if (callback != null) {
-        array = map(array, callback, thisArg);
-      }
-      return baseFlatten(array, isShallow);
-    }
-
-    /**
-     * Gets the index at which the first occurrence of `value` is found using
-     * strict equality for comparisons, i.e. `===`. If the array is already sorted
-     * providing `true` for `fromIndex` will run a faster binary search.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {*} value The value to search for.
-     * @param {boolean|number} [fromIndex=0] The index to search from or `true`
-     *  to perform a binary search on a sorted array.
-     * @returns {number} Returns the index of the matched value or `-1`.
-     * @example
-     *
-     * _.indexOf([1, 2, 3, 1, 2, 3], 2);
-     * // => 1
-     *
-     * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
-     * // => 4
-     *
-     * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
-     * // => 2
-     */
-    function indexOf(array, value, fromIndex) {
-      if (typeof fromIndex == 'number') {
-        var length = array ? array.length : 0;
-        fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
-      } else if (fromIndex) {
-        var index = sortedIndex(array, value);
-        return array[index] === value ? index : -1;
-      }
-      return baseIndexOf(array, value, fromIndex);
-    }
-
-    /**
-     * Gets all but the last element or last `n` elements of an array. If a
-     * callback is provided elements at the end of the array are excluded from
-     * the result as long as the callback returns truey. The callback is bound
-     * to `thisArg` and invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback=1] The function called
-     *  per element or the number of elements to exclude. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a slice of `array`.
-     * @example
-     *
-     * _.initial([1, 2, 3]);
-     * // => [1, 2]
-     *
-     * _.initial([1, 2, 3], 2);
-     * // => [1]
-     *
-     * _.initial([1, 2, 3], function(num) {
-     *   return num > 1;
-     * });
-     * // => [1]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.initial(characters, 'blocked');
-     * // => [{ 'name': 'barney',  'blocked': false, 'employer': 'slate' }]
-     *
-     * // using "_.where" callback shorthand
-     * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
-     * // => ['barney', 'fred']
-     */
-    function initial(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = length;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (index-- && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = (callback == null || thisArg) ? 1 : callback || n;
-      }
-      return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
-    }
-
-    /**
-     * Creates an array of unique values present in all provided arrays using
-     * strict equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of shared values.
-     * @example
-     *
-     * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-     * // => [1, 2]
-     */
-    function intersection() {
-      var args = [],
-          argsIndex = -1,
-          argsLength = arguments.length,
-          caches = getArray(),
-          indexOf = getIndexOf(),
-          trustIndexOf = indexOf === baseIndexOf,
-          seen = getArray();
-
-      while (++argsIndex < argsLength) {
-        var value = arguments[argsIndex];
-        if (isArray(value) || isArguments(value)) {
-          args.push(value);
-          caches.push(trustIndexOf && value.length >= largeArraySize &&
-            createCache(argsIndex ? args[argsIndex] : seen));
-        }
-      }
-      var array = args[0],
-          index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      outer:
-      while (++index < length) {
-        var cache = caches[0];
-        value = array[index];
-
-        if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
-          argsIndex = argsLength;
-          (cache || seen).push(value);
-          while (--argsIndex) {
-            cache = caches[argsIndex];
-            if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
-              continue outer;
-            }
-          }
-          result.push(value);
-        }
-      }
-      while (argsLength--) {
-        cache = caches[argsLength];
-        if (cache) {
-          releaseObject(cache);
-        }
-      }
-      releaseArray(caches);
-      releaseArray(seen);
-      return result;
-    }
-
-    /**
-     * Gets the last element or last `n` elements of an array. If a callback is
-     * provided elements at the end of the array are returned as long as the
-     * callback returns truey. The callback is bound to `thisArg` and invoked
-     * with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback] The function called
-     *  per element or the number of elements to return. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the last element(s) of `array`.
-     * @example
-     *
-     * _.last([1, 2, 3]);
-     * // => 3
-     *
-     * _.last([1, 2, 3], 2);
-     * // => [2, 3]
-     *
-     * _.last([1, 2, 3], function(num) {
-     *   return num > 1;
-     * });
-     * // => [2, 3]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.pluck(_.last(characters, 'blocked'), 'name');
-     * // => ['fred', 'pebbles']
-     *
-     * // using "_.where" callback shorthand
-     * _.last(characters, { 'employer': 'na' });
-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-     */
-    function last(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = length;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (index-- && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = callback;
-        if (n == null || thisArg) {
-          return array ? array[length - 1] : undefined;
-        }
-      }
-      return slice(array, nativeMax(0, length - n));
-    }
-
-    /**
-     * Gets the index at which the last occurrence of `value` is found using strict
-     * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
-     * as the offset from the end of the collection.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {*} value The value to search for.
-     * @param {number} [fromIndex=array.length-1] The index to search from.
-     * @returns {number} Returns the index of the matched value or `-1`.
-     * @example
-     *
-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
-     * // => 4
-     *
-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
-     * // => 1
-     */
-    function lastIndexOf(array, value, fromIndex) {
-      var index = array ? array.length : 0;
-      if (typeof fromIndex == 'number') {
-        index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
-      }
-      while (index--) {
-        if (array[index] === value) {
-          return index;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * Removes all provided values from the given array using strict equality for
-     * comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to modify.
-     * @param {...*} [value] The values to remove.
-     * @returns {Array} Returns `array`.
-     * @example
-     *
-     * var array = [1, 2, 3, 1, 2, 3];
-     * _.pull(array, 2, 3);
-     * console.log(array);
-     * // => [1, 1]
-     */
-    function pull(array) {
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = args.length,
-          length = array ? array.length : 0;
-
-      while (++argsIndex < argsLength) {
-        var index = -1,
-            value = args[argsIndex];
-        while (++index < length) {
-          if (array[index] === value) {
-            splice.call(array, index--, 1);
-            length--;
-          }
-        }
-      }
-      return array;
-    }
-
-    /**
-     * Creates an array of numbers (positive and/or negative) progressing from
-     * `start` up to but not including `end`. If `start` is less than `stop` a
-     * zero-length range is created unless a negative `step` is specified.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {number} [start=0] The start of the range.
-     * @param {number} end The end of the range.
-     * @param {number} [step=1] The value to increment or decrement by.
-     * @returns {Array} Returns a new range array.
-     * @example
-     *
-     * _.range(4);
-     * // => [0, 1, 2, 3]
-     *
-     * _.range(1, 5);
-     * // => [1, 2, 3, 4]
-     *
-     * _.range(0, 20, 5);
-     * // => [0, 5, 10, 15]
-     *
-     * _.range(0, -4, -1);
-     * // => [0, -1, -2, -3]
-     *
-     * _.range(1, 4, 0);
-     * // => [1, 1, 1]
-     *
-     * _.range(0);
-     * // => []
-     */
-    function range(start, end, step) {
-      start = +start || 0;
-      step = typeof step == 'number' ? step : (+step || 1);
-
-      if (end == null) {
-        end = start;
-        start = 0;
-      }
-      // use `Array(length)` so engines like Chakra and V8 avoid slower modes
-      // http://youtu.be/XAqIpGU8ZZk#t=17m25s
-      var index = -1,
-          length = nativeMax(0, ceil((end - start) / (step || 1))),
-          result = Array(length);
-
-      while (++index < length) {
-        result[index] = start;
-        start += step;
-      }
-      return result;
-    }
-
-    /**
-     * Removes all elements from an array that the callback returns truey for
-     * and returns an array of removed elements. The callback is bound to `thisArg`
-     * and invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to modify.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of removed elements.
-     * @example
-     *
-     * var array = [1, 2, 3, 4, 5, 6];
-     * var evens = _.remove(array, function(num) { return num % 2 == 0; });
-     *
-     * console.log(array);
-     * // => [1, 3, 5]
-     *
-     * console.log(evens);
-     * // => [2, 4, 6]
-     */
-    function remove(array, callback, thisArg) {
-      var index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (++index < length) {
-        var value = array[index];
-        if (callback(value, index, array)) {
-          result.push(value);
-          splice.call(array, index--, 1);
-          length--;
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The opposite of `_.initial` this method gets all but the first element or
-     * first `n` elements of an array. If a callback function is provided elements
-     * at the beginning of the array are excluded from the result as long as the
-     * callback returns truey. The callback is bound to `thisArg` and invoked
-     * with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias drop, tail
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback=1] The function called
-     *  per element or the number of elements to exclude. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a slice of `array`.
-     * @example
-     *
-     * _.rest([1, 2, 3]);
-     * // => [2, 3]
-     *
-     * _.rest([1, 2, 3], 2);
-     * // => [3]
-     *
-     * _.rest([1, 2, 3], function(num) {
-     *   return num < 3;
-     * });
-     * // => [3]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': false,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.pluck(_.rest(characters, 'blocked'), 'name');
-     * // => ['fred', 'pebbles']
-     *
-     * // using "_.where" callback shorthand
-     * _.rest(characters, { 'employer': 'slate' });
-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-     */
-    function rest(array, callback, thisArg) {
-      if (typeof callback != 'number' && callback != null) {
-        var n = 0,
-            index = -1,
-            length = array ? array.length : 0;
-
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (++index < length && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
-      }
-      return slice(array, n);
-    }
-
-    /**
-     * Uses a binary search to determine the smallest index at which a value
-     * should be inserted into a given sorted array in order to maintain the sort
-     * order of the array. If a callback is provided it will be executed for
-     * `value` and each element of `array` to compute their sort ranking. The
-     * callback is bound to `thisArg` and invoked with one argument; (value).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to inspect.
-     * @param {*} value The value to evaluate.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index at which `value` should be inserted
-     *  into `array`.
-     * @example
-     *
-     * _.sortedIndex([20, 30, 50], 40);
-     * // => 2
-     *
-     * // using "_.pluck" callback shorthand
-     * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
-     * // => 2
-     *
-     * var dict = {
-     *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
-     * };
-     *
-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
-     *   return dict.wordToNumber[word];
-     * });
-     * // => 2
-     *
-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
-     *   return this.wordToNumber[word];
-     * }, dict);
-     * // => 2
-     */
-    function sortedIndex(array, value, callback, thisArg) {
-      var low = 0,
-          high = array ? array.length : low;
-
-      // explicitly reference `identity` for better inlining in Firefox
-      callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
-      value = callback(value);
-
-      while (low < high) {
-        var mid = (low + high) >>> 1;
-        (callback(array[mid]) < value)
-          ? low = mid + 1
-          : high = mid;
-      }
-      return low;
-    }
-
-    /**
-     * Creates an array of unique values, in order, of the provided arrays using
-     * strict equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of combined values.
-     * @example
-     *
-     * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-     * // => [1, 2, 3, 5, 4]
-     */
-    function union() {
-      return baseUniq(baseFlatten(arguments, true, true));
-    }
-
-    /**
-     * Creates a duplicate-value-free version of an array using strict equality
-     * for comparisons, i.e. `===`. If the array is sorted, providing
-     * `true` for `isSorted` will use a faster algorithm. If a callback is provided
-     * each element of `array` is passed through the callback before uniqueness
-     * is computed. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias unique
-     * @category Arrays
-     * @param {Array} array The array to process.
-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a duplicate-value-free array.
-     * @example
-     *
-     * _.uniq([1, 2, 1, 3, 1]);
-     * // => [1, 2, 3]
-     *
-     * _.uniq([1, 1, 2, 2, 3], true);
-     * // => [1, 2, 3]
-     *
-     * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
-     * // => ['A', 'b', 'C']
-     *
-     * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
-     * // => [1, 2.5, 3]
-     *
-     * // using "_.pluck" callback shorthand
-     * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
-     * // => [{ 'x': 1 }, { 'x': 2 }]
-     */
-    function uniq(array, isSorted, callback, thisArg) {
-      // juggle arguments
-      if (typeof isSorted != 'boolean' && isSorted != null) {
-        thisArg = callback;
-        callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
-        isSorted = false;
-      }
-      if (callback != null) {
-        callback = lodash.createCallback(callback, thisArg, 3);
-      }
-      return baseUniq(array, isSorted, callback);
-    }
-
-    /**
-     * Creates an array excluding all provided values using strict equality for
-     * comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to filter.
-     * @param {...*} [value] The values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
-     * // => [2, 3, 4]
-     */
-    function without(array) {
-      return baseDifference(array, slice(arguments, 1));
-    }
-
-    /**
-     * Creates an array that is the symmetric difference of the provided arrays.
-     * See http://en.wikipedia.org/wiki/Symmetric_difference.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of values.
-     * @example
-     *
-     * _.xor([1, 2, 3], [5, 2, 1, 4]);
-     * // => [3, 5, 4]
-     *
-     * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
-     * // => [1, 4, 5]
-     */
-    function xor() {
-      var index = -1,
-          length = arguments.length;
-
-      while (++index < length) {
-        var array = arguments[index];
-        if (isArray(array) || isArguments(array)) {
-          var result = result
-            ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
-            : array;
-        }
-      }
-      return result || [];
-    }
-
-    /**
-     * Creates an array of grouped elements, the first of which contains the first
-     * elements of the given arrays, the second of which contains the second
-     * elements of the given arrays, and so on.
-     *
-     * @static
-     * @memberOf _
-     * @alias unzip
-     * @category Arrays
-     * @param {...Array} [array] Arrays to process.
-     * @returns {Array} Returns a new array of grouped elements.
-     * @example
-     *
-     * _.zip(['fred', 'barney'], [30, 40], [true, false]);
-     * // => [['fred', 30, true], ['barney', 40, false]]
-     */
-    function zip() {
-      var array = arguments.length > 1 ? arguments : arguments[0],
-          index = -1,
-          length = array ? max(pluck(array, 'length')) : 0,
-          result = Array(length < 0 ? 0 : length);
-
-      while (++index < length) {
-        result[index] = pluck(array, index);
-      }
-      return result;
-    }
-
-    /**
-     * Creates an object composed from arrays of `keys` and `values`. Provide
-     * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
-     * or two arrays, one of `keys` and one of corresponding `values`.
-     *
-     * @static
-     * @memberOf _
-     * @alias object
-     * @category Arrays
-     * @param {Array} keys The array of keys.
-     * @param {Array} [values=[]] The array of values.
-     * @returns {Object} Returns an object composed of the given keys and
-     *  corresponding values.
-     * @example
-     *
-     * _.zipObject(['fred', 'barney'], [30, 40]);
-     * // => { 'fred': 30, 'barney': 40 }
-     */
-    function zipObject(keys, values) {
-      var index = -1,
-          length = keys ? keys.length : 0,
-          result = {};
-
-      if (!values && length && !isArray(keys[0])) {
-        values = [];
-      }
-      while (++index < length) {
-        var key = keys[index];
-        if (values) {
-          result[key] = values[index];
-        } else if (key) {
-          result[key[0]] = key[1];
-        }
-      }
-      return result;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a function that executes `func`, with  the `this` binding and
-     * arguments of the created function, only after being called `n` times.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {number} n The number of times the function must be called before
-     *  `func` is executed.
-     * @param {Function} func The function to restrict.
-     * @returns {Function} Returns the new restricted function.
-     * @example
-     *
-     * var saves = ['profile', 'settings'];
-     *
-     * var done = _.after(saves.length, function() {
-     *   console.log('Done saving!');
-     * });
-     *
-     * _.forEach(saves, function(type) {
-     *   asyncSave({ 'type': type, 'complete': done });
-     * });
-     * // => logs 'Done saving!', after all saves have completed
-     */
-    function after(n, func) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      return function() {
-        if (--n < 1) {
-          return func.apply(this, arguments);
-        }
-      };
-    }
-
-    /**
-     * Creates a function that, when called, invokes `func` with the `this`
-     * binding of `thisArg` and prepends any additional `bind` arguments to those
-     * provided to the bound function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to bind.
-     * @param {*} [thisArg] The `this` binding of `func`.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new bound function.
-     * @example
-     *
-     * var func = function(greeting) {
-     *   return greeting + ' ' + this.name;
-     * };
-     *
-     * func = _.bind(func, { 'name': 'fred' }, 'hi');
-     * func();
-     * // => 'hi fred'
-     */
-    function bind(func, thisArg) {
-      return arguments.length > 2
-        ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
-        : createWrapper(func, 1, null, null, thisArg);
-    }
-
-    /**
-     * Binds methods of an object to the object itself, overwriting the existing
-     * method. Method names may be specified as individual arguments or as arrays
-     * of method names. If no method names are provided all the function properties
-     * of `object` will be bound.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Object} object The object to bind and assign the bound methods to.
-     * @param {...string} [methodName] The object method names to
-     *  bind, specified as individual method names or arrays of method names.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * var view = {
-     *   'label': 'docs',
-     *   'onClick': function() { console.log('clicked ' + this.label); }
-     * };
-     *
-     * _.bindAll(view);
-     * jQuery('#docs').on('click', view.onClick);
-     * // => logs 'clicked docs', when the button is clicked
-     */
-    function bindAll(object) {
-      var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
-          index = -1,
-          length = funcs.length;
-
-      while (++index < length) {
-        var key = funcs[index];
-        object[key] = createWrapper(object[key], 1, null, null, object);
-      }
-      return object;
-    }
-
-    /**
-     * Creates a function that, when called, invokes the method at `object[key]`
-     * and prepends any additional `bindKey` arguments to those provided to the bound
-     * function. This method differs from `_.bind` by allowing bound functions to
-     * reference methods that will be redefined or don't yet exist.
-     * See http://michaux.ca/articles/lazy-function-definition-pattern.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Object} object The object the method belongs to.
-     * @param {string} key The key of the method.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new bound function.
-     * @example
-     *
-     * var object = {
-     *   'name': 'fred',
-     *   'greet': function(greeting) {
-     *     return greeting + ' ' + this.name;
-     *   }
-     * };
-     *
-     * var func = _.bindKey(object, 'greet', 'hi');
-     * func();
-     * // => 'hi fred'
-     *
-     * object.greet = function(greeting) {
-     *   return greeting + 'ya ' + this.name + '!';
-     * };
-     *
-     * func();
-     * // => 'hiya fred!'
-     */
-    function bindKey(object, key) {
-      return arguments.length > 2
-        ? createWrapper(key, 19, slice(arguments, 2), null, object)
-        : createWrapper(key, 3, null, null, object);
-    }
-
-    /**
-     * Creates a function that is the composition of the provided functions,
-     * where each function consumes the return value of the function that follows.
-     * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
-     * Each function is executed with the `this` binding of the composed function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {...Function} [func] Functions to compose.
-     * @returns {Function} Returns the new composed function.
-     * @example
-     *
-     * var realNameMap = {
-     *   'pebbles': 'penelope'
-     * };
-     *
-     * var format = function(name) {
-     *   name = realNameMap[name.toLowerCase()] || name;
-     *   return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
-     * };
-     *
-     * var greet = function(formatted) {
-     *   return 'Hiya ' + formatted + '!';
-     * };
-     *
-     * var welcome = _.compose(greet, format);
-     * welcome('pebbles');
-     * // => 'Hiya Penelope!'
-     */
-    function compose() {
-      var funcs = arguments,
-          length = funcs.length;
-
-      while (length--) {
-        if (!isFunction(funcs[length])) {
-          throw new TypeError;
-        }
-      }
-      return function() {
-        var args = arguments,
-            length = funcs.length;
-
-        while (length--) {
-          args = [funcs[length].apply(this, args)];
-        }
-        return args[0];
-      };
-    }
-
-    /**
-     * Creates a function which accepts one or more arguments of `func` that when
-     * invoked either executes `func` returning its result, if all `func` arguments
-     * have been provided, or returns a function that accepts one or more of the
-     * remaining `func` arguments, and so on. The arity of `func` can be specified
-     * if `func.length` is not sufficient.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to curry.
-     * @param {number} [arity=func.length] The arity of `func`.
-     * @returns {Function} Returns the new curried function.
-     * @example
-     *
-     * var curried = _.curry(function(a, b, c) {
-     *   console.log(a + b + c);
-     * });
-     *
-     * curried(1)(2)(3);
-     * // => 6
-     *
-     * curried(1, 2)(3);
-     * // => 6
-     *
-     * curried(1, 2, 3);
-     * // => 6
-     */
-    function curry(func, arity) {
-      arity = typeof arity == 'number' ? arity : (+arity || func.length);
-      return createWrapper(func, 4, null, null, null, arity);
-    }
-
-    /**
-     * Creates a function that will delay the execution of `func` until after
-     * `wait` milliseconds have elapsed since the last time it was invoked.
-     * Provide an options object to indicate that `func` should be invoked on
-     * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
-     * to the debounced function will return the result of the last `func` call.
-     *
-     * Note: If `leading` and `trailing` options are `true` `func` will be called
-     * on the trailing edge of the timeout only if the the debounced function is
-     * invoked more than once during the `wait` timeout.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to debounce.
-     * @param {number} wait The number of milliseconds to delay.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
-     * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
-     * @returns {Function} Returns the new debounced function.
-     * @example
-     *
-     * // avoid costly calculations while the window size is in flux
-     * var lazyLayout = _.debounce(calculateLayout, 150);
-     * jQuery(window).on('resize', lazyLayout);
-     *
-     * // execute `sendMail` when the click event is fired, debouncing subsequent calls
-     * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
-     *   'leading': true,
-     *   'trailing': false
-     * });
-     *
-     * // ensure `batchLog` is executed once after 1 second of debounced calls
-     * var source = new EventSource('/stream');
-     * source.addEventListener('message', _.debounce(batchLog, 250, {
-     *   'maxWait': 1000
-     * }, false);
-     */
-    function debounce(func, wait, options) {
-      var args,
-          maxTimeoutId,
-          result,
-          stamp,
-          thisArg,
-          timeoutId,
-          trailingCall,
-          lastCalled = 0,
-          maxWait = false,
-          trailing = true;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      wait = nativeMax(0, wait) || 0;
-      if (options === true) {
-        var leading = true;
-        trailing = false;
-      } else if (isObject(options)) {
-        leading = options.leading;
-        maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
-        trailing = 'trailing' in options ? options.trailing : trailing;
-      }
-      var delayed = function() {
-        var remaining = wait - (now() - stamp);
-        if (remaining <= 0) {
-          if (maxTimeoutId) {
-            clearTimeout(maxTimeoutId);
-          }
-          var isCalled = trailingCall;
-          maxTimeoutId = timeoutId = trailingCall = undefined;
-          if (isCalled) {
-            lastCalled = now();
-            result = func.apply(thisArg, args);
-            if (!timeoutId && !maxTimeoutId) {
-              args = thisArg = null;
-            }
-          }
-        } else {
-          timeoutId = setTimeout(delayed, remaining);
-        }
-      };
-
-      var maxDelayed = function() {
-        if (timeoutId) {
-          clearTimeout(timeoutId);
-        }
-        maxTimeoutId = timeoutId = trailingCall = undefined;
-        if (trailing || (maxWait !== wait)) {
-          lastCalled = now();
-          result = func.apply(thisArg, args);
-          if (!timeoutId && !maxTimeoutId) {
-            args = thisArg = null;
-          }
-        }
-      };
-
-      return function() {
-        args = arguments;
-        stamp = now();
-        thisArg = this;
-        trailingCall = trailing && (timeoutId || !leading);
-
-        if (maxWait === false) {
-          var leadingCall = leading && !timeoutId;
-        } else {
-          if (!maxTimeoutId && !leading) {
-            lastCalled = stamp;
-          }
-          var remaining = maxWait - (stamp - lastCalled),
-              isCalled = remaining <= 0;
-
-          if (isCalled) {
-            if (maxTimeoutId) {
-              maxTimeoutId = clearTimeout(maxTimeoutId);
-            }
-            lastCalled = stamp;
-            result = func.apply(thisArg, args);
-          }
-          else if (!maxTimeoutId) {
-            maxTimeoutId = setTimeout(maxDelayed, remaining);
-          }
-        }
-        if (isCalled && timeoutId) {
-          timeoutId = clearTimeout(timeoutId);
-        }
-        else if (!timeoutId && wait !== maxWait) {
-          timeoutId = setTimeout(delayed, wait);
-        }
-        if (leadingCall) {
-          isCalled = true;
-          result = func.apply(thisArg, args);
-        }
-        if (isCalled && !timeoutId && !maxTimeoutId) {
-          args = thisArg = null;
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Defers executing the `func` function until the current call stack has cleared.
-     * Additional arguments will be provided to `func` when it is invoked.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to defer.
-     * @param {...*} [arg] Arguments to invoke the function with.
-     * @returns {number} Returns the timer id.
-     * @example
-     *
-     * _.defer(function(text) { console.log(text); }, 'deferred');
-     * // logs 'deferred' after one or more milliseconds
-     */
-    function defer(func) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var args = slice(arguments, 1);
-      return setTimeout(function() { func.apply(undefined, args); }, 1);
-    }
-
-    /**
-     * Executes the `func` function after `wait` milliseconds. Additional arguments
-     * will be provided to `func` when it is invoked.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to delay.
-     * @param {number} wait The number of milliseconds to delay execution.
-     * @param {...*} [arg] Arguments to invoke the function with.
-     * @returns {number} Returns the timer id.
-     * @example
-     *
-     * _.delay(function(text) { console.log(text); }, 1000, 'later');
-     * // => logs 'later' after one second
-     */
-    function delay(func, wait) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var args = slice(arguments, 2);
-      return setTimeout(function() { func.apply(undefined, args); }, wait);
-    }
-
-    /**
-     * Creates a function that memoizes the result of `func`. If `resolver` is
-     * provided it will be used to determine the cache key for storing the result
-     * based on the arguments provided to the memoized function. By default, the
-     * first argument provided to the memoized function is used as the cache key.
-     * The `func` is executed with the `this` binding of the memoized function.
-     * The result cache is exposed as the `cache` property on the memoized function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to have its output memoized.
-     * @param {Function} [resolver] A function used to resolve the cache key.
-     * @returns {Function} Returns the new memoizing function.
-     * @example
-     *
-     * var fibonacci = _.memoize(function(n) {
-     *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
-     * });
-     *
-     * fibonacci(9)
-     * // => 34
-     *
-     * var data = {
-     *   'fred': { 'name': 'fred', 'age': 40 },
-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
-     * };
-     *
-     * // modifying the result cache
-     * var get = _.memoize(function(name) { return data[name]; }, _.identity);
-     * get('pebbles');
-     * // => { 'name': 'pebbles', 'age': 1 }
-     *
-     * get.cache.pebbles.name = 'penelope';
-     * get('pebbles');
-     * // => { 'name': 'penelope', 'age': 1 }
-     */
-    function memoize(func, resolver) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var memoized = function() {
-        var cache = memoized.cache,
-            key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
-
-        return hasOwnProperty.call(cache, key)
-          ? cache[key]
-          : (cache[key] = func.apply(this, arguments));
-      }
-      memoized.cache = {};
-      return memoized;
-    }
-
-    /**
-     * Creates a function that is restricted to execute `func` once. Repeat calls to
-     * the function will return the value of the first call. The `func` is executed
-     * with the `this` binding of the created function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to restrict.
-     * @returns {Function} Returns the new restricted function.
-     * @example
-     *
-     * var initialize = _.once(createApplication);
-     * initialize();
-     * initialize();
-     * // `initialize` executes `createApplication` once
-     */
-    function once(func) {
-      var ran,
-          result;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      return function() {
-        if (ran) {
-          return result;
-        }
-        ran = true;
-        result = func.apply(this, arguments);
-
-        // clear the `func` variable so the function may be garbage collected
-        func = null;
-        return result;
-      };
-    }
-
-    /**
-     * Creates a function that, when called, invokes `func` with any additional
-     * `partial` arguments prepended to those provided to the new function. This
-     * method is similar to `_.bind` except it does **not** alter the `this` binding.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to partially apply arguments to.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new partially applied function.
-     * @example
-     *
-     * var greet = function(greeting, name) { return greeting + ' ' + name; };
-     * var hi = _.partial(greet, 'hi');
-     * hi('fred');
-     * // => 'hi fred'
-     */
-    function partial(func) {
-      return createWrapper(func, 16, slice(arguments, 1));
-    }
-
-    /**
-     * This method is like `_.partial` except that `partial` arguments are
-     * appended to those provided to the new function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to partially apply arguments to.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new partially applied function.
-     * @example
-     *
-     * var defaultsDeep = _.partialRight(_.merge, _.defaults);
-     *
-     * var options = {
-     *   'variable': 'data',
-     *   'imports': { 'jq': $ }
-     * };
-     *
-     * defaultsDeep(options, _.templateSettings);
-     *
-     * options.variable
-     * // => 'data'
-     *
-     * options.imports
-     * // => { '_': _, 'jq': $ }
-     */
-    function partialRight(func) {
-      return createWrapper(func, 32, null, slice(arguments, 1));
-    }
-
-    /**
-     * Creates a function that, when executed, will only call the `func` function
-     * at most once per every `wait` milliseconds. Provide an options object to
-     * indicate that `func` should be invoked on the leading and/or trailing edge
-     * of the `wait` timeout. Subsequent calls to the throttled function will
-     * return the result of the last `func` call.
-     *
-     * Note: If `leading` and `trailing` options are `true` `func` will be called
-     * on the trailing edge of the timeout only if the the throttled function is
-     * invoked more than once during the `wait` timeout.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to throttle.
-     * @param {number} wait The number of milliseconds to throttle executions to.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
-     * @returns {Function} Returns the new throttled function.
-     * @example
-     *
-     * // avoid excessively updating the position while scrolling
-     * var throttled = _.throttle(updatePosition, 100);
-     * jQuery(window).on('scroll', throttled);
-     *
-     * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
-     * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
-     *   'trailing': false
-     * }));
-     */
-    function throttle(func, wait, options) {
-      var leading = true,
-          trailing = true;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      if (options === false) {
-        leading = false;
-      } else if (isObject(options)) {
-        leading = 'leading' in options ? options.leading : leading;
-        trailing = 'trailing' in options ? options.trailing : trailing;
-      }
-      debounceOptions.leading = leading;
-      debounceOptions.maxWait = wait;
-      debounceOptions.trailing = trailing;
-
-      return debounce(func, wait, debounceOptions);
-    }
-
-    /**
-     * Creates a function that provides `value` to the wrapper function as its
-     * first argument. Additional arguments provided to the function are appended
-     * to those provided to the wrapper function. The wrapper is executed with
-     * the `this` binding of the created function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {*} value The value to wrap.
-     * @param {Function} wrapper The wrapper function.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var p = _.wrap(_.escape, function(func, text) {
-     *   return '<p>' + func(text) + '</p>';
-     * });
-     *
-     * p('Fred, Wilma, & Pebbles');
-     * // => '<p>Fred, Wilma, & Pebbles</p>'
-     */
-    function wrap(value, wrapper) {
-      return createWrapper(wrapper, 16, [value]);
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a function that returns `value`.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} value The value to return from the new function.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * var getter = _.constant(object);
-     * getter() === object;
-     * // => true
-     */
-    function constant(value) {
-      return function() {
-        return value;
-      };
-    }
-
-    /**
-     * Produces a callback bound to an optional `thisArg`. If `func` is a property
-     * name the created callback will return the property value for a given element.
-     * If `func` is an object the created callback will return `true` for elements
-     * that contain the equivalent object properties, otherwise it will return `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} [func=identity] The value to convert to a callback.
-     * @param {*} [thisArg] The `this` binding of the created callback.
-     * @param {number} [argCount] The number of arguments the callback accepts.
-     * @returns {Function} Returns a callback function.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // wrap to create custom callback shorthands
-     * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
-     *   var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
-     *   return !match ? func(callback, thisArg) : function(object) {
-     *     return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
-     *   };
-     * });
-     *
-     * _.filter(characters, 'age__gt38');
-     * // => [{ 'name': 'fred', 'age': 40 }]
-     */
-    function createCallback(func, thisArg, argCount) {
-      var type = typeof func;
-      if (func == null || type == 'function') {
-        return baseCreateCallback(func, thisArg, argCount);
-      }
-      // handle "_.pluck" style callback shorthands
-      if (type != 'object') {
-        return property(func);
-      }
-      var props = keys(func),
-          key = props[0],
-          a = func[key];
-
-      // handle "_.where" style callback shorthands
-      if (props.length == 1 && a === a && !isObject(a)) {
-        // fast path the common case of providing an object with a single
-        // property containing a primitive value
-        return function(object) {
-          var b = object[key];
-          return a === b && (a !== 0 || (1 / a == 1 / b));
-        };
-      }
-      return function(object) {
-        var length = props.length,
-            result = false;
-
-        while (length--) {
-          if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
-            break;
-          }
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
-     * corresponding HTML entities.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} string The string to escape.
-     * @returns {string} Returns the escaped string.
-     * @example
-     *
-     * _.escape('Fred, Wilma, & Pebbles');
-     * // => 'Fred, Wilma, & Pebbles'
-     */
-    function escape(string) {
-      return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
-    }
-
-    /**
-     * This method returns the first argument provided to it.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} value Any value.
-     * @returns {*} Returns `value`.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * _.identity(object) === object;
-     * // => true
-     */
-    function identity(value) {
-      return value;
-    }
-
-    /**
-     * Adds function properties of a source object to the destination object.
-     * If `object` is a function methods will be added to its prototype as well.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {Function|Object} [object=lodash] object The destination object.
-     * @param {Object} source The object of functions to add.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
-     * @example
-     *
-     * function capitalize(string) {
-     *   return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
-     * }
-     *
-     * _.mixin({ 'capitalize': capitalize });
-     * _.capitalize('fred');
-     * // => 'Fred'
-     *
-     * _('fred').capitalize().value();
-     * // => 'Fred'
-     *
-     * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
-     * _('fred').capitalize();
-     * // => 'Fred'
-     */
-    function mixin(object, source, options) {
-      var chain = true,
-          methodNames = source && functions(source);
-
-      if (!source || (!options && !methodNames.length)) {
-        if (options == null) {
-          options = source;
-        }
-        ctor = lodashWrapper;
-        source = object;
-        object = lodash;
-        methodNames = functions(source);
-      }
-      if (options === false) {
-        chain = false;
-      } else if (isObject(options) && 'chain' in options) {
-        chain = options.chain;
-      }
-      var ctor = object,
-          isFunc = isFunction(ctor);
-
-      forEach(methodNames, function(methodName) {
-        var func = object[methodName] = source[methodName];
-        if (isFunc) {
-          ctor.prototype[methodName] = function() {
-            var chainAll = this.__chain__,
-                value = this.__wrapped__,
-                args = [value];
-
-            push.apply(args, arguments);
-            var result = func.apply(object, args);
-            if (chain || chainAll) {
-              if (value === result && isObject(result)) {
-                return this;
-              }
-              result = new ctor(result);
-              result.__chain__ = chainAll;
-            }
-            return result;
-          };
-        }
-      });
-    }
-
-    /**
-     * Reverts the '_' variable to its previous value and returns a reference to
-     * the `lodash` function.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @returns {Function} Returns the `lodash` function.
-     * @example
-     *
-     * var lodash = _.noConflict();
-     */
-    function noConflict() {
-      context._ = oldDash;
-      return this;
-    }
-
-    /**
-     * A no-operation function.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * _.noop(object) === undefined;
-     * // => true
-     */
-    function noop() {
-      // no operation performed
-    }
-
-    /**
-     * Gets the number of milliseconds that have elapsed since the Unix epoch
-     * (1 January 1970 00:00:00 UTC).
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @example
-     *
-     * var stamp = _.now();
-     * _.defer(function() { console.log(_.now() - stamp); });
-     * // => logs the number of milliseconds it took for the deferred function to be called
-     */
-    var now = isNative(now = Date.now) && now || function() {
-      return new Date().getTime();
-    };
-
-    /**
-     * Converts the given value into an integer of the specified radix.
-     * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
-     * `value` is a hexadecimal, in which case a `radix` of `16` is used.
-     *
-     * Note: This method avoids differences in native ES3 and ES5 `parseInt`
-     * implementations. See http://es5.github.io/#E.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} value The value to parse.
-     * @param {number} [radix] The radix used to interpret the value to parse.
-     * @returns {number} Returns the new integer value.
-     * @example
-     *
-     * _.parseInt('08');
-     * // => 8
-     */
-    var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
-      // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
-      return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
-    };
-
-    /**
-     * Creates a "_.pluck" style function, which returns the `key` value of a
-     * given object.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} key The name of the property to retrieve.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'fred',   'age': 40 },
-     *   { 'name': 'barney', 'age': 36 }
-     * ];
-     *
-     * var getName = _.property('name');
-     *
-     * _.map(characters, getName);
-     * // => ['barney', 'fred']
-     *
-     * _.sortBy(characters, getName);
-     * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred',   'age': 40 }]
-     */
-    function property(key) {
-      return function(object) {
-        return object[key];
-      };
-    }
-
-    /**
-     * Produces a random number between `min` and `max` (inclusive). If only one
-     * argument is provided a number between `0` and the given number will be
-     * returned. If `floating` is truey or either `min` or `max` are floats a
-     * floating-point number will be returned instead of an integer.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {number} [min=0] The minimum possible value.
-     * @param {number} [max=1] The maximum possible value.
-     * @param {boolean} [floating=false] Specify returning a floating-point number.
-     * @returns {number} Returns a random number.
-     * @example
-     *
-     * _.random(0, 5);
-     * // => an integer between 0 and 5
-     *
-     * _.random(5);
-     * // => also an integer between 0 and 5
-     *
-     * _.random(5, true);
-     * // => a floating-point number between 0 and 5
-     *
-     * _.random(1.2, 5.2);
-     * // => a floating-point number between 1.2 and 5.2
-     */
-    function random(min, max, floating) {
-      var noMin = min == null,
-          noMax = max == null;
-
-      if (floating == null) {
-        if (typeof min == 'boolean' && noMax) {
-          floating = min;
-          min = 1;
-        }
-        else if (!noMax && typeof max == 'boolean') {
-          floating = max;
-          noMax = true;
-        }
-      }
-      if (noMin && noMax) {
-        max = 1;
-      }
-      min = +min || 0;
-      if (noMax) {
-        max = min;
-        min = 0;
-      } else {
-        max = +max || 0;
-      }
-      if (floating || min % 1 || max % 1) {
-        var rand = nativeRandom();
-        return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
-      }
-      return baseRandom(min, max);
-    }
-
-    /**
-     * Resolves the value of property `key` on `object`. If `key` is a function
-     * it will be invoked with the `this` binding of `object` and its result returned,
-     * else the property value is returned. If `object` is falsey then `undefined`
-     * is returned.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {Object} object The object to inspect.
-     * @param {string} key The name of the property to resolve.
-     * @returns {*} Returns the resolved value.
-     * @example
-     *
-     * var object = {
-     *   'cheese': 'crumpets',
-     *   'stuff': function() {
-     *     return 'nonsense';
-     *   }
-     * };
-     *
-     * _.result(object, 'cheese');
-     * // => 'crumpets'
-     *
-     * _.result(object, 'stuff');
-     * // => 'nonsense'
-     */
-    function result(object, key) {
-      if (object) {
-        var value = object[key];
-        return isFunction(value) ? object[key]() : value;
-      }
-    }
-
-    /**
-     * A micro-templating method that handles arbitrary delimiters, preserves
-     * whitespace, and correctly escapes quotes within interpolated code.
-     *
-     * Note: In the development build, `_.template` utilizes sourceURLs for easier
-     * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-     *
-     * For more information on precompiling templates see:
-     * https://lodash.com/custom-builds
-     *
-     * For more information on Chrome extension sandboxes see:
-     * http://developer.chrome.com/stable/extensions/sandboxingEval.html
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} text The template text.
-     * @param {Object} data The data object used to populate the text.
-     * @param {Object} [options] The options object.
-     * @param {RegExp} [options.escape] The "escape" delimiter.
-     * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
-     * @param {Object} [options.imports] An object to import into the template as local variables.
-     * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
-     * @param {string} [sourceURL] The sourceURL of the template's compiled source.
-     * @param {string} [variable] The data object variable name.
-     * @returns {Function|string} Returns a compiled function when no `data` object
-     *  is given, else it returns the interpolated text.
-     * @example
-     *
-     * // using the "interpolate" delimiter to create a compiled template
-     * var compiled = _.template('hello <%= name %>');
-     * compiled({ 'name': 'fred' });
-     * // => 'hello fred'
-     *
-     * // using the "escape" delimiter to escape HTML in data property values
-     * _.template('<b><%- value %></b>', { 'value': '<script>' });
-     * // => '<b><script></b>'
-     *
-     * // using the "evaluate" delimiter to generate HTML
-     * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
-     * _.template(list, { 'people': ['fred', 'barney'] });
-     * // => '<li>fred</li><li>barney</li>'
-     *
-     * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
-     * _.template('hello ${ name }', { 'name': 'pebbles' });
-     * // => 'hello pebbles'
-     *
-     * // using the internal `print` function in "evaluate" delimiters
-     * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
-     * // => 'hello barney!'
-     *
-     * // using a custom template delimiters
-     * _.templateSettings = {
-     *   'interpolate': /{{([\s\S]+?)}}/g
-     * };
-     *
-     * _.template('hello {{ name }}!', { 'name': 'mustache' });
-     * // => 'hello mustache!'
-     *
-     * // using the `imports` option to import jQuery
-     * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
-     * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
-     * // => '<li>fred</li><li>barney</li>'
-     *
-     * // using the `sourceURL` option to specify a custom sourceURL for the template
-     * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
-     * compiled(data);
-     * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
-     *
-     * // using the `variable` option to ensure a with-statement isn't used in the compiled template
-     * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
-     * compiled.source;
-     * // => function(data) {
-     *   var __t, __p = '', __e = _.escape;
-     *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
-     *   return __p;
-     * }
-     *
-     * // using the `source` property to inline compiled templates for meaningful
-     * // line numbers in error messages and a stack trace
-     * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
-     *   var JST = {\
-     *     "main": ' + _.template(mainText).source + '\
-     *   };\
-     * ');
-     */
-    function template(text, data, options) {
-      // based on John Resig's `tmpl` implementation
-      // http://ejohn.org/blog/javascript-micro-templating/
-      // and Laura Doktorova's doT.js
-      // https://github.com/olado/doT
-      var settings = lodash.templateSettings;
-      text = String(text || '');
-
-      // avoid missing dependencies when `iteratorTemplate` is not defined
-      options = defaults({}, options, settings);
-
-      var imports = defaults({}, options.imports, settings.imports),
-          importsKeys = keys(imports),
-          importsValues = values(imports);
-
-      var isEvaluating,
-          index = 0,
-          interpolate = options.interpolate || reNoMatch,
-          source = "__p += '";
-
-      // compile the regexp to match each delimiter
-      var reDelimiters = RegExp(
-        (options.escape || reNoMatch).source + '|' +
-        interpolate.source + '|' +
-        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
-        (options.evaluate || reNoMatch).source + '|$'
-      , 'g');
-
-      text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
-        interpolateValue || (interpolateValue = esTemplateValue);
-
-        // escape characters that cannot be included in string literals
-        source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
-
-        // replace delimiters with snippets
-        if (escapeValue) {
-          source += "' +\n__e(" + escapeValue + ") +\n'";
-        }
-        if (evaluateValue) {
-          isEvaluating = true;
-          source += "';\n" + evaluateValue + ";\n__p += '";
-        }
-        if (interpolateValue) {
-          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
-        }
-        index = offset + match.length;
-
-        // the JS engine embedded in Adobe products requires returning the `match`
-        // string in order to produce the correct `offset` value
-        return match;
-      });
-
-      source += "';\n";
-
-      // if `variable` is not specified, wrap a with-statement around the generated
-      // code to add the data object to the top of the scope chain
-      var variable = options.variable,
-          hasVariable = variable;
-
-      if (!hasVariable) {
-        variable = 'obj';
-        source = 'with (' + variable + ') {\n' + source + '\n}\n';
-      }
-      // cleanup code by stripping empty strings
-      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
-        .replace(reEmptyStringMiddle, '$1')
-        .replace(reEmptyStringTrailing, '$1;');
-
-      // frame code as the function body
-      source = 'function(' + variable + ') {\n' +
-        (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
-        "var __t, __p = '', __e = _.escape" +
-        (isEvaluating
-          ? ', __j = Array.prototype.join;\n' +
-            "function print() { __p += __j.call(arguments, '') }\n"
-          : ';\n'
-        ) +
-        source +
-        'return __p\n}';
-
-      // Use a sourceURL for easier debugging.
-      // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-      var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
-
-      try {
-        var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
-      } catch(e) {
-        e.source = source;
-        throw e;
-      }
-      if (data) {
-        return result(data);
-      }
-      // provide the compiled function's source by its `toString` method, in
-      // supported environments, or the `source` property as a convenience for
-      // inlining compiled templates during the build process
-      result.source = source;
-      return result;
-    }
-
-    /**
-     * Executes the callback `n` times, returning an array of the results
-     * of each callback execution. The callback is bound to `thisArg` and invoked
-     * with one argument; (index).
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {number} n The number of times to execute the callback.
-     * @param {Function} callback The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns an array of the results of each `callback` execution.
-     * @example
-     *
-     * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
-     * // => [3, 6, 4]
-     *
-     * _.times(3, function(n) { mage.castSpell(n); });
-     * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
-     *
-     * _.times(3, function(n) { this.cast(n); }, mage);
-     * // => also calls `mage.castSpell(n)` three times
-     */
-    function times(n, callback, thisArg) {
-      n = (n = +n) > -1 ? n : 0;
-      var index = -1,
-          result = Array(n);
-
-      callback = baseCreateCallback(callback, thisArg, 1);
-      while (++index < n) {
-        result[index] = callback(index);
-      }
-      return result;
-    }
-
-    /**
-     * The inverse of `_.escape` this method converts the HTML entities
-     * `&`, `<`, `>`, `"`, and `'` in `string` to their
-     * corresponding characters.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} string The string to unescape.
-     * @returns {string} Returns the unescaped string.
-     * @example
-     *
-     * _.unescape('Fred, Barney & Pebbles');
-     * // => 'Fred, Barney & Pebbles'
-     */
-    function unescape(string) {
-      return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
-    }
-
-    /**
-     * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} [prefix] The value to prefix the ID with.
-     * @returns {string} Returns the unique ID.
-     * @example
-     *
-     * _.uniqueId('contact_');
-     * // => 'contact_104'
-     *
-     * _.uniqueId();
-     * // => '105'
-     */
-    function uniqueId(prefix) {
-      var id = ++idCounter;
-      return String(prefix == null ? '' : prefix) + id;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a `lodash` object that wraps the given value with explicit
-     * method chaining enabled.
-     *
-     * @static
-     * @memberOf _
-     * @category Chaining
-     * @param {*} value The value to wrap.
-     * @returns {Object} Returns the wrapper object.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36 },
-     *   { 'name': 'fred',    'age': 40 },
-     *   { 'name': 'pebbles', 'age': 1 }
-     * ];
-     *
-     * var youngest = _.chain(characters)
-     *     .sortBy('age')
-     *     .map(function(chr) { return chr.name + ' is ' + chr.age; })
-     *     .first()
-     *     .value();
-     * // => 'pebbles is 1'
-     */
-    function chain(value) {
-      value = new lodashWrapper(value);
-      value.__chain__ = true;
-      return value;
-    }
-
-    /**
-     * Invokes `interceptor` with the `value` as the first argument and then
-     * returns `value`. The purpose of this method is to "tap into" a method
-     * chain in order to perform operations on intermediate results within
-     * the chain.
-     *
-     * @static
-     * @memberOf _
-     * @category Chaining
-     * @param {*} value The value to provide to `interceptor`.
-     * @param {Function} interceptor The function to invoke.
-     * @returns {*} Returns `value`.
-     * @example
-     *
-     * _([1, 2, 3, 4])
-     *  .tap(function(array) { array.pop(); })
-     *  .reverse()
-     *  .value();
-     * // => [3, 2, 1]
-     */
-    function tap(value, interceptor) {
-      interceptor(value);
-      return value;
-    }
-
-    /**
-     * Enables explicit method chaining on the wrapper object.
-     *
-     * @name chain
-     * @memberOf _
-     * @category Chaining
-     * @returns {*} Returns the wrapper object.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // without explicit chaining
-     * _(characters).first();
-     * // => { 'name': 'barney', 'age': 36 }
-     *
-     * // with explicit chaining
-     * _(characters).chain()
-     *   .first()
-     *   .pick('age')
-     *   .value();
-     * // => { 'age': 36 }
-     */
-    function wrapperChain() {
-      this.__chain__ = true;
-      return this;
-    }
-
-    /**
-     * Produces the `toString` result of the wrapped value.
-     *
-     * @name toString
-     * @memberOf _
-     * @category Chaining
-     * @returns {string} Returns the string result.
-     * @example
-     *
-     * _([1, 2, 3]).toString();
-     * // => '1,2,3'
-     */
-    function wrapperToString() {
-      return String(this.__wrapped__);
-    }
-
-    /**
-     * Extracts the wrapped value.
-     *
-     * @name valueOf
-     * @memberOf _
-     * @alias value
-     * @category Chaining
-     * @returns {*} Returns the wrapped value.
-     * @example
-     *
-     * _([1, 2, 3]).valueOf();
-     * // => [1, 2, 3]
-     */
-    function wrapperValueOf() {
-      return this.__wrapped__;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions that return wrapped values when chaining
-    lodash.after = after;
-    lodash.assign = assign;
-    lodash.at = at;
-    lodash.bind = bind;
-    lodash.bindAll = bindAll;
-    lodash.bindKey = bindKey;
-    lodash.chain = chain;
-    lodash.compact = compact;
-    lodash.compose = compose;
-    lodash.constant = constant;
-    lodash.countBy = countBy;
-    lodash.create = create;
-    lodash.createCallback = createCallback;
-    lodash.curry = curry;
-    lodash.debounce = debounce;
-    lodash.defaults = defaults;
-    lodash.defer = defer;
-    lodash.delay = delay;
-    lodash.difference = difference;
-    lodash.filter = filter;
-    lodash.flatten = flatten;
-    lodash.forEach = forEach;
-    lodash.forEachRight = forEachRight;
-    lodash.forIn = forIn;
-    lodash.forInRight = forInRight;
-    lodash.forOwn = forOwn;
-    lodash.forOwnRight = forOwnRight;
-    lodash.functions = functions;
-    lodash.groupBy = groupBy;
-    lodash.indexBy = indexBy;
-    lodash.initial = initial;
-    lodash.intersection = intersection;
-    lodash.invert = invert;
-    lodash.invoke = invoke;
-    lodash.keys = keys;
-    lodash.map = map;
-    lodash.mapValues = mapValues;
-    lodash.max = max;
-    lodash.memoize = memoize;
-    lodash.merge = merge;
-    lodash.min = min;
-    lodash.omit = omit;
-    lodash.once = once;
-    lodash.pairs = pairs;
-    lodash.partial = partial;
-    lodash.partialRight = partialRight;
-    lodash.pick = pick;
-    lodash.pluck = pluck;
-    lodash.property = property;
-    lodash.pull = pull;
-    lodash.range = range;
-    lodash.reject = reject;
-    lodash.remove = remove;
-    lodash.rest = rest;
-    lodash.shuffle = shuffle;
-    lodash.sortBy = sortBy;
-    lodash.tap = tap;
-    lodash.throttle = throttle;
-    lodash.times = times;
-    lodash.toArray = toArray;
-    lodash.transform = transform;
-    lodash.union = union;
-    lodash.uniq = uniq;
-    lodash.values = values;
-    lodash.where = where;
-    lodash.without = without;
-    lodash.wrap = wrap;
-    lodash.xor = xor;
-    lodash.zip = zip;
-    lodash.zipObject = zipObject;
-
-    // add aliases
-    lodash.collect = map;
-    lodash.drop = rest;
-    lodash.each = forEach;
-    lodash.eachRight = forEachRight;
-    lodash.extend = assign;
-    lodash.methods = functions;
-    lodash.object = zipObject;
-    lodash.select = filter;
-    lodash.tail = rest;
-    lodash.unique = uniq;
-    lodash.unzip = zip;
-
-    // add functions to `lodash.prototype`
-    mixin(lodash);
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions that return unwrapped values when chaining
-    lodash.clone = clone;
-    lodash.cloneDeep = cloneDeep;
-    lodash.contains = contains;
-    lodash.escape = escape;
-    lodash.every = every;
-    lodash.find = find;
-    lodash.findIndex = findIndex;
-    lodash.findKey = findKey;
-    lodash.findLast = findLast;
-    lodash.findLastIndex = findLastIndex;
-    lodash.findLastKey = findLastKey;
-    lodash.has = has;
-    lodash.identity = identity;
-    lodash.indexOf = indexOf;
-    lodash.isArguments = isArguments;
-    lodash.isArray = isArray;
-    lodash.isBoolean = isBoolean;
-    lodash.isDate = isDate;
-    lodash.isElement = isElement;
-    lodash.isEmpty = isEmpty;
-    lodash.isEqual = isEqual;
-    lodash.isFinite = isFinite;
-    lodash.isFunction = isFunction;
-    lodash.isNaN = isNaN;
-    lodash.isNull = isNull;
-    lodash.isNumber = isNumber;
-    lodash.isObject = isObject;
-    lodash.isPlainObject = isPlainObject;
-    lodash.isRegExp = isRegExp;
-    lodash.isString = isString;
-    lodash.isUndefined = isUndefined;
-    lodash.lastIndexOf = lastIndexOf;
-    lodash.mixin = mixin;
-    lodash.noConflict = noConflict;
-    lodash.noop = noop;
-    lodash.now = now;
-    lodash.parseInt = parseInt;
-    lodash.random = random;
-    lodash.reduce = reduce;
-    lodash.reduceRight = reduceRight;
-    lodash.result = result;
-    lodash.runInContext = runInContext;
-    lodash.size = size;
-    lodash.some = some;
-    lodash.sortedIndex = sortedIndex;
-    lodash.template = template;
-    lodash.unescape = unescape;
-    lodash.uniqueId = uniqueId;
-
-    // add aliases
-    lodash.all = every;
-    lodash.any = some;
-    lodash.detect = find;
-    lodash.findWhere = find;
-    lodash.foldl = reduce;
-    lodash.foldr = reduceRight;
-    lodash.include = contains;
-    lodash.inject = reduce;
-
-    mixin(function() {
-      var source = {}
-      forOwn(lodash, function(func, methodName) {
-        if (!lodash.prototype[methodName]) {
-          source[methodName] = func;
-        }
-      });
-      return source;
-    }(), false);
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions capable of returning wrapped and unwrapped values when chaining
-    lodash.first = first;
-    lodash.last = last;
-    lodash.sample = sample;
-
-    // add aliases
-    lodash.take = first;
-    lodash.head = first;
-
-    forOwn(lodash, function(func, methodName) {
-      var callbackable = methodName !== 'sample';
-      if (!lodash.prototype[methodName]) {
-        lodash.prototype[methodName]= function(n, guard) {
-          var chainAll = this.__chain__,
-              result = func(this.__wrapped__, n, guard);
-
-          return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
-            ? result
-            : new lodashWrapper(result, chainAll);
-        };
-      }
-    });
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * The semantic version number.
-     *
-     * @static
-     * @memberOf _
-     * @type string
-     */
-    lodash.VERSION = '2.4.2';
-
-    // add "Chaining" functions to the wrapper
-    lodash.prototype.chain = wrapperChain;
-    lodash.prototype.toString = wrapperToString;
-    lodash.prototype.value = wrapperValueOf;
-    lodash.prototype.valueOf = wrapperValueOf;
-
-    // add `Array` functions that return unwrapped values
-    forEach(['join', 'pop', 'shift'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        var chainAll = this.__chain__,
-            result = func.apply(this.__wrapped__, arguments);
-
-        return chainAll
-          ? new lodashWrapper(result, chainAll)
-          : result;
-      };
-    });
-
-    // add `Array` functions that return the existing wrapped value
-    forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        func.apply(this.__wrapped__, arguments);
-        return this;
-      };
-    });
-
-    // add `Array` functions that return new wrapped values
-    forEach(['concat', 'slice', 'splice'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
-      };
-    });
-
-    return lodash;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  // expose Lo-Dash
-  var _ = runInContext();
-
-  // some AMD build optimizers like r.js check for condition patterns like the following:
-  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
-    // Expose Lo-Dash to the global object even when an AMD loader is present in
-    // case Lo-Dash is loaded with a RequireJS shim config.
-    // See http://requirejs.org/docs/api.html#config-shim
-    root._ = _;
-
-    // define as an anonymous module so, through path mapping, it can be
-    // referenced as the "underscore" module
-    define(function() {
-      return _;
-    });
-  }
-  // check for `exports` after `define` in case a build optimizer adds an `exports` object
-  else if (freeExports && freeModule) {
-    // in Node.js or RingoJS
-    if (moduleExports) {
-      (freeModule.exports = _)._ = _;
-    }
-    // in Narwhal or Rhino -require
-    else {
-      freeExports._ = _;
-    }
-  }
-  else {
-    // in a browser or Rhino
-    root._ = _;
-  }
-}.call(this));
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-
-},{}],60:[function(require,module,exports){
-/**
- * Copyright (c) 2014, Chris Pettitt
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors
- * may be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-var lib = require("./lib");
-
-module.exports = {
-  Graph: lib.Graph,
-  json: require("./lib/json"),
-  alg: require("./lib/alg"),
-  version: lib.version
-};
-
-},{"./lib":76,"./lib/alg":67,"./lib/json":77}],61:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = components;
-
-function components(g) {
-  var visited = {},
-      cmpts = [],
-      cmpt;
-
-  function dfs(v) {
-    if (_.has(visited, v)) return;
-    visited[v] = true;
-    cmpt.push(v);
-    _.each(g.successors(v), dfs);
-    _.each(g.predecessors(v), dfs);
-  }
-
-  _.each(g.nodes(), function(v) {
-    cmpt = [];
-    dfs(v);
-    if (cmpt.length) {
-      cmpts.push(cmpt);
-    }
-  });
-
-  return cmpts;
-}
-
-},{"../lodash":78}],62:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = dfs;
-
-/*
- * A helper that preforms a pre- or post-order traversal on the input graph
- * and returns the nodes in the order they were visited. This algorithm treats
- * the input as undirected.
- *
- * Order must be one of "pre" or "post".
- */
-function dfs(g, vs, order) {
-  if (!_.isArray(vs)) {
-    vs = [vs];
-  }
-
-  var acc = [],
-      visited = {};
-  _.each(vs, function(v) {
-    if (!g.hasNode(v)) {
-      throw new Error("Graph does not have node: " + v);
-    }
-
-    doDfs(g, v, order === "post", visited, acc);
-  });
-  return acc;
-}
-
-function doDfs(g, v, postorder, visited, acc) {
-  if (!_.has(visited, v)) {
-    visited[v] = true;
-
-    if (!postorder) { acc.push(v); }
-    _.each(g.neighbors(v), function(w) {
-      doDfs(g, w, postorder, visited, acc);
-    });
-    if (postorder) { acc.push(v); }
-  }
-}
-
-},{"../lodash":78}],63:[function(require,module,exports){
-var dijkstra = require("./dijkstra"),
-    _ = require("../lodash");
-
-module.exports = dijkstraAll;
-
-function dijkstraAll(g, weightFunc, edgeFunc) {
-  return _.transform(g.nodes(), function(acc, v) {
-    acc[v] = dijkstra(g, v, weightFunc, edgeFunc);
-  }, {});
-}
-
-},{"../lodash":78,"./dijkstra":64}],64:[function(require,module,exports){
-var _ = require("../lodash"),
-    PriorityQueue = require("../data/priority-queue");
-
-module.exports = dijkstra;
-
-var DEFAULT_WEIGHT_FUNC = _.constant(1);
-
-function dijkstra(g, source, weightFn, edgeFn) {
-  return runDijkstra(g, String(source),
-                     weightFn || DEFAULT_WEIGHT_FUNC,
-                     edgeFn || function(v) { return g.outEdges(v); });
-}
-
-function runDijkstra(g, source, weightFn, edgeFn) {
-  var results = {},
-      pq = new PriorityQueue(),
-      v, vEntry;
-
-  var updateNeighbors = function(edge) {
-    var w = edge.v !== v ? edge.v : edge.w,
-        wEntry = results[w],
-        weight = weightFn(edge),
-        distance = vEntry.distance + weight;
-
-    if (weight < 0) {
-      throw new Error("dijkstra does not allow negative edge weights. " +
-                      "Bad edge: " + edge + " Weight: " + weight);
-    }
-
-    if (distance < wEntry.distance) {
-      wEntry.distance = distance;
-      wEntry.predecessor = v;
-      pq.decrease(w, distance);
-    }
-  };
-
-  g.nodes().forEach(function(v) {
-    var distance = v === source ? 0 : Number.POSITIVE_INFINITY;
-    results[v] = { distance: distance };
-    pq.add(v, distance);
-  });
-
-  while (pq.size() > 0) {
-    v = pq.removeMin();
-    vEntry = results[v];
-    if (vEntry.distance === Number.POSITIVE_INFINITY) {
-      break;
-    }
-
-    edgeFn(v).forEach(updateNeighbors);
-  }
-
-  return results;
-}
-
-},{"../data/priority-queue":74,"../lodash":78}],65:[function(require,module,exports){
-var _ = require("../lodash"),
-    tarjan = require("./tarjan");
-
-module.exports = findCycles;
-
-function findCycles(g) {
-  return _.filter(tarjan(g), function(cmpt) { return cmpt.length > 1; });
-}
-
-},{"../lodash":78,"./tarjan":72}],66:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = floydWarshall;
-
-var DEFAULT_WEIGHT_FUNC = _.constant(1);
-
-function floydWarshall(g, weightFn, edgeFn) {
-  return runFloydWarshall(g,
-                          weightFn || DEFAULT_WEIGHT_FUNC,
-                          edgeFn || function(v) { return g.outEdges(v); });
-}
-
-function runFloydWarshall(g, weightFn, edgeFn) {
-  var results = {},
-      nodes = g.nodes();
-
-  nodes.forEach(function(v) {
-    results[v] = {};
-    results[v][v] = { distance: 0 };
-    nodes.forEach(function(w) {
-      if (v !== w) {
-        results[v][w] = { distance: Number.POSITIVE_INFINITY };
-      }
-    });
-    edgeFn(v).forEach(function(edge) {
-      var w = edge.v === v ? edge.w : edge.v,
-          d = weightFn(edge);
-      results[v][w] = { distance: d, predecessor: v };
-    });
-  });
-
-  nodes.forEach(function(k) {
-    var rowK = results[k];
-    nodes.forEach(function(i) {
-      var rowI = results[i];
-      nodes.forEach(function(j) {
-        var ik = rowI[k];
-        var kj = rowK[j];
-        var ij = rowI[j];
-        var altDistance = ik.distance + kj.distance;
-        if (altDistance < ij.distance) {
-          ij.distance = altDistance;
-          ij.predecessor = kj.predecessor;
-        }
-      });
-    });
-  });
-
-  return results;
-}
-
-},{"../lodash":78}],67:[function(require,module,exports){
-module.exports = {
-  components: require("./components"),
-  dijkstra: require("./dijkstra"),
-  dijkstraAll: require("./dijkstra-all"),
-  findCycles: require("./find-cycles"),
-  floydWarshall: require("./floyd-warshall"),
-  isAcyclic: require("./is-acyclic"),
-  postorder: require("./postorder"),
-  preorder: require("./preorder"),
-  prim: require("./prim"),
-  tarjan: require("./tarjan"),
-  topsort: require("./topsort")
-};
-
-},{"./components":61,"./dijkstra":64,"./dijkstra-all":63,"./find-cycles":65,"./floyd-warshall":66,"./is-acyclic":68,"./postorder":69,"./preorder":70,"./prim":71,"./tarjan":72,"./topsort":73}],68:[function(require,module,exports){
-var topsort = require("./topsort");
-
-module.exports = isAcyclic;
-
-function isAcyclic(g) {
-  try {
-    topsort(g);
-  } catch (e) {
-    if (e instanceof topsort.CycleException) {
-      return false;
-    }
-    throw e;
-  }
-  return true;
-}
-
-},{"./topsort":73}],69:[function(require,module,exports){
-var dfs = require("./dfs");
-
-module.exports = postorder;
-
-function postorder(g, vs) {
-  return dfs(g, vs, "post");
-}
-
-},{"./dfs":62}],70:[function(require,module,exports){
-var dfs = require("./dfs");
-
-module.exports = preorder;
-
-function preorder(g, vs) {
-  return dfs(g, vs, "pre");
-}
-
-},{"./dfs":62}],71:[function(require,module,exports){
-var _ = require("../lodash"),
-    Graph = require("../graph"),
-    PriorityQueue = require("../data/priority-queue");
-
-module.exports = prim;
-
-function prim(g, weightFunc) {
-  var result = new Graph(),
-      parents = {},
-      pq = new PriorityQueue(),
-      v;
-
-  function updateNeighbors(edge) {
-    var w = edge.v === v ? edge.w : edge.v,
-        pri = pq.priority(w);
-    if (pri !== undefined) {
-      var edgeWeight = weightFunc(edge);
-      if (edgeWeight < pri) {
-        parents[w] = v;
-        pq.decrease(w, edgeWeight);
-      }
-    }
-  }
-
-  if (g.nodeCount() === 0) {
-    return result;
-  }
-
-  _.each(g.nodes(), function(v) {
-    pq.add(v, Number.POSITIVE_INFINITY);
-    result.setNode(v);
-  });
-
-  // Start from an arbitrary node
-  pq.decrease(g.nodes()[0], 0);
-
-  var init = false;
-  while (pq.size() > 0) {
-    v = pq.removeMin();
-    if (_.has(parents, v)) {
-      result.setEdge(v, parents[v]);
-    } else if (init) {
-      throw new Error("Input graph is not connected: " + g);
-    } else {
-      init = true;
-    }
-
-    g.nodeEdges(v).forEach(updateNeighbors);
-  }
-
-  return result;
-}
-
-},{"../data/priority-queue":74,"../graph":75,"../lodash":78}],72:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = tarjan;
-
-function tarjan(g) {
-  var index = 0,
-      stack = [],
-      visited = {}, // node id -> { onStack, lowlink, index }
-      results = [];
-
-  function dfs(v) {
-    var entry = visited[v] = {
-      onStack: true,
-      lowlink: index,
-      index: index++
-    };
-    stack.push(v);
-
-    g.successors(v).forEach(function(w) {
-      if (!_.has(visited, w)) {
-        dfs(w);
-        entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
-      } else if (visited[w].onStack) {
-        entry.lowlink = Math.min(entry.lowlink, visited[w].index);
-      }
-    });
-
-    if (entry.lowlink === entry.index) {
-      var cmpt = [],
-          w;
-      do {
-        w = stack.pop();
-        visited[w].onStack = false;
-        cmpt.push(w);
-      } while (v !== w);
-      results.push(cmpt);
-    }
-  }
-
-  g.nodes().forEach(function(v) {
-    if (!_.has(visited, v)) {
-      dfs(v);
-    }
-  });
-
-  return results;
-}
-
-},{"../lodash":78}],73:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = topsort;
-topsort.CycleException = CycleException;
-
-function topsort(g) {
-  var visited = {},
-      stack = {},
-      results = [];
-
-  function visit(node) {
-    if (_.has(stack, node)) {
-      throw new CycleException();
-    }
-
-    if (!_.has(visited, node)) {
-      stack[node] = true;
-      visited[node] = true;
-      _.each(g.predecessors(node), visit);
-      delete stack[node];
-      results.push(node);
-    }
-  }
-
-  _.each(g.sinks(), visit);
-
-  if (_.size(visited) !== g.nodeCount()) {
-    throw new CycleException();
-  }
-
-  return results;
-}
-
-function CycleException() {}
-
-},{"../lodash":78}],74:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = PriorityQueue;
-
-/**
- * A min-priority queue data structure. This algorithm is derived from Cormen,
- * et al., "Introduction to Algorithms". The basic idea of a min-priority
- * queue is that you can efficiently (in O(1) time) get the smallest key in
- * the queue. Adding and removing elements takes O(log n) time. A key can
- * have its priority decreased in O(log n) time.
- */
-function PriorityQueue() {
-  this._arr = [];
-  this._keyIndices = {};
-}
-
-/**
- * Returns the number of elements in the queue. Takes `O(1)` time.
- */
-PriorityQueue.prototype.size = function() {
-  return this._arr.length;
-};
-
-/**
- * Returns the keys that are in the queue. Takes `O(n)` time.
- */
-PriorityQueue.prototype.keys = function() {
-  return this._arr.map(function(x) { return x.key; });
-};
-
-/**
- * Returns `true` if **key** is in the queue and `false` if not.
- */
-PriorityQueue.prototype.has = function(key) {
-  return _.has(this._keyIndices, key);
-};
-
-/**
- * Returns the priority for **key**. If **key** is not present in the queue
- * then this function returns `undefined`. Takes `O(1)` time.
- *
- * @param {Object} key
- */
-PriorityQueue.prototype.priority = function(key) {
-  var index = this._keyIndices[key];
-  if (index !== undefined) {
-    return this._arr[index].priority;
-  }
-};
-
-/**
- * Returns the key for the minimum element in this queue. If the queue is
- * empty this function throws an Error. Takes `O(1)` time.
- */
-PriorityQueue.prototype.min = function() {
-  if (this.size() === 0) {
-    throw new Error("Queue underflow");
-  }
-  return this._arr[0].key;
-};
-
-/**
- * Inserts a new key into the priority queue. If the key already exists in
- * the queue this function returns `false`; otherwise it will return `true`.
- * Takes `O(n)` time.
- *
- * @param {Object} key the key to add
- * @param {Number} priority the initial priority for the key
- */
-PriorityQueue.prototype.add = function(key, priority) {
-  var keyIndices = this._keyIndices;
-  key = String(key);
-  if (!_.has(keyIndices, key)) {
-    var arr = this._arr;
-    var index = arr.length;
-    keyIndices[key] = index;
-    arr.push({key: key, priority: priority});
-    this._decrease(index);
-    return true;
-  }
-  return false;
-};
-
-/**
- * Removes and returns the smallest key in the queue. Takes `O(log n)` time.
- */
-PriorityQueue.prototype.removeMin = function() {
-  this._swap(0, this._arr.length - 1);
-  var min = this._arr.pop();
-  delete this._keyIndices[min.key];
-  this._heapify(0);
-  return min.key;
-};
-
-/**
- * Decreases the priority for **key** to **priority**. If the new priority is
- * greater than the previous priority, this function will throw an Error.
- *
- * @param {Object} key the key for which to raise priority
- * @param {Number} priority the new priority for the key
- */
-PriorityQueue.prototype.decrease = function(key, priority) {
-  var index = this._keyIndices[key];
-  if (priority > this._arr[index].priority) {
-    throw new Error("New priority is greater than current priority. " +
-        "Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority);
-  }
-  this._arr[index].priority = priority;
-  this._decrease(index);
-};
-
-PriorityQueue.prototype._heapify = function(i) {
-  var arr = this._arr;
-  var l = 2 * i,
-      r = l + 1,
-      largest = i;
-  if (l < arr.length) {
-    largest = arr[l].priority < arr[largest].priority ? l : largest;
-    if (r < arr.length) {
-      largest = arr[r].priority < arr[largest].priority ? r : largest;
-    }
-    if (largest !== i) {
-      this._swap(i, largest);
-      this._heapify(largest);
-    }
-  }
-};
-
-PriorityQueue.prototype._decrease = function(index) {
-  var arr = this._arr;
-  var priority = arr[index].priority;
-  var parent;
-  while (index !== 0) {
-    parent = index >> 1;
-    if (arr[parent].priority < priority) {
-      break;
-    }
-    this._swap(index, parent);
-    index = parent;
-  }
-};
-
-PriorityQueue.prototype._swap = function(i, j) {
-  var arr = this._arr;
-  var keyIndices = this._keyIndices;
-  var origArrI = arr[i];
-  var origArrJ = arr[j];
-  arr[i] = origArrJ;
-  arr[j] = origArrI;
-  keyIndices[origArrJ.key] = i;
-  keyIndices[origArrI.key] = j;
-};
-
-},{"../lodash":78}],75:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash");
-
-module.exports = Graph;
-
-var DEFAULT_EDGE_NAME = "\x00",
-    GRAPH_NODE = "\x00",
-    EDGE_KEY_DELIM = "\x01";
-
-// Implementation notes:
-//
-//  * Node id query functions should return string ids for the nodes
-//  * Edge id query functions should return an "edgeObj", edge object, that is
-//    composed of enough information to uniquely identify an edge: {v, w, name}.
-//  * Internally we use an "edgeId", a stringified form of the edgeObj, to
-//    reference edges. This is because we need a performant way to look these
-//    edges up and, object properties, which have string keys, are the closest
-//    we're going to get to a performant hashtable in JavaScript.
-
-function Graph(opts) {
-  this._isDirected = _.has(opts, "directed") ? opts.directed : true;
-  this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false;
-  this._isCompound = _.has(opts, "compound") ? opts.compound : false;
-
-  // Label for the graph itself
-  this._label = undefined;
-
-  // Defaults to be set when creating a new node
-  this._defaultNodeLabelFn = _.constant(undefined);
-
-  // Defaults to be set when creating a new edge
-  this._defaultEdgeLabelFn = _.constant(undefined);
-
-  // v -> label
-  this._nodes = {};
-
-  if (this._isCompound) {
-    // v -> parent
-    this._parent = {};
-
-    // v -> children
-    this._children = {};
-    this._children[GRAPH_NODE] = {};
-  }
-
-  // v -> edgeObj
-  this._in = {};
-
-  // u -> v -> Number
-  this._preds = {};
-
-  // v -> edgeObj
-  this._out = {};
-
-  // v -> w -> Number
-  this._sucs = {};
-
-  // e -> edgeObj
-  this._edgeObjs = {};
-
-  // e -> label
-  this._edgeLabels = {};
-}
-
-/* Number of nodes in the graph. Should only be changed by the implementation. */
-Graph.prototype._nodeCount = 0;
-
-/* Number of edges in the graph. Should only be changed by the implementation. */
-Graph.prototype._edgeCount = 0;
-
-
-/* === Graph functions ========= */
-
-Graph.prototype.isDirected = function() {
-  return this._isDirected;
-};
-
-Graph.prototype.isMultigraph = function() {
-  return this._isMultigraph;
-};
-
-Graph.prototype.isCompound = function() {
-  return this._isCompound;
-};
-
-Graph.prototype.setGraph = function(label) {
-  this._label = label;
-  return this;
-};
-
-Graph.prototype.graph = function() {
-  return this._label;
-};
-
-
-/* === Node functions ========== */
-
-Graph.prototype.setDefaultNodeLabel = function(newDefault) {
-  if (!_.isFunction(newDefault)) {
-    newDefault = _.constant(newDefault);
-  }
-  this._defaultNodeLabelFn = newDefault;
-  return this;
-};
-
-Graph.prototype.nodeCount = function() {
-  return this._nodeCount;
-};
-
-Graph.prototype.nodes = function() {
-  return _.keys(this._nodes);
-};
-
-Graph.prototype.sources = function() {
-  return _.filter(this.nodes(), function(v) {
-    return _.isEmpty(this._in[v]);
-  }, this);
-};
-
-Graph.prototype.sinks = function() {
-  return _.filter(this.nodes(), function(v) {
-    return _.isEmpty(this._out[v]);
-  }, this);
-};
-
-Graph.prototype.setNodes = function(vs, value) {
-  var args = arguments;
-  _.each(vs, function(v) {
-    if (args.length > 1) {
-      this.setNode(v, value);
-    } else {
-      this.setNode(v);
-    }
-  }, this);
-  return this;
-};
-
-Graph.prototype.setNode = function(v, value) {
-  if (_.has(this._nodes, v)) {
-    if (arguments.length > 1) {
-      this._nodes[v] = value;
-    }
-    return this;
-  }
-
-  this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
-  if (this._isCompound) {
-    this._parent[v] = GRAPH_NODE;
-    this._children[v] = {};
-    this._children[GRAPH_NODE][v] = true;
-  }
-  this._in[v] = {};
-  this._preds[v] = {};
-  this._out[v] = {};
-  this._sucs[v] = {};
-  ++this._nodeCount;
-  return this;
-};
-
-Graph.prototype.node = function(v) {
-  return this._nodes[v];
-};
-
-Graph.prototype.hasNode = function(v) {
-  return _.has(this._nodes, v);
-};
-
-Graph.prototype.removeNode =  function(v) {
-  var self = this;
-  if (_.has(this._nodes, v)) {
-    var removeEdge = function(e) { self.removeEdge(self._edgeObjs[e]); };
-    delete this._nodes[v];
-    if (this._isCompound) {
-      this._removeFromParentsChildList(v);
-      delete this._parent[v];
-      _.each(this.children(v), function(child) {
-        this.setParent(child);
-      }, this);
-      delete this._children[v];
-    }
-    _.each(_.keys(this._in[v]), removeEdge);
-    delete this._in[v];
-    delete this._preds[v];
-    _.each(_.keys(this._out[v]), removeEdge);
-    delete this._out[v];
-    delete this._sucs[v];
-    --this._nodeCount;
-  }
-  return this;
-};
-
-Graph.prototype.setParent = function(v, parent) {
-  if (!this._isCompound) {
-    throw new Error("Cannot set parent in a non-compound graph");
-  }
-
-  if (_.isUndefined(parent)) {
-    parent = GRAPH_NODE;
-  } else {
-    // Coerce parent to string
-    parent += "";
-    for (var ancestor = parent;
-         !_.isUndefined(ancestor);
-         ancestor = this.parent(ancestor)) {
-      if (ancestor === v) {
-        throw new Error("Setting " + parent+ " as parent of " + v +
-                        " would create create a cycle");
-      }
-    }
-
-    this.setNode(parent);
-  }
-
-  this.setNode(v);
-  this._removeFromParentsChildList(v);
-  this._parent[v] = parent;
-  this._children[parent][v] = true;
-  return this;
-};
-
-Graph.prototype._removeFromParentsChildList = function(v) {
-  delete this._children[this._parent[v]][v];
-};
-
-Graph.prototype.parent = function(v) {
-  if (this._isCompound) {
-    var parent = this._parent[v];
-    if (parent !== GRAPH_NODE) {
-      return parent;
-    }
-  }
-};
-
-Graph.prototype.children = function(v) {
-  if (_.isUndefined(v)) {
-    v = GRAPH_NODE;
-  }
-
-  if (this._isCompound) {
-    var children = this._children[v];
-    if (children) {
-      return _.keys(children);
-    }
-  } else if (v === GRAPH_NODE) {
-    return this.nodes();
-  } else if (this.hasNode(v)) {
-    return [];
-  }
-};
-
-Graph.prototype.predecessors = function(v) {
-  var predsV = this._preds[v];
-  if (predsV) {
-    return _.keys(predsV);
-  }
-};
-
-Graph.prototype.successors = function(v) {
-  var sucsV = this._sucs[v];
-  if (sucsV) {
-    return _.keys(sucsV);
-  }
-};
-
-Graph.prototype.neighbors = function(v) {
-  var preds = this.predecessors(v);
-  if (preds) {
-    return _.union(preds, this.successors(v));
-  }
-};
-
-/* === Edge functions ========== */
-
-Graph.prototype.setDefaultEdgeLabel = function(newDefault) {
-  if (!_.isFunction(newDefault)) {
-    newDefault = _.constant(newDefault);
-  }
-  this._defaultEdgeLabelFn = newDefault;
-  return this;
-};
-
-Graph.prototype.edgeCount = function() {
-  return this._edgeCount;
-};
-
-Graph.prototype.edges = function() {
-  return _.values(this._edgeObjs);
-};
-
-Graph.prototype.setPath = function(vs, value) {
-  var self = this,
-      args = arguments;
-  _.reduce(vs, function(v, w) {
-    if (args.length > 1) {
-      self.setEdge(v, w, value);
-    } else {
-      self.setEdge(v, w);
-    }
-    return w;
-  });
-  return this;
-};
-
-/*
- * setEdge(v, w, [value, [name]])
- * setEdge({ v, w, [name] }, [value])
- */
-Graph.prototype.setEdge = function() {
-  var v, w, name, value,
-      valueSpecified = false;
-
-  if (_.isPlainObject(arguments[0])) {
-    v = arguments[0].v;
-    w = arguments[0].w;
-    name = arguments[0].name;
-    if (arguments.length === 2) {
-      value = arguments[1];
-      valueSpecified = true;
-    }
-  } else {
-    v = arguments[0];
-    w = arguments[1];
-    name = arguments[3];
-    if (arguments.length > 2) {
-      value = arguments[2];
-      valueSpecified = true;
-    }
-  }
-
-  v = "" + v;
-  w = "" + w;
-  if (!_.isUndefined(name)) {
-    name = "" + name;
-  }
-
-  var e = edgeArgsToId(this._isDirected, v, w, name);
-  if (_.has(this._edgeLabels, e)) {
-    if (valueSpecified) {
-      this._edgeLabels[e] = value;
-    }
-    return this;
-  }
-
-  if (!_.isUndefined(name) && !this._isMultigraph) {
-    throw new Error("Cannot set a named edge when isMultigraph = false");
-  }
-
-  // It didn't exist, so we need to create it.
-  // First ensure the nodes exist.
-  this.setNode(v);
-  this.setNode(w);
-
-  this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name);
-
-  var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
-  // Ensure we add undirected edges in a consistent way.
-  v = edgeObj.v;
-  w = edgeObj.w;
-
-  Object.freeze(edgeObj);
-  this._edgeObjs[e] = edgeObj;
-  incrementOrInitEntry(this._preds[w], v);
-  incrementOrInitEntry(this._sucs[v], w);
-  this._in[w][e] = edgeObj;
-  this._out[v][e] = edgeObj;
-  this._edgeCount++;
-  return this;
-};
-
-Graph.prototype.edge = function(v, w, name) {
-  var e = (arguments.length === 1
-            ? edgeObjToId(this._isDirected, arguments[0])
-            : edgeArgsToId(this._isDirected, v, w, name));
-  return this._edgeLabels[e];
-};
-
-Graph.prototype.hasEdge = function(v, w, name) {
-  var e = (arguments.length === 1
-            ? edgeObjToId(this._isDirected, arguments[0])
-            : edgeArgsToId(this._isDirected, v, w, name));
-  return _.has(this._edgeLabels, e);
-};
-
-Graph.prototype.removeEdge = function(v, w, name) {
-  var e = (arguments.length === 1
-            ? edgeObjToId(this._isDirected, arguments[0])
-            : edgeArgsToId(this._isDirected, v, w, name)),
-      edge = this._edgeObjs[e];
-  if (edge) {
-    v = edge.v;
-    w = edge.w;
-    delete this._edgeLabels[e];
-    delete this._edgeObjs[e];
-    decrementOrRemoveEntry(this._preds[w], v);
-    decrementOrRemoveEntry(this._sucs[v], w);
-    delete this._in[w][e];
-    delete this._out[v][e];
-    this._edgeCount--;
-  }
-  return this;
-};
-
-Graph.prototype.inEdges = function(v, u) {
-  var inV = this._in[v];
-  if (inV) {
-    var edges = _.values(inV);
-    if (!u) {
-      return edges;
-    }
-    return _.filter(edges, function(edge) { return edge.v === u; });
-  }
-};
-
-Graph.prototype.outEdges = function(v, w) {
-  var outV = this._out[v];
-  if (outV) {
-    var edges = _.values(outV);
-    if (!w) {
-      return edges;
-    }
-    return _.filter(edges, function(edge) { return edge.w === w; });
-  }
-};
-
-Graph.prototype.nodeEdges = function(v, w) {
-  var inEdges = this.inEdges(v, w);
-  if (inEdges) {
-    return inEdges.concat(this.outEdges(v, w));
-  }
-};
-
-function incrementOrInitEntry(map, k) {
-  if (_.has(map, k)) {
-    map[k]++;
-  } else {
-    map[k] = 1;
-  }
-}
-
-function decrementOrRemoveEntry(map, k) {
-  if (!--map[k]) { delete map[k]; }
-}
-
-function edgeArgsToId(isDirected, v, w, name) {
-  if (!isDirected && v > w) {
-    var tmp = v;
-    v = w;
-    w = tmp;
-  }
-  return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM +
-             (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name);
-}
-
-function edgeArgsToObj(isDirected, v, w, name) {
-  if (!isDirected && v > w) {
-    var tmp = v;
-    v = w;
-    w = tmp;
-  }
-  var edgeObj =  { v: v, w: w };
-  if (name) {
-    edgeObj.name = name;
-  }
-  return edgeObj;
-}
-
-function edgeObjToId(isDirected, edgeObj) {
-  return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
-}
-
-},{"./lodash":78}],76:[function(require,module,exports){
-// Includes only the "core" of graphlib
-module.exports = {
-  Graph: require("./graph"),
-  version: require("./version")
-};
-
-},{"./graph":75,"./version":79}],77:[function(require,module,exports){
-var _ = require("./lodash"),
-    Graph = require("./graph");
-
-module.exports = {
-  write: write,
-  read: read
-};
-
-function write(g) {
-  var json = {
-    options: {
-      directed: g.isDirected(),
-      multigraph: g.isMultigraph(),
-      compound: g.isCompound()
-    },
-    nodes: writeNodes(g),
-    edges: writeEdges(g)
-  };
-  if (!_.isUndefined(g.graph())) {
-    json.value = _.clone(g.graph());
-  }
-  return json;
-}
-
-function writeNodes(g) {
-  return _.map(g.nodes(), function(v) {
-    var nodeValue = g.node(v),
-        parent = g.parent(v),
-        node = { v: v };
-    if (!_.isUndefined(nodeValue)) {
-      node.value = nodeValue;
-    }
-    if (!_.isUndefined(parent)) {
-      node.parent = parent;
-    }
-    return node;
-  });
-}
-
-function writeEdges(g) {
-  return _.map(g.edges(), function(e) {
-    var edgeValue = g.edge(e),
-        edge = { v: e.v, w: e.w };
-    if (!_.isUndefined(e.name)) {
-      edge.name = e.name;
-    }
-    if (!_.isUndefined(edgeValue)) {
-      edge.value = edgeValue;
-    }
-    return edge;
-  });
-}
-
-function read(json) {
-  var g = new Graph(json.options).setGraph(json.value);
-  _.each(json.nodes, function(entry) {
-    g.setNode(entry.v, entry.value);
-    if (entry.parent) {
-      g.setParent(entry.v, entry.parent);
-    }
-  });
-  _.each(json.edges, function(entry) {
-    g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value);
-  });
-  return g;
-}
-
-},{"./graph":75,"./lodash":78}],78:[function(require,module,exports){
-/* global window */
-
-var lodash;
-
-if (typeof require === "function") {
-  try {
-    lodash = require("lodash");
-  } catch (e) {}
-}
-
-if (!lodash) {
-  lodash = window._;
-}
-
-module.exports = lodash;
-
-},{"lodash":80}],79:[function(require,module,exports){
-module.exports = '1.0.3';
-
-},{}],80:[function(require,module,exports){
-(function (global){
-/**
- * @license
- * Lo-Dash 2.4.2 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern -o ./dist/lodash.js`
- * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-;(function() {
-
-  /** Used as a safe reference for `undefined` in pre ES5 environments */
-  var undefined;
-
-  /** Used to pool arrays and objects used internally */
-  var arrayPool = [],
-      objectPool = [];
-
-  /** Used to generate unique IDs */
-  var idCounter = 0;
-
-  /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
-  var keyPrefix = +new Date + '';
-
-  /** Used as the size when optimizations are enabled for large arrays */
-  var largeArraySize = 75;
-
-  /** Used as the max size of the `arrayPool` and `objectPool` */
-  var maxPoolSize = 40;
-
-  /** Used to detect and test whitespace */
-  var whitespace = (
-    // whitespace
-    ' \t\x0B\f\xA0\ufeff' +
-
-    // line terminators
-    '\n\r\u2028\u2029' +
-
-    // unicode category "Zs" space separators
-    '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
-  );
-
-  /** Used to match empty string literals in compiled template source */
-  var reEmptyStringLeading = /\b__p \+= '';/g,
-      reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
-      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
-
-  /**
-   * Used to match ES6 template delimiters
-   * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
-   */
-  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
-
-  /** Used to match regexp flags from their coerced string values */
-  var reFlags = /\w*$/;
-
-  /** Used to detected named functions */
-  var reFuncName = /^\s*function[ \n\r\t]+\w/;
-
-  /** Used to match "interpolate" template delimiters */
-  var reInterpolate = /<%=([\s\S]+?)%>/g;
-
-  /** Used to match leading whitespace and zeros to be removed */
-  var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
-
-  /** Used to ensure capturing order of template delimiters */
-  var reNoMatch = /($^)/;
-
-  /** Used to detect functions containing a `this` reference */
-  var reThis = /\bthis\b/;
-
-  /** Used to match unescaped characters in compiled string literals */
-  var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
-
-  /** Used to assign default `context` object properties */
-  var contextProps = [
-    'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
-    'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
-    'parseInt', 'setTimeout'
-  ];
-
-  /** Used to make template sourceURLs easier to identify */
-  var templateCounter = 0;
-
-  /** `Object#toString` result shortcuts */
-  var argsClass = '[object Arguments]',
-      arrayClass = '[object Array]',
-      boolClass = '[object Boolean]',
-      dateClass = '[object Date]',
-      funcClass = '[object Function]',
-      numberClass = '[object Number]',
-      objectClass = '[object Object]',
-      regexpClass = '[object RegExp]',
-      stringClass = '[object String]';
-
-  /** Used to identify object classifications that `_.clone` supports */
-  var cloneableClasses = {};
-  cloneableClasses[funcClass] = false;
-  cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
-  cloneableClasses[boolClass] = cloneableClasses[dateClass] =
-  cloneableClasses[numberClass] = cloneableClasses[objectClass] =
-  cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
-
-  /** Used as an internal `_.debounce` options object */
-  var debounceOptions = {
-    'leading': false,
-    'maxWait': 0,
-    'trailing': false
-  };
-
-  /** Used as the property descriptor for `__bindData__` */
-  var descriptor = {
-    'configurable': false,
-    'enumerable': false,
-    'value': null,
-    'writable': false
-  };
-
-  /** Used to determine if values are of the language type Object */
-  var objectTypes = {
-    'boolean': false,
-    'function': true,
-    'object': true,
-    'number': false,
-    'string': false,
-    'undefined': false
-  };
-
-  /** Used to escape characters for inclusion in compiled string literals */
-  var stringEscapes = {
-    '\\': '\\',
-    "'": "'",
-    '\n': 'n',
-    '\r': 'r',
-    '\t': 't',
-    '\u2028': 'u2028',
-    '\u2029': 'u2029'
-  };
-
-  /** Used as a reference to the global object */
-  var root = (objectTypes[typeof window] && window) || this;
-
-  /** Detect free variable `exports` */
-  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
-
-  /** Detect free variable `module` */
-  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
-
-  /** Detect the popular CommonJS extension `module.exports` */
-  var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
-
-  /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
-  var freeGlobal = objectTypes[typeof global] && global;
-  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
-    root = freeGlobal;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * The base implementation of `_.indexOf` without support for binary searches
-   * or `fromIndex` constraints.
-   *
-   * @private
-   * @param {Array} array The array to search.
-   * @param {*} value The value to search for.
-   * @param {number} [fromIndex=0] The index to search from.
-   * @returns {number} Returns the index of the matched value or `-1`.
-   */
-  function baseIndexOf(array, value, fromIndex) {
-    var index = (fromIndex || 0) - 1,
-        length = array ? array.length : 0;
-
-    while (++index < length) {
-      if (array[index] === value) {
-        return index;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * An implementation of `_.contains` for cache objects that mimics the return
-   * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
-   *
-   * @private
-   * @param {Object} cache The cache object to inspect.
-   * @param {*} value The value to search for.
-   * @returns {number} Returns `0` if `value` is found, else `-1`.
-   */
-  function cacheIndexOf(cache, value) {
-    var type = typeof value;
-    cache = cache.cache;
-
-    if (type == 'boolean' || value == null) {
-      return cache[value] ? 0 : -1;
-    }
-    if (type != 'number' && type != 'string') {
-      type = 'object';
-    }
-    var key = type == 'number' ? value : keyPrefix + value;
-    cache = (cache = cache[type]) && cache[key];
-
-    return type == 'object'
-      ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
-      : (cache ? 0 : -1);
-  }
-
-  /**
-   * Adds a given value to the corresponding cache object.
-   *
-   * @private
-   * @param {*} value The value to add to the cache.
-   */
-  function cachePush(value) {
-    var cache = this.cache,
-        type = typeof value;
-
-    if (type == 'boolean' || value == null) {
-      cache[value] = true;
-    } else {
-      if (type != 'number' && type != 'string') {
-        type = 'object';
-      }
-      var key = type == 'number' ? value : keyPrefix + value,
-          typeCache = cache[type] || (cache[type] = {});
-
-      if (type == 'object') {
-        (typeCache[key] || (typeCache[key] = [])).push(value);
-      } else {
-        typeCache[key] = true;
-      }
-    }
-  }
-
-  /**
-   * Used by `_.max` and `_.min` as the default callback when a given
-   * collection is a string value.
-   *
-   * @private
-   * @param {string} value The character to inspect.
-   * @returns {number} Returns the code unit of given character.
-   */
-  function charAtCallback(value) {
-    return value.charCodeAt(0);
-  }
-
-  /**
-   * Used by `sortBy` to compare transformed `collection` elements, stable sorting
-   * them in ascending order.
-   *
-   * @private
-   * @param {Object} a The object to compare to `b`.
-   * @param {Object} b The object to compare to `a`.
-   * @returns {number} Returns the sort order indicator of `1` or `-1`.
-   */
-  function compareAscending(a, b) {
-    var ac = a.criteria,
-        bc = b.criteria,
-        index = -1,
-        length = ac.length;
-
-    while (++index < length) {
-      var value = ac[index],
-          other = bc[index];
-
-      if (value !== other) {
-        if (value > other || typeof value == 'undefined') {
-          return 1;
-        }
-        if (value < other || typeof other == 'undefined') {
-          return -1;
-        }
-      }
-    }
-    // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
-    // that causes it, under certain circumstances, to return the same value for
-    // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
-    //
-    // This also ensures a stable sort in V8 and other engines.
-    // See http://code.google.com/p/v8/issues/detail?id=90
-    return a.index - b.index;
-  }
-
-  /**
-   * Creates a cache object to optimize linear searches of large arrays.
-   *
-   * @private
-   * @param {Array} [array=[]] The array to search.
-   * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
-   */
-  function createCache(array) {
-    var index = -1,
-        length = array.length,
-        first = array[0],
-        mid = array[(length / 2) | 0],
-        last = array[length - 1];
-
-    if (first && typeof first == 'object' &&
-        mid && typeof mid == 'object' && last && typeof last == 'object') {
-      return false;
-    }
-    var cache = getObject();
-    cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
-
-    var result = getObject();
-    result.array = array;
-    result.cache = cache;
-    result.push = cachePush;
-
-    while (++index < length) {
-      result.push(array[index]);
-    }
-    return result;
-  }
-
-  /**
-   * Used by `template` to escape characters for inclusion in compiled
-   * string literals.
-   *
-   * @private
-   * @param {string} match The matched character to escape.
-   * @returns {string} Returns the escaped character.
-   */
-  function escapeStringChar(match) {
-    return '\\' + stringEscapes[match];
-  }
-
-  /**
-   * Gets an array from the array pool or creates a new one if the pool is empty.
-   *
-   * @private
-   * @returns {Array} The array from the pool.
-   */
-  function getArray() {
-    return arrayPool.pop() || [];
-  }
-
-  /**
-   * Gets an object from the object pool or creates a new one if the pool is empty.
-   *
-   * @private
-   * @returns {Object} The object from the pool.
-   */
-  function getObject() {
-    return objectPool.pop() || {
-      'array': null,
-      'cache': null,
-      'criteria': null,
-      'false': false,
-      'index': 0,
-      'null': false,
-      'number': null,
-      'object': null,
-      'push': null,
-      'string': null,
-      'true': false,
-      'undefined': false,
-      'value': null
-    };
-  }
-
-  /**
-   * Releases the given array back to the array pool.
-   *
-   * @private
-   * @param {Array} [array] The array to release.
-   */
-  function releaseArray(array) {
-    array.length = 0;
-    if (arrayPool.length < maxPoolSize) {
-      arrayPool.push(array);
-    }
-  }
-
-  /**
-   * Releases the given object back to the object pool.
-   *
-   * @private
-   * @param {Object} [object] The object to release.
-   */
-  function releaseObject(object) {
-    var cache = object.cache;
-    if (cache) {
-      releaseObject(cache);
-    }
-    object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
-    if (objectPool.length < maxPoolSize) {
-      objectPool.push(object);
-    }
-  }
-
-  /**
-   * Slices the `collection` from the `start` index up to, but not including,
-   * the `end` index.
-   *
-   * Note: This function is used instead of `Array#slice` to support node lists
-   * in IE < 9 and to ensure dense arrays are returned.
-   *
-   * @private
-   * @param {Array|Object|string} collection The collection to slice.
-   * @param {number} start The start index.
-   * @param {number} end The end index.
-   * @returns {Array} Returns the new array.
-   */
-  function slice(array, start, end) {
-    start || (start = 0);
-    if (typeof end == 'undefined') {
-      end = array ? array.length : 0;
-    }
-    var index = -1,
-        length = end - start || 0,
-        result = Array(length < 0 ? 0 : length);
-
-    while (++index < length) {
-      result[index] = array[start + index];
-    }
-    return result;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * Create a new `lodash` function using the given context object.
-   *
-   * @static
-   * @memberOf _
-   * @category Utilities
-   * @param {Object} [context=root] The context object.
-   * @returns {Function} Returns the `lodash` function.
-   */
-  function runInContext(context) {
-    // Avoid issues with some ES3 environments that attempt to use values, named
-    // after built-in constructors like `Object`, for the creation of literals.
-    // ES5 clears this up by stating that literals must use built-in constructors.
-    // See http://es5.github.io/#x11.1.5.
-    context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
-
-    /** Native constructor references */
-    var Array = context.Array,
-        Boolean = context.Boolean,
-        Date = context.Date,
-        Function = context.Function,
-        Math = context.Math,
-        Number = context.Number,
-        Object = context.Object,
-        RegExp = context.RegExp,
-        String = context.String,
-        TypeError = context.TypeError;
-
-    /**
-     * Used for `Array` method references.
-     *
-     * Normally `Array.prototype` would suffice, however, using an array literal
-     * avoids issues in Narwhal.
-     */
-    var arrayRef = [];
-
-    /** Used for native method references */
-    var objectProto = Object.prototype;
-
-    /** Used to restore the original `_` reference in `noConflict` */
-    var oldDash = context._;
-
-    /** Used to resolve the internal [[Class]] of values */
-    var toString = objectProto.toString;
-
-    /** Used to detect if a method is native */
-    var reNative = RegExp('^' +
-      String(toString)
-        .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
-        .replace(/toString| for [^\]]+/g, '.*?') + '$'
-    );
-
-    /** Native method shortcuts */
-    var ceil = Math.ceil,
-        clearTimeout = context.clearTimeout,
-        floor = Math.floor,
-        fnToString = Function.prototype.toString,
-        getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
-        hasOwnProperty = objectProto.hasOwnProperty,
-        push = arrayRef.push,
-        setTimeout = context.setTimeout,
-        splice = arrayRef.splice,
-        unshift = arrayRef.unshift;
-
-    /** Used to set meta data on functions */
-    var defineProperty = (function() {
-      // IE 8 only accepts DOM elements
-      try {
-        var o = {},
-            func = isNative(func = Object.defineProperty) && func,
-            result = func(o, o, o) && func;
-      } catch(e) { }
-      return result;
-    }());
-
-    /* Native method shortcuts for methods with the same name as other `lodash` methods */
-    var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
-        nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
-        nativeIsFinite = context.isFinite,
-        nativeIsNaN = context.isNaN,
-        nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
-        nativeMax = Math.max,
-        nativeMin = Math.min,
-        nativeParseInt = context.parseInt,
-        nativeRandom = Math.random;
-
-    /** Used to lookup a built-in constructor by [[Class]] */
-    var ctorByClass = {};
-    ctorByClass[arrayClass] = Array;
-    ctorByClass[boolClass] = Boolean;
-    ctorByClass[dateClass] = Date;
-    ctorByClass[funcClass] = Function;
-    ctorByClass[objectClass] = Object;
-    ctorByClass[numberClass] = Number;
-    ctorByClass[regexpClass] = RegExp;
-    ctorByClass[stringClass] = String;
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a `lodash` object which wraps the given value to enable intuitive
-     * method chaining.
-     *
-     * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
-     * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
-     * and `unshift`
-     *
-     * Chaining is supported in custom builds as long as the `value` method is
-     * implicitly or explicitly included in the build.
-     *
-     * The chainable wrapper functions are:
-     * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
-     * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
-     * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
-     * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
-     * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
-     * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
-     * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
-     * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
-     * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
-     * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
-     * and `zip`
-     *
-     * The non-chainable wrapper functions are:
-     * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
-     * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
-     * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
-     * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
-     * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
-     * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
-     * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
-     * `template`, `unescape`, `uniqueId`, and `value`
-     *
-     * The wrapper functions `first` and `last` return wrapped values when `n` is
-     * provided, otherwise they return unwrapped values.
-     *
-     * Explicit chaining can be enabled by using the `_.chain` method.
-     *
-     * @name _
-     * @constructor
-     * @category Chaining
-     * @param {*} value The value to wrap in a `lodash` instance.
-     * @returns {Object} Returns a `lodash` instance.
-     * @example
-     *
-     * var wrapped = _([1, 2, 3]);
-     *
-     * // returns an unwrapped value
-     * wrapped.reduce(function(sum, num) {
-     *   return sum + num;
-     * });
-     * // => 6
-     *
-     * // returns a wrapped value
-     * var squares = wrapped.map(function(num) {
-     *   return num * num;
-     * });
-     *
-     * _.isArray(squares);
-     * // => false
-     *
-     * _.isArray(squares.value());
-     * // => true
-     */
-    function lodash(value) {
-      // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
-      return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
-       ? value
-       : new lodashWrapper(value);
-    }
-
-    /**
-     * A fast path for creating `lodash` wrapper objects.
-     *
-     * @private
-     * @param {*} value The value to wrap in a `lodash` instance.
-     * @param {boolean} chainAll A flag to enable chaining for all methods
-     * @returns {Object} Returns a `lodash` instance.
-     */
-    function lodashWrapper(value, chainAll) {
-      this.__chain__ = !!chainAll;
-      this.__wrapped__ = value;
-    }
-    // ensure `new lodashWrapper` is an instance of `lodash`
-    lodashWrapper.prototype = lodash.prototype;
-
-    /**
-     * An object used to flag environments features.
-     *
-     * @static
-     * @memberOf _
-     * @type Object
-     */
-    var support = lodash.support = {};
-
-    /**
-     * Detect if functions can be decompiled by `Function#toString`
-     * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
-     *
-     * @memberOf _.support
-     * @type boolean
-     */
-    support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
-
-    /**
-     * Detect if `Function#name` is supported (all but IE).
-     *
-     * @memberOf _.support
-     * @type boolean
-     */
-    support.funcNames = typeof Function.name == 'string';
-
-    /**
-     * By default, the template delimiters used by Lo-Dash are similar to those in
-     * embedded Ruby (ERB). Change the following template settings to use alternative
-     * delimiters.
-     *
-     * @static
-     * @memberOf _
-     * @type Object
-     */
-    lodash.templateSettings = {
-
-      /**
-       * Used to detect `data` property values to be HTML-escaped.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'escape': /<%-([\s\S]+?)%>/g,
-
-      /**
-       * Used to detect code to be evaluated.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'evaluate': /<%([\s\S]+?)%>/g,
-
-      /**
-       * Used to detect `data` property values to inject.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'interpolate': reInterpolate,
-
-      /**
-       * Used to reference the data object in the template text.
-       *
-       * @memberOf _.templateSettings
-       * @type string
-       */
-      'variable': '',
-
-      /**
-       * Used to import variables into the compiled template.
-       *
-       * @memberOf _.templateSettings
-       * @type Object
-       */
-      'imports': {
-
-        /**
-         * A reference to the `lodash` function.
-         *
-         * @memberOf _.templateSettings.imports
-         * @type Function
-         */
-        '_': lodash
-      }
-    };
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * The base implementation of `_.bind` that creates the bound function and
-     * sets its meta data.
-     *
-     * @private
-     * @param {Array} bindData The bind data array.
-     * @returns {Function} Returns the new bound function.
-     */
-    function baseBind(bindData) {
-      var func = bindData[0],
-          partialArgs = bindData[2],
-          thisArg = bindData[4];
-
-      function bound() {
-        // `Function#bind` spec
-        // http://es5.github.io/#x15.3.4.5
-        if (partialArgs) {
-          // avoid `arguments` object deoptimizations by using `slice` instead
-          // of `Array.prototype.slice.call` and not assigning `arguments` to a
-          // variable as a ternary expression
-          var args = slice(partialArgs);
-          push.apply(args, arguments);
-        }
-        // mimic the constructor's `return` behavior
-        // http://es5.github.io/#x13.2.2
-        if (this instanceof bound) {
-          // ensure `new bound` is an instance of `func`
-          var thisBinding = baseCreate(func.prototype),
-              result = func.apply(thisBinding, args || arguments);
-          return isObject(result) ? result : thisBinding;
-        }
-        return func.apply(thisArg, args || arguments);
-      }
-      setBindData(bound, bindData);
-      return bound;
-    }
-
-    /**
-     * The base implementation of `_.clone` without argument juggling or support
-     * for `thisArg` binding.
-     *
-     * @private
-     * @param {*} value The value to clone.
-     * @param {boolean} [isDeep=false] Specify a deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {Array} [stackA=[]] Tracks traversed source objects.
-     * @param {Array} [stackB=[]] Associates clones with source counterparts.
-     * @returns {*} Returns the cloned value.
-     */
-    function baseClone(value, isDeep, callback, stackA, stackB) {
-      if (callback) {
-        var result = callback(value);
-        if (typeof result != 'undefined') {
-          return result;
-        }
-      }
-      // inspect [[Class]]
-      var isObj = isObject(value);
-      if (isObj) {
-        var className = toString.call(value);
-        if (!cloneableClasses[className]) {
-          return value;
-        }
-        var ctor = ctorByClass[className];
-        switch (className) {
-          case boolClass:
-          case dateClass:
-            return new ctor(+value);
-
-          case numberClass:
-          case stringClass:
-            return new ctor(value);
-
-          case regexpClass:
-            result = ctor(value.source, reFlags.exec(value));
-            result.lastIndex = value.lastIndex;
-            return result;
-        }
-      } else {
-        return value;
-      }
-      var isArr = isArray(value);
-      if (isDeep) {
-        // check for circular references and return corresponding clone
-        var initedStack = !stackA;
-        stackA || (stackA = getArray());
-        stackB || (stackB = getArray());
-
-        var length = stackA.length;
-        while (length--) {
-          if (stackA[length] == value) {
-            return stackB[length];
-          }
-        }
-        result = isArr ? ctor(value.length) : {};
-      }
-      else {
-        result = isArr ? slice(value) : assign({}, value);
-      }
-      // add array properties assigned by `RegExp#exec`
-      if (isArr) {
-        if (hasOwnProperty.call(value, 'index')) {
-          result.index = value.index;
-        }
-        if (hasOwnProperty.call(value, 'input')) {
-          result.input = value.input;
-        }
-      }
-      // exit for shallow clone
-      if (!isDeep) {
-        return result;
-      }
-      // add the source value to the stack of traversed objects
-      // and associate it with its clone
-      stackA.push(value);
-      stackB.push(result);
-
-      // recursively populate clone (susceptible to call stack limits)
-      (isArr ? forEach : forOwn)(value, function(objValue, key) {
-        result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
-      });
-
-      if (initedStack) {
-        releaseArray(stackA);
-        releaseArray(stackB);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.create` without support for assigning
-     * properties to the created object.
-     *
-     * @private
-     * @param {Object} prototype The object to inherit from.
-     * @returns {Object} Returns the new object.
-     */
-    function baseCreate(prototype, properties) {
-      return isObject(prototype) ? nativeCreate(prototype) : {};
-    }
-    // fallback for browsers without `Object.create`
-    if (!nativeCreate) {
-      baseCreate = (function() {
-        function Object() {}
-        return function(prototype) {
-          if (isObject(prototype)) {
-            Object.prototype = prototype;
-            var result = new Object;
-            Object.prototype = null;
-          }
-          return result || context.Object();
-        };
-      }());
-    }
-
-    /**
-     * The base implementation of `_.createCallback` without support for creating
-     * "_.pluck" or "_.where" style callbacks.
-     *
-     * @private
-     * @param {*} [func=identity] The value to convert to a callback.
-     * @param {*} [thisArg] The `this` binding of the created callback.
-     * @param {number} [argCount] The number of arguments the callback accepts.
-     * @returns {Function} Returns a callback function.
-     */
-    function baseCreateCallback(func, thisArg, argCount) {
-      if (typeof func != 'function') {
-        return identity;
-      }
-      // exit early for no `thisArg` or already bound by `Function#bind`
-      if (typeof thisArg == 'undefined' || !('prototype' in func)) {
-        return func;
-      }
-      var bindData = func.__bindData__;
-      if (typeof bindData == 'undefined') {
-        if (support.funcNames) {
-          bindData = !func.name;
-        }
-        bindData = bindData || !support.funcDecomp;
-        if (!bindData) {
-          var source = fnToString.call(func);
-          if (!support.funcNames) {
-            bindData = !reFuncName.test(source);
-          }
-          if (!bindData) {
-            // checks if `func` references the `this` keyword and stores the result
-            bindData = reThis.test(source);
-            setBindData(func, bindData);
-          }
-        }
-      }
-      // exit early if there are no `this` references or `func` is bound
-      if (bindData === false || (bindData !== true && bindData[1] & 1)) {
-        return func;
-      }
-      switch (argCount) {
-        case 1: return function(value) {
-          return func.call(thisArg, value);
-        };
-        case 2: return function(a, b) {
-          return func.call(thisArg, a, b);
-        };
-        case 3: return function(value, index, collection) {
-          return func.call(thisArg, value, index, collection);
-        };
-        case 4: return function(accumulator, value, index, collection) {
-          return func.call(thisArg, accumulator, value, index, collection);
-        };
-      }
-      return bind(func, thisArg);
-    }
-
-    /**
-     * The base implementation of `createWrapper` that creates the wrapper and
-     * sets its meta data.
-     *
-     * @private
-     * @param {Array} bindData The bind data array.
-     * @returns {Function} Returns the new function.
-     */
-    function baseCreateWrapper(bindData) {
-      var func = bindData[0],
-          bitmask = bindData[1],
-          partialArgs = bindData[2],
-          partialRightArgs = bindData[3],
-          thisArg = bindData[4],
-          arity = bindData[5];
-
-      var isBind = bitmask & 1,
-          isBindKey = bitmask & 2,
-          isCurry = bitmask & 4,
-          isCurryBound = bitmask & 8,
-          key = func;
-
-      function bound() {
-        var thisBinding = isBind ? thisArg : this;
-        if (partialArgs) {
-          var args = slice(partialArgs);
-          push.apply(args, arguments);
-        }
-        if (partialRightArgs || isCurry) {
-          args || (args = slice(arguments));
-          if (partialRightArgs) {
-            push.apply(args, partialRightArgs);
-          }
-          if (isCurry && args.length < arity) {
-            bitmask |= 16 & ~32;
-            return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
-          }
-        }
-        args || (args = arguments);
-        if (isBindKey) {
-          func = thisBinding[key];
-        }
-        if (this instanceof bound) {
-          thisBinding = baseCreate(func.prototype);
-          var result = func.apply(thisBinding, args);
-          return isObject(result) ? result : thisBinding;
-        }
-        return func.apply(thisBinding, args);
-      }
-      setBindData(bound, bindData);
-      return bound;
-    }
-
-    /**
-     * The base implementation of `_.difference` that accepts a single array
-     * of values to exclude.
-     *
-     * @private
-     * @param {Array} array The array to process.
-     * @param {Array} [values] The array of values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     */
-    function baseDifference(array, values) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = array ? array.length : 0,
-          isLarge = length >= largeArraySize && indexOf === baseIndexOf,
-          result = [];
-
-      if (isLarge) {
-        var cache = createCache(values);
-        if (cache) {
-          indexOf = cacheIndexOf;
-          values = cache;
-        } else {
-          isLarge = false;
-        }
-      }
-      while (++index < length) {
-        var value = array[index];
-        if (indexOf(values, value) < 0) {
-          result.push(value);
-        }
-      }
-      if (isLarge) {
-        releaseObject(values);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.flatten` without support for callback
-     * shorthands or `thisArg` binding.
-     *
-     * @private
-     * @param {Array} array The array to flatten.
-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
-     * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
-     * @param {number} [fromIndex=0] The index to start from.
-     * @returns {Array} Returns a new flattened array.
-     */
-    function baseFlatten(array, isShallow, isStrict, fromIndex) {
-      var index = (fromIndex || 0) - 1,
-          length = array ? array.length : 0,
-          result = [];
-
-      while (++index < length) {
-        var value = array[index];
-
-        if (value && typeof value == 'object' && typeof value.length == 'number'
-            && (isArray(value) || isArguments(value))) {
-          // recursively flatten arrays (susceptible to call stack limits)
-          if (!isShallow) {
-            value = baseFlatten(value, isShallow, isStrict);
-          }
-          var valIndex = -1,
-              valLength = value.length,
-              resIndex = result.length;
-
-          result.length += valLength;
-          while (++valIndex < valLength) {
-            result[resIndex++] = value[valIndex];
-          }
-        } else if (!isStrict) {
-          result.push(value);
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.isEqual`, without support for `thisArg` binding,
-     * that allows partial "_.where" style comparisons.
-     *
-     * @private
-     * @param {*} a The value to compare.
-     * @param {*} b The other value to compare.
-     * @param {Function} [callback] The function to customize comparing values.
-     * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
-     * @param {Array} [stackA=[]] Tracks traversed `a` objects.
-     * @param {Array} [stackB=[]] Tracks traversed `b` objects.
-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-     */
-    function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
-      // used to indicate that when comparing objects, `a` has at least the properties of `b`
-      if (callback) {
-        var result = callback(a, b);
-        if (typeof result != 'undefined') {
-          return !!result;
-        }
-      }
-      // exit early for identical values
-      if (a === b) {
-        // treat `+0` vs. `-0` as not equal
-        return a !== 0 || (1 / a == 1 / b);
-      }
-      var type = typeof a,
-          otherType = typeof b;
-
-      // exit early for unlike primitive values
-      if (a === a &&
-          !(a && objectTypes[type]) &&
-          !(b && objectTypes[otherType])) {
-        return false;
-      }
-      // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
-      // http://es5.github.io/#x15.3.4.4
-      if (a == null || b == null) {
-        return a === b;
-      }
-      // compare [[Class]] names
-      var className = toString.call(a),
-          otherClass = toString.call(b);
-
-      if (className == argsClass) {
-        className = objectClass;
-      }
-      if (otherClass == argsClass) {
-        otherClass = objectClass;
-      }
-      if (className != otherClass) {
-        return false;
-      }
-      switch (className) {
-        case boolClass:
-        case dateClass:
-          // coerce dates and booleans to numbers, dates to milliseconds and booleans
-          // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
-          return +a == +b;
-
-        case numberClass:
-          // treat `NaN` vs. `NaN` as equal
-          return (a != +a)
-            ? b != +b
-            // but treat `+0` vs. `-0` as not equal
-            : (a == 0 ? (1 / a == 1 / b) : a == +b);
-
-        case regexpClass:
-        case stringClass:
-          // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
-          // treat string primitives and their corresponding object instances as equal
-          return a == String(b);
-      }
-      var isArr = className == arrayClass;
-      if (!isArr) {
-        // unwrap any `lodash` wrapped values
-        var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
-            bWrapped = hasOwnProperty.call(b, '__wrapped__');
-
-        if (aWrapped || bWrapped) {
-          return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
-        }
-        // exit for functions and DOM nodes
-        if (className != objectClass) {
-          return false;
-        }
-        // in older versions of Opera, `arguments` objects have `Array` constructors
-        var ctorA = a.constructor,
-            ctorB = b.constructor;
-
-        // non `Object` object instances with different constructors are not equal
-        if (ctorA != ctorB &&
-              !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
-              ('constructor' in a && 'constructor' in b)
-            ) {
-          return false;
-        }
-      }
-      // assume cyclic structures are equal
-      // the algorithm for detecting cyclic structures is adapted from ES 5.1
-      // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
-      var initedStack = !stackA;
-      stackA || (stackA = getArray());
-      stackB || (stackB = getArray());
-
-      var length = stackA.length;
-      while (length--) {
-        if (stackA[length] == a) {
-          return stackB[length] == b;
-        }
-      }
-      var size = 0;
-      result = true;
-
-      // add `a` and `b` to the stack of traversed objects
-      stackA.push(a);
-      stackB.push(b);
-
-      // recursively compare objects and arrays (susceptible to call stack limits)
-      if (isArr) {
-        // compare lengths to determine if a deep comparison is necessary
-        length = a.length;
-        size = b.length;
-        result = size == length;
-
-        if (result || isWhere) {
-          // deep compare the contents, ignoring non-numeric properties
-          while (size--) {
-            var index = length,
-                value = b[size];
-
-            if (isWhere) {
-              while (index--) {
-                if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
-                  break;
-                }
-              }
-            } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
-              break;
-            }
-          }
-        }
-      }
-      else {
-        // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
-        // which, in this case, is more costly
-        forIn(b, function(value, key, b) {
-          if (hasOwnProperty.call(b, key)) {
-            // count the number of properties.
-            size++;
-            // deep compare each property value.
-            return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
-          }
-        });
-
-        if (result && !isWhere) {
-          // ensure both objects have the same number of properties
-          forIn(a, function(value, key, a) {
-            if (hasOwnProperty.call(a, key)) {
-              // `size` will be `-1` if `a` has more properties than `b`
-              return (result = --size > -1);
-            }
-          });
-        }
-      }
-      stackA.pop();
-      stackB.pop();
-
-      if (initedStack) {
-        releaseArray(stackA);
-        releaseArray(stackB);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.merge` without argument juggling or support
-     * for `thisArg` binding.
-     *
-     * @private
-     * @param {Object} object The destination object.
-     * @param {Object} source The source object.
-     * @param {Function} [callback] The function to customize merging properties.
-     * @param {Array} [stackA=[]] Tracks traversed source objects.
-     * @param {Array} [stackB=[]] Associates values with source counterparts.
-     */
-    function baseMerge(object, source, callback, stackA, stackB) {
-      (isArray(source) ? forEach : forOwn)(source, function(source, key) {
-        var found,
-            isArr,
-            result = source,
-            value = object[key];
-
-        if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
-          // avoid merging previously merged cyclic sources
-          var stackLength = stackA.length;
-          while (stackLength--) {
-            if ((found = stackA[stackLength] == source)) {
-              value = stackB[stackLength];
-              break;
-            }
-          }
-          if (!found) {
-            var isShallow;
-            if (callback) {
-              result = callback(value, source);
-              if ((isShallow = typeof result != 'undefined')) {
-                value = result;
-              }
-            }
-            if (!isShallow) {
-              value = isArr
-                ? (isArray(value) ? value : [])
-                : (isPlainObject(value) ? value : {});
-            }
-            // add `source` and associated `value` to the stack of traversed objects
-            stackA.push(source);
-            stackB.push(value);
-
-            // recursively merge objects and arrays (susceptible to call stack limits)
-            if (!isShallow) {
-              baseMerge(value, source, callback, stackA, stackB);
-            }
-          }
-        }
-        else {
-          if (callback) {
-            result = callback(value, source);
-            if (typeof result == 'undefined') {
-              result = source;
-            }
-          }
-          if (typeof result != 'undefined') {
-            value = result;
-          }
-        }
-        object[key] = value;
-      });
-    }
-
-    /**
-     * The base implementation of `_.random` without argument juggling or support
-     * for returning floating-point numbers.
-     *
-     * @private
-     * @param {number} min The minimum possible value.
-     * @param {number} max The maximum possible value.
-     * @returns {number} Returns a random number.
-     */
-    function baseRandom(min, max) {
-      return min + floor(nativeRandom() * (max - min + 1));
-    }
-
-    /**
-     * The base implementation of `_.uniq` without support for callback shorthands
-     * or `thisArg` binding.
-     *
-     * @private
-     * @param {Array} array The array to process.
-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
-     * @param {Function} [callback] The function called per iteration.
-     * @returns {Array} Returns a duplicate-value-free array.
-     */
-    function baseUniq(array, isSorted, callback) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = array ? array.length : 0,
-          result = [];
-
-      var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
-          seen = (callback || isLarge) ? getArray() : result;
-
-      if (isLarge) {
-        var cache = createCache(seen);
-        indexOf = cacheIndexOf;
-        seen = cache;
-      }
-      while (++index < length) {
-        var value = array[index],
-            computed = callback ? callback(value, index, array) : value;
-
-        if (isSorted
-              ? !index || seen[seen.length - 1] !== computed
-              : indexOf(seen, computed) < 0
-            ) {
-          if (callback || isLarge) {
-            seen.push(computed);
-          }
-          result.push(value);
-        }
-      }
-      if (isLarge) {
-        releaseArray(seen.array);
-        releaseObject(seen);
-      } else if (callback) {
-        releaseArray(seen);
-      }
-      return result;
-    }
-
-    /**
-     * Creates a function that aggregates a collection, creating an object composed
-     * of keys generated from the results of running each element of the collection
-     * through a callback. The given `setter` function sets the keys and values
-     * of the composed object.
-     *
-     * @private
-     * @param {Function} setter The setter function.
-     * @returns {Function} Returns the new aggregator function.
-     */
-    function createAggregator(setter) {
-      return function(collection, callback, thisArg) {
-        var result = {};
-        callback = lodash.createCallback(callback, thisArg, 3);
-
-        var index = -1,
-            length = collection ? collection.length : 0;
-
-        if (typeof length == 'number') {
-          while (++index < length) {
-            var value = collection[index];
-            setter(result, value, callback(value, index, collection), collection);
-          }
-        } else {
-          forOwn(collection, function(value, key, collection) {
-            setter(result, value, callback(value, key, collection), collection);
-          });
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Creates a function that, when called, either curries or invokes `func`
-     * with an optional `this` binding and partially applied arguments.
-     *
-     * @private
-     * @param {Function|string} func The function or method name to reference.
-     * @param {number} bitmask The bitmask of method flags to compose.
-     *  The bitmask may be composed of the following flags:
-     *  1 - `_.bind`
-     *  2 - `_.bindKey`
-     *  4 - `_.curry`
-     *  8 - `_.curry` (bound)
-     *  16 - `_.partial`
-     *  32 - `_.partialRight`
-     * @param {Array} [partialArgs] An array of arguments to prepend to those
-     *  provided to the new function.
-     * @param {Array} [partialRightArgs] An array of arguments to append to those
-     *  provided to the new function.
-     * @param {*} [thisArg] The `this` binding of `func`.
-     * @param {number} [arity] The arity of `func`.
-     * @returns {Function} Returns the new function.
-     */
-    function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
-      var isBind = bitmask & 1,
-          isBindKey = bitmask & 2,
-          isCurry = bitmask & 4,
-          isCurryBound = bitmask & 8,
-          isPartial = bitmask & 16,
-          isPartialRight = bitmask & 32;
-
-      if (!isBindKey && !isFunction(func)) {
-        throw new TypeError;
-      }
-      if (isPartial && !partialArgs.length) {
-        bitmask &= ~16;
-        isPartial = partialArgs = false;
-      }
-      if (isPartialRight && !partialRightArgs.length) {
-        bitmask &= ~32;
-        isPartialRight = partialRightArgs = false;
-      }
-      var bindData = func && func.__bindData__;
-      if (bindData && bindData !== true) {
-        // clone `bindData`
-        bindData = slice(bindData);
-        if (bindData[2]) {
-          bindData[2] = slice(bindData[2]);
-        }
-        if (bindData[3]) {
-          bindData[3] = slice(bindData[3]);
-        }
-        // set `thisBinding` is not previously bound
-        if (isBind && !(bindData[1] & 1)) {
-          bindData[4] = thisArg;
-        }
-        // set if previously bound but not currently (subsequent curried functions)
-        if (!isBind && bindData[1] & 1) {
-          bitmask |= 8;
-        }
-        // set curried arity if not yet set
-        if (isCurry && !(bindData[1] & 4)) {
-          bindData[5] = arity;
-        }
-        // append partial left arguments
-        if (isPartial) {
-          push.apply(bindData[2] || (bindData[2] = []), partialArgs);
-        }
-        // append partial right arguments
-        if (isPartialRight) {
-          unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
-        }
-        // merge flags
-        bindData[1] |= bitmask;
-        return createWrapper.apply(null, bindData);
-      }
-      // fast path for `_.bind`
-      var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
-      return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
-    }
-
-    /**
-     * Used by `escape` to convert characters to HTML entities.
-     *
-     * @private
-     * @param {string} match The matched character to escape.
-     * @returns {string} Returns the escaped character.
-     */
-    function escapeHtmlChar(match) {
-      return htmlEscapes[match];
-    }
-
-    /**
-     * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
-     * customized, this method returns the custom method, otherwise it returns
-     * the `baseIndexOf` function.
-     *
-     * @private
-     * @returns {Function} Returns the "indexOf" function.
-     */
-    function getIndexOf() {
-      var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
-      return result;
-    }
-
-    /**
-     * Checks if `value` is a native function.
-     *
-     * @private
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
-     */
-    function isNative(value) {
-      return typeof value == 'function' && reNative.test(value);
-    }
-
-    /**
-     * Sets `this` binding data on a given function.
-     *
-     * @private
-     * @param {Function} func The function to set data on.
-     * @param {Array} value The data array to set.
-     */
-    var setBindData = !defineProperty ? noop : function(func, value) {
-      descriptor.value = value;
-      defineProperty(func, '__bindData__', descriptor);
-      descriptor.value = null;
-    };
-
-    /**
-     * A fallback implementation of `isPlainObject` which checks if a given value
-     * is an object created by the `Object` constructor, assuming objects created
-     * by the `Object` constructor have no inherited enumerable properties and that
-     * there are no `Object.prototype` extensions.
-     *
-     * @private
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-     */
-    function shimIsPlainObject(value) {
-      var ctor,
-          result;
-
-      // avoid non Object objects, `arguments` objects, and DOM elements
-      if (!(value && toString.call(value) == objectClass) ||
-          (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
-        return false;
-      }
-      // In most environments an object's own properties are iterated before
-      // its inherited properties. If the last iterated property is an object's
-      // own property then there are no inherited enumerable properties.
-      forIn(value, function(value, key) {
-        result = key;
-      });
-      return typeof result == 'undefined' || hasOwnProperty.call(value, result);
-    }
-
-    /**
-     * Used by `unescape` to convert HTML entities to characters.
-     *
-     * @private
-     * @param {string} match The matched character to unescape.
-     * @returns {string} Returns the unescaped character.
-     */
-    function unescapeHtmlChar(match) {
-      return htmlUnescapes[match];
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Checks if `value` is an `arguments` object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
-     * @example
-     *
-     * (function() { return _.isArguments(arguments); })(1, 2, 3);
-     * // => true
-     *
-     * _.isArguments([1, 2, 3]);
-     * // => false
-     */
-    function isArguments(value) {
-      return value && typeof value == 'object' && typeof value.length == 'number' &&
-        toString.call(value) == argsClass || false;
-    }
-
-    /**
-     * Checks if `value` is an array.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
-     * @example
-     *
-     * (function() { return _.isArray(arguments); })();
-     * // => false
-     *
-     * _.isArray([1, 2, 3]);
-     * // => true
-     */
-    var isArray = nativeIsArray || function(value) {
-      return value && typeof value == 'object' && typeof value.length == 'number' &&
-        toString.call(value) == arrayClass || false;
-    };
-
-    /**
-     * A fallback implementation of `Object.keys` which produces an array of the
-     * given object's own enumerable property names.
-     *
-     * @private
-     * @type Function
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names.
-     */
-    var shimKeys = function(object) {
-      var index, iterable = object, result = [];
-      if (!iterable) return result;
-      if (!(objectTypes[typeof object])) return result;
-        for (index in iterable) {
-          if (hasOwnProperty.call(iterable, index)) {
-            result.push(index);
-          }
-        }
-      return result
-    };
-
-    /**
-     * Creates an array composed of the own enumerable property names of an object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names.
-     * @example
-     *
-     * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
-     */
-    var keys = !nativeKeys ? shimKeys : function(object) {
-      if (!isObject(object)) {
-        return [];
-      }
-      return nativeKeys(object);
-    };
-
-    /**
-     * Used to convert characters to HTML entities:
-     *
-     * Though the `>` character is escaped for symmetry, characters like `>` and `/`
-     * don't require escaping in HTML and have no special meaning unless they're part
-     * of a tag or an unquoted attribute value.
-     * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
-     */
-    var htmlEscapes = {
-      '&': '&',
-      '<': '<',
-      '>': '>',
-      '"': '"',
-      "'": '''
-    };
-
-    /** Used to convert HTML entities to characters */
-    var htmlUnescapes = invert(htmlEscapes);
-
-    /** Used to match HTML entities and HTML characters */
-    var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
-        reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Assigns own enumerable properties of source object(s) to the destination
-     * object. Subsequent sources will overwrite property assignments of previous
-     * sources. If a callback is provided it will be executed to produce the
-     * assigned values. The callback is bound to `thisArg` and invoked with two
-     * arguments; (objectValue, sourceValue).
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @alias extend
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param {Function} [callback] The function to customize assigning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
-     * // => { 'name': 'fred', 'employer': 'slate' }
-     *
-     * var defaults = _.partialRight(_.assign, function(a, b) {
-     *   return typeof a == 'undefined' ? b : a;
-     * });
-     *
-     * var object = { 'name': 'barney' };
-     * defaults(object, { 'name': 'fred', 'employer': 'slate' });
-     * // => { 'name': 'barney', 'employer': 'slate' }
-     */
-    var assign = function(object, source, guard) {
-      var index, iterable = object, result = iterable;
-      if (!iterable) return result;
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = typeof guard == 'number' ? 2 : args.length;
-      if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
-        var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
-      } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
-        callback = args[--argsLength];
-      }
-      while (++argsIndex < argsLength) {
-        iterable = args[argsIndex];
-        if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
-        }
-        }
-      }
-      return result
-    };
-
-    /**
-     * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
-     * be cloned, otherwise they will be assigned by reference. If a callback
-     * is provided it will be executed to produce the cloned values. If the
-     * callback returns `undefined` cloning will be handled by the method instead.
-     * The callback is bound to `thisArg` and invoked with one argument; (value).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to clone.
-     * @param {boolean} [isDeep=false] Specify a deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the cloned value.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * var shallow = _.clone(characters);
-     * shallow[0] === characters[0];
-     * // => true
-     *
-     * var deep = _.clone(characters, true);
-     * deep[0] === characters[0];
-     * // => false
-     *
-     * _.mixin({
-     *   'clone': _.partialRight(_.clone, function(value) {
-     *     return _.isElement(value) ? value.cloneNode(false) : undefined;
-     *   })
-     * });
-     *
-     * var clone = _.clone(document.body);
-     * clone.childNodes.length;
-     * // => 0
-     */
-    function clone(value, isDeep, callback, thisArg) {
-      // allows working with "Collections" methods without using their `index`
-      // and `collection` arguments for `isDeep` and `callback`
-      if (typeof isDeep != 'boolean' && isDeep != null) {
-        thisArg = callback;
-        callback = isDeep;
-        isDeep = false;
-      }
-      return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
-    }
-
-    /**
-     * Creates a deep clone of `value`. If a callback is provided it will be
-     * executed to produce the cloned values. If the callback returns `undefined`
-     * cloning will be handled by the method instead. The callback is bound to
-     * `thisArg` and invoked with one argument; (value).
-     *
-     * Note: This method is loosely based on the structured clone algorithm. Functions
-     * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
-     * objects created by constructors other than `Object` are cloned to plain `Object` objects.
-     * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the deep cloned value.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * var deep = _.cloneDeep(characters);
-     * deep[0] === characters[0];
-     * // => false
-     *
-     * var view = {
-     *   'label': 'docs',
-     *   'node': element
-     * };
-     *
-     * var clone = _.cloneDeep(view, function(value) {
-     *   return _.isElement(value) ? value.cloneNode(true) : undefined;
-     * });
-     *
-     * clone.node == view.node;
-     * // => false
-     */
-    function cloneDeep(value, callback, thisArg) {
-      return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
-    }
-
-    /**
-     * Creates an object that inherits from the given `prototype` object. If a
-     * `properties` object is provided its own enumerable properties are assigned
-     * to the created object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} prototype The object to inherit from.
-     * @param {Object} [properties] The properties to assign to the object.
-     * @returns {Object} Returns the new object.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * function Circle() {
-     *   Shape.call(this);
-     * }
-     *
-     * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
-     *
-     * var circle = new Circle;
-     * circle instanceof Circle;
-     * // => true
-     *
-     * circle instanceof Shape;
-     * // => true
-     */
-    function create(prototype, properties) {
-      var result = baseCreate(prototype);
-      return properties ? assign(result, properties) : result;
-    }
-
-    /**
-     * Assigns own enumerable properties of source object(s) to the destination
-     * object for all destination properties that resolve to `undefined`. Once a
-     * property is set, additional defaults of the same property will be ignored.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param- {Object} [guard] Allows working with `_.reduce` without using its
-     *  `key` and `object` arguments as sources.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * var object = { 'name': 'barney' };
-     * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
-     * // => { 'name': 'barney', 'employer': 'slate' }
-     */
-    var defaults = function(object, source, guard) {
-      var index, iterable = object, result = iterable;
-      if (!iterable) return result;
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = typeof guard == 'number' ? 2 : args.length;
-      while (++argsIndex < argsLength) {
-        iterable = args[argsIndex];
-        if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (typeof result[index] == 'undefined') result[index] = iterable[index];
-        }
-        }
-      }
-      return result
-    };
-
-    /**
-     * This method is like `_.findIndex` except that it returns the key of the
-     * first element that passes the callback check, instead of the element itself.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to search.
-     * @param {Function|Object|string} [callback=identity] The function called per
-     *  iteration. If a property name or object is provided it will be used to
-     *  create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
-     * @example
-     *
-     * var characters = {
-     *   'barney': {  'age': 36, 'blocked': false },
-     *   'fred': {    'age': 40, 'blocked': true },
-     *   'pebbles': { 'age': 1,  'blocked': false }
-     * };
-     *
-     * _.findKey(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => 'barney' (property order is not guaranteed across environments)
-     *
-     * // using "_.where" callback shorthand
-     * _.findKey(characters, { 'age': 1 });
-     * // => 'pebbles'
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findKey(characters, 'blocked');
-     * // => 'fred'
-     */
-    function findKey(object, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forOwn(object, function(value, key, object) {
-        if (callback(value, key, object)) {
-          result = key;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * This method is like `_.findKey` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to search.
-     * @param {Function|Object|string} [callback=identity] The function called per
-     *  iteration. If a property name or object is provided it will be used to
-     *  create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
-     * @example
-     *
-     * var characters = {
-     *   'barney': {  'age': 36, 'blocked': true },
-     *   'fred': {    'age': 40, 'blocked': false },
-     *   'pebbles': { 'age': 1,  'blocked': true }
-     * };
-     *
-     * _.findLastKey(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => returns `pebbles`, assuming `_.findKey` returns `barney`
-     *
-     * // using "_.where" callback shorthand
-     * _.findLastKey(characters, { 'age': 40 });
-     * // => 'fred'
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findLastKey(characters, 'blocked');
-     * // => 'pebbles'
-     */
-    function findLastKey(object, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forOwnRight(object, function(value, key, object) {
-        if (callback(value, key, object)) {
-          result = key;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * Iterates over own and inherited enumerable properties of an object,
-     * executing the callback for each property. The callback is bound to `thisArg`
-     * and invoked with three arguments; (value, key, object). Callbacks may exit
-     * iteration early by explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * Shape.prototype.move = function(x, y) {
-     *   this.x += x;
-     *   this.y += y;
-     * };
-     *
-     * _.forIn(new Shape, function(value, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
-     */
-    var forIn = function(collection, callback, thisArg) {
-      var index, iterable = collection, result = iterable;
-      if (!iterable) return result;
-      if (!objectTypes[typeof iterable]) return result;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-        for (index in iterable) {
-          if (callback(iterable[index], index, collection) === false) return result;
-        }
-      return result
-    };
-
-    /**
-     * This method is like `_.forIn` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * Shape.prototype.move = function(x, y) {
-     *   this.x += x;
-     *   this.y += y;
-     * };
-     *
-     * _.forInRight(new Shape, function(value, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
-     */
-    function forInRight(object, callback, thisArg) {
-      var pairs = [];
-
-      forIn(object, function(value, key) {
-        pairs.push(key, value);
-      });
-
-      var length = pairs.length;
-      callback = baseCreateCallback(callback, thisArg, 3);
-      while (length--) {
-        if (callback(pairs[length--], pairs[length], object) === false) {
-          break;
-        }
-      }
-      return object;
-    }
-
-    /**
-     * Iterates over own enumerable properties of an object, executing the callback
-     * for each property. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, key, object). Callbacks may exit iteration early by
-     * explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
-     *   console.log(key);
-     * });
-     * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
-     */
-    var forOwn = function(collection, callback, thisArg) {
-      var index, iterable = collection, result = iterable;
-      if (!iterable) return result;
-      if (!objectTypes[typeof iterable]) return result;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (callback(iterable[index], index, collection) === false) return result;
-        }
-      return result
-    };
-
-    /**
-     * This method is like `_.forOwn` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
-     */
-    function forOwnRight(object, callback, thisArg) {
-      var props = keys(object),
-          length = props.length;
-
-      callback = baseCreateCallback(callback, thisArg, 3);
-      while (length--) {
-        var key = props[length];
-        if (callback(object[key], key, object) === false) {
-          break;
-        }
-      }
-      return object;
-    }
-
-    /**
-     * Creates a sorted array of property names of all enumerable properties,
-     * own and inherited, of `object` that have function values.
-     *
-     * @static
-     * @memberOf _
-     * @alias methods
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names that have function values.
-     * @example
-     *
-     * _.functions(_);
-     * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
-     */
-    function functions(object) {
-      var result = [];
-      forIn(object, function(value, key) {
-        if (isFunction(value)) {
-          result.push(key);
-        }
-      });
-      return result.sort();
-    }
-
-    /**
-     * Checks if the specified property name exists as a direct property of `object`,
-     * instead of an inherited property.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @param {string} key The name of the property to check.
-     * @returns {boolean} Returns `true` if key is a direct property, else `false`.
-     * @example
-     *
-     * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
-     * // => true
-     */
-    function has(object, key) {
-      return object ? hasOwnProperty.call(object, key) : false;
-    }
-
-    /**
-     * Creates an object composed of the inverted keys and values of the given object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to invert.
-     * @returns {Object} Returns the created inverted object.
-     * @example
-     *
-     * _.invert({ 'first': 'fred', 'second': 'barney' });
-     * // => { 'fred': 'first', 'barney': 'second' }
-     */
-    function invert(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = {};
-
-      while (++index < length) {
-        var key = props[index];
-        result[object[key]] = key;
-      }
-      return result;
-    }
-
-    /**
-     * Checks if `value` is a boolean value.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
-     * @example
-     *
-     * _.isBoolean(null);
-     * // => false
-     */
-    function isBoolean(value) {
-      return value === true || value === false ||
-        value && typeof value == 'object' && toString.call(value) == boolClass || false;
-    }
-
-    /**
-     * Checks if `value` is a date.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
-     * @example
-     *
-     * _.isDate(new Date);
-     * // => true
-     */
-    function isDate(value) {
-      return value && typeof value == 'object' && toString.call(value) == dateClass || false;
-    }
-
-    /**
-     * Checks if `value` is a DOM element.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
-     * @example
-     *
-     * _.isElement(document.body);
-     * // => true
-     */
-    function isElement(value) {
-      return value && value.nodeType === 1 || false;
-    }
-
-    /**
-     * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
-     * length of `0` and objects with no own enumerable properties are considered
-     * "empty".
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Array|Object|string} value The value to inspect.
-     * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
-     * @example
-     *
-     * _.isEmpty([1, 2, 3]);
-     * // => false
-     *
-     * _.isEmpty({});
-     * // => true
-     *
-     * _.isEmpty('');
-     * // => true
-     */
-    function isEmpty(value) {
-      var result = true;
-      if (!value) {
-        return result;
-      }
-      var className = toString.call(value),
-          length = value.length;
-
-      if ((className == arrayClass || className == stringClass || className == argsClass ) ||
-          (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
-        return !length;
-      }
-      forOwn(value, function() {
-        return (result = false);
-      });
-      return result;
-    }
-
-    /**
-     * Performs a deep comparison between two values to determine if they are
-     * equivalent to each other. If a callback is provided it will be executed
-     * to compare values. If the callback returns `undefined` comparisons will
-     * be handled by the method instead. The callback is bound to `thisArg` and
-     * invoked with two arguments; (a, b).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} a The value to compare.
-     * @param {*} b The other value to compare.
-     * @param {Function} [callback] The function to customize comparing values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * var copy = { 'name': 'fred' };
-     *
-     * object == copy;
-     * // => false
-     *
-     * _.isEqual(object, copy);
-     * // => true
-     *
-     * var words = ['hello', 'goodbye'];
-     * var otherWords = ['hi', 'goodbye'];
-     *
-     * _.isEqual(words, otherWords, function(a, b) {
-     *   var reGreet = /^(?:hello|hi)$/i,
-     *       aGreet = _.isString(a) && reGreet.test(a),
-     *       bGreet = _.isString(b) && reGreet.test(b);
-     *
-     *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
-     * });
-     * // => true
-     */
-    function isEqual(a, b, callback, thisArg) {
-      return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
-    }
-
-    /**
-     * Checks if `value` is, or can be coerced to, a finite number.
-     *
-     * Note: This is not the same as native `isFinite` which will return true for
-     * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
-     * @example
-     *
-     * _.isFinite(-101);
-     * // => true
-     *
-     * _.isFinite('10');
-     * // => true
-     *
-     * _.isFinite(true);
-     * // => false
-     *
-     * _.isFinite('');
-     * // => false
-     *
-     * _.isFinite(Infinity);
-     * // => false
-     */
-    function isFinite(value) {
-      return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
-    }
-
-    /**
-     * Checks if `value` is a function.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
-     * @example
-     *
-     * _.isFunction(_);
-     * // => true
-     */
-    function isFunction(value) {
-      return typeof value == 'function';
-    }
-
-    /**
-     * Checks if `value` is the language type of Object.
-     * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
-     * @example
-     *
-     * _.isObject({});
-     * // => true
-     *
-     * _.isObject([1, 2, 3]);
-     * // => true
-     *
-     * _.isObject(1);
-     * // => false
-     */
-    function isObject(value) {
-      // check if the value is the ECMAScript language type of Object
-      // http://es5.github.io/#x8
-      // and avoid a V8 bug
-      // http://code.google.com/p/v8/issues/detail?id=2291
-      return !!(value && objectTypes[typeof value]);
-    }
-
-    /**
-     * Checks if `value` is `NaN`.
-     *
-     * Note: This is not the same as native `isNaN` which will return `true` for
-     * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
-     * @example
-     *
-     * _.isNaN(NaN);
-     * // => true
-     *
-     * _.isNaN(new Number(NaN));
-     * // => true
-     *
-     * isNaN(undefined);
-     * // => true
-     *
-     * _.isNaN(undefined);
-     * // => false
-     */
-    function isNaN(value) {
-      // `NaN` as a primitive is the only value that is not equal to itself
-      // (perform the [[Class]] check first to avoid errors with some host objects in IE)
-      return isNumber(value) && value != +value;
-    }
-
-    /**
-     * Checks if `value` is `null`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
-     * @example
-     *
-     * _.isNull(null);
-     * // => true
-     *
-     * _.isNull(undefined);
-     * // => false
-     */
-    function isNull(value) {
-      return value === null;
-    }
-
-    /**
-     * Checks if `value` is a number.
-     *
-     * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
-     * @example
-     *
-     * _.isNumber(8.4 * 5);
-     * // => true
-     */
-    function isNumber(value) {
-      return typeof value == 'number' ||
-        value && typeof value == 'object' && toString.call(value) == numberClass || false;
-    }
-
-    /**
-     * Checks if `value` is an object created by the `Object` constructor.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * _.isPlainObject(new Shape);
-     * // => false
-     *
-     * _.isPlainObject([1, 2, 3]);
-     * // => false
-     *
-     * _.isPlainObject({ 'x': 0, 'y': 0 });
-     * // => true
-     */
-    var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
-      if (!(value && toString.call(value) == objectClass)) {
-        return false;
-      }
-      var valueOf = value.valueOf,
-          objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
-
-      return objProto
-        ? (value == objProto || getPrototypeOf(value) == objProto)
-        : shimIsPlainObject(value);
-    };
-
-    /**
-     * Checks if `value` is a regular expression.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
-     * @example
-     *
-     * _.isRegExp(/fred/);
-     * // => true
-     */
-    function isRegExp(value) {
-      return value && typeof value == 'object' && toString.call(value) == regexpClass || false;
-    }
-
-    /**
-     * Checks if `value` is a string.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
-     * @example
-     *
-     * _.isString('fred');
-     * // => true
-     */
-    function isString(value) {
-      return typeof value == 'string' ||
-        value && typeof value == 'object' && toString.call(value) == stringClass || false;
-    }
-
-    /**
-     * Checks if `value` is `undefined`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
-     * @example
-     *
-     * _.isUndefined(void 0);
-     * // => true
-     */
-    function isUndefined(value) {
-      return typeof value == 'undefined';
-    }
-
-    /**
-     * Creates an object with the same keys as `object` and values generated by
-     * running each own enumerable property of `object` through the callback.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new object with values of the results of each `callback` execution.
-     * @example
-     *
-     * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     *
-     * var characters = {
-     *   'fred': { 'name': 'fred', 'age': 40 },
-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
-     * };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.mapValues(characters, 'age');
-     * // => { 'fred': 40, 'pebbles': 1 }
-     */
-    function mapValues(object, callback, thisArg) {
-      var result = {};
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      forOwn(object, function(value, key, object) {
-        result[key] = callback(value, key, object);
-      });
-      return result;
-    }
-
-    /**
-     * Recursively merges own enumerable properties of the source object(s), that
-     * don't resolve to `undefined` into the destination object. Subsequent sources
-     * will overwrite property assignments of previous sources. If a callback is
-     * provided it will be executed to produce the merged values of the destination
-     * and source properties. If the callback returns `undefined` merging will
-     * be handled by the method instead. The callback is bound to `thisArg` and
-     * invoked with two arguments; (objectValue, sourceValue).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param {Function} [callback] The function to customize merging properties.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * var names = {
-     *   'characters': [
-     *     { 'name': 'barney' },
-     *     { 'name': 'fred' }
-     *   ]
-     * };
-     *
-     * var ages = {
-     *   'characters': [
-     *     { 'age': 36 },
-     *     { 'age': 40 }
-     *   ]
-     * };
-     *
-     * _.merge(names, ages);
-     * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
-     *
-     * var food = {
-     *   'fruits': ['apple'],
-     *   'vegetables': ['beet']
-     * };
-     *
-     * var otherFood = {
-     *   'fruits': ['banana'],
-     *   'vegetables': ['carrot']
-     * };
-     *
-     * _.merge(food, otherFood, function(a, b) {
-     *   return _.isArray(a) ? a.concat(b) : undefined;
-     * });
-     * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
-     */
-    function merge(object) {
-      var args = arguments,
-          length = 2;
-
-      if (!isObject(object)) {
-        return object;
-      }
-      // allows working with `_.reduce` and `_.reduceRight` without using
-      // their `index` and `collection` arguments
-      if (typeof args[2] != 'number') {
-        length = args.length;
-      }
-      if (length > 3 && typeof args[length - 2] == 'function') {
-        var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
-      } else if (length > 2 && typeof args[length - 1] == 'function') {
-        callback = args[--length];
-      }
-      var sources = slice(arguments, 1, length),
-          index = -1,
-          stackA = getArray(),
-          stackB = getArray();
-
-      while (++index < length) {
-        baseMerge(object, sources[index], callback, stackA, stackB);
-      }
-      releaseArray(stackA);
-      releaseArray(stackB);
-      return object;
-    }
-
-    /**
-     * Creates a shallow clone of `object` excluding the specified properties.
-     * Property names may be specified as individual arguments or as arrays of
-     * property names. If a callback is provided it will be executed for each
-     * property of `object` omitting the properties the callback returns truey
-     * for. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The source object.
-     * @param {Function|...string|string[]} [callback] The properties to omit or the
-     *  function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns an object without the omitted properties.
-     * @example
-     *
-     * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
-     * // => { 'name': 'fred' }
-     *
-     * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
-     *   return typeof value == 'number';
-     * });
-     * // => { 'name': 'fred' }
-     */
-    function omit(object, callback, thisArg) {
-      var result = {};
-      if (typeof callback != 'function') {
-        var props = [];
-        forIn(object, function(value, key) {
-          props.push(key);
-        });
-        props = baseDifference(props, baseFlatten(arguments, true, false, 1));
-
-        var index = -1,
-            length = props.length;
-
-        while (++index < length) {
-          var key = props[index];
-          result[key] = object[key];
-        }
-      } else {
-        callback = lodash.createCallback(callback, thisArg, 3);
-        forIn(object, function(value, key, object) {
-          if (!callback(value, key, object)) {
-            result[key] = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Creates a two dimensional array of an object's key-value pairs,
-     * i.e. `[[key1, value1], [key2, value2]]`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns new array of key-value pairs.
-     * @example
-     *
-     * _.pairs({ 'barney': 36, 'fred': 40 });
-     * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
-     */
-    function pairs(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = Array(length);
-
-      while (++index < length) {
-        var key = props[index];
-        result[index] = [key, object[key]];
-      }
-      return result;
-    }
-
-    /**
-     * Creates a shallow clone of `object` composed of the specified properties.
-     * Property names may be specified as individual arguments or as arrays of
-     * property names. If a callback is provided it will be executed for each
-     * property of `object` picking the properties the callback returns truey
-     * for. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The source object.
-     * @param {Function|...string|string[]} [callback] The function called per
-     *  iteration or property names to pick, specified as individual property
-     *  names or arrays of property names.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns an object composed of the picked properties.
-     * @example
-     *
-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
-     * // => { 'name': 'fred' }
-     *
-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
-     *   return key.charAt(0) != '_';
-     * });
-     * // => { 'name': 'fred' }
-     */
-    function pick(object, callback, thisArg) {
-      var result = {};
-      if (typeof callback != 'function') {
-        var index = -1,
-            props = baseFlatten(arguments, true, false, 1),
-            length = isObject(object) ? props.length : 0;
-
-        while (++index < length) {
-          var key = props[index];
-          if (key in object) {
-            result[key] = object[key];
-          }
-        }
-      } else {
-        callback = lodash.createCallback(callback, thisArg, 3);
-        forIn(object, function(value, key, object) {
-          if (callback(value, key, object)) {
-            result[key] = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * An alternative to `_.reduce` this method transforms `object` to a new
-     * `accumulator` object which is the result of running each of its own
-     * enumerable properties through a callback, with each callback execution
-     * potentially mutating the `accumulator` object. The callback is bound to
-     * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
-     * Callbacks may exit iteration early by explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Array|Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] The custom accumulator value.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
-     *   num *= num;
-     *   if (num % 2) {
-     *     return result.push(num) < 3;
-     *   }
-     * });
-     * // => [1, 9, 25]
-     *
-     * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
-     *   result[key] = num * 3;
-     * });
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     */
-    function transform(object, callback, accumulator, thisArg) {
-      var isArr = isArray(object);
-      if (accumulator == null) {
-        if (isArr) {
-          accumulator = [];
-        } else {
-          var ctor = object && object.constructor,
-              proto = ctor && ctor.prototype;
-
-          accumulator = baseCreate(proto);
-        }
-      }
-      if (callback) {
-        callback = lodash.createCallback(callback, thisArg, 4);
-        (isArr ? forEach : forOwn)(object, function(value, index, object) {
-          return callback(accumulator, value, index, object);
-        });
-      }
-      return accumulator;
-    }
-
-    /**
-     * Creates an array composed of the own enumerable property values of `object`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property values.
-     * @example
-     *
-     * _.values({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => [1, 2, 3] (property order is not guaranteed across environments)
-     */
-    function values(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = Array(length);
-
-      while (++index < length) {
-        result[index] = object[props[index]];
-      }
-      return result;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates an array of elements from the specified indexes, or keys, of the
-     * `collection`. Indexes may be specified as individual arguments or as arrays
-     * of indexes.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
-     *   to retrieve, specified as individual indexes or arrays of indexes.
-     * @returns {Array} Returns a new array of elements corresponding to the
-     *  provided indexes.
-     * @example
-     *
-     * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
-     * // => ['a', 'c', 'e']
-     *
-     * _.at(['fred', 'barney', 'pebbles'], 0, 2);
-     * // => ['fred', 'pebbles']
-     */
-    function at(collection) {
-      var args = arguments,
-          index = -1,
-          props = baseFlatten(args, true, false, 1),
-          length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
-          result = Array(length);
-
-      while(++index < length) {
-        result[index] = collection[props[index]];
-      }
-      return result;
-    }
-
-    /**
-     * Checks if a given value is present in a collection using strict equality
-     * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
-     * offset from the end of the collection.
-     *
-     * @static
-     * @memberOf _
-     * @alias include
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {*} target The value to check for.
-     * @param {number} [fromIndex=0] The index to search from.
-     * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
-     * @example
-     *
-     * _.contains([1, 2, 3], 1);
-     * // => true
-     *
-     * _.contains([1, 2, 3], 1, 2);
-     * // => false
-     *
-     * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
-     * // => true
-     *
-     * _.contains('pebbles', 'eb');
-     * // => true
-     */
-    function contains(collection, target, fromIndex) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = collection ? collection.length : 0,
-          result = false;
-
-      fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
-      if (isArray(collection)) {
-        result = indexOf(collection, target, fromIndex) > -1;
-      } else if (typeof length == 'number') {
-        result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
-      } else {
-        forOwn(collection, function(value) {
-          if (++index >= fromIndex) {
-            return !(result = value === target);
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of `collection` through the callback. The corresponding value
-     * of each key is the number of times the key was returned by the callback.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
-     * // => { '4': 1, '6': 2 }
-     *
-     * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-     * // => { '4': 1, '6': 2 }
-     *
-     * _.countBy(['one', 'two', 'three'], 'length');
-     * // => { '3': 2, '5': 1 }
-     */
-    var countBy = createAggregator(function(result, value, key) {
-      (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
-    });
-
-    /**
-     * Checks if the given callback returns truey value for **all** elements of
-     * a collection. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias all
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if all elements passed the callback check,
-     *  else `false`.
-     * @example
-     *
-     * _.every([true, 1, null, 'yes']);
-     * // => false
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.every(characters, 'age');
-     * // => true
-     *
-     * // using "_.where" callback shorthand
-     * _.every(characters, { 'age': 36 });
-     * // => false
-     */
-    function every(collection, callback, thisArg) {
-      var result = true;
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if (!(result = !!callback(collection[index], index, collection))) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          return (result = !!callback(value, index, collection));
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, returning an array of all elements
-     * the callback returns truey for. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias select
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of elements that passed the callback check.
-     * @example
-     *
-     * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-     * // => [2, 4, 6]
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.filter(characters, 'blocked');
-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
-     *
-     * // using "_.where" callback shorthand
-     * _.filter(characters, { 'age': 36 });
-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-     */
-    function filter(collection, callback, thisArg) {
-      var result = [];
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          var value = collection[index];
-          if (callback(value, index, collection)) {
-            result.push(value);
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          if (callback(value, index, collection)) {
-            result.push(value);
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, returning the first element that
-     * the callback returns truey for. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias detect, findWhere
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the found element, else `undefined`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
-     * ];
-     *
-     * _.find(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => { 'name': 'barney', 'age': 36, 'blocked': false }
-     *
-     * // using "_.where" callback shorthand
-     * _.find(characters, { 'age': 1 });
-     * // =>  { 'name': 'pebbles', 'age': 1, 'blocked': false }
-     *
-     * // using "_.pluck" callback shorthand
-     * _.find(characters, 'blocked');
-     * // => { 'name': 'fred', 'age': 40, 'blocked': true }
-     */
-    function find(collection, callback, thisArg) {
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          var value = collection[index];
-          if (callback(value, index, collection)) {
-            return value;
-          }
-        }
-      } else {
-        var result;
-        forOwn(collection, function(value, index, collection) {
-          if (callback(value, index, collection)) {
-            result = value;
-            return false;
-          }
-        });
-        return result;
-      }
-    }
-
-    /**
-     * This method is like `_.find` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the found element, else `undefined`.
-     * @example
-     *
-     * _.findLast([1, 2, 3, 4], function(num) {
-     *   return num % 2 == 1;
-     * });
-     * // => 3
-     */
-    function findLast(collection, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forEachRight(collection, function(value, index, collection) {
-        if (callback(value, index, collection)) {
-          result = value;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, executing the callback for each
-     * element. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection). Callbacks may exit iteration early by
-     * explicitly returning `false`.
-     *
-     * Note: As with other "Collections" methods, objects with a `length` property
-     * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
-     * may be used for object iteration.
-     *
-     * @static
-     * @memberOf _
-     * @alias each
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array|Object|string} Returns `collection`.
-     * @example
-     *
-     * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
-     * // => logs each number and returns '1,2,3'
-     *
-     * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
-     * // => logs each number and returns the object (property order is not guaranteed across environments)
-     */
-    function forEach(collection, callback, thisArg) {
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if (callback(collection[index], index, collection) === false) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, callback);
-      }
-      return collection;
-    }
-
-    /**
-     * This method is like `_.forEach` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @alias eachRight
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array|Object|string} Returns `collection`.
-     * @example
-     *
-     * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
-     * // => logs each number from right to left and returns '3,2,1'
-     */
-    function forEachRight(collection, callback, thisArg) {
-      var length = collection ? collection.length : 0;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        while (length--) {
-          if (callback(collection[length], length, collection) === false) {
-            break;
-          }
-        }
-      } else {
-        var props = keys(collection);
-        length = props.length;
-        forOwn(collection, function(value, key, collection) {
-          key = props ? props[--length] : --length;
-          return callback(collection[key], key, collection);
-        });
-      }
-      return collection;
-    }
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of a collection through the callback. The corresponding value
-     * of each key is an array of the elements responsible for generating the key.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
-     * // => { '4': [4.2], '6': [6.1, 6.4] }
-     *
-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-     * // => { '4': [4.2], '6': [6.1, 6.4] }
-     *
-     * // using "_.pluck" callback shorthand
-     * _.groupBy(['one', 'two', 'three'], 'length');
-     * // => { '3': ['one', 'two'], '5': ['three'] }
-     */
-    var groupBy = createAggregator(function(result, value, key) {
-      (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
-    });
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of the collection through the given callback. The corresponding
-     * value of each key is the last element responsible for generating the key.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * var keys = [
-     *   { 'dir': 'left', 'code': 97 },
-     *   { 'dir': 'right', 'code': 100 }
-     * ];
-     *
-     * _.indexBy(keys, 'dir');
-     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
-     *
-     * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
-     *
-     * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
-     */
-    var indexBy = createAggregator(function(result, value, key) {
-      result[key] = value;
-    });
-
-    /**
-     * Invokes the method named by `methodName` on each element in the `collection`
-     * returning an array of the results of each invoked method. Additional arguments
-     * will be provided to each invoked method. If `methodName` is a function it
-     * will be invoked for, and `this` bound to, each element in the `collection`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|string} methodName The name of the method to invoke or
-     *  the function invoked per iteration.
-     * @param {...*} [arg] Arguments to invoke the method with.
-     * @returns {Array} Returns a new array of the results of each invoked method.
-     * @example
-     *
-     * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
-     * // => [[1, 5, 7], [1, 2, 3]]
-     *
-     * _.invoke([123, 456], String.prototype.split, '');
-     * // => [['1', '2', '3'], ['4', '5', '6']]
-     */
-    function invoke(collection, methodName) {
-      var args = slice(arguments, 2),
-          index = -1,
-          isFunc = typeof methodName == 'function',
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      forEach(collection, function(value) {
-        result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
-      });
-      return result;
-    }
-
-    /**
-     * Creates an array of values by running each element in the collection
-     * through the callback. The callback is bound to `thisArg` and invoked with
-     * three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias collect
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of the results of each `callback` execution.
-     * @example
-     *
-     * _.map([1, 2, 3], function(num) { return num * 3; });
-     * // => [3, 6, 9]
-     *
-     * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
-     * // => [3, 6, 9] (property order is not guaranteed across environments)
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.map(characters, 'name');
-     * // => ['barney', 'fred']
-     */
-    function map(collection, callback, thisArg) {
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        var result = Array(length);
-        while (++index < length) {
-          result[index] = callback(collection[index], index, collection);
-        }
-      } else {
-        result = [];
-        forOwn(collection, function(value, key, collection) {
-          result[++index] = callback(value, key, collection);
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the maximum value of a collection. If the collection is empty or
-     * falsey `-Infinity` is returned. If a callback is provided it will be executed
-     * for each value in the collection to generate the criterion by which the value
-     * is ranked. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the maximum value.
-     * @example
-     *
-     * _.max([4, 2, 8, 6]);
-     * // => 8
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.max(characters, function(chr) { return chr.age; });
-     * // => { 'name': 'fred', 'age': 40 };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.max(characters, 'age');
-     * // => { 'name': 'fred', 'age': 40 };
-     */
-    function max(collection, callback, thisArg) {
-      var computed = -Infinity,
-          result = computed;
-
-      // allows working with functions like `_.map` without using
-      // their `index` argument as a callback
-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
-        callback = null;
-      }
-      if (callback == null && isArray(collection)) {
-        var index = -1,
-            length = collection.length;
-
-        while (++index < length) {
-          var value = collection[index];
-          if (value > result) {
-            result = value;
-          }
-        }
-      } else {
-        callback = (callback == null && isString(collection))
-          ? charAtCallback
-          : lodash.createCallback(callback, thisArg, 3);
-
-        forEach(collection, function(value, index, collection) {
-          var current = callback(value, index, collection);
-          if (current > computed) {
-            computed = current;
-            result = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the minimum value of a collection. If the collection is empty or
-     * falsey `Infinity` is returned. If a callback is provided it will be executed
-     * for each value in the collection to generate the criterion by which the value
-     * is ranked. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the minimum value.
-     * @example
-     *
-     * _.min([4, 2, 8, 6]);
-     * // => 2
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.min(characters, function(chr) { return chr.age; });
-     * // => { 'name': 'barney', 'age': 36 };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.min(characters, 'age');
-     * // => { 'name': 'barney', 'age': 36 };
-     */
-    function min(collection, callback, thisArg) {
-      var computed = Infinity,
-          result = computed;
-
-      // allows working with functions like `_.map` without using
-      // their `index` argument as a callback
-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
-        callback = null;
-      }
-      if (callback == null && isArray(collection)) {
-        var index = -1,
-            length = collection.length;
-
-        while (++index < length) {
-          var value = collection[index];
-          if (value < result) {
-            result = value;
-          }
-        }
-      } else {
-        callback = (callback == null && isString(collection))
-          ? charAtCallback
-          : lodash.createCallback(callback, thisArg, 3);
-
-        forEach(collection, function(value, index, collection) {
-          var current = callback(value, index, collection);
-          if (current < computed) {
-            computed = current;
-            result = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the value of a specified property from all elements in the collection.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {string} property The name of the property to pluck.
-     * @returns {Array} Returns a new array of property values.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.pluck(characters, 'name');
-     * // => ['barney', 'fred']
-     */
-    var pluck = map;
-
-    /**
-     * Reduces a collection to a value which is the accumulated result of running
-     * each element in the collection through the callback, where each successive
-     * callback execution consumes the return value of the previous execution. If
-     * `accumulator` is not provided the first element of the collection will be
-     * used as the initial `accumulator` value. The callback is bound to `thisArg`
-     * and invoked with four arguments; (accumulator, value, index|key, collection).
-     *
-     * @static
-     * @memberOf _
-     * @alias foldl, inject
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] Initial value of the accumulator.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var sum = _.reduce([1, 2, 3], function(sum, num) {
-     *   return sum + num;
-     * });
-     * // => 6
-     *
-     * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
-     *   result[key] = num * 3;
-     *   return result;
-     * }, {});
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     */
-    function reduce(collection, callback, accumulator, thisArg) {
-      if (!collection) return accumulator;
-      var noaccum = arguments.length < 3;
-      callback = lodash.createCallback(callback, thisArg, 4);
-
-      var index = -1,
-          length = collection.length;
-
-      if (typeof length == 'number') {
-        if (noaccum) {
-          accumulator = collection[++index];
-        }
-        while (++index < length) {
-          accumulator = callback(accumulator, collection[index], index, collection);
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          accumulator = noaccum
-            ? (noaccum = false, value)
-            : callback(accumulator, value, index, collection)
-        });
-      }
-      return accumulator;
-    }
-
-    /**
-     * This method is like `_.reduce` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @alias foldr
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] Initial value of the accumulator.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var list = [[0, 1], [2, 3], [4, 5]];
-     * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
-     * // => [4, 5, 2, 3, 0, 1]
-     */
-    function reduceRight(collection, callback, accumulator, thisArg) {
-      var noaccum = arguments.length < 3;
-      callback = lodash.createCallback(callback, thisArg, 4);
-      forEachRight(collection, function(value, index, collection) {
-        accumulator = noaccum
-          ? (noaccum = false, value)
-          : callback(accumulator, value, index, collection);
-      });
-      return accumulator;
-    }
-
-    /**
-     * The opposite of `_.filter` this method returns the elements of a
-     * collection that the callback does **not** return truey for.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of elements that failed the callback check.
-     * @example
-     *
-     * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-     * // => [1, 3, 5]
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.reject(characters, 'blocked');
-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-     *
-     * // using "_.where" callback shorthand
-     * _.reject(characters, { 'age': 36 });
-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
-     */
-    function reject(collection, callback, thisArg) {
-      callback = lodash.createCallback(callback, thisArg, 3);
-      return filter(collection, function(value, index, collection) {
-        return !callback(value, index, collection);
-      });
-    }
-
-    /**
-     * Retrieves a random element or `n` random elements from a collection.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to sample.
-     * @param {number} [n] The number of elements to sample.
-     * @param- {Object} [guard] Allows working with functions like `_.map`
-     *  without using their `index` arguments as `n`.
-     * @returns {Array} Returns the random sample(s) of `collection`.
-     * @example
-     *
-     * _.sample([1, 2, 3, 4]);
-     * // => 2
-     *
-     * _.sample([1, 2, 3, 4], 2);
-     * // => [3, 1]
-     */
-    function sample(collection, n, guard) {
-      if (collection && typeof collection.length != 'number') {
-        collection = values(collection);
-      }
-      if (n == null || guard) {
-        return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
-      }
-      var result = shuffle(collection);
-      result.length = nativeMin(nativeMax(0, n), result.length);
-      return result;
-    }
-
-    /**
-     * Creates an array of shuffled values, using a version of the Fisher-Yates
-     * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to shuffle.
-     * @returns {Array} Returns a new shuffled collection.
-     * @example
-     *
-     * _.shuffle([1, 2, 3, 4, 5, 6]);
-     * // => [4, 1, 6, 3, 5, 2]
-     */
-    function shuffle(collection) {
-      var index = -1,
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      forEach(collection, function(value) {
-        var rand = baseRandom(0, ++index);
-        result[index] = result[rand];
-        result[rand] = value;
-      });
-      return result;
-    }
-
-    /**
-     * Gets the size of the `collection` by returning `collection.length` for arrays
-     * and array-like objects or the number of own enumerable properties for objects.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to inspect.
-     * @returns {number} Returns `collection.length` or number of own enumerable properties.
-     * @example
-     *
-     * _.size([1, 2]);
-     * // => 2
-     *
-     * _.size({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => 3
-     *
-     * _.size('pebbles');
-     * // => 7
-     */
-    function size(collection) {
-      var length = collection ? collection.length : 0;
-      return typeof length == 'number' ? length : keys(collection).length;
-    }
-
-    /**
-     * Checks if the callback returns a truey value for **any** element of a
-     * collection. The function returns as soon as it finds a passing value and
-     * does not iterate over the entire collection. The callback is bound to
-     * `thisArg` and invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias any
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if any element passed the callback check,
-     *  else `false`.
-     * @example
-     *
-     * _.some([null, 0, 'yes', false], Boolean);
-     * // => true
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.some(characters, 'blocked');
-     * // => true
-     *
-     * // using "_.where" callback shorthand
-     * _.some(characters, { 'age': 1 });
-     * // => false
-     */
-    function some(collection, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if ((result = callback(collection[index], index, collection))) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          return !(result = callback(value, index, collection));
-        });
-      }
-      return !!result;
-    }
-
-    /**
-     * Creates an array of elements, sorted in ascending order by the results of
-     * running each element in a collection through the callback. This method
-     * performs a stable sort, that is, it will preserve the original sort order
-     * of equal elements. The callback is bound to `thisArg` and invoked with
-     * three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an array of property names is provided for `callback` the collection
-     * will be sorted by each property value.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Array|Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of sorted elements.
-     * @example
-     *
-     * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
-     * // => [3, 1, 2]
-     *
-     * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
-     * // => [3, 1, 2]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36 },
-     *   { 'name': 'fred',    'age': 40 },
-     *   { 'name': 'barney',  'age': 26 },
-     *   { 'name': 'fred',    'age': 30 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.map(_.sortBy(characters, 'age'), _.values);
-     * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
-     *
-     * // sorting by multiple properties
-     * _.map(_.sortBy(characters, ['name', 'age']), _.values);
-     * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
-     */
-    function sortBy(collection, callback, thisArg) {
-      var index = -1,
-          isArr = isArray(callback),
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      if (!isArr) {
-        callback = lodash.createCallback(callback, thisArg, 3);
-      }
-      forEach(collection, function(value, key, collection) {
-        var object = result[++index] = getObject();
-        if (isArr) {
-          object.criteria = map(callback, function(key) { return value[key]; });
-        } else {
-          (object.criteria = getArray())[0] = callback(value, key, collection);
-        }
-        object.index = index;
-        object.value = value;
-      });
-
-      length = result.length;
-      result.sort(compareAscending);
-      while (length--) {
-        var object = result[length];
-        result[length] = object.value;
-        if (!isArr) {
-          releaseArray(object.criteria);
-        }
-        releaseObject(object);
-      }
-      return result;
-    }
-
-    /**
-     * Converts the `collection` to an array.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to convert.
-     * @returns {Array} Returns the new converted array.
-     * @example
-     *
-     * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
-     * // => [2, 3, 4]
-     */
-    function toArray(collection) {
-      if (collection && typeof collection.length == 'number') {
-        return slice(collection);
-      }
-      return values(collection);
-    }
-
-    /**
-     * Performs a deep comparison of each element in a `collection` to the given
-     * `properties` object, returning an array of all elements that have equivalent
-     * property values.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Object} props The object of property values to filter by.
-     * @returns {Array} Returns a new array of elements that have the given properties.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
-     * ];
-     *
-     * _.where(characters, { 'age': 36 });
-     * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
-     *
-     * _.where(characters, { 'pets': ['dino'] });
-     * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
-     */
-    var where = filter;
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates an array with all falsey values removed. The values `false`, `null`,
-     * `0`, `""`, `undefined`, and `NaN` are all falsey.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to compact.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.compact([0, 1, false, 2, '', 3]);
-     * // => [1, 2, 3]
-     */
-    function compact(array) {
-      var index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      while (++index < length) {
-        var value = array[index];
-        if (value) {
-          result.push(value);
-        }
-      }
-      return result;
-    }
-
-    /**
-     * Creates an array excluding all values of the provided arrays using strict
-     * equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to process.
-     * @param {...Array} [values] The arrays of values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
-     * // => [1, 3, 4]
-     */
-    function difference(array) {
-      return baseDifference(array, baseFlatten(arguments, true, true, 1));
-    }
-
-    /**
-     * This method is like `_.find` except that it returns the index of the first
-     * element that passes the callback check, instead of the element itself.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index of the found element, else `-1`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
-     * ];
-     *
-     * _.findIndex(characters, function(chr) {
-     *   return chr.age < 20;
-     * });
-     * // => 2
-     *
-     * // using "_.where" callback shorthand
-     * _.findIndex(characters, { 'age': 36 });
-     * // => 0
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findIndex(characters, 'blocked');
-     * // => 1
-     */
-    function findIndex(array, callback, thisArg) {
-      var index = -1,
-          length = array ? array.length : 0;
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (++index < length) {
-        if (callback(array[index], index, array)) {
-          return index;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * This method is like `_.findIndex` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index of the found element, else `-1`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': true },
-     *   { 'name': 'fred',    'age': 40, 'blocked': false },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': true }
-     * ];
-     *
-     * _.findLastIndex(characters, function(chr) {
-     *   return chr.age > 30;
-     * });
-     * // => 1
-     *
-     * // using "_.where" callback shorthand
-     * _.findLastIndex(characters, { 'age': 36 });
-     * // => 0
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findLastIndex(characters, 'blocked');
-     * // => 2
-     */
-    function findLastIndex(array, callback, thisArg) {
-      var length = array ? array.length : 0;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (length--) {
-        if (callback(array[length], length, array)) {
-          return length;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * Gets the first element or first `n` elements of an array. If a callback
-     * is provided elements at the beginning of the array are returned as long
-     * as the callback returns truey. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias head, take
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback] The function called
-     *  per element or the number of elements to return. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the first element(s) of `array`.
-     * @example
-     *
-     * _.first([1, 2, 3]);
-     * // => 1
-     *
-     * _.first([1, 2, 3], 2);
-     * // => [1, 2]
-     *
-     * _.first([1, 2, 3], function(num) {
-     *   return num < 3;
-     * });
-     * // => [1, 2]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.first(characters, 'blocked');
-     * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
-     *
-     * // using "_.where" callback shorthand
-     * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
-     * // => ['barney', 'fred']
-     */
-    function first(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = -1;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (++index < length && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = callback;
-        if (n == null || thisArg) {
-          return array ? array[0] : undefined;
-        }
-      }
-      return slice(array, 0, nativeMin(nativeMax(0, n), length));
-    }
-
-    /**
-     * Flattens a nested array (the nesting can be to any depth). If `isShallow`
-     * is truey, the array will only be flattened a single level. If a callback
-     * is provided each element of the array is passed through the callback before
-     * flattening. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to flatten.
-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new flattened array.
-     * @example
-     *
-     * _.flatten([1, [2], [3, [[4]]]]);
-     * // => [1, 2, 3, 4];
-     *
-     * _.flatten([1, [2], [3, [[4]]]], true);
-     * // => [1, 2, 3, [[4]]];
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.flatten(characters, 'pets');
-     * // => ['hoppy', 'baby puss', 'dino']
-     */
-    function flatten(array, isShallow, callback, thisArg) {
-      // juggle arguments
-      if (typeof isShallow != 'boolean' && isShallow != null) {
-        thisArg = callback;
-        callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
-        isShallow = false;
-      }
-      if (callback != null) {
-        array = map(array, callback, thisArg);
-      }
-      return baseFlatten(array, isShallow);
-    }
-
-    /**
-     * Gets the index at which the first occurrence of `value` is found using
-     * strict equality for comparisons, i.e. `===`. If the array is already sorted
-     * providing `true` for `fromIndex` will run a faster binary search.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {*} value The value to search for.
-     * @param {boolean|number} [fromIndex=0] The index to search from or `true`
-     *  to perform a binary search on a sorted array.
-     * @returns {number} Returns the index of the matched value or `-1`.
-     * @example
-     *
-     * _.indexOf([1, 2, 3, 1, 2, 3], 2);
-     * // => 1
-     *
-     * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
-     * // => 4
-     *
-     * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
-     * // => 2
-     */
-    function indexOf(array, value, fromIndex) {
-      if (typeof fromIndex == 'number') {
-        var length = array ? array.length : 0;
-        fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
-      } else if (fromIndex) {
-        var index = sortedIndex(array, value);
-        return array[index] === value ? index : -1;
-      }
-      return baseIndexOf(array, value, fromIndex);
-    }
-
-    /**
-     * Gets all but the last element or last `n` elements of an array. If a
-     * callback is provided elements at the end of the array are excluded from
-     * the result as long as the callback returns truey. The callback is bound
-     * to `thisArg` and invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback=1] The function called
-     *  per element or the number of elements to exclude. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a slice of `array`.
-     * @example
-     *
-     * _.initial([1, 2, 3]);
-     * // => [1, 2]
-     *
-     * _.initial([1, 2, 3], 2);
-     * // => [1]
-     *
-     * _.initial([1, 2, 3], function(num) {
-     *   return num > 1;
-     * });
-     * // => [1]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.initial(characters, 'blocked');
-     * // => [{ 'name': 'barney',  'blocked': false, 'employer': 'slate' }]
-     *
-     * // using "_.where" callback shorthand
-     * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
-     * // => ['barney', 'fred']
-     */
-    function initial(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = length;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (index-- && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = (callback == null || thisArg) ? 1 : callback || n;
-      }
-      return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
-    }
-
-    /**
-     * Creates an array of unique values present in all provided arrays using
-     * strict equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of shared values.
-     * @example
-     *
-     * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-     * // => [1, 2]
-     */
-    function intersection() {
-      var args = [],
-          argsIndex = -1,
-          argsLength = arguments.length,
-          caches = getArray(),
-          indexOf = getIndexOf(),
-          trustIndexOf = indexOf === baseIndexOf,
-          seen = getArray();
-
-      while (++argsIndex < argsLength) {
-        var value = arguments[argsIndex];
-        if (isArray(value) || isArguments(value)) {
-          args.push(value);
-          caches.push(trustIndexOf && value.length >= largeArraySize &&
-            createCache(argsIndex ? args[argsIndex] : seen));
-        }
-      }
-      var array = args[0],
-          index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      outer:
-      while (++index < length) {
-        var cache = caches[0];
-        value = array[index];
-
-        if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
-          argsIndex = argsLength;
-          (cache || seen).push(value);
-          while (--argsIndex) {
-            cache = caches[argsIndex];
-            if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
-              continue outer;
-            }
-          }
-          result.push(value);
-        }
-      }
-      while (argsLength--) {
-        cache = caches[argsLength];
-        if (cache) {
-          releaseObject(cache);
-        }
-      }
-      releaseArray(caches);
-      releaseArray(seen);
-      return result;
-    }
-
-    /**
-     * Gets the last element or last `n` elements of an array. If a callback is
-     * provided elements at the end of the array are returned as long as the
-     * callback returns truey. The callback is bound to `thisArg` and invoked
-     * with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback] The function called
-     *  per element or the number of elements to return. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the last element(s) of `array`.
-     * @example
-     *
-     * _.last([1, 2, 3]);
-     * // => 3
-     *
-     * _.last([1, 2, 3], 2);
-     * // => [2, 3]
-     *
-     * _.last([1, 2, 3], function(num) {
-     *   return num > 1;
-     * });
-     * // => [2, 3]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.pluck(_.last(characters, 'blocked'), 'name');
-     * // => ['fred', 'pebbles']
-     *
-     * // using "_.where" callback shorthand
-     * _.last(characters, { 'employer': 'na' });
-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-     */
-    function last(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = length;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (index-- && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = callback;
-        if (n == null || thisArg) {
-          return array ? array[length - 1] : undefined;
-        }
-      }
-      return slice(array, nativeMax(0, length - n));
-    }
-
-    /**
-     * Gets the index at which the last occurrence of `value` is found using strict
-     * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
-     * as the offset from the end of the collection.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {*} value The value to search for.
-     * @param {number} [fromIndex=array.length-1] The index to search from.
-     * @returns {number} Returns the index of the matched value or `-1`.
-     * @example
-     *
-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
-     * // => 4
-     *
-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
-     * // => 1
-     */
-    function lastIndexOf(array, value, fromIndex) {
-      var index = array ? array.length : 0;
-      if (typeof fromIndex == 'number') {
-        index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
-      }
-      while (index--) {
-        if (array[index] === value) {
-          return index;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * Removes all provided values from the given array using strict equality for
-     * comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to modify.
-     * @param {...*} [value] The values to remove.
-     * @returns {Array} Returns `array`.
-     * @example
-     *
-     * var array = [1, 2, 3, 1, 2, 3];
-     * _.pull(array, 2, 3);
-     * console.log(array);
-     * // => [1, 1]
-     */
-    function pull(array) {
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = args.length,
-          length = array ? array.length : 0;
-
-      while (++argsIndex < argsLength) {
-        var index = -1,
-            value = args[argsIndex];
-        while (++index < length) {
-          if (array[index] === value) {
-            splice.call(array, index--, 1);
-            length--;
-          }
-        }
-      }
-      return array;
-    }
-
-    /**
-     * Creates an array of numbers (positive and/or negative) progressing from
-     * `start` up to but not including `end`. If `start` is less than `stop` a
-     * zero-length range is created unless a negative `step` is specified.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {number} [start=0] The start of the range.
-     * @param {number} end The end of the range.
-     * @param {number} [step=1] The value to increment or decrement by.
-     * @returns {Array} Returns a new range array.
-     * @example
-     *
-     * _.range(4);
-     * // => [0, 1, 2, 3]
-     *
-     * _.range(1, 5);
-     * // => [1, 2, 3, 4]
-     *
-     * _.range(0, 20, 5);
-     * // => [0, 5, 10, 15]
-     *
-     * _.range(0, -4, -1);
-     * // => [0, -1, -2, -3]
-     *
-     * _.range(1, 4, 0);
-     * // => [1, 1, 1]
-     *
-     * _.range(0);
-     * // => []
-     */
-    function range(start, end, step) {
-      start = +start || 0;
-      step = typeof step == 'number' ? step : (+step || 1);
-
-      if (end == null) {
-        end = start;
-        start = 0;
-      }
-      // use `Array(length)` so engines like Chakra and V8 avoid slower modes
-      // http://youtu.be/XAqIpGU8ZZk#t=17m25s
-      var index = -1,
-          length = nativeMax(0, ceil((end - start) / (step || 1))),
-          result = Array(length);
-
-      while (++index < length) {
-        result[index] = start;
-        start += step;
-      }
-      return result;
-    }
-
-    /**
-     * Removes all elements from an array that the callback returns truey for
-     * and returns an array of removed elements. The callback is bound to `thisArg`
-     * and invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to modify.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of removed elements.
-     * @example
-     *
-     * var array = [1, 2, 3, 4, 5, 6];
-     * var evens = _.remove(array, function(num) { return num % 2 == 0; });
-     *
-     * console.log(array);
-     * // => [1, 3, 5]
-     *
-     * console.log(evens);
-     * // => [2, 4, 6]
-     */
-    function remove(array, callback, thisArg) {
-      var index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (++index < length) {
-        var value = array[index];
-        if (callback(value, index, array)) {
-          result.push(value);
-          splice.call(array, index--, 1);
-          length--;
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The opposite of `_.initial` this method gets all but the first element or
-     * first `n` elements of an array. If a callback function is provided elements
-     * at the beginning of the array are excluded from the result as long as the
-     * callback returns truey. The callback is bound to `thisArg` and invoked
-     * with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias drop, tail
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback=1] The function called
-     *  per element or the number of elements to exclude. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a slice of `array`.
-     * @example
-     *
-     * _.rest([1, 2, 3]);
-     * // => [2, 3]
-     *
-     * _.rest([1, 2, 3], 2);
-     * // => [3]
-     *
-     * _.rest([1, 2, 3], function(num) {
-     *   return num < 3;
-     * });
-     * // => [3]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': false,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.pluck(_.rest(characters, 'blocked'), 'name');
-     * // => ['fred', 'pebbles']
-     *
-     * // using "_.where" callback shorthand
-     * _.rest(characters, { 'employer': 'slate' });
-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-     */
-    function rest(array, callback, thisArg) {
-      if (typeof callback != 'number' && callback != null) {
-        var n = 0,
-            index = -1,
-            length = array ? array.length : 0;
-
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (++index < length && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
-      }
-      return slice(array, n);
-    }
-
-    /**
-     * Uses a binary search to determine the smallest index at which a value
-     * should be inserted into a given sorted array in order to maintain the sort
-     * order of the array. If a callback is provided it will be executed for
-     * `value` and each element of `array` to compute their sort ranking. The
-     * callback is bound to `thisArg` and invoked with one argument; (value).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to inspect.
-     * @param {*} value The value to evaluate.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index at which `value` should be inserted
-     *  into `array`.
-     * @example
-     *
-     * _.sortedIndex([20, 30, 50], 40);
-     * // => 2
-     *
-     * // using "_.pluck" callback shorthand
-     * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
-     * // => 2
-     *
-     * var dict = {
-     *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
-     * };
-     *
-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
-     *   return dict.wordToNumber[word];
-     * });
-     * // => 2
-     *
-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
-     *   return this.wordToNumber[word];
-     * }, dict);
-     * // => 2
-     */
-    function sortedIndex(array, value, callback, thisArg) {
-      var low = 0,
-          high = array ? array.length : low;
-
-      // explicitly reference `identity` for better inlining in Firefox
-      callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
-      value = callback(value);
-
-      while (low < high) {
-        var mid = (low + high) >>> 1;
-        (callback(array[mid]) < value)
-          ? low = mid + 1
-          : high = mid;
-      }
-      return low;
-    }
-
-    /**
-     * Creates an array of unique values, in order, of the provided arrays using
-     * strict equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of combined values.
-     * @example
-     *
-     * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-     * // => [1, 2, 3, 5, 4]
-     */
-    function union() {
-      return baseUniq(baseFlatten(arguments, true, true));
-    }
-
-    /**
-     * Creates a duplicate-value-free version of an array using strict equality
-     * for comparisons, i.e. `===`. If the array is sorted, providing
-     * `true` for `isSorted` will use a faster algorithm. If a callback is provided
-     * each element of `array` is passed through the callback before uniqueness
-     * is computed. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias unique
-     * @category Arrays
-     * @param {Array} array The array to process.
-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a duplicate-value-free array.
-     * @example
-     *
-     * _.uniq([1, 2, 1, 3, 1]);
-     * // => [1, 2, 3]
-     *
-     * _.uniq([1, 1, 2, 2, 3], true);
-     * // => [1, 2, 3]
-     *
-     * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
-     * // => ['A', 'b', 'C']
-     *
-     * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
-     * // => [1, 2.5, 3]
-     *
-     * // using "_.pluck" callback shorthand
-     * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
-     * // => [{ 'x': 1 }, { 'x': 2 }]
-     */
-    function uniq(array, isSorted, callback, thisArg) {
-      // juggle arguments
-      if (typeof isSorted != 'boolean' && isSorted != null) {
-        thisArg = callback;
-        callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
-        isSorted = false;
-      }
-      if (callback != null) {
-        callback = lodash.createCallback(callback, thisArg, 3);
-      }
-      return baseUniq(array, isSorted, callback);
-    }
-
-    /**
-     * Creates an array excluding all provided values using strict equality for
-     * comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to filter.
-     * @param {...*} [value] The values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
-     * // => [2, 3, 4]
-     */
-    function without(array) {
-      return baseDifference(array, slice(arguments, 1));
-    }
-
-    /**
-     * Creates an array that is the symmetric difference of the provided arrays.
-     * See http://en.wikipedia.org/wiki/Symmetric_difference.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of values.
-     * @example
-     *
-     * _.xor([1, 2, 3], [5, 2, 1, 4]);
-     * // => [3, 5, 4]
-     *
-     * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
-     * // => [1, 4, 5]
-     */
-    function xor() {
-      var index = -1,
-          length = arguments.length;
-
-      while (++index < length) {
-        var array = arguments[index];
-        if (isArray(array) || isArguments(array)) {
-          var result = result
-            ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
-            : array;
-        }
-      }
-      return result || [];
-    }
-
-    /**
-     * Creates an array of grouped elements, the first of which contains the first
-     * elements of the given arrays, the second of which contains the second
-     * elements of the given arrays, and so on.
-     *
-     * @static
-     * @memberOf _
-     * @alias unzip
-     * @category Arrays
-     * @param {...Array} [array] Arrays to process.
-     * @returns {Array} Returns a new array of grouped elements.
-     * @example
-     *
-     * _.zip(['fred', 'barney'], [30, 40], [true, false]);
-     * // => [['fred', 30, true], ['barney', 40, false]]
-     */
-    function zip() {
-      var array = arguments.length > 1 ? arguments : arguments[0],
-          index = -1,
-          length = array ? max(pluck(array, 'length')) : 0,
-          result = Array(length < 0 ? 0 : length);
-
-      while (++index < length) {
-        result[index] = pluck(array, index);
-      }
-      return result;
-    }
-
-    /**
-     * Creates an object composed from arrays of `keys` and `values`. Provide
-     * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
-     * or two arrays, one of `keys` and one of corresponding `values`.
-     *
-     * @static
-     * @memberOf _
-     * @alias object
-     * @category Arrays
-     * @param {Array} keys The array of keys.
-     * @param {Array} [values=[]] The array of values.
-     * @returns {Object} Returns an object composed of the given keys and
-     *  corresponding values.
-     * @example
-     *
-     * _.zipObject(['fred', 'barney'], [30, 40]);
-     * // => { 'fred': 30, 'barney': 40 }
-     */
-    function zipObject(keys, values) {
-      var index = -1,
-          length = keys ? keys.length : 0,
-          result = {};
-
-      if (!values && length && !isArray(keys[0])) {
-        values = [];
-      }
-      while (++index < length) {
-        var key = keys[index];
-        if (values) {
-          result[key] = values[index];
-        } else if (key) {
-          result[key[0]] = key[1];
-        }
-      }
-      return result;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a function that executes `func`, with  the `this` binding and
-     * arguments of the created function, only after being called `n` times.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {number} n The number of times the function must be called before
-     *  `func` is executed.
-     * @param {Function} func The function to restrict.
-     * @returns {Function} Returns the new restricted function.
-     * @example
-     *
-     * var saves = ['profile', 'settings'];
-     *
-     * var done = _.after(saves.length, function() {
-     *   console.log('Done saving!');
-     * });
-     *
-     * _.forEach(saves, function(type) {
-     *   asyncSave({ 'type': type, 'complete': done });
-     * });
-     * // => logs 'Done saving!', after all saves have completed
-     */
-    function after(n, func) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      return function() {
-        if (--n < 1) {
-          return func.apply(this, arguments);
-        }
-      };
-    }
-
-    /**
-     * Creates a function that, when called, invokes `func` with the `this`
-     * binding of `thisArg` and prepends any additional `bind` arguments to those
-     * provided to the bound function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to bind.
-     * @param {*} [thisArg] The `this` binding of `func`.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new bound function.
-     * @example
-     *
-     * var func = function(greeting) {
-     *   return greeting + ' ' + this.name;
-     * };
-     *
-     * func = _.bind(func, { 'name': 'fred' }, 'hi');
-     * func();
-     * // => 'hi fred'
-     */
-    function bind(func, thisArg) {
-      return arguments.length > 2
-        ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
-        : createWrapper(func, 1, null, null, thisArg);
-    }
-
-    /**
-     * Binds methods of an object to the object itself, overwriting the existing
-     * method. Method names may be specified as individual arguments or as arrays
-     * of method names. If no method names are provided all the function properties
-     * of `object` will be bound.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Object} object The object to bind and assign the bound methods to.
-     * @param {...string} [methodName] The object method names to
-     *  bind, specified as individual method names or arrays of method names.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * var view = {
-     *   'label': 'docs',
-     *   'onClick': function() { console.log('clicked ' + this.label); }
-     * };
-     *
-     * _.bindAll(view);
-     * jQuery('#docs').on('click', view.onClick);
-     * // => logs 'clicked docs', when the button is clicked
-     */
-    function bindAll(object) {
-      var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
-          index = -1,
-          length = funcs.length;
-
-      while (++index < length) {
-        var key = funcs[index];
-        object[key] = createWrapper(object[key], 1, null, null, object);
-      }
-      return object;
-    }
-
-    /**
-     * Creates a function that, when called, invokes the method at `object[key]`
-     * and prepends any additional `bindKey` arguments to those provided to the bound
-     * function. This method differs from `_.bind` by allowing bound functions to
-     * reference methods that will be redefined or don't yet exist.
-     * See http://michaux.ca/articles/lazy-function-definition-pattern.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Object} object The object the method belongs to.
-     * @param {string} key The key of the method.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new bound function.
-     * @example
-     *
-     * var object = {
-     *   'name': 'fred',
-     *   'greet': function(greeting) {
-     *     return greeting + ' ' + this.name;
-     *   }
-     * };
-     *
-     * var func = _.bindKey(object, 'greet', 'hi');
-     * func();
-     * // => 'hi fred'
-     *
-     * object.greet = function(greeting) {
-     *   return greeting + 'ya ' + this.name + '!';
-     * };
-     *
-     * func();
-     * // => 'hiya fred!'
-     */
-    function bindKey(object, key) {
-      return arguments.length > 2
-        ? createWrapper(key, 19, slice(arguments, 2), null, object)
-        : createWrapper(key, 3, null, null, object);
-    }
-
-    /**
-     * Creates a function that is the composition of the provided functions,
-     * where each function consumes the return value of the function that follows.
-     * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
-     * Each function is executed with the `this` binding of the composed function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {...Function} [func] Functions to compose.
-     * @returns {Function} Returns the new composed function.
-     * @example
-     *
-     * var realNameMap = {
-     *   'pebbles': 'penelope'
-     * };
-     *
-     * var format = function(name) {
-     *   name = realNameMap[name.toLowerCase()] || name;
-     *   return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
-     * };
-     *
-     * var greet = function(formatted) {
-     *   return 'Hiya ' + formatted + '!';
-     * };
-     *
-     * var welcome = _.compose(greet, format);
-     * welcome('pebbles');
-     * // => 'Hiya Penelope!'
-     */
-    function compose() {
-      var funcs = arguments,
-          length = funcs.length;
-
-      while (length--) {
-        if (!isFunction(funcs[length])) {
-          throw new TypeError;
-        }
-      }
-      return function() {
-        var args = arguments,
-            length = funcs.length;
-
-        while (length--) {
-          args = [funcs[length].apply(this, args)];
-        }
-        return args[0];
-      };
-    }
-
-    /**
-     * Creates a function which accepts one or more arguments of `func` that when
-     * invoked either executes `func` returning its result, if all `func` arguments
-     * have been provided, or returns a function that accepts one or more of the
-     * remaining `func` arguments, and so on. The arity of `func` can be specified
-     * if `func.length` is not sufficient.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to curry.
-     * @param {number} [arity=func.length] The arity of `func`.
-     * @returns {Function} Returns the new curried function.
-     * @example
-     *
-     * var curried = _.curry(function(a, b, c) {
-     *   console.log(a + b + c);
-     * });
-     *
-     * curried(1)(2)(3);
-     * // => 6
-     *
-     * curried(1, 2)(3);
-     * // => 6
-     *
-     * curried(1, 2, 3);
-     * // => 6
-     */
-    function curry(func, arity) {
-      arity = typeof arity == 'number' ? arity : (+arity || func.length);
-      return createWrapper(func, 4, null, null, null, arity);
-    }
-
-    /**
-     * Creates a function that will delay the execution of `func` until after
-     * `wait` milliseconds have elapsed since the last time it was invoked.
-     * Provide an options object to indicate that `func` should be invoked on
-     * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
-     * to the debounced function will return the result of the last `func` call.
-     *
-     * Note: If `leading` and `trailing` options are `true` `func` will be called
-     * on the trailing edge of the timeout only if the the debounced function is
-     * invoked more than once during the `wait` timeout.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to debounce.
-     * @param {number} wait The number of milliseconds to delay.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
-     * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
-     * @returns {Function} Returns the new debounced function.
-     * @example
-     *
-     * // avoid costly calculations while the window size is in flux
-     * var lazyLayout = _.debounce(calculateLayout, 150);
-     * jQuery(window).on('resize', lazyLayout);
-     *
-     * // execute `sendMail` when the click event is fired, debouncing subsequent calls
-     * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
-     *   'leading': true,
-     *   'trailing': false
-     * });
-     *
-     * // ensure `batchLog` is executed once after 1 second of debounced calls
-     * var source = new EventSource('/stream');
-     * source.addEventListener('message', _.debounce(batchLog, 250, {
-     *   'maxWait': 1000
-     * }, false);
-     */
-    function debounce(func, wait, options) {
-      var args,
-          maxTimeoutId,
-          result,
-          stamp,
-          thisArg,
-          timeoutId,
-          trailingCall,
-          lastCalled = 0,
-          maxWait = false,
-          trailing = true;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      wait = nativeMax(0, wait) || 0;
-      if (options === true) {
-        var leading = true;
-        trailing = false;
-      } else if (isObject(options)) {
-        leading = options.leading;
-        maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
-        trailing = 'trailing' in options ? options.trailing : trailing;
-      }
-      var delayed = function() {
-        var remaining = wait - (now() - stamp);
-        if (remaining <= 0) {
-          if (maxTimeoutId) {
-            clearTimeout(maxTimeoutId);
-          }
-          var isCalled = trailingCall;
-          maxTimeoutId = timeoutId = trailingCall = undefined;
-          if (isCalled) {
-            lastCalled = now();
-            result = func.apply(thisArg, args);
-            if (!timeoutId && !maxTimeoutId) {
-              args = thisArg = null;
-            }
-          }
-        } else {
-          timeoutId = setTimeout(delayed, remaining);
-        }
-      };
-
-      var maxDelayed = function() {
-        if (timeoutId) {
-          clearTimeout(timeoutId);
-        }
-        maxTimeoutId = timeoutId = trailingCall = undefined;
-        if (trailing || (maxWait !== wait)) {
-          lastCalled = now();
-          result = func.apply(thisArg, args);
-          if (!timeoutId && !maxTimeoutId) {
-            args = thisArg = null;
-          }
-        }
-      };
-
-      return function() {
-        args = arguments;
-        stamp = now();
-        thisArg = this;
-        trailingCall = trailing && (timeoutId || !leading);
-
-        if (maxWait === false) {
-          var leadingCall = leading && !timeoutId;
-        } else {
-          if (!maxTimeoutId && !leading) {
-            lastCalled = stamp;
-          }
-          var remaining = maxWait - (stamp - lastCalled),
-              isCalled = remaining <= 0;
-
-          if (isCalled) {
-            if (maxTimeoutId) {
-              maxTimeoutId = clearTimeout(maxTimeoutId);
-            }
-            lastCalled = stamp;
-            result = func.apply(thisArg, args);
-          }
-          else if (!maxTimeoutId) {
-            maxTimeoutId = setTimeout(maxDelayed, remaining);
-          }
-        }
-        if (isCalled && timeoutId) {
-          timeoutId = clearTimeout(timeoutId);
-        }
-        else if (!timeoutId && wait !== maxWait) {
-          timeoutId = setTimeout(delayed, wait);
-        }
-        if (leadingCall) {
-          isCalled = true;
-          result = func.apply(thisArg, args);
-        }
-        if (isCalled && !timeoutId && !maxTimeoutId) {
-          args = thisArg = null;
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Defers executing the `func` function until the current call stack has cleared.
-     * Additional arguments will be provided to `func` when it is invoked.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to defer.
-     * @param {...*} [arg] Arguments to invoke the function with.
-     * @returns {number} Returns the timer id.
-     * @example
-     *
-     * _.defer(function(text) { console.log(text); }, 'deferred');
-     * // logs 'deferred' after one or more milliseconds
-     */
-    function defer(func) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var args = slice(arguments, 1);
-      return setTimeout(function() { func.apply(undefined, args); }, 1);
-    }
-
-    /**
-     * Executes the `func` function after `wait` milliseconds. Additional arguments
-     * will be provided to `func` when it is invoked.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to delay.
-     * @param {number} wait The number of milliseconds to delay execution.
-     * @param {...*} [arg] Arguments to invoke the function with.
-     * @returns {number} Returns the timer id.
-     * @example
-     *
-     * _.delay(function(text) { console.log(text); }, 1000, 'later');
-     * // => logs 'later' after one second
-     */
-    function delay(func, wait) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var args = slice(arguments, 2);
-      return setTimeout(function() { func.apply(undefined, args); }, wait);
-    }
-
-    /**
-     * Creates a function that memoizes the result of `func`. If `resolver` is
-     * provided it will be used to determine the cache key for storing the result
-     * based on the arguments provided to the memoized function. By default, the
-     * first argument provided to the memoized function is used as the cache key.
-     * The `func` is executed with the `this` binding of the memoized function.
-     * The result cache is exposed as the `cache` property on the memoized function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to have its output memoized.
-     * @param {Function} [resolver] A function used to resolve the cache key.
-     * @returns {Function} Returns the new memoizing function.
-     * @example
-     *
-     * var fibonacci = _.memoize(function(n) {
-     *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
-     * });
-     *
-     * fibonacci(9)
-     * // => 34
-     *
-     * var data = {
-     *   'fred': { 'name': 'fred', 'age': 40 },
-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
-     * };
-     *
-     * // modifying the result cache
-     * var get = _.memoize(function(name) { return data[name]; }, _.identity);
-     * get('pebbles');
-     * // => { 'name': 'pebbles', 'age': 1 }
-     *
-     * get.cache.pebbles.name = 'penelope';
-     * get('pebbles');
-     * // => { 'name': 'penelope', 'age': 1 }
-     */
-    function memoize(func, resolver) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var memoized = function() {
-        var cache = memoized.cache,
-            key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
-
-        return hasOwnProperty.call(cache, key)
-          ? cache[key]
-          : (cache[key] = func.apply(this, arguments));
-      }
-      memoized.cache = {};
-      return memoized;
-    }
-
-    /**
-     * Creates a function that is restricted to execute `func` once. Repeat calls to
-     * the function will return the value of the first call. The `func` is executed
-     * with the `this` binding of the created function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to restrict.
-     * @returns {Function} Returns the new restricted function.
-     * @example
-     *
-     * var initialize = _.once(createApplication);
-     * initialize();
-     * initialize();
-     * // `initialize` executes `createApplication` once
-     */
-    function once(func) {
-      var ran,
-          result;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      return function() {
-        if (ran) {
-          return result;
-        }
-        ran = true;
-        result = func.apply(this, arguments);
-
-        // clear the `func` variable so the function may be garbage collected
-        func = null;
-        return result;
-      };
-    }
-
-    /**
-     * Creates a function that, when called, invokes `func` with any additional
-     * `partial` arguments prepended to those provided to the new function. This
-     * method is similar to `_.bind` except it does **not** alter the `this` binding.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to partially apply arguments to.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new partially applied function.
-     * @example
-     *
-     * var greet = function(greeting, name) { return greeting + ' ' + name; };
-     * var hi = _.partial(greet, 'hi');
-     * hi('fred');
-     * // => 'hi fred'
-     */
-    function partial(func) {
-      return createWrapper(func, 16, slice(arguments, 1));
-    }
-
-    /**
-     * This method is like `_.partial` except that `partial` arguments are
-     * appended to those provided to the new function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to partially apply arguments to.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new partially applied function.
-     * @example
-     *
-     * var defaultsDeep = _.partialRight(_.merge, _.defaults);
-     *
-     * var options = {
-     *   'variable': 'data',
-     *   'imports': { 'jq': $ }
-     * };
-     *
-     * defaultsDeep(options, _.templateSettings);
-     *
-     * options.variable
-     * // => 'data'
-     *
-     * options.imports
-     * // => { '_': _, 'jq': $ }
-     */
-    function partialRight(func) {
-      return createWrapper(func, 32, null, slice(arguments, 1));
-    }
-
-    /**
-     * Creates a function that, when executed, will only call the `func` function
-     * at most once per every `wait` milliseconds. Provide an options object to
-     * indicate that `func` should be invoked on the leading and/or trailing edge
-     * of the `wait` timeout. Subsequent calls to the throttled function will
-     * return the result of the last `func` call.
-     *
-     * Note: If `leading` and `trailing` options are `true` `func` will be called
-     * on the trailing edge of the timeout only if the the throttled function is
-     * invoked more than once during the `wait` timeout.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to throttle.
-     * @param {number} wait The number of milliseconds to throttle executions to.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
-     * @returns {Function} Returns the new throttled function.
-     * @example
-     *
-     * // avoid excessively updating the position while scrolling
-     * var throttled = _.throttle(updatePosition, 100);
-     * jQuery(window).on('scroll', throttled);
-     *
-     * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
-     * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
-     *   'trailing': false
-     * }));
-     */
-    function throttle(func, wait, options) {
-      var leading = true,
-          trailing = true;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      if (options === false) {
-        leading = false;
-      } else if (isObject(options)) {
-        leading = 'leading' in options ? options.leading : leading;
-        trailing = 'trailing' in options ? options.trailing : trailing;
-      }
-      debounceOptions.leading = leading;
-      debounceOptions.maxWait = wait;
-      debounceOptions.trailing = trailing;
-
-      return debounce(func, wait, debounceOptions);
-    }
-
-    /**
-     * Creates a function that provides `value` to the wrapper function as its
-     * first argument. Additional arguments provided to the function are appended
-     * to those provided to the wrapper function. The wrapper is executed with
-     * the `this` binding of the created function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {*} value The value to wrap.
-     * @param {Function} wrapper The wrapper function.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var p = _.wrap(_.escape, function(func, text) {
-     *   return '<p>' + func(text) + '</p>';
-     * });
-     *
-     * p('Fred, Wilma, & Pebbles');
-     * // => '<p>Fred, Wilma, & Pebbles</p>'
-     */
-    function wrap(value, wrapper) {
-      return createWrapper(wrapper, 16, [value]);
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a function that returns `value`.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} value The value to return from the new function.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * var getter = _.constant(object);
-     * getter() === object;
-     * // => true
-     */
-    function constant(value) {
-      return function() {
-        return value;
-      };
-    }
-
-    /**
-     * Produces a callback bound to an optional `thisArg`. If `func` is a property
-     * name the created callback will return the property value for a given element.
-     * If `func` is an object the created callback will return `true` for elements
-     * that contain the equivalent object properties, otherwise it will return `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} [func=identity] The value to convert to a callback.
-     * @param {*} [thisArg] The `this` binding of the created callback.
-     * @param {number} [argCount] The number of arguments the callback accepts.
-     * @returns {Function} Returns a callback function.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // wrap to create custom callback shorthands
-     * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
-     *   var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
-     *   return !match ? func(callback, thisArg) : function(object) {
-     *     return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
-     *   };
-     * });
-     *
-     * _.filter(characters, 'age__gt38');
-     * // => [{ 'name': 'fred', 'age': 40 }]
-     */
-    function createCallback(func, thisArg, argCount) {
-      var type = typeof func;
-      if (func == null || type == 'function') {
-        return baseCreateCallback(func, thisArg, argCount);
-      }
-      // handle "_.pluck" style callback shorthands
-      if (type != 'object') {
-        return property(func);
-      }
-      var props = keys(func),
-          key = props[0],
-          a = func[key];
-
-      // handle "_.where" style callback shorthands
-      if (props.length == 1 && a === a && !isObject(a)) {
-        // fast path the common case of providing an object with a single
-        // property containing a primitive value
-        return function(object) {
-          var b = object[key];
-          return a === b && (a !== 0 || (1 / a == 1 / b));
-        };
-      }
-      return function(object) {
-        var length = props.length,
-            result = false;
-
-        while (length--) {
-          if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
-            break;
-          }
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
-     * corresponding HTML entities.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} string The string to escape.
-     * @returns {string} Returns the escaped string.
-     * @example
-     *
-     * _.escape('Fred, Wilma, & Pebbles');
-     * // => 'Fred, Wilma, & Pebbles'
-     */
-    function escape(string) {
-      return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
-    }
-
-    /**
-     * This method returns the first argument provided to it.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} value Any value.
-     * @returns {*} Returns `value`.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * _.identity(object) === object;
-     * // => true
-     */
-    function identity(value) {
-      return value;
-    }
-
-    /**
-     * Adds function properties of a source object to the destination object.
-     * If `object` is a function methods will be added to its prototype as well.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {Function|Object} [object=lodash] object The destination object.
-     * @param {Object} source The object of functions to add.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
-     * @example
-     *
-     * function capitalize(string) {
-     *   return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
-     * }
-     *
-     * _.mixin({ 'capitalize': capitalize });
-     * _.capitalize('fred');
-     * // => 'Fred'
-     *
-     * _('fred').capitalize().value();
-     * // => 'Fred'
-     *
-     * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
-     * _('fred').capitalize();
-     * // => 'Fred'
-     */
-    function mixin(object, source, options) {
-      var chain = true,
-          methodNames = source && functions(source);
-
-      if (!source || (!options && !methodNames.length)) {
-        if (options == null) {
-          options = source;
-        }
-        ctor = lodashWrapper;
-        source = object;
-        object = lodash;
-        methodNames = functions(source);
-      }
-      if (options === false) {
-        chain = false;
-      } else if (isObject(options) && 'chain' in options) {
-        chain = options.chain;
-      }
-      var ctor = object,
-          isFunc = isFunction(ctor);
-
-      forEach(methodNames, function(methodName) {
-        var func = object[methodName] = source[methodName];
-        if (isFunc) {
-          ctor.prototype[methodName] = function() {
-            var chainAll = this.__chain__,
-                value = this.__wrapped__,
-                args = [value];
-
-            push.apply(args, arguments);
-            var result = func.apply(object, args);
-            if (chain || chainAll) {
-              if (value === result && isObject(result)) {
-                return this;
-              }
-              result = new ctor(result);
-              result.__chain__ = chainAll;
-            }
-            return result;
-          };
-        }
-      });
-    }
-
-    /**
-     * Reverts the '_' variable to its previous value and returns a reference to
-     * the `lodash` function.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @returns {Function} Returns the `lodash` function.
-     * @example
-     *
-     * var lodash = _.noConflict();
-     */
-    function noConflict() {
-      context._ = oldDash;
-      return this;
-    }
-
-    /**
-     * A no-operation function.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * _.noop(object) === undefined;
-     * // => true
-     */
-    function noop() {
-      // no operation performed
-    }
-
-    /**
-     * Gets the number of milliseconds that have elapsed since the Unix epoch
-     * (1 January 1970 00:00:00 UTC).
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @example
-     *
-     * var stamp = _.now();
-     * _.defer(function() { console.log(_.now() - stamp); });
-     * // => logs the number of milliseconds it took for the deferred function to be called
-     */
-    var now = isNative(now = Date.now) && now || function() {
-      return new Date().getTime();
-    };
-
-    /**
-     * Converts the given value into an integer of the specified radix.
-     * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
-     * `value` is a hexadecimal, in which case a `radix` of `16` is used.
-     *
-     * Note: This method avoids differences in native ES3 and ES5 `parseInt`
-     * implementations. See http://es5.github.io/#E.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} value The value to parse.
-     * @param {number} [radix] The radix used to interpret the value to parse.
-     * @returns {number} Returns the new integer value.
-     * @example
-     *
-     * _.parseInt('08');
-     * // => 8
-     */
-    var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
-      // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
-      return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
-    };
-
-    /**
-     * Creates a "_.pluck" style function, which returns the `key` value of a
-     * given object.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} key The name of the property to retrieve.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'fred',   'age': 40 },
-     *   { 'name': 'barney', 'age': 36 }
-     * ];
-     *
-     * var getName = _.property('name');
-     *
-     * _.map(characters, getName);
-     * // => ['barney', 'fred']
-     *
-     * _.sortBy(characters, getName);
-     * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred',   'age': 40 }]
-     */
-    function property(key) {
-      return function(object) {
-        return object[key];
-      };
-    }
-
-    /**
-     * Produces a random number between `min` and `max` (inclusive). If only one
-     * argument is provided a number between `0` and the given number will be
-     * returned. If `floating` is truey or either `min` or `max` are floats a
-     * floating-point number will be returned instead of an integer.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {number} [min=0] The minimum possible value.
-     * @param {number} [max=1] The maximum possible value.
-     * @param {boolean} [floating=false] Specify returning a floating-point number.
-     * @returns {number} Returns a random number.
-     * @example
-     *
-     * _.random(0, 5);
-     * // => an integer between 0 and 5
-     *
-     * _.random(5);
-     * // => also an integer between 0 and 5
-     *
-     * _.random(5, true);
-     * // => a floating-point number between 0 and 5
-     *
-     * _.random(1.2, 5.2);
-     * // => a floating-point number between 1.2 and 5.2
-     */
-    function random(min, max, floating) {
-      var noMin = min == null,
-          noMax = max == null;
-
-      if (floating == null) {
-        if (typeof min == 'boolean' && noMax) {
-          floating = min;
-          min = 1;
-        }
-        else if (!noMax && typeof max == 'boolean') {
-          floating = max;
-          noMax = true;
-        }
-      }
-      if (noMin && noMax) {
-        max = 1;
-      }
-      min = +min || 0;
-      if (noMax) {
-        max = min;
-        min = 0;
-      } else {
-        max = +max || 0;
-      }
-      if (floating || min % 1 || max % 1) {
-        var rand = nativeRandom();
-        return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
-      }
-      return baseRandom(min, max);
-    }
-
-    /**
-     * Resolves the value of property `key` on `object`. If `key` is a function
-     * it will be invoked with the `this` binding of `object` and its result returned,
-     * else the property value is returned. If `object` is falsey then `undefined`
-     * is returned.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {Object} object The object to inspect.
-     * @param {string} key The name of the property to resolve.
-     * @returns {*} Returns the resolved value.
-     * @example
-     *
-     * var object = {
-     *   'cheese': 'crumpets',
-     *   'stuff': function() {
-     *     return 'nonsense';
-     *   }
-     * };
-     *
-     * _.result(object, 'cheese');
-     * // => 'crumpets'
-     *
-     * _.result(object, 'stuff');
-     * // => 'nonsense'
-     */
-    function result(object, key) {
-      if (object) {
-        var value = object[key];
-        return isFunction(value) ? object[key]() : value;
-      }
-    }
-
-    /**
-     * A micro-templating method that handles arbitrary delimiters, preserves
-     * whitespace, and correctly escapes quotes within interpolated code.
-     *
-     * Note: In the development build, `_.template` utilizes sourceURLs for easier
-     * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-     *
-     * For more information on precompiling templates see:
-     * https://lodash.com/custom-builds
-     *
-     * For more information on Chrome extension sandboxes see:
-     * http://developer.chrome.com/stable/extensions/sandboxingEval.html
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} text The template text.
-     * @param {Object} data The data object used to populate the text.
-     * @param {Object} [options] The options object.
-     * @param {RegExp} [options.escape] The "escape" delimiter.
-     * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
-     * @param {Object} [options.imports] An object to import into the template as local variables.
-     * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
-     * @param {string} [sourceURL] The sourceURL of the template's compiled source.
-     * @param {string} [variable] The data object variable name.
-     * @returns {Function|string} Returns a compiled function when no `data` object
-     *  is given, else it returns the interpolated text.
-     * @example
-     *
-     * // using the "interpolate" delimiter to create a compiled template
-     * var compiled = _.template('hello <%= name %>');
-     * compiled({ 'name': 'fred' });
-     * // => 'hello fred'
-     *
-     * // using the "escape" delimiter to escape HTML in data property values
-     * _.template('<b><%- value %></b>', { 'value': '<script>' });
-     * // => '<b><script></b>'
-     *
-     * // using the "evaluate" delimiter to generate HTML
-     * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
-     * _.template(list, { 'people': ['fred', 'barney'] });
-     * // => '<li>fred</li><li>barney</li>'
-     *
-     * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
-     * _.template('hello ${ name }', { 'name': 'pebbles' });
-     * // => 'hello pebbles'
-     *
-     * // using the internal `print` function in "evaluate" delimiters
-     * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
-     * // => 'hello barney!'
-     *
-     * // using a custom template delimiters
-     * _.templateSettings = {
-     *   'interpolate': /{{([\s\S]+?)}}/g
-     * };
-     *
-     * _.template('hello {{ name }}!', { 'name': 'mustache' });
-     * // => 'hello mustache!'
-     *
-     * // using the `imports` option to import jQuery
-     * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
-     * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
-     * // => '<li>fred</li><li>barney</li>'
-     *
-     * // using the `sourceURL` option to specify a custom sourceURL for the template
-     * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
-     * compiled(data);
-     * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
-     *
-     * // using the `variable` option to ensure a with-statement isn't used in the compiled template
-     * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
-     * compiled.source;
-     * // => function(data) {
-     *   var __t, __p = '', __e = _.escape;
-     *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
-     *   return __p;
-     * }
-     *
-     * // using the `source` property to inline compiled templates for meaningful
-     * // line numbers in error messages and a stack trace
-     * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
-     *   var JST = {\
-     *     "main": ' + _.template(mainText).source + '\
-     *   };\
-     * ');
-     */
-    function template(text, data, options) {
-      // based on John Resig's `tmpl` implementation
-      // http://ejohn.org/blog/javascript-micro-templating/
-      // and Laura Doktorova's doT.js
-      // https://github.com/olado/doT
-      var settings = lodash.templateSettings;
-      text = String(text || '');
-
-      // avoid missing dependencies when `iteratorTemplate` is not defined
-      options = defaults({}, options, settings);
-
-      var imports = defaults({}, options.imports, settings.imports),
-          importsKeys = keys(imports),
-          importsValues = values(imports);
-
-      var isEvaluating,
-          index = 0,
-          interpolate = options.interpolate || reNoMatch,
-          source = "__p += '";
-
-      // compile the regexp to match each delimiter
-      var reDelimiters = RegExp(
-        (options.escape || reNoMatch).source + '|' +
-        interpolate.source + '|' +
-        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
-        (options.evaluate || reNoMatch).source + '|$'
-      , 'g');
-
-      text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
-        interpolateValue || (interpolateValue = esTemplateValue);
-
-        // escape characters that cannot be included in string literals
-        source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
-
-        // replace delimiters with snippets
-        if (escapeValue) {
-          source += "' +\n__e(" + escapeValue + ") +\n'";
-        }
-        if (evaluateValue) {
-          isEvaluating = true;
-          source += "';\n" + evaluateValue + ";\n__p += '";
-        }
-        if (interpolateValue) {
-          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
-        }
-        index = offset + match.length;
-
-        // the JS engine embedded in Adobe products requires returning the `match`
-        // string in order to produce the correct `offset` value
-        return match;
-      });
-
-      source += "';\n";
-
-      // if `variable` is not specified, wrap a with-statement around the generated
-      // code to add the data object to the top of the scope chain
-      var variable = options.variable,
-          hasVariable = variable;
-
-      if (!hasVariable) {
-        variable = 'obj';
-        source = 'with (' + variable + ') {\n' + source + '\n}\n';
-      }
-      // cleanup code by stripping empty strings
-      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
-        .replace(reEmptyStringMiddle, '$1')
-        .replace(reEmptyStringTrailing, '$1;');
-
-      // frame code as the function body
-      source = 'function(' + variable + ') {\n' +
-        (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
-        "var __t, __p = '', __e = _.escape" +
-        (isEvaluating
-          ? ', __j = Array.prototype.join;\n' +
-            "function print() { __p += __j.call(arguments, '') }\n"
-          : ';\n'
-        ) +
-        source +
-        'return __p\n}';
-
-      // Use a sourceURL for easier debugging.
-      // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-      var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
-
-      try {
-        var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
-      } catch(e) {
-        e.source = source;
-        throw e;
-      }
-      if (data) {
-        return result(data);
-      }
-      // provide the compiled function's source by its `toString` method, in
-      // supported environments, or the `source` property as a convenience for
-      // inlining compiled templates during the build process
-      result.source = source;
-      return result;
-    }
-
-    /**
-     * Executes the callback `n` times, returning an array of the results
-     * of each callback execution. The callback is bound to `thisArg` and invoked
-     * with one argument; (index).
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {number} n The number of times to execute the callback.
-     * @param {Function} callback The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns an array of the results of each `callback` execution.
-     * @example
-     *
-     * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
-     * // => [3, 6, 4]
-     *
-     * _.times(3, function(n) { mage.castSpell(n); });
-     * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
-     *
-     * _.times(3, function(n) { this.cast(n); }, mage);
-     * // => also calls `mage.castSpell(n)` three times
-     */
-    function times(n, callback, thisArg) {
-      n = (n = +n) > -1 ? n : 0;
-      var index = -1,
-          result = Array(n);
-
-      callback = baseCreateCallback(callback, thisArg, 1);
-      while (++index < n) {
-        result[index] = callback(index);
-      }
-      return result;
-    }
-
-    /**
-     * The inverse of `_.escape` this method converts the HTML entities
-     * `&`, `<`, `>`, `"`, and `'` in `string` to their
-     * corresponding characters.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} string The string to unescape.
-     * @returns {string} Returns the unescaped string.
-     * @example
-     *
-     * _.unescape('Fred, Barney & Pebbles');
-     * // => 'Fred, Barney & Pebbles'
-     */
-    function unescape(string) {
-      return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
-    }
-
-    /**
-     * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} [prefix] The value to prefix the ID with.
-     * @returns {string} Returns the unique ID.
-     * @example
-     *
-     * _.uniqueId('contact_');
-     * // => 'contact_104'
-     *
-     * _.uniqueId();
-     * // => '105'
-     */
-    function uniqueId(prefix) {
-      var id = ++idCounter;
-      return String(prefix == null ? '' : prefix) + id;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a `lodash` object that wraps the given value with explicit
-     * method chaining enabled.
-     *
-     * @static
-     * @memberOf _
-     * @category Chaining
-     * @param {*} value The value to wrap.
-     * @returns {Object} Returns the wrapper object.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36 },
-     *   { 'name': 'fred',    'age': 40 },
-     *   { 'name': 'pebbles', 'age': 1 }
-     * ];
-     *
-     * var youngest = _.chain(characters)
-     *     .sortBy('age')
-     *     .map(function(chr) { return chr.name + ' is ' + chr.age; })
-     *     .first()
-     *     .value();
-     * // => 'pebbles is 1'
-     */
-    function chain(value) {
-      value = new lodashWrapper(value);
-      value.__chain__ = true;
-      return value;
-    }
-
-    /**
-     * Invokes `interceptor` with the `value` as the first argument and then
-     * returns `value`. The purpose of this method is to "tap into" a method
-     * chain in order to perform operations on intermediate results within
-     * the chain.
-     *
-     * @static
-     * @memberOf _
-     * @category Chaining
-     * @param {*} value The value to provide to `interceptor`.
-     * @param {Function} interceptor The function to invoke.
-     * @returns {*} Returns `value`.
-     * @example
-     *
-     * _([1, 2, 3, 4])
-     *  .tap(function(array) { array.pop(); })
-     *  .reverse()
-     *  .value();
-     * // => [3, 2, 1]
-     */
-    function tap(value, interceptor) {
-      interceptor(value);
-      return value;
-    }
-
-    /**
-     * Enables explicit method chaining on the wrapper object.
-     *
-     * @name chain
-     * @memberOf _
-     * @category Chaining
-     * @returns {*} Returns the wrapper object.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // without explicit chaining
-     * _(characters).first();
-     * // => { 'name': 'barney', 'age': 36 }
-     *
-     * // with explicit chaining
-     * _(characters).chain()
-     *   .first()
-     *   .pick('age')
-     *   .value();
-     * // => { 'age': 36 }
-     */
-    function wrapperChain() {
-      this.__chain__ = true;
-      return this;
-    }
-
-    /**
-     * Produces the `toString` result of the wrapped value.
-     *
-     * @name toString
-     * @memberOf _
-     * @category Chaining
-     * @returns {string} Returns the string result.
-     * @example
-     *
-     * _([1, 2, 3]).toString();
-     * // => '1,2,3'
-     */
-    function wrapperToString() {
-      return String(this.__wrapped__);
-    }
-
-    /**
-     * Extracts the wrapped value.
-     *
-     * @name valueOf
-     * @memberOf _
-     * @alias value
-     * @category Chaining
-     * @returns {*} Returns the wrapped value.
-     * @example
-     *
-     * _([1, 2, 3]).valueOf();
-     * // => [1, 2, 3]
-     */
-    function wrapperValueOf() {
-      return this.__wrapped__;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions that return wrapped values when chaining
-    lodash.after = after;
-    lodash.assign = assign;
-    lodash.at = at;
-    lodash.bind = bind;
-    lodash.bindAll = bindAll;
-    lodash.bindKey = bindKey;
-    lodash.chain = chain;
-    lodash.compact = compact;
-    lodash.compose = compose;
-    lodash.constant = constant;
-    lodash.countBy = countBy;
-    lodash.create = create;
-    lodash.createCallback = createCallback;
-    lodash.curry = curry;
-    lodash.debounce = debounce;
-    lodash.defaults = defaults;
-    lodash.defer = defer;
-    lodash.delay = delay;
-    lodash.difference = difference;
-    lodash.filter = filter;
-    lodash.flatten = flatten;
-    lodash.forEach = forEach;
-    lodash.forEachRight = forEachRight;
-    lodash.forIn = forIn;
-    lodash.forInRight = forInRight;
-    lodash.forOwn = forOwn;
-    lodash.forOwnRight = forOwnRight;
-    lodash.functions = functions;
-    lodash.groupBy = groupBy;
-    lodash.indexBy = indexBy;
-    lodash.initial = initial;
-    lodash.intersection = intersection;
-    lodash.invert = invert;
-    lodash.invoke = invoke;
-    lodash.keys = keys;
-    lodash.map = map;
-    lodash.mapValues = mapValues;
-    lodash.max = max;
-    lodash.memoize = memoize;
-    lodash.merge = merge;
-    lodash.min = min;
-    lodash.omit = omit;
-    lodash.once = once;
-    lodash.pairs = pairs;
-    lodash.partial = partial;
-    lodash.partialRight = partialRight;
-    lodash.pick = pick;
-    lodash.pluck = pluck;
-    lodash.property = property;
-    lodash.pull = pull;
-    lodash.range = range;
-    lodash.reject = reject;
-    lodash.remove = remove;
-    lodash.rest = rest;
-    lodash.shuffle = shuffle;
-    lodash.sortBy = sortBy;
-    lodash.tap = tap;
-    lodash.throttle = throttle;
-    lodash.times = times;
-    lodash.toArray = toArray;
-    lodash.transform = transform;
-    lodash.union = union;
-    lodash.uniq = uniq;
-    lodash.values = values;
-    lodash.where = where;
-    lodash.without = without;
-    lodash.wrap = wrap;
-    lodash.xor = xor;
-    lodash.zip = zip;
-    lodash.zipObject = zipObject;
-
-    // add aliases
-    lodash.collect = map;
-    lodash.drop = rest;
-    lodash.each = forEach;
-    lodash.eachRight = forEachRight;
-    lodash.extend = assign;
-    lodash.methods = functions;
-    lodash.object = zipObject;
-    lodash.select = filter;
-    lodash.tail = rest;
-    lodash.unique = uniq;
-    lodash.unzip = zip;
-
-    // add functions to `lodash.prototype`
-    mixin(lodash);
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions that return unwrapped values when chaining
-    lodash.clone = clone;
-    lodash.cloneDeep = cloneDeep;
-    lodash.contains = contains;
-    lodash.escape = escape;
-    lodash.every = every;
-    lodash.find = find;
-    lodash.findIndex = findIndex;
-    lodash.findKey = findKey;
-    lodash.findLast = findLast;
-    lodash.findLastIndex = findLastIndex;
-    lodash.findLastKey = findLastKey;
-    lodash.has = has;
-    lodash.identity = identity;
-    lodash.indexOf = indexOf;
-    lodash.isArguments = isArguments;
-    lodash.isArray = isArray;
-    lodash.isBoolean = isBoolean;
-    lodash.isDate = isDate;
-    lodash.isElement = isElement;
-    lodash.isEmpty = isEmpty;
-    lodash.isEqual = isEqual;
-    lodash.isFinite = isFinite;
-    lodash.isFunction = isFunction;
-    lodash.isNaN = isNaN;
-    lodash.isNull = isNull;
-    lodash.isNumber = isNumber;
-    lodash.isObject = isObject;
-    lodash.isPlainObject = isPlainObject;
-    lodash.isRegExp = isRegExp;
-    lodash.isString = isString;
-    lodash.isUndefined = isUndefined;
-    lodash.lastIndexOf = lastIndexOf;
-    lodash.mixin = mixin;
-    lodash.noConflict = noConflict;
-    lodash.noop = noop;
-    lodash.now = now;
-    lodash.parseInt = parseInt;
-    lodash.random = random;
-    lodash.reduce = reduce;
-    lodash.reduceRight = reduceRight;
-    lodash.result = result;
-    lodash.runInContext = runInContext;
-    lodash.size = size;
-    lodash.some = some;
-    lodash.sortedIndex = sortedIndex;
-    lodash.template = template;
-    lodash.unescape = unescape;
-    lodash.uniqueId = uniqueId;
-
-    // add aliases
-    lodash.all = every;
-    lodash.any = some;
-    lodash.detect = find;
-    lodash.findWhere = find;
-    lodash.foldl = reduce;
-    lodash.foldr = reduceRight;
-    lodash.include = contains;
-    lodash.inject = reduce;
-
-    mixin(function() {
-      var source = {}
-      forOwn(lodash, function(func, methodName) {
-        if (!lodash.prototype[methodName]) {
-          source[methodName] = func;
-        }
-      });
-      return source;
-    }(), false);
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions capable of returning wrapped and unwrapped values when chaining
-    lodash.first = first;
-    lodash.last = last;
-    lodash.sample = sample;
-
-    // add aliases
-    lodash.take = first;
-    lodash.head = first;
-
-    forOwn(lodash, function(func, methodName) {
-      var callbackable = methodName !== 'sample';
-      if (!lodash.prototype[methodName]) {
-        lodash.prototype[methodName]= function(n, guard) {
-          var chainAll = this.__chain__,
-              result = func(this.__wrapped__, n, guard);
-
-          return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
-            ? result
-            : new lodashWrapper(result, chainAll);
-        };
-      }
-    });
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * The semantic version number.
-     *
-     * @static
-     * @memberOf _
-     * @type string
-     */
-    lodash.VERSION = '2.4.2';
-
-    // add "Chaining" functions to the wrapper
-    lodash.prototype.chain = wrapperChain;
-    lodash.prototype.toString = wrapperToString;
-    lodash.prototype.value = wrapperValueOf;
-    lodash.prototype.valueOf = wrapperValueOf;
-
-    // add `Array` functions that return unwrapped values
-    forEach(['join', 'pop', 'shift'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        var chainAll = this.__chain__,
-            result = func.apply(this.__wrapped__, arguments);
-
-        return chainAll
-          ? new lodashWrapper(result, chainAll)
-          : result;
-      };
-    });
-
-    // add `Array` functions that return the existing wrapped value
-    forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        func.apply(this.__wrapped__, arguments);
-        return this;
-      };
-    });
-
-    // add `Array` functions that return new wrapped values
-    forEach(['concat', 'slice', 'splice'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
-      };
-    });
-
-    return lodash;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  // expose Lo-Dash
-  var _ = runInContext();
-
-  // some AMD build optimizers like r.js check for condition patterns like the following:
-  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
-    // Expose Lo-Dash to the global object even when an AMD loader is present in
-    // case Lo-Dash is loaded with a RequireJS shim config.
-    // See http://requirejs.org/docs/api.html#config-shim
-    root._ = _;
-
-    // define as an anonymous module so, through path mapping, it can be
-    // referenced as the "underscore" module
-    define(function() {
-      return _;
-    });
-  }
-  // check for `exports` after `define` in case a build optimizer adds an `exports` object
-  else if (freeExports && freeModule) {
-    // in Node.js or RingoJS
-    if (moduleExports) {
-      (freeModule.exports = _)._ = _;
-    }
-    // in Narwhal or Rhino -require
-    else {
-      freeExports._ = _;
-    }
-  }
-  else {
-    // in a browser or Rhino
-    root._ = _;
-  }
-}.call(this));
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-
-},{}],81:[function(require,module,exports){
-(function (global){
-/**
- * @license
- * Lo-Dash 2.4.2 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern -o ./dist/lodash.js`
- * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-;(function() {
-
-  /** Used as a safe reference for `undefined` in pre ES5 environments */
-  var undefined;
-
-  /** Used to pool arrays and objects used internally */
-  var arrayPool = [],
-      objectPool = [];
-
-  /** Used to generate unique IDs */
-  var idCounter = 0;
-
-  /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
-  var keyPrefix = +new Date + '';
-
-  /** Used as the size when optimizations are enabled for large arrays */
-  var largeArraySize = 75;
-
-  /** Used as the max size of the `arrayPool` and `objectPool` */
-  var maxPoolSize = 40;
-
-  /** Used to detect and test whitespace */
-  var whitespace = (
-    // whitespace
-    ' \t\x0B\f\xA0\ufeff' +
-
-    // line terminators
-    '\n\r\u2028\u2029' +
-
-    // unicode category "Zs" space separators
-    '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
-  );
-
-  /** Used to match empty string literals in compiled template source */
-  var reEmptyStringLeading = /\b__p \+= '';/g,
-      reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
-      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
-
-  /**
-   * Used to match ES6 template delimiters
-   * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
-   */
-  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
-
-  /** Used to match regexp flags from their coerced string values */
-  var reFlags = /\w*$/;
-
-  /** Used to detected named functions */
-  var reFuncName = /^\s*function[ \n\r\t]+\w/;
-
-  /** Used to match "interpolate" template delimiters */
-  var reInterpolate = /<%=([\s\S]+?)%>/g;
-
-  /** Used to match leading whitespace and zeros to be removed */
-  var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
-
-  /** Used to ensure capturing order of template delimiters */
-  var reNoMatch = /($^)/;
-
-  /** Used to detect functions containing a `this` reference */
-  var reThis = /\bthis\b/;
-
-  /** Used to match unescaped characters in compiled string literals */
-  var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
-
-  /** Used to assign default `context` object properties */
-  var contextProps = [
-    'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
-    'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
-    'parseInt', 'setTimeout'
-  ];
-
-  /** Used to make template sourceURLs easier to identify */
-  var templateCounter = 0;
-
-  /** `Object#toString` result shortcuts */
-  var argsClass = '[object Arguments]',
-      arrayClass = '[object Array]',
-      boolClass = '[object Boolean]',
-      dateClass = '[object Date]',
-      funcClass = '[object Function]',
-      numberClass = '[object Number]',
-      objectClass = '[object Object]',
-      regexpClass = '[object RegExp]',
-      stringClass = '[object String]';
-
-  /** Used to identify object classifications that `_.clone` supports */
-  var cloneableClasses = {};
-  cloneableClasses[funcClass] = false;
-  cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
-  cloneableClasses[boolClass] = cloneableClasses[dateClass] =
-  cloneableClasses[numberClass] = cloneableClasses[objectClass] =
-  cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
-
-  /** Used as an internal `_.debounce` options object */
-  var debounceOptions = {
-    'leading': false,
-    'maxWait': 0,
-    'trailing': false
-  };
-
-  /** Used as the property descriptor for `__bindData__` */
-  var descriptor = {
-    'configurable': false,
-    'enumerable': false,
-    'value': null,
-    'writable': false
-  };
-
-  /** Used to determine if values are of the language type Object */
-  var objectTypes = {
-    'boolean': false,
-    'function': true,
-    'object': true,
-    'number': false,
-    'string': false,
-    'undefined': false
-  };
-
-  /** Used to escape characters for inclusion in compiled string literals */
-  var stringEscapes = {
-    '\\': '\\',
-    "'": "'",
-    '\n': 'n',
-    '\r': 'r',
-    '\t': 't',
-    '\u2028': 'u2028',
-    '\u2029': 'u2029'
-  };
-
-  /** Used as a reference to the global object */
-  var root = (objectTypes[typeof window] && window) || this;
-
-  /** Detect free variable `exports` */
-  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
-
-  /** Detect free variable `module` */
-  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
-
-  /** Detect the popular CommonJS extension `module.exports` */
-  var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
-
-  /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
-  var freeGlobal = objectTypes[typeof global] && global;
-  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
-    root = freeGlobal;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * The base implementation of `_.indexOf` without support for binary searches
-   * or `fromIndex` constraints.
-   *
-   * @private
-   * @param {Array} array The array to search.
-   * @param {*} value The value to search for.
-   * @param {number} [fromIndex=0] The index to search from.
-   * @returns {number} Returns the index of the matched value or `-1`.
-   */
-  function baseIndexOf(array, value, fromIndex) {
-    var index = (fromIndex || 0) - 1,
-        length = array ? array.length : 0;
-
-    while (++index < length) {
-      if (array[index] === value) {
-        return index;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * An implementation of `_.contains` for cache objects that mimics the return
-   * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
-   *
-   * @private
-   * @param {Object} cache The cache object to inspect.
-   * @param {*} value The value to search for.
-   * @returns {number} Returns `0` if `value` is found, else `-1`.
-   */
-  function cacheIndexOf(cache, value) {
-    var type = typeof value;
-    cache = cache.cache;
-
-    if (type == 'boolean' || value == null) {
-      return cache[value] ? 0 : -1;
-    }
-    if (type != 'number' && type != 'string') {
-      type = 'object';
-    }
-    var key = type == 'number' ? value : keyPrefix + value;
-    cache = (cache = cache[type]) && cache[key];
-
-    return type == 'object'
-      ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
-      : (cache ? 0 : -1);
-  }
-
-  /**
-   * Adds a given value to the corresponding cache object.
-   *
-   * @private
-   * @param {*} value The value to add to the cache.
-   */
-  function cachePush(value) {
-    var cache = this.cache,
-        type = typeof value;
-
-    if (type == 'boolean' || value == null) {
-      cache[value] = true;
-    } else {
-      if (type != 'number' && type != 'string') {
-        type = 'object';
-      }
-      var key = type == 'number' ? value : keyPrefix + value,
-          typeCache = cache[type] || (cache[type] = {});
-
-      if (type == 'object') {
-        (typeCache[key] || (typeCache[key] = [])).push(value);
-      } else {
-        typeCache[key] = true;
-      }
-    }
-  }
-
-  /**
-   * Used by `_.max` and `_.min` as the default callback when a given
-   * collection is a string value.
-   *
-   * @private
-   * @param {string} value The character to inspect.
-   * @returns {number} Returns the code unit of given character.
-   */
-  function charAtCallback(value) {
-    return value.charCodeAt(0);
-  }
-
-  /**
-   * Used by `sortBy` to compare transformed `collection` elements, stable sorting
-   * them in ascending order.
-   *
-   * @private
-   * @param {Object} a The object to compare to `b`.
-   * @param {Object} b The object to compare to `a`.
-   * @returns {number} Returns the sort order indicator of `1` or `-1`.
-   */
-  function compareAscending(a, b) {
-    var ac = a.criteria,
-        bc = b.criteria,
-        index = -1,
-        length = ac.length;
-
-    while (++index < length) {
-      var value = ac[index],
-          other = bc[index];
-
-      if (value !== other) {
-        if (value > other || typeof value == 'undefined') {
-          return 1;
-        }
-        if (value < other || typeof other == 'undefined') {
-          return -1;
-        }
-      }
-    }
-    // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
-    // that causes it, under certain circumstances, to return the same value for
-    // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
-    //
-    // This also ensures a stable sort in V8 and other engines.
-    // See http://code.google.com/p/v8/issues/detail?id=90
-    return a.index - b.index;
-  }
-
-  /**
-   * Creates a cache object to optimize linear searches of large arrays.
-   *
-   * @private
-   * @param {Array} [array=[]] The array to search.
-   * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
-   */
-  function createCache(array) {
-    var index = -1,
-        length = array.length,
-        first = array[0],
-        mid = array[(length / 2) | 0],
-        last = array[length - 1];
-
-    if (first && typeof first == 'object' &&
-        mid && typeof mid == 'object' && last && typeof last == 'object') {
-      return false;
-    }
-    var cache = getObject();
-    cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
-
-    var result = getObject();
-    result.array = array;
-    result.cache = cache;
-    result.push = cachePush;
-
-    while (++index < length) {
-      result.push(array[index]);
-    }
-    return result;
-  }
-
-  /**
-   * Used by `template` to escape characters for inclusion in compiled
-   * string literals.
-   *
-   * @private
-   * @param {string} match The matched character to escape.
-   * @returns {string} Returns the escaped character.
-   */
-  function escapeStringChar(match) {
-    return '\\' + stringEscapes[match];
-  }
-
-  /**
-   * Gets an array from the array pool or creates a new one if the pool is empty.
-   *
-   * @private
-   * @returns {Array} The array from the pool.
-   */
-  function getArray() {
-    return arrayPool.pop() || [];
-  }
-
-  /**
-   * Gets an object from the object pool or creates a new one if the pool is empty.
-   *
-   * @private
-   * @returns {Object} The object from the pool.
-   */
-  function getObject() {
-    return objectPool.pop() || {
-      'array': null,
-      'cache': null,
-      'criteria': null,
-      'false': false,
-      'index': 0,
-      'null': false,
-      'number': null,
-      'object': null,
-      'push': null,
-      'string': null,
-      'true': false,
-      'undefined': false,
-      'value': null
-    };
-  }
-
-  /**
-   * Releases the given array back to the array pool.
-   *
-   * @private
-   * @param {Array} [array] The array to release.
-   */
-  function releaseArray(array) {
-    array.length = 0;
-    if (arrayPool.length < maxPoolSize) {
-      arrayPool.push(array);
-    }
-  }
-
-  /**
-   * Releases the given object back to the object pool.
-   *
-   * @private
-   * @param {Object} [object] The object to release.
-   */
-  function releaseObject(object) {
-    var cache = object.cache;
-    if (cache) {
-      releaseObject(cache);
-    }
-    object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
-    if (objectPool.length < maxPoolSize) {
-      objectPool.push(object);
-    }
-  }
-
-  /**
-   * Slices the `collection` from the `start` index up to, but not including,
-   * the `end` index.
-   *
-   * Note: This function is used instead of `Array#slice` to support node lists
-   * in IE < 9 and to ensure dense arrays are returned.
-   *
-   * @private
-   * @param {Array|Object|string} collection The collection to slice.
-   * @param {number} start The start index.
-   * @param {number} end The end index.
-   * @returns {Array} Returns the new array.
-   */
-  function slice(array, start, end) {
-    start || (start = 0);
-    if (typeof end == 'undefined') {
-      end = array ? array.length : 0;
-    }
-    var index = -1,
-        length = end - start || 0,
-        result = Array(length < 0 ? 0 : length);
-
-    while (++index < length) {
-      result[index] = array[start + index];
-    }
-    return result;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * Create a new `lodash` function using the given context object.
-   *
-   * @static
-   * @memberOf _
-   * @category Utilities
-   * @param {Object} [context=root] The context object.
-   * @returns {Function} Returns the `lodash` function.
-   */
-  function runInContext(context) {
-    // Avoid issues with some ES3 environments that attempt to use values, named
-    // after built-in constructors like `Object`, for the creation of literals.
-    // ES5 clears this up by stating that literals must use built-in constructors.
-    // See http://es5.github.io/#x11.1.5.
-    context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
-
-    /** Native constructor references */
-    var Array = context.Array,
-        Boolean = context.Boolean,
-        Date = context.Date,
-        Function = context.Function,
-        Math = context.Math,
-        Number = context.Number,
-        Object = context.Object,
-        RegExp = context.RegExp,
-        String = context.String,
-        TypeError = context.TypeError;
-
-    /**
-     * Used for `Array` method references.
-     *
-     * Normally `Array.prototype` would suffice, however, using an array literal
-     * avoids issues in Narwhal.
-     */
-    var arrayRef = [];
-
-    /** Used for native method references */
-    var objectProto = Object.prototype;
-
-    /** Used to restore the original `_` reference in `noConflict` */
-    var oldDash = context._;
-
-    /** Used to resolve the internal [[Class]] of values */
-    var toString = objectProto.toString;
-
-    /** Used to detect if a method is native */
-    var reNative = RegExp('^' +
-      String(toString)
-        .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
-        .replace(/toString| for [^\]]+/g, '.*?') + '$'
-    );
-
-    /** Native method shortcuts */
-    var ceil = Math.ceil,
-        clearTimeout = context.clearTimeout,
-        floor = Math.floor,
-        fnToString = Function.prototype.toString,
-        getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
-        hasOwnProperty = objectProto.hasOwnProperty,
-        push = arrayRef.push,
-        setTimeout = context.setTimeout,
-        splice = arrayRef.splice,
-        unshift = arrayRef.unshift;
-
-    /** Used to set meta data on functions */
-    var defineProperty = (function() {
-      // IE 8 only accepts DOM elements
-      try {
-        var o = {},
-            func = isNative(func = Object.defineProperty) && func,
-            result = func(o, o, o) && func;
-      } catch(e) { }
-      return result;
-    }());
-
-    /* Native method shortcuts for methods with the same name as other `lodash` methods */
-    var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
-        nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
-        nativeIsFinite = context.isFinite,
-        nativeIsNaN = context.isNaN,
-        nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
-        nativeMax = Math.max,
-        nativeMin = Math.min,
-        nativeParseInt = context.parseInt,
-        nativeRandom = Math.random;
-
-    /** Used to lookup a built-in constructor by [[Class]] */
-    var ctorByClass = {};
-    ctorByClass[arrayClass] = Array;
-    ctorByClass[boolClass] = Boolean;
-    ctorByClass[dateClass] = Date;
-    ctorByClass[funcClass] = Function;
-    ctorByClass[objectClass] = Object;
-    ctorByClass[numberClass] = Number;
-    ctorByClass[regexpClass] = RegExp;
-    ctorByClass[stringClass] = String;
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a `lodash` object which wraps the given value to enable intuitive
-     * method chaining.
-     *
-     * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
-     * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
-     * and `unshift`
-     *
-     * Chaining is supported in custom builds as long as the `value` method is
-     * implicitly or explicitly included in the build.
-     *
-     * The chainable wrapper functions are:
-     * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
-     * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
-     * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
-     * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
-     * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
-     * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
-     * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
-     * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
-     * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
-     * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
-     * and `zip`
-     *
-     * The non-chainable wrapper functions are:
-     * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
-     * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
-     * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
-     * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
-     * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
-     * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
-     * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
-     * `template`, `unescape`, `uniqueId`, and `value`
-     *
-     * The wrapper functions `first` and `last` return wrapped values when `n` is
-     * provided, otherwise they return unwrapped values.
-     *
-     * Explicit chaining can be enabled by using the `_.chain` method.
-     *
-     * @name _
-     * @constructor
-     * @category Chaining
-     * @param {*} value The value to wrap in a `lodash` instance.
-     * @returns {Object} Returns a `lodash` instance.
-     * @example
-     *
-     * var wrapped = _([1, 2, 3]);
-     *
-     * // returns an unwrapped value
-     * wrapped.reduce(function(sum, num) {
-     *   return sum + num;
-     * });
-     * // => 6
-     *
-     * // returns a wrapped value
-     * var squares = wrapped.map(function(num) {
-     *   return num * num;
-     * });
-     *
-     * _.isArray(squares);
-     * // => false
-     *
-     * _.isArray(squares.value());
-     * // => true
-     */
-    function lodash(value) {
-      // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
-      return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
-       ? value
-       : new lodashWrapper(value);
-    }
-
-    /**
-     * A fast path for creating `lodash` wrapper objects.
-     *
-     * @private
-     * @param {*} value The value to wrap in a `lodash` instance.
-     * @param {boolean} chainAll A flag to enable chaining for all methods
-     * @returns {Object} Returns a `lodash` instance.
-     */
-    function lodashWrapper(value, chainAll) {
-      this.__chain__ = !!chainAll;
-      this.__wrapped__ = value;
-    }
-    // ensure `new lodashWrapper` is an instance of `lodash`
-    lodashWrapper.prototype = lodash.prototype;
-
-    /**
-     * An object used to flag environments features.
-     *
-     * @static
-     * @memberOf _
-     * @type Object
-     */
-    var support = lodash.support = {};
-
-    /**
-     * Detect if functions can be decompiled by `Function#toString`
-     * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
-     *
-     * @memberOf _.support
-     * @type boolean
-     */
-    support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
-
-    /**
-     * Detect if `Function#name` is supported (all but IE).
-     *
-     * @memberOf _.support
-     * @type boolean
-     */
-    support.funcNames = typeof Function.name == 'string';
-
-    /**
-     * By default, the template delimiters used by Lo-Dash are similar to those in
-     * embedded Ruby (ERB). Change the following template settings to use alternative
-     * delimiters.
-     *
-     * @static
-     * @memberOf _
-     * @type Object
-     */
-    lodash.templateSettings = {
-
-      /**
-       * Used to detect `data` property values to be HTML-escaped.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'escape': /<%-([\s\S]+?)%>/g,
-
-      /**
-       * Used to detect code to be evaluated.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'evaluate': /<%([\s\S]+?)%>/g,
-
-      /**
-       * Used to detect `data` property values to inject.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'interpolate': reInterpolate,
-
-      /**
-       * Used to reference the data object in the template text.
-       *
-       * @memberOf _.templateSettings
-       * @type string
-       */
-      'variable': '',
-
-      /**
-       * Used to import variables into the compiled template.
-       *
-       * @memberOf _.templateSettings
-       * @type Object
-       */
-      'imports': {
-
-        /**
-         * A reference to the `lodash` function.
-         *
-         * @memberOf _.templateSettings.imports
-         * @type Function
-         */
-        '_': lodash
-      }
-    };
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * The base implementation of `_.bind` that creates the bound function and
-     * sets its meta data.
-     *
-     * @private
-     * @param {Array} bindData The bind data array.
-     * @returns {Function} Returns the new bound function.
-     */
-    function baseBind(bindData) {
-      var func = bindData[0],
-          partialArgs = bindData[2],
-          thisArg = bindData[4];
-
-      function bound() {
-        // `Function#bind` spec
-        // http://es5.github.io/#x15.3.4.5
-        if (partialArgs) {
-          // avoid `arguments` object deoptimizations by using `slice` instead
-          // of `Array.prototype.slice.call` and not assigning `arguments` to a
-          // variable as a ternary expression
-          var args = slice(partialArgs);
-          push.apply(args, arguments);
-        }
-        // mimic the constructor's `return` behavior
-        // http://es5.github.io/#x13.2.2
-        if (this instanceof bound) {
-          // ensure `new bound` is an instance of `func`
-          var thisBinding = baseCreate(func.prototype),
-              result = func.apply(thisBinding, args || arguments);
-          return isObject(result) ? result : thisBinding;
-        }
-        return func.apply(thisArg, args || arguments);
-      }
-      setBindData(bound, bindData);
-      return bound;
-    }
-
-    /**
-     * The base implementation of `_.clone` without argument juggling or support
-     * for `thisArg` binding.
-     *
-     * @private
-     * @param {*} value The value to clone.
-     * @param {boolean} [isDeep=false] Specify a deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {Array} [stackA=[]] Tracks traversed source objects.
-     * @param {Array} [stackB=[]] Associates clones with source counterparts.
-     * @returns {*} Returns the cloned value.
-     */
-    function baseClone(value, isDeep, callback, stackA, stackB) {
-      if (callback) {
-        var result = callback(value);
-        if (typeof result != 'undefined') {
-          return result;
-        }
-      }
-      // inspect [[Class]]
-      var isObj = isObject(value);
-      if (isObj) {
-        var className = toString.call(value);
-        if (!cloneableClasses[className]) {
-          return value;
-        }
-        var ctor = ctorByClass[className];
-        switch (className) {
-          case boolClass:
-          case dateClass:
-            return new ctor(+value);
-
-          case numberClass:
-          case stringClass:
-            return new ctor(value);
-
-          case regexpClass:
-            result = ctor(value.source, reFlags.exec(value));
-            result.lastIndex = value.lastIndex;
-            return result;
-        }
-      } else {
-        return value;
-      }
-      var isArr = isArray(value);
-      if (isDeep) {
-        // check for circular references and return corresponding clone
-        var initedStack = !stackA;
-        stackA || (stackA = getArray());
-        stackB || (stackB = getArray());
-
-        var length = stackA.length;
-        while (length--) {
-          if (stackA[length] == value) {
-            return stackB[length];
-          }
-        }
-        result = isArr ? ctor(value.length) : {};
-      }
-      else {
-        result = isArr ? slice(value) : assign({}, value);
-      }
-      // add array properties assigned by `RegExp#exec`
-      if (isArr) {
-        if (hasOwnProperty.call(value, 'index')) {
-          result.index = value.index;
-        }
-        if (hasOwnProperty.call(value, 'input')) {
-          result.input = value.input;
-        }
-      }
-      // exit for shallow clone
-      if (!isDeep) {
-        return result;
-      }
-      // add the source value to the stack of traversed objects
-      // and associate it with its clone
-      stackA.push(value);
-      stackB.push(result);
-
-      // recursively populate clone (susceptible to call stack limits)
-      (isArr ? forEach : forOwn)(value, function(objValue, key) {
-        result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
-      });
-
-      if (initedStack) {
-        releaseArray(stackA);
-        releaseArray(stackB);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.create` without support for assigning
-     * properties to the created object.
-     *
-     * @private
-     * @param {Object} prototype The object to inherit from.
-     * @returns {Object} Returns the new object.
-     */
-    function baseCreate(prototype, properties) {
-      return isObject(prototype) ? nativeCreate(prototype) : {};
-    }
-    // fallback for browsers without `Object.create`
-    if (!nativeCreate) {
-      baseCreate = (function() {
-        function Object() {}
-        return function(prototype) {
-          if (isObject(prototype)) {
-            Object.prototype = prototype;
-            var result = new Object;
-            Object.prototype = null;
-          }
-          return result || context.Object();
-        };
-      }());
-    }
-
-    /**
-     * The base implementation of `_.createCallback` without support for creating
-     * "_.pluck" or "_.where" style callbacks.
-     *
-     * @private
-     * @param {*} [func=identity] The value to convert to a callback.
-     * @param {*} [thisArg] The `this` binding of the created callback.
-     * @param {number} [argCount] The number of arguments the callback accepts.
-     * @returns {Function} Returns a callback function.
-     */
-    function baseCreateCallback(func, thisArg, argCount) {
-      if (typeof func != 'function') {
-        return identity;
-      }
-      // exit early for no `thisArg` or already bound by `Function#bind`
-      if (typeof thisArg == 'undefined' || !('prototype' in func)) {
-        return func;
-      }
-      var bindData = func.__bindData__;
-      if (typeof bindData == 'undefined') {
-        if (support.funcNames) {
-          bindData = !func.name;
-        }
-        bindData = bindData || !support.funcDecomp;
-        if (!bindData) {
-          var source = fnToString.call(func);
-          if (!support.funcNames) {
-            bindData = !reFuncName.test(source);
-          }
-          if (!bindData) {
-            // checks if `func` references the `this` keyword and stores the result
-            bindData = reThis.test(source);
-            setBindData(func, bindData);
-          }
-        }
-      }
-      // exit early if there are no `this` references or `func` is bound
-      if (bindData === false || (bindData !== true && bindData[1] & 1)) {
-        return func;
-      }
-      switch (argCount) {
-        case 1: return function(value) {
-          return func.call(thisArg, value);
-        };
-        case 2: return function(a, b) {
-          return func.call(thisArg, a, b);
-        };
-        case 3: return function(value, index, collection) {
-          return func.call(thisArg, value, index, collection);
-        };
-        case 4: return function(accumulator, value, index, collection) {
-          return func.call(thisArg, accumulator, value, index, collection);
-        };
-      }
-      return bind(func, thisArg);
-    }
-
-    /**
-     * The base implementation of `createWrapper` that creates the wrapper and
-     * sets its meta data.
-     *
-     * @private
-     * @param {Array} bindData The bind data array.
-     * @returns {Function} Returns the new function.
-     */
-    function baseCreateWrapper(bindData) {
-      var func = bindData[0],
-          bitmask = bindData[1],
-          partialArgs = bindData[2],
-          partialRightArgs = bindData[3],
-          thisArg = bindData[4],
-          arity = bindData[5];
-
-      var isBind = bitmask & 1,
-          isBindKey = bitmask & 2,
-          isCurry = bitmask & 4,
-          isCurryBound = bitmask & 8,
-          key = func;
-
-      function bound() {
-        var thisBinding = isBind ? thisArg : this;
-        if (partialArgs) {
-          var args = slice(partialArgs);
-          push.apply(args, arguments);
-        }
-        if (partialRightArgs || isCurry) {
-          args || (args = slice(arguments));
-          if (partialRightArgs) {
-            push.apply(args, partialRightArgs);
-          }
-          if (isCurry && args.length < arity) {
-            bitmask |= 16 & ~32;
-            return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
-          }
-        }
-        args || (args = arguments);
-        if (isBindKey) {
-          func = thisBinding[key];
-        }
-        if (this instanceof bound) {
-          thisBinding = baseCreate(func.prototype);
-          var result = func.apply(thisBinding, args);
-          return isObject(result) ? result : thisBinding;
-        }
-        return func.apply(thisBinding, args);
-      }
-      setBindData(bound, bindData);
-      return bound;
-    }
-
-    /**
-     * The base implementation of `_.difference` that accepts a single array
-     * of values to exclude.
-     *
-     * @private
-     * @param {Array} array The array to process.
-     * @param {Array} [values] The array of values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     */
-    function baseDifference(array, values) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = array ? array.length : 0,
-          isLarge = length >= largeArraySize && indexOf === baseIndexOf,
-          result = [];
-
-      if (isLarge) {
-        var cache = createCache(values);
-        if (cache) {
-          indexOf = cacheIndexOf;
-          values = cache;
-        } else {
-          isLarge = false;
-        }
-      }
-      while (++index < length) {
-        var value = array[index];
-        if (indexOf(values, value) < 0) {
-          result.push(value);
-        }
-      }
-      if (isLarge) {
-        releaseObject(values);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.flatten` without support for callback
-     * shorthands or `thisArg` binding.
-     *
-     * @private
-     * @param {Array} array The array to flatten.
-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
-     * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
-     * @param {number} [fromIndex=0] The index to start from.
-     * @returns {Array} Returns a new flattened array.
-     */
-    function baseFlatten(array, isShallow, isStrict, fromIndex) {
-      var index = (fromIndex || 0) - 1,
-          length = array ? array.length : 0,
-          result = [];
-
-      while (++index < length) {
-        var value = array[index];
-
-        if (value && typeof value == 'object' && typeof value.length == 'number'
-            && (isArray(value) || isArguments(value))) {
-          // recursively flatten arrays (susceptible to call stack limits)
-          if (!isShallow) {
-            value = baseFlatten(value, isShallow, isStrict);
-          }
-          var valIndex = -1,
-              valLength = value.length,
-              resIndex = result.length;
-
-          result.length += valLength;
-          while (++valIndex < valLength) {
-            result[resIndex++] = value[valIndex];
-          }
-        } else if (!isStrict) {
-          result.push(value);
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.isEqual`, without support for `thisArg` binding,
-     * that allows partial "_.where" style comparisons.
-     *
-     * @private
-     * @param {*} a The value to compare.
-     * @param {*} b The other value to compare.
-     * @param {Function} [callback] The function to customize comparing values.
-     * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
-     * @param {Array} [stackA=[]] Tracks traversed `a` objects.
-     * @param {Array} [stackB=[]] Tracks traversed `b` objects.
-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-     */
-    function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
-      // used to indicate that when comparing objects, `a` has at least the properties of `b`
-      if (callback) {
-        var result = callback(a, b);
-        if (typeof result != 'undefined') {
-          return !!result;
-        }
-      }
-      // exit early for identical values
-      if (a === b) {
-        // treat `+0` vs. `-0` as not equal
-        return a !== 0 || (1 / a == 1 / b);
-      }
-      var type = typeof a,
-          otherType = typeof b;
-
-      // exit early for unlike primitive values
-      if (a === a &&
-          !(a && objectTypes[type]) &&
-          !(b && objectTypes[otherType])) {
-        return false;
-      }
-      // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
-      // http://es5.github.io/#x15.3.4.4
-      if (a == null || b == null) {
-        return a === b;
-      }
-      // compare [[Class]] names
-      var className = toString.call(a),
-          otherClass = toString.call(b);
-
-      if (className == argsClass) {
-        className = objectClass;
-      }
-      if (otherClass == argsClass) {
-        otherClass = objectClass;
-      }
-      if (className != otherClass) {
-        return false;
-      }
-      switch (className) {
-        case boolClass:
-        case dateClass:
-          // coerce dates and booleans to numbers, dates to milliseconds and booleans
-          // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
-          return +a == +b;
-
-        case numberClass:
-          // treat `NaN` vs. `NaN` as equal
-          return (a != +a)
-            ? b != +b
-            // but treat `+0` vs. `-0` as not equal
-            : (a == 0 ? (1 / a == 1 / b) : a == +b);
-
-        case regexpClass:
-        case stringClass:
-          // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
-          // treat string primitives and their corresponding object instances as equal
-          return a == String(b);
-      }
-      var isArr = className == arrayClass;
-      if (!isArr) {
-        // unwrap any `lodash` wrapped values
-        var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
-            bWrapped = hasOwnProperty.call(b, '__wrapped__');
-
-        if (aWrapped || bWrapped) {
-          return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
-        }
-        // exit for functions and DOM nodes
-        if (className != objectClass) {
-          return false;
-        }
-        // in older versions of Opera, `arguments` objects have `Array` constructors
-        var ctorA = a.constructor,
-            ctorB = b.constructor;
-
-        // non `Object` object instances with different constructors are not equal
-        if (ctorA != ctorB &&
-              !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
-              ('constructor' in a && 'constructor' in b)
-            ) {
-          return false;
-        }
-      }
-      // assume cyclic structures are equal
-      // the algorithm for detecting cyclic structures is adapted from ES 5.1
-      // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
-      var initedStack = !stackA;
-      stackA || (stackA = getArray());
-      stackB || (stackB = getArray());
-
-      var length = stackA.length;
-      while (length--) {
-        if (stackA[length] == a) {
-          return stackB[length] == b;
-        }
-      }
-      var size = 0;
-      result = true;
-
-      // add `a` and `b` to the stack of traversed objects
-      stackA.push(a);
-      stackB.push(b);
-
-      // recursively compare objects and arrays (susceptible to call stack limits)
-      if (isArr) {
-        // compare lengths to determine if a deep comparison is necessary
-        length = a.length;
-        size = b.length;
-        result = size == length;
-
-        if (result || isWhere) {
-          // deep compare the contents, ignoring non-numeric properties
-          while (size--) {
-            var index = length,
-                value = b[size];
-
-            if (isWhere) {
-              while (index--) {
-                if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
-                  break;
-                }
-              }
-            } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
-              break;
-            }
-          }
-        }
-      }
-      else {
-        // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
-        // which, in this case, is more costly
-        forIn(b, function(value, key, b) {
-          if (hasOwnProperty.call(b, key)) {
-            // count the number of properties.
-            size++;
-            // deep compare each property value.
-            return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
-          }
-        });
-
-        if (result && !isWhere) {
-          // ensure both objects have the same number of properties
-          forIn(a, function(value, key, a) {
-            if (hasOwnProperty.call(a, key)) {
-              // `size` will be `-1` if `a` has more properties than `b`
-              return (result = --size > -1);
-            }
-          });
-        }
-      }
-      stackA.pop();
-      stackB.pop();
-
-      if (initedStack) {
-        releaseArray(stackA);
-        releaseArray(stackB);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.merge` without argument juggling or support
-     * for `thisArg` binding.
-     *
-     * @private
-     * @param {Object} object The destination object.
-     * @param {Object} source The source object.
-     * @param {Function} [callback] The function to customize merging properties.
-     * @param {Array} [stackA=[]] Tracks traversed source objects.
-     * @param {Array} [stackB=[]] Associates values with source counterparts.
-     */
-    function baseMerge(object, source, callback, stackA, stackB) {
-      (isArray(source) ? forEach : forOwn)(source, function(source, key) {
-        var found,
-            isArr,
-            result = source,
-            value = object[key];
-
-        if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
-          // avoid merging previously merged cyclic sources
-          var stackLength = stackA.length;
-          while (stackLength--) {
-            if ((found = stackA[stackLength] == source)) {
-              value = stackB[stackLength];
-              break;
-            }
-          }
-          if (!found) {
-            var isShallow;
-            if (callback) {
-              result = callback(value, source);
-              if ((isShallow = typeof result != 'undefined')) {
-                value = result;
-              }
-            }
-            if (!isShallow) {
-              value = isArr
-                ? (isArray(value) ? value : [])
-                : (isPlainObject(value) ? value : {});
-            }
-            // add `source` and associated `value` to the stack of traversed objects
-            stackA.push(source);
-            stackB.push(value);
-
-            // recursively merge objects and arrays (susceptible to call stack limits)
-            if (!isShallow) {
-              baseMerge(value, source, callback, stackA, stackB);
-            }
-          }
-        }
-        else {
-          if (callback) {
-            result = callback(value, source);
-            if (typeof result == 'undefined') {
-              result = source;
-            }
-          }
-          if (typeof result != 'undefined') {
-            value = result;
-          }
-        }
-        object[key] = value;
-      });
-    }
-
-    /**
-     * The base implementation of `_.random` without argument juggling or support
-     * for returning floating-point numbers.
-     *
-     * @private
-     * @param {number} min The minimum possible value.
-     * @param {number} max The maximum possible value.
-     * @returns {number} Returns a random number.
-     */
-    function baseRandom(min, max) {
-      return min + floor(nativeRandom() * (max - min + 1));
-    }
-
-    /**
-     * The base implementation of `_.uniq` without support for callback shorthands
-     * or `thisArg` binding.
-     *
-     * @private
-     * @param {Array} array The array to process.
-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
-     * @param {Function} [callback] The function called per iteration.
-     * @returns {Array} Returns a duplicate-value-free array.
-     */
-    function baseUniq(array, isSorted, callback) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = array ? array.length : 0,
-          result = [];
-
-      var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
-          seen = (callback || isLarge) ? getArray() : result;
-
-      if (isLarge) {
-        var cache = createCache(seen);
-        indexOf = cacheIndexOf;
-        seen = cache;
-      }
-      while (++index < length) {
-        var value = array[index],
-            computed = callback ? callback(value, index, array) : value;
-
-        if (isSorted
-              ? !index || seen[seen.length - 1] !== computed
-              : indexOf(seen, computed) < 0
-            ) {
-          if (callback || isLarge) {
-            seen.push(computed);
-          }
-          result.push(value);
-        }
-      }
-      if (isLarge) {
-        releaseArray(seen.array);
-        releaseObject(seen);
-      } else if (callback) {
-        releaseArray(seen);
-      }
-      return result;
-    }
-
-    /**
-     * Creates a function that aggregates a collection, creating an object composed
-     * of keys generated from the results of running each element of the collection
-     * through a callback. The given `setter` function sets the keys and values
-     * of the composed object.
-     *
-     * @private
-     * @param {Function} setter The setter function.
-     * @returns {Function} Returns the new aggregator function.
-     */
-    function createAggregator(setter) {
-      return function(collection, callback, thisArg) {
-        var result = {};
-        callback = lodash.createCallback(callback, thisArg, 3);
-
-        var index = -1,
-            length = collection ? collection.length : 0;
-
-        if (typeof length == 'number') {
-          while (++index < length) {
-            var value = collection[index];
-            setter(result, value, callback(value, index, collection), collection);
-          }
-        } else {
-          forOwn(collection, function(value, key, collection) {
-            setter(result, value, callback(value, key, collection), collection);
-          });
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Creates a function that, when called, either curries or invokes `func`
-     * with an optional `this` binding and partially applied arguments.
-     *
-     * @private
-     * @param {Function|string} func The function or method name to reference.
-     * @param {number} bitmask The bitmask of method flags to compose.
-     *  The bitmask may be composed of the following flags:
-     *  1 - `_.bind`
-     *  2 - `_.bindKey`
-     *  4 - `_.curry`
-     *  8 - `_.curry` (bound)
-     *  16 - `_.partial`
-     *  32 - `_.partialRight`
-     * @param {Array} [partialArgs] An array of arguments to prepend to those
-     *  provided to the new function.
-     * @param {Array} [partialRightArgs] An array of arguments to append to those
-     *  provided to the new function.
-     * @param {*} [thisArg] The `this` binding of `func`.
-     * @param {number} [arity] The arity of `func`.
-     * @returns {Function} Returns the new function.
-     */
-    function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
-      var isBind = bitmask & 1,
-          isBindKey = bitmask & 2,
-          isCurry = bitmask & 4,
-          isCurryBound = bitmask & 8,
-          isPartial = bitmask & 16,
-          isPartialRight = bitmask & 32;
-
-      if (!isBindKey && !isFunction(func)) {
-        throw new TypeError;
-      }
-      if (isPartial && !partialArgs.length) {
-        bitmask &= ~16;
-        isPartial = partialArgs = false;
-      }
-      if (isPartialRight && !partialRightArgs.length) {
-        bitmask &= ~32;
-        isPartialRight = partialRightArgs = false;
-      }
-      var bindData = func && func.__bindData__;
-      if (bindData && bindData !== true) {
-        // clone `bindData`
-        bindData = slice(bindData);
-        if (bindData[2]) {
-          bindData[2] = slice(bindData[2]);
-        }
-        if (bindData[3]) {
-          bindData[3] = slice(bindData[3]);
-        }
-        // set `thisBinding` is not previously bound
-        if (isBind && !(bindData[1] & 1)) {
-          bindData[4] = thisArg;
-        }
-        // set if previously bound but not currently (subsequent curried functions)
-        if (!isBind && bindData[1] & 1) {
-          bitmask |= 8;
-        }
-        // set curried arity if not yet set
-        if (isCurry && !(bindData[1] & 4)) {
-          bindData[5] = arity;
-        }
-        // append partial left arguments
-        if (isPartial) {
-          push.apply(bindData[2] || (bindData[2] = []), partialArgs);
-        }
-        // append partial right arguments
-        if (isPartialRight) {
-          unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
-        }
-        // merge flags
-        bindData[1] |= bitmask;
-        return createWrapper.apply(null, bindData);
-      }
-      // fast path for `_.bind`
-      var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
-      return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
-    }
-
-    /**
-     * Used by `escape` to convert characters to HTML entities.
-     *
-     * @private
-     * @param {string} match The matched character to escape.
-     * @returns {string} Returns the escaped character.
-     */
-    function escapeHtmlChar(match) {
-      return htmlEscapes[match];
-    }
-
-    /**
-     * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
-     * customized, this method returns the custom method, otherwise it returns
-     * the `baseIndexOf` function.
-     *
-     * @private
-     * @returns {Function} Returns the "indexOf" function.
-     */
-    function getIndexOf() {
-      var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
-      return result;
-    }
-
-    /**
-     * Checks if `value` is a native function.
-     *
-     * @private
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
-     */
-    function isNative(value) {
-      return typeof value == 'function' && reNative.test(value);
-    }
-
-    /**
-     * Sets `this` binding data on a given function.
-     *
-     * @private
-     * @param {Function} func The function to set data on.
-     * @param {Array} value The data array to set.
-     */
-    var setBindData = !defineProperty ? noop : function(func, value) {
-      descriptor.value = value;
-      defineProperty(func, '__bindData__', descriptor);
-      descriptor.value = null;
-    };
-
-    /**
-     * A fallback implementation of `isPlainObject` which checks if a given value
-     * is an object created by the `Object` constructor, assuming objects created
-     * by the `Object` constructor have no inherited enumerable properties and that
-     * there are no `Object.prototype` extensions.
-     *
-     * @private
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-     */
-    function shimIsPlainObject(value) {
-      var ctor,
-          result;
-
-      // avoid non Object objects, `arguments` objects, and DOM elements
-      if (!(value && toString.call(value) == objectClass) ||
-          (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
-        return false;
-      }
-      // In most environments an object's own properties are iterated before
-      // its inherited properties. If the last iterated property is an object's
-      // own property then there are no inherited enumerable properties.
-      forIn(value, function(value, key) {
-        result = key;
-      });
-      return typeof result == 'undefined' || hasOwnProperty.call(value, result);
-    }
-
-    /**
-     * Used by `unescape` to convert HTML entities to characters.
-     *
-     * @private
-     * @param {string} match The matched character to unescape.
-     * @returns {string} Returns the unescaped character.
-     */
-    function unescapeHtmlChar(match) {
-      return htmlUnescapes[match];
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Checks if `value` is an `arguments` object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
-     * @example
-     *
-     * (function() { return _.isArguments(arguments); })(1, 2, 3);
-     * // => true
-     *
-     * _.isArguments([1, 2, 3]);
-     * // => false
-     */
-    function isArguments(value) {
-      return value && typeof value == 'object' && typeof value.length == 'number' &&
-        toString.call(value) == argsClass || false;
-    }
-
-    /**
-     * Checks if `value` is an array.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
-     * @example
-     *
-     * (function() { return _.isArray(arguments); })();
-     * // => false
-     *
-     * _.isArray([1, 2, 3]);
-     * // => true
-     */
-    var isArray = nativeIsArray || function(value) {
-      return value && typeof value == 'object' && typeof value.length == 'number' &&
-        toString.call(value) == arrayClass || false;
-    };
-
-    /**
-     * A fallback implementation of `Object.keys` which produces an array of the
-     * given object's own enumerable property names.
-     *
-     * @private
-     * @type Function
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names.
-     */
-    var shimKeys = function(object) {
-      var index, iterable = object, result = [];
-      if (!iterable) return result;
-      if (!(objectTypes[typeof object])) return result;
-        for (index in iterable) {
-          if (hasOwnProperty.call(iterable, index)) {
-            result.push(index);
-          }
-        }
-      return result
-    };
-
-    /**
-     * Creates an array composed of the own enumerable property names of an object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names.
-     * @example
-     *
-     * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
-     */
-    var keys = !nativeKeys ? shimKeys : function(object) {
-      if (!isObject(object)) {
-        return [];
-      }
-      return nativeKeys(object);
-    };
-
-    /**
-     * Used to convert characters to HTML entities:
-     *
-     * Though the `>` character is escaped for symmetry, characters like `>` and `/`
-     * don't require escaping in HTML and have no special meaning unless they're part
-     * of a tag or an unquoted attribute value.
-     * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
-     */
-    var htmlEscapes = {
-      '&': '&',
-      '<': '<',
-      '>': '>',
-      '"': '"',
-      "'": '''
-    };
-
-    /** Used to convert HTML entities to characters */
-    var htmlUnescapes = invert(htmlEscapes);
-
-    /** Used to match HTML entities and HTML characters */
-    var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
-        reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Assigns own enumerable properties of source object(s) to the destination
-     * object. Subsequent sources will overwrite property assignments of previous
-     * sources. If a callback is provided it will be executed to produce the
-     * assigned values. The callback is bound to `thisArg` and invoked with two
-     * arguments; (objectValue, sourceValue).
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @alias extend
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param {Function} [callback] The function to customize assigning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
-     * // => { 'name': 'fred', 'employer': 'slate' }
-     *
-     * var defaults = _.partialRight(_.assign, function(a, b) {
-     *   return typeof a == 'undefined' ? b : a;
-     * });
-     *
-     * var object = { 'name': 'barney' };
-     * defaults(object, { 'name': 'fred', 'employer': 'slate' });
-     * // => { 'name': 'barney', 'employer': 'slate' }
-     */
-    var assign = function(object, source, guard) {
-      var index, iterable = object, result = iterable;
-      if (!iterable) return result;
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = typeof guard == 'number' ? 2 : args.length;
-      if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
-        var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
-      } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
-        callback = args[--argsLength];
-      }
-      while (++argsIndex < argsLength) {
-        iterable = args[argsIndex];
-        if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
-        }
-        }
-      }
-      return result
-    };
-
-    /**
-     * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
-     * be cloned, otherwise they will be assigned by reference. If a callback
-     * is provided it will be executed to produce the cloned values. If the
-     * callback returns `undefined` cloning will be handled by the method instead.
-     * The callback is bound to `thisArg` and invoked with one argument; (value).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to clone.
-     * @param {boolean} [isDeep=false] Specify a deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the cloned value.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * var shallow = _.clone(characters);
-     * shallow[0] === characters[0];
-     * // => true
-     *
-     * var deep = _.clone(characters, true);
-     * deep[0] === characters[0];
-     * // => false
-     *
-     * _.mixin({
-     *   'clone': _.partialRight(_.clone, function(value) {
-     *     return _.isElement(value) ? value.cloneNode(false) : undefined;
-     *   })
-     * });
-     *
-     * var clone = _.clone(document.body);
-     * clone.childNodes.length;
-     * // => 0
-     */
-    function clone(value, isDeep, callback, thisArg) {
-      // allows working with "Collections" methods without using their `index`
-      // and `collection` arguments for `isDeep` and `callback`
-      if (typeof isDeep != 'boolean' && isDeep != null) {
-        thisArg = callback;
-        callback = isDeep;
-        isDeep = false;
-      }
-      return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
-    }
-
-    /**
-     * Creates a deep clone of `value`. If a callback is provided it will be
-     * executed to produce the cloned values. If the callback returns `undefined`
-     * cloning will be handled by the method instead. The callback is bound to
-     * `thisArg` and invoked with one argument; (value).
-     *
-     * Note: This method is loosely based on the structured clone algorithm. Functions
-     * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
-     * objects created by constructors other than `Object` are cloned to plain `Object` objects.
-     * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the deep cloned value.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * var deep = _.cloneDeep(characters);
-     * deep[0] === characters[0];
-     * // => false
-     *
-     * var view = {
-     *   'label': 'docs',
-     *   'node': element
-     * };
-     *
-     * var clone = _.cloneDeep(view, function(value) {
-     *   return _.isElement(value) ? value.cloneNode(true) : undefined;
-     * });
-     *
-     * clone.node == view.node;
-     * // => false
-     */
-    function cloneDeep(value, callback, thisArg) {
-      return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
-    }
-
-    /**
-     * Creates an object that inherits from the given `prototype` object. If a
-     * `properties` object is provided its own enumerable properties are assigned
-     * to the created object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} prototype The object to inherit from.
-     * @param {Object} [properties] The properties to assign to the object.
-     * @returns {Object} Returns the new object.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * function Circle() {
-     *   Shape.call(this);
-     * }
-     *
-     * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
-     *
-     * var circle = new Circle;
-     * circle instanceof Circle;
-     * // => true
-     *
-     * circle instanceof Shape;
-     * // => true
-     */
-    function create(prototype, properties) {
-      var result = baseCreate(prototype);
-      return properties ? assign(result, properties) : result;
-    }
-
-    /**
-     * Assigns own enumerable properties of source object(s) to the destination
-     * object for all destination properties that resolve to `undefined`. Once a
-     * property is set, additional defaults of the same property will be ignored.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param- {Object} [guard] Allows working with `_.reduce` without using its
-     *  `key` and `object` arguments as sources.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * var object = { 'name': 'barney' };
-     * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
-     * // => { 'name': 'barney', 'employer': 'slate' }
-     */
-    var defaults = function(object, source, guard) {
-      var index, iterable = object, result = iterable;
-      if (!iterable) return result;
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = typeof guard == 'number' ? 2 : args.length;
-      while (++argsIndex < argsLength) {
-        iterable = args[argsIndex];
-        if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (typeof result[index] == 'undefined') result[index] = iterable[index];
-        }
-        }
-      }
-      return result
-    };
-
-    /**
-     * This method is like `_.findIndex` except that it returns the key of the
-     * first element that passes the callback check, instead of the element itself.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to search.
-     * @param {Function|Object|string} [callback=identity] The function called per
-     *  iteration. If a property name or object is provided it will be used to
-     *  create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
-     * @example
-     *
-     * var characters = {
-     *   'barney': {  'age': 36, 'blocked': false },
-     *   'fred': {    'age': 40, 'blocked': true },
-     *   'pebbles': { 'age': 1,  'blocked': false }
-     * };
-     *
-     * _.findKey(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => 'barney' (property order is not guaranteed across environments)
-     *
-     * // using "_.where" callback shorthand
-     * _.findKey(characters, { 'age': 1 });
-     * // => 'pebbles'
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findKey(characters, 'blocked');
-     * // => 'fred'
-     */
-    function findKey(object, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forOwn(object, function(value, key, object) {
-        if (callback(value, key, object)) {
-          result = key;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * This method is like `_.findKey` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to search.
-     * @param {Function|Object|string} [callback=identity] The function called per
-     *  iteration. If a property name or object is provided it will be used to
-     *  create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
-     * @example
-     *
-     * var characters = {
-     *   'barney': {  'age': 36, 'blocked': true },
-     *   'fred': {    'age': 40, 'blocked': false },
-     *   'pebbles': { 'age': 1,  'blocked': true }
-     * };
-     *
-     * _.findLastKey(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => returns `pebbles`, assuming `_.findKey` returns `barney`
-     *
-     * // using "_.where" callback shorthand
-     * _.findLastKey(characters, { 'age': 40 });
-     * // => 'fred'
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findLastKey(characters, 'blocked');
-     * // => 'pebbles'
-     */
-    function findLastKey(object, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forOwnRight(object, function(value, key, object) {
-        if (callback(value, key, object)) {
-          result = key;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * Iterates over own and inherited enumerable properties of an object,
-     * executing the callback for each property. The callback is bound to `thisArg`
-     * and invoked with three arguments; (value, key, object). Callbacks may exit
-     * iteration early by explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * Shape.prototype.move = function(x, y) {
-     *   this.x += x;
-     *   this.y += y;
-     * };
-     *
-     * _.forIn(new Shape, function(value, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
-     */
-    var forIn = function(collection, callback, thisArg) {
-      var index, iterable = collection, result = iterable;
-      if (!iterable) return result;
-      if (!objectTypes[typeof iterable]) return result;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-        for (index in iterable) {
-          if (callback(iterable[index], index, collection) === false) return result;
-        }
-      return result
-    };
-
-    /**
-     * This method is like `_.forIn` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * Shape.prototype.move = function(x, y) {
-     *   this.x += x;
-     *   this.y += y;
-     * };
-     *
-     * _.forInRight(new Shape, function(value, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
-     */
-    function forInRight(object, callback, thisArg) {
-      var pairs = [];
-
-      forIn(object, function(value, key) {
-        pairs.push(key, value);
-      });
-
-      var length = pairs.length;
-      callback = baseCreateCallback(callback, thisArg, 3);
-      while (length--) {
-        if (callback(pairs[length--], pairs[length], object) === false) {
-          break;
-        }
-      }
-      return object;
-    }
-
-    /**
-     * Iterates over own enumerable properties of an object, executing the callback
-     * for each property. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, key, object). Callbacks may exit iteration early by
-     * explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
-     *   console.log(key);
-     * });
-     * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
-     */
-    var forOwn = function(collection, callback, thisArg) {
-      var index, iterable = collection, result = iterable;
-      if (!iterable) return result;
-      if (!objectTypes[typeof iterable]) return result;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (callback(iterable[index], index, collection) === false) return result;
-        }
-      return result
-    };
-
-    /**
-     * This method is like `_.forOwn` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
-     */
-    function forOwnRight(object, callback, thisArg) {
-      var props = keys(object),
-          length = props.length;
-
-      callback = baseCreateCallback(callback, thisArg, 3);
-      while (length--) {
-        var key = props[length];
-        if (callback(object[key], key, object) === false) {
-          break;
-        }
-      }
-      return object;
-    }
-
-    /**
-     * Creates a sorted array of property names of all enumerable properties,
-     * own and inherited, of `object` that have function values.
-     *
-     * @static
-     * @memberOf _
-     * @alias methods
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names that have function values.
-     * @example
-     *
-     * _.functions(_);
-     * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
-     */
-    function functions(object) {
-      var result = [];
-      forIn(object, function(value, key) {
-        if (isFunction(value)) {
-          result.push(key);
-        }
-      });
-      return result.sort();
-    }
-
-    /**
-     * Checks if the specified property name exists as a direct property of `object`,
-     * instead of an inherited property.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @param {string} key The name of the property to check.
-     * @returns {boolean} Returns `true` if key is a direct property, else `false`.
-     * @example
-     *
-     * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
-     * // => true
-     */
-    function has(object, key) {
-      return object ? hasOwnProperty.call(object, key) : false;
-    }
-
-    /**
-     * Creates an object composed of the inverted keys and values of the given object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to invert.
-     * @returns {Object} Returns the created inverted object.
-     * @example
-     *
-     * _.invert({ 'first': 'fred', 'second': 'barney' });
-     * // => { 'fred': 'first', 'barney': 'second' }
-     */
-    function invert(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = {};
-
-      while (++index < length) {
-        var key = props[index];
-        result[object[key]] = key;
-      }
-      return result;
-    }
-
-    /**
-     * Checks if `value` is a boolean value.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
-     * @example
-     *
-     * _.isBoolean(null);
-     * // => false
-     */
-    function isBoolean(value) {
-      return value === true || value === false ||
-        value && typeof value == 'object' && toString.call(value) == boolClass || false;
-    }
-
-    /**
-     * Checks if `value` is a date.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
-     * @example
-     *
-     * _.isDate(new Date);
-     * // => true
-     */
-    function isDate(value) {
-      return value && typeof value == 'object' && toString.call(value) == dateClass || false;
-    }
-
-    /**
-     * Checks if `value` is a DOM element.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
-     * @example
-     *
-     * _.isElement(document.body);
-     * // => true
-     */
-    function isElement(value) {
-      return value && value.nodeType === 1 || false;
-    }
-
-    /**
-     * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
-     * length of `0` and objects with no own enumerable properties are considered
-     * "empty".
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Array|Object|string} value The value to inspect.
-     * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
-     * @example
-     *
-     * _.isEmpty([1, 2, 3]);
-     * // => false
-     *
-     * _.isEmpty({});
-     * // => true
-     *
-     * _.isEmpty('');
-     * // => true
-     */
-    function isEmpty(value) {
-      var result = true;
-      if (!value) {
-        return result;
-      }
-      var className = toString.call(value),
-          length = value.length;
-
-      if ((className == arrayClass || className == stringClass || className == argsClass ) ||
-          (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
-        return !length;
-      }
-      forOwn(value, function() {
-        return (result = false);
-      });
-      return result;
-    }
-
-    /**
-     * Performs a deep comparison between two values to determine if they are
-     * equivalent to each other. If a callback is provided it will be executed
-     * to compare values. If the callback returns `undefined` comparisons will
-     * be handled by the method instead. The callback is bound to `thisArg` and
-     * invoked with two arguments; (a, b).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} a The value to compare.
-     * @param {*} b The other value to compare.
-     * @param {Function} [callback] The function to customize comparing values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * var copy = { 'name': 'fred' };
-     *
-     * object == copy;
-     * // => false
-     *
-     * _.isEqual(object, copy);
-     * // => true
-     *
-     * var words = ['hello', 'goodbye'];
-     * var otherWords = ['hi', 'goodbye'];
-     *
-     * _.isEqual(words, otherWords, function(a, b) {
-     *   var reGreet = /^(?:hello|hi)$/i,
-     *       aGreet = _.isString(a) && reGreet.test(a),
-     *       bGreet = _.isString(b) && reGreet.test(b);
-     *
-     *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
-     * });
-     * // => true
-     */
-    function isEqual(a, b, callback, thisArg) {
-      return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
-    }
-
-    /**
-     * Checks if `value` is, or can be coerced to, a finite number.
-     *
-     * Note: This is not the same as native `isFinite` which will return true for
-     * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
-     * @example
-     *
-     * _.isFinite(-101);
-     * // => true
-     *
-     * _.isFinite('10');
-     * // => true
-     *
-     * _.isFinite(true);
-     * // => false
-     *
-     * _.isFinite('');
-     * // => false
-     *
-     * _.isFinite(Infinity);
-     * // => false
-     */
-    function isFinite(value) {
-      return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
-    }
-
-    /**
-     * Checks if `value` is a function.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
-     * @example
-     *
-     * _.isFunction(_);
-     * // => true
-     */
-    function isFunction(value) {
-      return typeof value == 'function';
-    }
-
-    /**
-     * Checks if `value` is the language type of Object.
-     * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
-     * @example
-     *
-     * _.isObject({});
-     * // => true
-     *
-     * _.isObject([1, 2, 3]);
-     * // => true
-     *
-     * _.isObject(1);
-     * // => false
-     */
-    function isObject(value) {
-      // check if the value is the ECMAScript language type of Object
-      // http://es5.github.io/#x8
-      // and avoid a V8 bug
-      // http://code.google.com/p/v8/issues/detail?id=2291
-      return !!(value && objectTypes[typeof value]);
-    }
-
-    /**
-     * Checks if `value` is `NaN`.
-     *
-     * Note: This is not the same as native `isNaN` which will return `true` for
-     * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
-     * @example
-     *
-     * _.isNaN(NaN);
-     * // => true
-     *
-     * _.isNaN(new Number(NaN));
-     * // => true
-     *
-     * isNaN(undefined);
-     * // => true
-     *
-     * _.isNaN(undefined);
-     * // => false
-     */
-    function isNaN(value) {
-      // `NaN` as a primitive is the only value that is not equal to itself
-      // (perform the [[Class]] check first to avoid errors with some host objects in IE)
-      return isNumber(value) && value != +value;
-    }
-
-    /**
-     * Checks if `value` is `null`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
-     * @example
-     *
-     * _.isNull(null);
-     * // => true
-     *
-     * _.isNull(undefined);
-     * // => false
-     */
-    function isNull(value) {
-      return value === null;
-    }
-
-    /**
-     * Checks if `value` is a number.
-     *
-     * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
-     * @example
-     *
-     * _.isNumber(8.4 * 5);
-     * // => true
-     */
-    function isNumber(value) {
-      return typeof value == 'number' ||
-        value && typeof value == 'object' && toString.call(value) == numberClass || false;
-    }
-
-    /**
-     * Checks if `value` is an object created by the `Object` constructor.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * _.isPlainObject(new Shape);
-     * // => false
-     *
-     * _.isPlainObject([1, 2, 3]);
-     * // => false
-     *
-     * _.isPlainObject({ 'x': 0, 'y': 0 });
-     * // => true
-     */
-    var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
-      if (!(value && toString.call(value) == objectClass)) {
-        return false;
-      }
-      var valueOf = value.valueOf,
-          objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
-
-      return objProto
-        ? (value == objProto || getPrototypeOf(value) == objProto)
-        : shimIsPlainObject(value);
-    };
-
-    /**
-     * Checks if `value` is a regular expression.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
-     * @example
-     *
-     * _.isRegExp(/fred/);
-     * // => true
-     */
-    function isRegExp(value) {
-      return value && typeof value == 'object' && toString.call(value) == regexpClass || false;
-    }
-
-    /**
-     * Checks if `value` is a string.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
-     * @example
-     *
-     * _.isString('fred');
-     * // => true
-     */
-    function isString(value) {
-      return typeof value == 'string' ||
-        value && typeof value == 'object' && toString.call(value) == stringClass || false;
-    }
-
-    /**
-     * Checks if `value` is `undefined`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
-     * @example
-     *
-     * _.isUndefined(void 0);
-     * // => true
-     */
-    function isUndefined(value) {
-      return typeof value == 'undefined';
-    }
-
-    /**
-     * Creates an object with the same keys as `object` and values generated by
-     * running each own enumerable property of `object` through the callback.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new object with values of the results of each `callback` execution.
-     * @example
-     *
-     * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     *
-     * var characters = {
-     *   'fred': { 'name': 'fred', 'age': 40 },
-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
-     * };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.mapValues(characters, 'age');
-     * // => { 'fred': 40, 'pebbles': 1 }
-     */
-    function mapValues(object, callback, thisArg) {
-      var result = {};
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      forOwn(object, function(value, key, object) {
-        result[key] = callback(value, key, object);
-      });
-      return result;
-    }
-
-    /**
-     * Recursively merges own enumerable properties of the source object(s), that
-     * don't resolve to `undefined` into the destination object. Subsequent sources
-     * will overwrite property assignments of previous sources. If a callback is
-     * provided it will be executed to produce the merged values of the destination
-     * and source properties. If the callback returns `undefined` merging will
-     * be handled by the method instead. The callback is bound to `thisArg` and
-     * invoked with two arguments; (objectValue, sourceValue).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param {Function} [callback] The function to customize merging properties.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * var names = {
-     *   'characters': [
-     *     { 'name': 'barney' },
-     *     { 'name': 'fred' }
-     *   ]
-     * };
-     *
-     * var ages = {
-     *   'characters': [
-     *     { 'age': 36 },
-     *     { 'age': 40 }
-     *   ]
-     * };
-     *
-     * _.merge(names, ages);
-     * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
-     *
-     * var food = {
-     *   'fruits': ['apple'],
-     *   'vegetables': ['beet']
-     * };
-     *
-     * var otherFood = {
-     *   'fruits': ['banana'],
-     *   'vegetables': ['carrot']
-     * };
-     *
-     * _.merge(food, otherFood, function(a, b) {
-     *   return _.isArray(a) ? a.concat(b) : undefined;
-     * });
-     * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
-     */
-    function merge(object) {
-      var args = arguments,
-          length = 2;
-
-      if (!isObject(object)) {
-        return object;
-      }
-      // allows working with `_.reduce` and `_.reduceRight` without using
-      // their `index` and `collection` arguments
-      if (typeof args[2] != 'number') {
-        length = args.length;
-      }
-      if (length > 3 && typeof args[length - 2] == 'function') {
-        var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
-      } else if (length > 2 && typeof args[length - 1] == 'function') {
-        callback = args[--length];
-      }
-      var sources = slice(arguments, 1, length),
-          index = -1,
-          stackA = getArray(),
-          stackB = getArray();
-
-      while (++index < length) {
-        baseMerge(object, sources[index], callback, stackA, stackB);
-      }
-      releaseArray(stackA);
-      releaseArray(stackB);
-      return object;
-    }
-
-    /**
-     * Creates a shallow clone of `object` excluding the specified properties.
-     * Property names may be specified as individual arguments or as arrays of
-     * property names. If a callback is provided it will be executed for each
-     * property of `object` omitting the properties the callback returns truey
-     * for. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The source object.
-     * @param {Function|...string|string[]} [callback] The properties to omit or the
-     *  function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns an object without the omitted properties.
-     * @example
-     *
-     * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
-     * // => { 'name': 'fred' }
-     *
-     * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
-     *   return typeof value == 'number';
-     * });
-     * // => { 'name': 'fred' }
-     */
-    function omit(object, callback, thisArg) {
-      var result = {};
-      if (typeof callback != 'function') {
-        var props = [];
-        forIn(object, function(value, key) {
-          props.push(key);
-        });
-        props = baseDifference(props, baseFlatten(arguments, true, false, 1));
-
-        var index = -1,
-            length = props.length;
-
-        while (++index < length) {
-          var key = props[index];
-          result[key] = object[key];
-        }
-      } else {
-        callback = lodash.createCallback(callback, thisArg, 3);
-        forIn(object, function(value, key, object) {
-          if (!callback(value, key, object)) {
-            result[key] = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Creates a two dimensional array of an object's key-value pairs,
-     * i.e. `[[key1, value1], [key2, value2]]`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns new array of key-value pairs.
-     * @example
-     *
-     * _.pairs({ 'barney': 36, 'fred': 40 });
-     * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
-     */
-    function pairs(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = Array(length);
-
-      while (++index < length) {
-        var key = props[index];
-        result[index] = [key, object[key]];
-      }
-      return result;
-    }
-
-    /**
-     * Creates a shallow clone of `object` composed of the specified properties.
-     * Property names may be specified as individual arguments or as arrays of
-     * property names. If a callback is provided it will be executed for each
-     * property of `object` picking the properties the callback returns truey
-     * for. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The source object.
-     * @param {Function|...string|string[]} [callback] The function called per
-     *  iteration or property names to pick, specified as individual property
-     *  names or arrays of property names.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns an object composed of the picked properties.
-     * @example
-     *
-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
-     * // => { 'name': 'fred' }
-     *
-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
-     *   return key.charAt(0) != '_';
-     * });
-     * // => { 'name': 'fred' }
-     */
-    function pick(object, callback, thisArg) {
-      var result = {};
-      if (typeof callback != 'function') {
-        var index = -1,
-            props = baseFlatten(arguments, true, false, 1),
-            length = isObject(object) ? props.length : 0;
-
-        while (++index < length) {
-          var key = props[index];
-          if (key in object) {
-            result[key] = object[key];
-          }
-        }
-      } else {
-        callback = lodash.createCallback(callback, thisArg, 3);
-        forIn(object, function(value, key, object) {
-          if (callback(value, key, object)) {
-            result[key] = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * An alternative to `_.reduce` this method transforms `object` to a new
-     * `accumulator` object which is the result of running each of its own
-     * enumerable properties through a callback, with each callback execution
-     * potentially mutating the `accumulator` object. The callback is bound to
-     * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
-     * Callbacks may exit iteration early by explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Array|Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] The custom accumulator value.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
-     *   num *= num;
-     *   if (num % 2) {
-     *     return result.push(num) < 3;
-     *   }
-     * });
-     * // => [1, 9, 25]
-     *
-     * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
-     *   result[key] = num * 3;
-     * });
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     */
-    function transform(object, callback, accumulator, thisArg) {
-      var isArr = isArray(object);
-      if (accumulator == null) {
-        if (isArr) {
-          accumulator = [];
-        } else {
-          var ctor = object && object.constructor,
-              proto = ctor && ctor.prototype;
-
-          accumulator = baseCreate(proto);
-        }
-      }
-      if (callback) {
-        callback = lodash.createCallback(callback, thisArg, 4);
-        (isArr ? forEach : forOwn)(object, function(value, index, object) {
-          return callback(accumulator, value, index, object);
-        });
-      }
-      return accumulator;
-    }
-
-    /**
-     * Creates an array composed of the own enumerable property values of `object`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property values.
-     * @example
-     *
-     * _.values({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => [1, 2, 3] (property order is not guaranteed across environments)
-     */
-    function values(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = Array(length);
-
-      while (++index < length) {
-        result[index] = object[props[index]];
-      }
-      return result;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates an array of elements from the specified indexes, or keys, of the
-     * `collection`. Indexes may be specified as individual arguments or as arrays
-     * of indexes.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
-     *   to retrieve, specified as individual indexes or arrays of indexes.
-     * @returns {Array} Returns a new array of elements corresponding to the
-     *  provided indexes.
-     * @example
-     *
-     * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
-     * // => ['a', 'c', 'e']
-     *
-     * _.at(['fred', 'barney', 'pebbles'], 0, 2);
-     * // => ['fred', 'pebbles']
-     */
-    function at(collection) {
-      var args = arguments,
-          index = -1,
-          props = baseFlatten(args, true, false, 1),
-          length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
-          result = Array(length);
-
-      while(++index < length) {
-        result[index] = collection[props[index]];
-      }
-      return result;
-    }
-
-    /**
-     * Checks if a given value is present in a collection using strict equality
-     * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
-     * offset from the end of the collection.
-     *
-     * @static
-     * @memberOf _
-     * @alias include
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {*} target The value to check for.
-     * @param {number} [fromIndex=0] The index to search from.
-     * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
-     * @example
-     *
-     * _.contains([1, 2, 3], 1);
-     * // => true
-     *
-     * _.contains([1, 2, 3], 1, 2);
-     * // => false
-     *
-     * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
-     * // => true
-     *
-     * _.contains('pebbles', 'eb');
-     * // => true
-     */
-    function contains(collection, target, fromIndex) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = collection ? collection.length : 0,
-          result = false;
-
-      fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
-      if (isArray(collection)) {
-        result = indexOf(collection, target, fromIndex) > -1;
-      } else if (typeof length == 'number') {
-        result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
-      } else {
-        forOwn(collection, function(value) {
-          if (++index >= fromIndex) {
-            return !(result = value === target);
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of `collection` through the callback. The corresponding value
-     * of each key is the number of times the key was returned by the callback.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
-     * // => { '4': 1, '6': 2 }
-     *
-     * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-     * // => { '4': 1, '6': 2 }
-     *
-     * _.countBy(['one', 'two', 'three'], 'length');
-     * // => { '3': 2, '5': 1 }
-     */
-    var countBy = createAggregator(function(result, value, key) {
-      (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
-    });
-
-    /**
-     * Checks if the given callback returns truey value for **all** elements of
-     * a collection. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias all
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if all elements passed the callback check,
-     *  else `false`.
-     * @example
-     *
-     * _.every([true, 1, null, 'yes']);
-     * // => false
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.every(characters, 'age');
-     * // => true
-     *
-     * // using "_.where" callback shorthand
-     * _.every(characters, { 'age': 36 });
-     * // => false
-     */
-    function every(collection, callback, thisArg) {
-      var result = true;
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if (!(result = !!callback(collection[index], index, collection))) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          return (result = !!callback(value, index, collection));
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, returning an array of all elements
-     * the callback returns truey for. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias select
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of elements that passed the callback check.
-     * @example
-     *
-     * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-     * // => [2, 4, 6]
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.filter(characters, 'blocked');
-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
-     *
-     * // using "_.where" callback shorthand
-     * _.filter(characters, { 'age': 36 });
-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-     */
-    function filter(collection, callback, thisArg) {
-      var result = [];
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          var value = collection[index];
-          if (callback(value, index, collection)) {
-            result.push(value);
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          if (callback(value, index, collection)) {
-            result.push(value);
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, returning the first element that
-     * the callback returns truey for. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias detect, findWhere
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the found element, else `undefined`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
-     * ];
-     *
-     * _.find(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => { 'name': 'barney', 'age': 36, 'blocked': false }
-     *
-     * // using "_.where" callback shorthand
-     * _.find(characters, { 'age': 1 });
-     * // =>  { 'name': 'pebbles', 'age': 1, 'blocked': false }
-     *
-     * // using "_.pluck" callback shorthand
-     * _.find(characters, 'blocked');
-     * // => { 'name': 'fred', 'age': 40, 'blocked': true }
-     */
-    function find(collection, callback, thisArg) {
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          var value = collection[index];
-          if (callback(value, index, collection)) {
-            return value;
-          }
-        }
-      } else {
-        var result;
-        forOwn(collection, function(value, index, collection) {
-          if (callback(value, index, collection)) {
-            result = value;
-            return false;
-          }
-        });
-        return result;
-      }
-    }
-
-    /**
-     * This method is like `_.find` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the found element, else `undefined`.
-     * @example
-     *
-     * _.findLast([1, 2, 3, 4], function(num) {
-     *   return num % 2 == 1;
-     * });
-     * // => 3
-     */
-    function findLast(collection, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forEachRight(collection, function(value, index, collection) {
-        if (callback(value, index, collection)) {
-          result = value;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, executing the callback for each
-     * element. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection). Callbacks may exit iteration early by
-     * explicitly returning `false`.
-     *
-     * Note: As with other "Collections" methods, objects with a `length` property
-     * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
-     * may be used for object iteration.
-     *
-     * @static
-     * @memberOf _
-     * @alias each
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array|Object|string} Returns `collection`.
-     * @example
-     *
-     * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
-     * // => logs each number and returns '1,2,3'
-     *
-     * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
-     * // => logs each number and returns the object (property order is not guaranteed across environments)
-     */
-    function forEach(collection, callback, thisArg) {
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if (callback(collection[index], index, collection) === false) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, callback);
-      }
-      return collection;
-    }
-
-    /**
-     * This method is like `_.forEach` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @alias eachRight
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array|Object|string} Returns `collection`.
-     * @example
-     *
-     * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
-     * // => logs each number from right to left and returns '3,2,1'
-     */
-    function forEachRight(collection, callback, thisArg) {
-      var length = collection ? collection.length : 0;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        while (length--) {
-          if (callback(collection[length], length, collection) === false) {
-            break;
-          }
-        }
-      } else {
-        var props = keys(collection);
-        length = props.length;
-        forOwn(collection, function(value, key, collection) {
-          key = props ? props[--length] : --length;
-          return callback(collection[key], key, collection);
-        });
-      }
-      return collection;
-    }
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of a collection through the callback. The corresponding value
-     * of each key is an array of the elements responsible for generating the key.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
-     * // => { '4': [4.2], '6': [6.1, 6.4] }
-     *
-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-     * // => { '4': [4.2], '6': [6.1, 6.4] }
-     *
-     * // using "_.pluck" callback shorthand
-     * _.groupBy(['one', 'two', 'three'], 'length');
-     * // => { '3': ['one', 'two'], '5': ['three'] }
-     */
-    var groupBy = createAggregator(function(result, value, key) {
-      (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
-    });
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of the collection through the given callback. The corresponding
-     * value of each key is the last element responsible for generating the key.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * var keys = [
-     *   { 'dir': 'left', 'code': 97 },
-     *   { 'dir': 'right', 'code': 100 }
-     * ];
-     *
-     * _.indexBy(keys, 'dir');
-     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
-     *
-     * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
-     *
-     * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
-     */
-    var indexBy = createAggregator(function(result, value, key) {
-      result[key] = value;
-    });
-
-    /**
-     * Invokes the method named by `methodName` on each element in the `collection`
-     * returning an array of the results of each invoked method. Additional arguments
-     * will be provided to each invoked method. If `methodName` is a function it
-     * will be invoked for, and `this` bound to, each element in the `collection`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|string} methodName The name of the method to invoke or
-     *  the function invoked per iteration.
-     * @param {...*} [arg] Arguments to invoke the method with.
-     * @returns {Array} Returns a new array of the results of each invoked method.
-     * @example
-     *
-     * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
-     * // => [[1, 5, 7], [1, 2, 3]]
-     *
-     * _.invoke([123, 456], String.prototype.split, '');
-     * // => [['1', '2', '3'], ['4', '5', '6']]
-     */
-    function invoke(collection, methodName) {
-      var args = slice(arguments, 2),
-          index = -1,
-          isFunc = typeof methodName == 'function',
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      forEach(collection, function(value) {
-        result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
-      });
-      return result;
-    }
-
-    /**
-     * Creates an array of values by running each element in the collection
-     * through the callback. The callback is bound to `thisArg` and invoked with
-     * three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias collect
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of the results of each `callback` execution.
-     * @example
-     *
-     * _.map([1, 2, 3], function(num) { return num * 3; });
-     * // => [3, 6, 9]
-     *
-     * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
-     * // => [3, 6, 9] (property order is not guaranteed across environments)
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.map(characters, 'name');
-     * // => ['barney', 'fred']
-     */
-    function map(collection, callback, thisArg) {
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        var result = Array(length);
-        while (++index < length) {
-          result[index] = callback(collection[index], index, collection);
-        }
-      } else {
-        result = [];
-        forOwn(collection, function(value, key, collection) {
-          result[++index] = callback(value, key, collection);
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the maximum value of a collection. If the collection is empty or
-     * falsey `-Infinity` is returned. If a callback is provided it will be executed
-     * for each value in the collection to generate the criterion by which the value
-     * is ranked. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the maximum value.
-     * @example
-     *
-     * _.max([4, 2, 8, 6]);
-     * // => 8
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.max(characters, function(chr) { return chr.age; });
-     * // => { 'name': 'fred', 'age': 40 };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.max(characters, 'age');
-     * // => { 'name': 'fred', 'age': 40 };
-     */
-    function max(collection, callback, thisArg) {
-      var computed = -Infinity,
-          result = computed;
-
-      // allows working with functions like `_.map` without using
-      // their `index` argument as a callback
-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
-        callback = null;
-      }
-      if (callback == null && isArray(collection)) {
-        var index = -1,
-            length = collection.length;
-
-        while (++index < length) {
-          var value = collection[index];
-          if (value > result) {
-            result = value;
-          }
-        }
-      } else {
-        callback = (callback == null && isString(collection))
-          ? charAtCallback
-          : lodash.createCallback(callback, thisArg, 3);
-
-        forEach(collection, function(value, index, collection) {
-          var current = callback(value, index, collection);
-          if (current > computed) {
-            computed = current;
-            result = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the minimum value of a collection. If the collection is empty or
-     * falsey `Infinity` is returned. If a callback is provided it will be executed
-     * for each value in the collection to generate the criterion by which the value
-     * is ranked. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the minimum value.
-     * @example
-     *
-     * _.min([4, 2, 8, 6]);
-     * // => 2
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.min(characters, function(chr) { return chr.age; });
-     * // => { 'name': 'barney', 'age': 36 };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.min(characters, 'age');
-     * // => { 'name': 'barney', 'age': 36 };
-     */
-    function min(collection, callback, thisArg) {
-      var computed = Infinity,
-          result = computed;
-
-      // allows working with functions like `_.map` without using
-      // their `index` argument as a callback
-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
-        callback = null;
-      }
-      if (callback == null && isArray(collection)) {
-        var index = -1,
-            length = collection.length;
-
-        while (++index < length) {
-          var value = collection[index];
-          if (value < result) {
-            result = value;
-          }
-        }
-      } else {
-        callback = (callback == null && isString(collection))
-          ? charAtCallback
-          : lodash.createCallback(callback, thisArg, 3);
-
-        forEach(collection, function(value, index, collection) {
-          var current = callback(value, index, collection);
-          if (current < computed) {
-            computed = current;
-            result = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the value of a specified property from all elements in the collection.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {string} property The name of the property to pluck.
-     * @returns {Array} Returns a new array of property values.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.pluck(characters, 'name');
-     * // => ['barney', 'fred']
-     */
-    var pluck = map;
-
-    /**
-     * Reduces a collection to a value which is the accumulated result of running
-     * each element in the collection through the callback, where each successive
-     * callback execution consumes the return value of the previous execution. If
-     * `accumulator` is not provided the first element of the collection will be
-     * used as the initial `accumulator` value. The callback is bound to `thisArg`
-     * and invoked with four arguments; (accumulator, value, index|key, collection).
-     *
-     * @static
-     * @memberOf _
-     * @alias foldl, inject
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] Initial value of the accumulator.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var sum = _.reduce([1, 2, 3], function(sum, num) {
-     *   return sum + num;
-     * });
-     * // => 6
-     *
-     * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
-     *   result[key] = num * 3;
-     *   return result;
-     * }, {});
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     */
-    function reduce(collection, callback, accumulator, thisArg) {
-      if (!collection) return accumulator;
-      var noaccum = arguments.length < 3;
-      callback = lodash.createCallback(callback, thisArg, 4);
-
-      var index = -1,
-          length = collection.length;
-
-      if (typeof length == 'number') {
-        if (noaccum) {
-          accumulator = collection[++index];
-        }
-        while (++index < length) {
-          accumulator = callback(accumulator, collection[index], index, collection);
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          accumulator = noaccum
-            ? (noaccum = false, value)
-            : callback(accumulator, value, index, collection)
-        });
-      }
-      return accumulator;
-    }
-
-    /**
-     * This method is like `_.reduce` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @alias foldr
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] Initial value of the accumulator.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var list = [[0, 1], [2, 3], [4, 5]];
-     * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
-     * // => [4, 5, 2, 3, 0, 1]
-     */
-    function reduceRight(collection, callback, accumulator, thisArg) {
-      var noaccum = arguments.length < 3;
-      callback = lodash.createCallback(callback, thisArg, 4);
-      forEachRight(collection, function(value, index, collection) {
-        accumulator = noaccum
-          ? (noaccum = false, value)
-          : callback(accumulator, value, index, collection);
-      });
-      return accumulator;
-    }
-
-    /**
-     * The opposite of `_.filter` this method returns the elements of a
-     * collection that the callback does **not** return truey for.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of elements that failed the callback check.
-     * @example
-     *
-     * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-     * // => [1, 3, 5]
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.reject(characters, 'blocked');
-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-     *
-     * // using "_.where" callback shorthand
-     * _.reject(characters, { 'age': 36 });
-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
-     */
-    function reject(collection, callback, thisArg) {
-      callback = lodash.createCallback(callback, thisArg, 3);
-      return filter(collection, function(value, index, collection) {
-        return !callback(value, index, collection);
-      });
-    }
-
-    /**
-     * Retrieves a random element or `n` random elements from a collection.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to sample.
-     * @param {number} [n] The number of elements to sample.
-     * @param- {Object} [guard] Allows working with functions like `_.map`
-     *  without using their `index` arguments as `n`.
-     * @returns {Array} Returns the random sample(s) of `collection`.
-     * @example
-     *
-     * _.sample([1, 2, 3, 4]);
-     * // => 2
-     *
-     * _.sample([1, 2, 3, 4], 2);
-     * // => [3, 1]
-     */
-    function sample(collection, n, guard) {
-      if (collection && typeof collection.length != 'number') {
-        collection = values(collection);
-      }
-      if (n == null || guard) {
-        return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
-      }
-      var result = shuffle(collection);
-      result.length = nativeMin(nativeMax(0, n), result.length);
-      return result;
-    }
-
-    /**
-     * Creates an array of shuffled values, using a version of the Fisher-Yates
-     * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to shuffle.
-     * @returns {Array} Returns a new shuffled collection.
-     * @example
-     *
-     * _.shuffle([1, 2, 3, 4, 5, 6]);
-     * // => [4, 1, 6, 3, 5, 2]
-     */
-    function shuffle(collection) {
-      var index = -1,
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      forEach(collection, function(value) {
-        var rand = baseRandom(0, ++index);
-        result[index] = result[rand];
-        result[rand] = value;
-      });
-      return result;
-    }
-
-    /**
-     * Gets the size of the `collection` by returning `collection.length` for arrays
-     * and array-like objects or the number of own enumerable properties for objects.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to inspect.
-     * @returns {number} Returns `collection.length` or number of own enumerable properties.
-     * @example
-     *
-     * _.size([1, 2]);
-     * // => 2
-     *
-     * _.size({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => 3
-     *
-     * _.size('pebbles');
-     * // => 7
-     */
-    function size(collection) {
-      var length = collection ? collection.length : 0;
-      return typeof length == 'number' ? length : keys(collection).length;
-    }
-
-    /**
-     * Checks if the callback returns a truey value for **any** element of a
-     * collection. The function returns as soon as it finds a passing value and
-     * does not iterate over the entire collection. The callback is bound to
-     * `thisArg` and invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias any
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if any element passed the callback check,
-     *  else `false`.
-     * @example
-     *
-     * _.some([null, 0, 'yes', false], Boolean);
-     * // => true
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.some(characters, 'blocked');
-     * // => true
-     *
-     * // using "_.where" callback shorthand
-     * _.some(characters, { 'age': 1 });
-     * // => false
-     */
-    function some(collection, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if ((result = callback(collection[index], index, collection))) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          return !(result = callback(value, index, collection));
-        });
-      }
-      return !!result;
-    }
-
-    /**
-     * Creates an array of elements, sorted in ascending order by the results of
-     * running each element in a collection through the callback. This method
-     * performs a stable sort, that is, it will preserve the original sort order
-     * of equal elements. The callback is bound to `thisArg` and invoked with
-     * three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an array of property names is provided for `callback` the collection
-     * will be sorted by each property value.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Array|Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of sorted elements.
-     * @example
-     *
-     * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
-     * // => [3, 1, 2]
-     *
-     * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
-     * // => [3, 1, 2]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36 },
-     *   { 'name': 'fred',    'age': 40 },
-     *   { 'name': 'barney',  'age': 26 },
-     *   { 'name': 'fred',    'age': 30 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.map(_.sortBy(characters, 'age'), _.values);
-     * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
-     *
-     * // sorting by multiple properties
-     * _.map(_.sortBy(characters, ['name', 'age']), _.values);
-     * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
-     */
-    function sortBy(collection, callback, thisArg) {
-      var index = -1,
-          isArr = isArray(callback),
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      if (!isArr) {
-        callback = lodash.createCallback(callback, thisArg, 3);
-      }
-      forEach(collection, function(value, key, collection) {
-        var object = result[++index] = getObject();
-        if (isArr) {
-          object.criteria = map(callback, function(key) { return value[key]; });
-        } else {
-          (object.criteria = getArray())[0] = callback(value, key, collection);
-        }
-        object.index = index;
-        object.value = value;
-      });
-
-      length = result.length;
-      result.sort(compareAscending);
-      while (length--) {
-        var object = result[length];
-        result[length] = object.value;
-        if (!isArr) {
-          releaseArray(object.criteria);
-        }
-        releaseObject(object);
-      }
-      return result;
-    }
-
-    /**
-     * Converts the `collection` to an array.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to convert.
-     * @returns {Array} Returns the new converted array.
-     * @example
-     *
-     * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
-     * // => [2, 3, 4]
-     */
-    function toArray(collection) {
-      if (collection && typeof collection.length == 'number') {
-        return slice(collection);
-      }
-      return values(collection);
-    }
-
-    /**
-     * Performs a deep comparison of each element in a `collection` to the given
-     * `properties` object, returning an array of all elements that have equivalent
-     * property values.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Object} props The object of property values to filter by.
-     * @returns {Array} Returns a new array of elements that have the given properties.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
-     * ];
-     *
-     * _.where(characters, { 'age': 36 });
-     * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
-     *
-     * _.where(characters, { 'pets': ['dino'] });
-     * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
-     */
-    var where = filter;
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates an array with all falsey values removed. The values `false`, `null`,
-     * `0`, `""`, `undefined`, and `NaN` are all falsey.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to compact.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.compact([0, 1, false, 2, '', 3]);
-     * // => [1, 2, 3]
-     */
-    function compact(array) {
-      var index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      while (++index < length) {
-        var value = array[index];
-        if (value) {
-          result.push(value);
-        }
-      }
-      return result;
-    }
-
-    /**
-     * Creates an array excluding all values of the provided arrays using strict
-     * equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to process.
-     * @param {...Array} [values] The arrays of values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
-     * // => [1, 3, 4]
-     */
-    function difference(array) {
-      return baseDifference(array, baseFlatten(arguments, true, true, 1));
-    }
-
-    /**
-     * This method is like `_.find` except that it returns the index of the first
-     * element that passes the callback check, instead of the element itself.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index of the found element, else `-1`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
-     * ];
-     *
-     * _.findIndex(characters, function(chr) {
-     *   return chr.age < 20;
-     * });
-     * // => 2
-     *
-     * // using "_.where" callback shorthand
-     * _.findIndex(characters, { 'age': 36 });
-     * // => 0
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findIndex(characters, 'blocked');
-     * // => 1
-     */
-    function findIndex(array, callback, thisArg) {
-      var index = -1,
-          length = array ? array.length : 0;
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (++index < length) {
-        if (callback(array[index], index, array)) {
-          return index;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * This method is like `_.findIndex` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index of the found element, else `-1`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': true },
-     *   { 'name': 'fred',    'age': 40, 'blocked': false },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': true }
-     * ];
-     *
-     * _.findLastIndex(characters, function(chr) {
-     *   return chr.age > 30;
-     * });
-     * // => 1
-     *
-     * // using "_.where" callback shorthand
-     * _.findLastIndex(characters, { 'age': 36 });
-     * // => 0
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findLastIndex(characters, 'blocked');
-     * // => 2
-     */
-    function findLastIndex(array, callback, thisArg) {
-      var length = array ? array.length : 0;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (length--) {
-        if (callback(array[length], length, array)) {
-          return length;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * Gets the first element or first `n` elements of an array. If a callback
-     * is provided elements at the beginning of the array are returned as long
-     * as the callback returns truey. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias head, take
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback] The function called
-     *  per element or the number of elements to return. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the first element(s) of `array`.
-     * @example
-     *
-     * _.first([1, 2, 3]);
-     * // => 1
-     *
-     * _.first([1, 2, 3], 2);
-     * // => [1, 2]
-     *
-     * _.first([1, 2, 3], function(num) {
-     *   return num < 3;
-     * });
-     * // => [1, 2]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.first(characters, 'blocked');
-     * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
-     *
-     * // using "_.where" callback shorthand
-     * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
-     * // => ['barney', 'fred']
-     */
-    function first(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = -1;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (++index < length && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = callback;
-        if (n == null || thisArg) {
-          return array ? array[0] : undefined;
-        }
-      }
-      return slice(array, 0, nativeMin(nativeMax(0, n), length));
-    }
-
-    /**
-     * Flattens a nested array (the nesting can be to any depth). If `isShallow`
-     * is truey, the array will only be flattened a single level. If a callback
-     * is provided each element of the array is passed through the callback before
-     * flattening. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to flatten.
-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new flattened array.
-     * @example
-     *
-     * _.flatten([1, [2], [3, [[4]]]]);
-     * // => [1, 2, 3, 4];
-     *
-     * _.flatten([1, [2], [3, [[4]]]], true);
-     * // => [1, 2, 3, [[4]]];
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.flatten(characters, 'pets');
-     * // => ['hoppy', 'baby puss', 'dino']
-     */
-    function flatten(array, isShallow, callback, thisArg) {
-      // juggle arguments
-      if (typeof isShallow != 'boolean' && isShallow != null) {
-        thisArg = callback;
-        callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
-        isShallow = false;
-      }
-      if (callback != null) {
-        array = map(array, callback, thisArg);
-      }
-      return baseFlatten(array, isShallow);
-    }
-
-    /**
-     * Gets the index at which the first occurrence of `value` is found using
-     * strict equality for comparisons, i.e. `===`. If the array is already sorted
-     * providing `true` for `fromIndex` will run a faster binary search.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {*} value The value to search for.
-     * @param {boolean|number} [fromIndex=0] The index to search from or `true`
-     *  to perform a binary search on a sorted array.
-     * @returns {number} Returns the index of the matched value or `-1`.
-     * @example
-     *
-     * _.indexOf([1, 2, 3, 1, 2, 3], 2);
-     * // => 1
-     *
-     * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
-     * // => 4
-     *
-     * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
-     * // => 2
-     */
-    function indexOf(array, value, fromIndex) {
-      if (typeof fromIndex == 'number') {
-        var length = array ? array.length : 0;
-        fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
-      } else if (fromIndex) {
-        var index = sortedIndex(array, value);
-        return array[index] === value ? index : -1;
-      }
-      return baseIndexOf(array, value, fromIndex);
-    }
-
-    /**
-     * Gets all but the last element or last `n` elements of an array. If a
-     * callback is provided elements at the end of the array are excluded from
-     * the result as long as the callback returns truey. The callback is bound
-     * to `thisArg` and invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback=1] The function called
-     *  per element or the number of elements to exclude. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a slice of `array`.
-     * @example
-     *
-     * _.initial([1, 2, 3]);
-     * // => [1, 2]
-     *
-     * _.initial([1, 2, 3], 2);
-     * // => [1]
-     *
-     * _.initial([1, 2, 3], function(num) {
-     *   return num > 1;
-     * });
-     * // => [1]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.initial(characters, 'blocked');
-     * // => [{ 'name': 'barney',  'blocked': false, 'employer': 'slate' }]
-     *
-     * // using "_.where" callback shorthand
-     * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
-     * // => ['barney', 'fred']
-     */
-    function initial(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = length;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (index-- && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = (callback == null || thisArg) ? 1 : callback || n;
-      }
-      return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
-    }
-
-    /**
-     * Creates an array of unique values present in all provided arrays using
-     * strict equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of shared values.
-     * @example
-     *
-     * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-     * // => [1, 2]
-     */
-    function intersection() {
-      var args = [],
-          argsIndex = -1,
-          argsLength = arguments.length,
-          caches = getArray(),
-          indexOf = getIndexOf(),
-          trustIndexOf = indexOf === baseIndexOf,
-          seen = getArray();
-
-      while (++argsIndex < argsLength) {
-        var value = arguments[argsIndex];
-        if (isArray(value) || isArguments(value)) {
-          args.push(value);
-          caches.push(trustIndexOf && value.length >= largeArraySize &&
-            createCache(argsIndex ? args[argsIndex] : seen));
-        }
-      }
-      var array = args[0],
-          index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      outer:
-      while (++index < length) {
-        var cache = caches[0];
-        value = array[index];
-
-        if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
-          argsIndex = argsLength;
-          (cache || seen).push(value);
-          while (--argsIndex) {
-            cache = caches[argsIndex];
-            if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
-              continue outer;
-            }
-          }
-          result.push(value);
-        }
-      }
-      while (argsLength--) {
-        cache = caches[argsLength];
-        if (cache) {
-          releaseObject(cache);
-        }
-      }
-      releaseArray(caches);
-      releaseArray(seen);
-      return result;
-    }
-
-    /**
-     * Gets the last element or last `n` elements of an array. If a callback is
-     * provided elements at the end of the array are returned as long as the
-     * callback returns truey. The callback is bound to `thisArg` and invoked
-     * with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback] The function called
-     *  per element or the number of elements to return. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the last element(s) of `array`.
-     * @example
-     *
-     * _.last([1, 2, 3]);
-     * // => 3
-     *
-     * _.last([1, 2, 3], 2);
-     * // => [2, 3]
-     *
-     * _.last([1, 2, 3], function(num) {
-     *   return num > 1;
-     * });
-     * // => [2, 3]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.pluck(_.last(characters, 'blocked'), 'name');
-     * // => ['fred', 'pebbles']
-     *
-     * // using "_.where" callback shorthand
-     * _.last(characters, { 'employer': 'na' });
-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-     */
-    function last(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = length;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (index-- && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = callback;
-        if (n == null || thisArg) {
-          return array ? array[length - 1] : undefined;
-        }
-      }
-      return slice(array, nativeMax(0, length - n));
-    }
-
-    /**
-     * Gets the index at which the last occurrence of `value` is found using strict
-     * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
-     * as the offset from the end of the collection.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {*} value The value to search for.
-     * @param {number} [fromIndex=array.length-1] The index to search from.
-     * @returns {number} Returns the index of the matched value or `-1`.
-     * @example
-     *
-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
-     * // => 4
-     *
-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
-     * // => 1
-     */
-    function lastIndexOf(array, value, fromIndex) {
-      var index = array ? array.length : 0;
-      if (typeof fromIndex == 'number') {
-        index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
-      }
-      while (index--) {
-        if (array[index] === value) {
-          return index;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * Removes all provided values from the given array using strict equality for
-     * comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to modify.
-     * @param {...*} [value] The values to remove.
-     * @returns {Array} Returns `array`.
-     * @example
-     *
-     * var array = [1, 2, 3, 1, 2, 3];
-     * _.pull(array, 2, 3);
-     * console.log(array);
-     * // => [1, 1]
-     */
-    function pull(array) {
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = args.length,
-          length = array ? array.length : 0;
-
-      while (++argsIndex < argsLength) {
-        var index = -1,
-            value = args[argsIndex];
-        while (++index < length) {
-          if (array[index] === value) {
-            splice.call(array, index--, 1);
-            length--;
-          }
-        }
-      }
-      return array;
-    }
-
-    /**
-     * Creates an array of numbers (positive and/or negative) progressing from
-     * `start` up to but not including `end`. If `start` is less than `stop` a
-     * zero-length range is created unless a negative `step` is specified.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {number} [start=0] The start of the range.
-     * @param {number} end The end of the range.
-     * @param {number} [step=1] The value to increment or decrement by.
-     * @returns {Array} Returns a new range array.
-     * @example
-     *
-     * _.range(4);
-     * // => [0, 1, 2, 3]
-     *
-     * _.range(1, 5);
-     * // => [1, 2, 3, 4]
-     *
-     * _.range(0, 20, 5);
-     * // => [0, 5, 10, 15]
-     *
-     * _.range(0, -4, -1);
-     * // => [0, -1, -2, -3]
-     *
-     * _.range(1, 4, 0);
-     * // => [1, 1, 1]
-     *
-     * _.range(0);
-     * // => []
-     */
-    function range(start, end, step) {
-      start = +start || 0;
-      step = typeof step == 'number' ? step : (+step || 1);
-
-      if (end == null) {
-        end = start;
-        start = 0;
-      }
-      // use `Array(length)` so engines like Chakra and V8 avoid slower modes
-      // http://youtu.be/XAqIpGU8ZZk#t=17m25s
-      var index = -1,
-          length = nativeMax(0, ceil((end - start) / (step || 1))),
-          result = Array(length);
-
-      while (++index < length) {
-        result[index] = start;
-        start += step;
-      }
-      return result;
-    }
-
-    /**
-     * Removes all elements from an array that the callback returns truey for
-     * and returns an array of removed elements. The callback is bound to `thisArg`
-     * and invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to modify.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of removed elements.
-     * @example
-     *
-     * var array = [1, 2, 3, 4, 5, 6];
-     * var evens = _.remove(array, function(num) { return num % 2 == 0; });
-     *
-     * console.log(array);
-     * // => [1, 3, 5]
-     *
-     * console.log(evens);
-     * // => [2, 4, 6]
-     */
-    function remove(array, callback, thisArg) {
-      var index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (++index < length) {
-        var value = array[index];
-        if (callback(value, index, array)) {
-          result.push(value);
-          splice.call(array, index--, 1);
-          length--;
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The opposite of `_.initial` this method gets all but the first element or
-     * first `n` elements of an array. If a callback function is provided elements
-     * at the beginning of the array are excluded from the result as long as the
-     * callback returns truey. The callback is bound to `thisArg` and invoked
-     * with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias drop, tail
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback=1] The function called
-     *  per element or the number of elements to exclude. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a slice of `array`.
-     * @example
-     *
-     * _.rest([1, 2, 3]);
-     * // => [2, 3]
-     *
-     * _.rest([1, 2, 3], 2);
-     * // => [3]
-     *
-     * _.rest([1, 2, 3], function(num) {
-     *   return num < 3;
-     * });
-     * // => [3]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': false,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.pluck(_.rest(characters, 'blocked'), 'name');
-     * // => ['fred', 'pebbles']
-     *
-     * // using "_.where" callback shorthand
-     * _.rest(characters, { 'employer': 'slate' });
-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-     */
-    function rest(array, callback, thisArg) {
-      if (typeof callback != 'number' && callback != null) {
-        var n = 0,
-            index = -1,
-            length = array ? array.length : 0;
-
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (++index < length && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
-      }
-      return slice(array, n);
-    }
-
-    /**
-     * Uses a binary search to determine the smallest index at which a value
-     * should be inserted into a given sorted array in order to maintain the sort
-     * order of the array. If a callback is provided it will be executed for
-     * `value` and each element of `array` to compute their sort ranking. The
-     * callback is bound to `thisArg` and invoked with one argument; (value).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to inspect.
-     * @param {*} value The value to evaluate.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index at which `value` should be inserted
-     *  into `array`.
-     * @example
-     *
-     * _.sortedIndex([20, 30, 50], 40);
-     * // => 2
-     *
-     * // using "_.pluck" callback shorthand
-     * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
-     * // => 2
-     *
-     * var dict = {
-     *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
-     * };
-     *
-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
-     *   return dict.wordToNumber[word];
-     * });
-     * // => 2
-     *
-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
-     *   return this.wordToNumber[word];
-     * }, dict);
-     * // => 2
-     */
-    function sortedIndex(array, value, callback, thisArg) {
-      var low = 0,
-          high = array ? array.length : low;
-
-      // explicitly reference `identity` for better inlining in Firefox
-      callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
-      value = callback(value);
-
-      while (low < high) {
-        var mid = (low + high) >>> 1;
-        (callback(array[mid]) < value)
-          ? low = mid + 1
-          : high = mid;
-      }
-      return low;
-    }
-
-    /**
-     * Creates an array of unique values, in order, of the provided arrays using
-     * strict equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of combined values.
-     * @example
-     *
-     * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-     * // => [1, 2, 3, 5, 4]
-     */
-    function union() {
-      return baseUniq(baseFlatten(arguments, true, true));
-    }
-
-    /**
-     * Creates a duplicate-value-free version of an array using strict equality
-     * for comparisons, i.e. `===`. If the array is sorted, providing
-     * `true` for `isSorted` will use a faster algorithm. If a callback is provided
-     * each element of `array` is passed through the callback before uniqueness
-     * is computed. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias unique
-     * @category Arrays
-     * @param {Array} array The array to process.
-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a duplicate-value-free array.
-     * @example
-     *
-     * _.uniq([1, 2, 1, 3, 1]);
-     * // => [1, 2, 3]
-     *
-     * _.uniq([1, 1, 2, 2, 3], true);
-     * // => [1, 2, 3]
-     *
-     * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
-     * // => ['A', 'b', 'C']
-     *
-     * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
-     * // => [1, 2.5, 3]
-     *
-     * // using "_.pluck" callback shorthand
-     * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
-     * // => [{ 'x': 1 }, { 'x': 2 }]
-     */
-    function uniq(array, isSorted, callback, thisArg) {
-      // juggle arguments
-      if (typeof isSorted != 'boolean' && isSorted != null) {
-        thisArg = callback;
-        callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
-        isSorted = false;
-      }
-      if (callback != null) {
-        callback = lodash.createCallback(callback, thisArg, 3);
-      }
-      return baseUniq(array, isSorted, callback);
-    }
-
-    /**
-     * Creates an array excluding all provided values using strict equality for
-     * comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to filter.
-     * @param {...*} [value] The values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
-     * // => [2, 3, 4]
-     */
-    function without(array) {
-      return baseDifference(array, slice(arguments, 1));
-    }
-
-    /**
-     * Creates an array that is the symmetric difference of the provided arrays.
-     * See http://en.wikipedia.org/wiki/Symmetric_difference.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of values.
-     * @example
-     *
-     * _.xor([1, 2, 3], [5, 2, 1, 4]);
-     * // => [3, 5, 4]
-     *
-     * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
-     * // => [1, 4, 5]
-     */
-    function xor() {
-      var index = -1,
-          length = arguments.length;
-
-      while (++index < length) {
-        var array = arguments[index];
-        if (isArray(array) || isArguments(array)) {
-          var result = result
-            ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
-            : array;
-        }
-      }
-      return result || [];
-    }
-
-    /**
-     * Creates an array of grouped elements, the first of which contains the first
-     * elements of the given arrays, the second of which contains the second
-     * elements of the given arrays, and so on.
-     *
-     * @static
-     * @memberOf _
-     * @alias unzip
-     * @category Arrays
-     * @param {...Array} [array] Arrays to process.
-     * @returns {Array} Returns a new array of grouped elements.
-     * @example
-     *
-     * _.zip(['fred', 'barney'], [30, 40], [true, false]);
-     * // => [['fred', 30, true], ['barney', 40, false]]
-     */
-    function zip() {
-      var array = arguments.length > 1 ? arguments : arguments[0],
-          index = -1,
-          length = array ? max(pluck(array, 'length')) : 0,
-          result = Array(length < 0 ? 0 : length);
-
-      while (++index < length) {
-        result[index] = pluck(array, index);
-      }
-      return result;
-    }
-
-    /**
-     * Creates an object composed from arrays of `keys` and `values`. Provide
-     * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
-     * or two arrays, one of `keys` and one of corresponding `values`.
-     *
-     * @static
-     * @memberOf _
-     * @alias object
-     * @category Arrays
-     * @param {Array} keys The array of keys.
-     * @param {Array} [values=[]] The array of values.
-     * @returns {Object} Returns an object composed of the given keys and
-     *  corresponding values.
-     * @example
-     *
-     * _.zipObject(['fred', 'barney'], [30, 40]);
-     * // => { 'fred': 30, 'barney': 40 }
-     */
-    function zipObject(keys, values) {
-      var index = -1,
-          length = keys ? keys.length : 0,
-          result = {};
-
-      if (!values && length && !isArray(keys[0])) {
-        values = [];
-      }
-      while (++index < length) {
-        var key = keys[index];
-        if (values) {
-          result[key] = values[index];
-        } else if (key) {
-          result[key[0]] = key[1];
-        }
-      }
-      return result;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a function that executes `func`, with  the `this` binding and
-     * arguments of the created function, only after being called `n` times.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {number} n The number of times the function must be called before
-     *  `func` is executed.
-     * @param {Function} func The function to restrict.
-     * @returns {Function} Returns the new restricted function.
-     * @example
-     *
-     * var saves = ['profile', 'settings'];
-     *
-     * var done = _.after(saves.length, function() {
-     *   console.log('Done saving!');
-     * });
-     *
-     * _.forEach(saves, function(type) {
-     *   asyncSave({ 'type': type, 'complete': done });
-     * });
-     * // => logs 'Done saving!', after all saves have completed
-     */
-    function after(n, func) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      return function() {
-        if (--n < 1) {
-          return func.apply(this, arguments);
-        }
-      };
-    }
-
-    /**
-     * Creates a function that, when called, invokes `func` with the `this`
-     * binding of `thisArg` and prepends any additional `bind` arguments to those
-     * provided to the bound function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to bind.
-     * @param {*} [thisArg] The `this` binding of `func`.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new bound function.
-     * @example
-     *
-     * var func = function(greeting) {
-     *   return greeting + ' ' + this.name;
-     * };
-     *
-     * func = _.bind(func, { 'name': 'fred' }, 'hi');
-     * func();
-     * // => 'hi fred'
-     */
-    function bind(func, thisArg) {
-      return arguments.length > 2
-        ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
-        : createWrapper(func, 1, null, null, thisArg);
-    }
-
-    /**
-     * Binds methods of an object to the object itself, overwriting the existing
-     * method. Method names may be specified as individual arguments or as arrays
-     * of method names. If no method names are provided all the function properties
-     * of `object` will be bound.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Object} object The object to bind and assign the bound methods to.
-     * @param {...string} [methodName] The object method names to
-     *  bind, specified as individual method names or arrays of method names.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * var view = {
-     *   'label': 'docs',
-     *   'onClick': function() { console.log('clicked ' + this.label); }
-     * };
-     *
-     * _.bindAll(view);
-     * jQuery('#docs').on('click', view.onClick);
-     * // => logs 'clicked docs', when the button is clicked
-     */
-    function bindAll(object) {
-      var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
-          index = -1,
-          length = funcs.length;
-
-      while (++index < length) {
-        var key = funcs[index];
-        object[key] = createWrapper(object[key], 1, null, null, object);
-      }
-      return object;
-    }
-
-    /**
-     * Creates a function that, when called, invokes the method at `object[key]`
-     * and prepends any additional `bindKey` arguments to those provided to the bound
-     * function. This method differs from `_.bind` by allowing bound functions to
-     * reference methods that will be redefined or don't yet exist.
-     * See http://michaux.ca/articles/lazy-function-definition-pattern.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Object} object The object the method belongs to.
-     * @param {string} key The key of the method.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new bound function.
-     * @example
-     *
-     * var object = {
-     *   'name': 'fred',
-     *   'greet': function(greeting) {
-     *     return greeting + ' ' + this.name;
-     *   }
-     * };
-     *
-     * var func = _.bindKey(object, 'greet', 'hi');
-     * func();
-     * // => 'hi fred'
-     *
-     * object.greet = function(greeting) {
-     *   return greeting + 'ya ' + this.name + '!';
-     * };
-     *
-     * func();
-     * // => 'hiya fred!'
-     */
-    function bindKey(object, key) {
-      return arguments.length > 2
-        ? createWrapper(key, 19, slice(arguments, 2), null, object)
-        : createWrapper(key, 3, null, null, object);
-    }
-
-    /**
-     * Creates a function that is the composition of the provided functions,
-     * where each function consumes the return value of the function that follows.
-     * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
-     * Each function is executed with the `this` binding of the composed function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {...Function} [func] Functions to compose.
-     * @returns {Function} Returns the new composed function.
-     * @example
-     *
-     * var realNameMap = {
-     *   'pebbles': 'penelope'
-     * };
-     *
-     * var format = function(name) {
-     *   name = realNameMap[name.toLowerCase()] || name;
-     *   return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
-     * };
-     *
-     * var greet = function(formatted) {
-     *   return 'Hiya ' + formatted + '!';
-     * };
-     *
-     * var welcome = _.compose(greet, format);
-     * welcome('pebbles');
-     * // => 'Hiya Penelope!'
-     */
-    function compose() {
-      var funcs = arguments,
-          length = funcs.length;
-
-      while (length--) {
-        if (!isFunction(funcs[length])) {
-          throw new TypeError;
-        }
-      }
-      return function() {
-        var args = arguments,
-            length = funcs.length;
-
-        while (length--) {
-          args = [funcs[length].apply(this, args)];
-        }
-        return args[0];
-      };
-    }
-
-    /**
-     * Creates a function which accepts one or more arguments of `func` that when
-     * invoked either executes `func` returning its result, if all `func` arguments
-     * have been provided, or returns a function that accepts one or more of the
-     * remaining `func` arguments, and so on. The arity of `func` can be specified
-     * if `func.length` is not sufficient.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to curry.
-     * @param {number} [arity=func.length] The arity of `func`.
-     * @returns {Function} Returns the new curried function.
-     * @example
-     *
-     * var curried = _.curry(function(a, b, c) {
-     *   console.log(a + b + c);
-     * });
-     *
-     * curried(1)(2)(3);
-     * // => 6
-     *
-     * curried(1, 2)(3);
-     * // => 6
-     *
-     * curried(1, 2, 3);
-     * // => 6
-     */
-    function curry(func, arity) {
-      arity = typeof arity == 'number' ? arity : (+arity || func.length);
-      return createWrapper(func, 4, null, null, null, arity);
-    }
-
-    /**
-     * Creates a function that will delay the execution of `func` until after
-     * `wait` milliseconds have elapsed since the last time it was invoked.
-     * Provide an options object to indicate that `func` should be invoked on
-     * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
-     * to the debounced function will return the result of the last `func` call.
-     *
-     * Note: If `leading` and `trailing` options are `true` `func` will be called
-     * on the trailing edge of the timeout only if the the debounced function is
-     * invoked more than once during the `wait` timeout.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to debounce.
-     * @param {number} wait The number of milliseconds to delay.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
-     * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
-     * @returns {Function} Returns the new debounced function.
-     * @example
-     *
-     * // avoid costly calculations while the window size is in flux
-     * var lazyLayout = _.debounce(calculateLayout, 150);
-     * jQuery(window).on('resize', lazyLayout);
-     *
-     * // execute `sendMail` when the click event is fired, debouncing subsequent calls
-     * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
-     *   'leading': true,
-     *   'trailing': false
-     * });
-     *
-     * // ensure `batchLog` is executed once after 1 second of debounced calls
-     * var source = new EventSource('/stream');
-     * source.addEventListener('message', _.debounce(batchLog, 250, {
-     *   'maxWait': 1000
-     * }, false);
-     */
-    function debounce(func, wait, options) {
-      var args,
-          maxTimeoutId,
-          result,
-          stamp,
-          thisArg,
-          timeoutId,
-          trailingCall,
-          lastCalled = 0,
-          maxWait = false,
-          trailing = true;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      wait = nativeMax(0, wait) || 0;
-      if (options === true) {
-        var leading = true;
-        trailing = false;
-      } else if (isObject(options)) {
-        leading = options.leading;
-        maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
-        trailing = 'trailing' in options ? options.trailing : trailing;
-      }
-      var delayed = function() {
-        var remaining = wait - (now() - stamp);
-        if (remaining <= 0) {
-          if (maxTimeoutId) {
-            clearTimeout(maxTimeoutId);
-          }
-          var isCalled = trailingCall;
-          maxTimeoutId = timeoutId = trailingCall = undefined;
-          if (isCalled) {
-            lastCalled = now();
-            result = func.apply(thisArg, args);
-            if (!timeoutId && !maxTimeoutId) {
-              args = thisArg = null;
-            }
-          }
-        } else {
-          timeoutId = setTimeout(delayed, remaining);
-        }
-      };
-
-      var maxDelayed = function() {
-        if (timeoutId) {
-          clearTimeout(timeoutId);
-        }
-        maxTimeoutId = timeoutId = trailingCall = undefined;
-        if (trailing || (maxWait !== wait)) {
-          lastCalled = now();
-          result = func.apply(thisArg, args);
-          if (!timeoutId && !maxTimeoutId) {
-            args = thisArg = null;
-          }
-        }
-      };
-
-      return function() {
-        args = arguments;
-        stamp = now();
-        thisArg = this;
-        trailingCall = trailing && (timeoutId || !leading);
-
-        if (maxWait === false) {
-          var leadingCall = leading && !timeoutId;
-        } else {
-          if (!maxTimeoutId && !leading) {
-            lastCalled = stamp;
-          }
-          var remaining = maxWait - (stamp - lastCalled),
-              isCalled = remaining <= 0;
-
-          if (isCalled) {
-            if (maxTimeoutId) {
-              maxTimeoutId = clearTimeout(maxTimeoutId);
-            }
-            lastCalled = stamp;
-            result = func.apply(thisArg, args);
-          }
-          else if (!maxTimeoutId) {
-            maxTimeoutId = setTimeout(maxDelayed, remaining);
-          }
-        }
-        if (isCalled && timeoutId) {
-          timeoutId = clearTimeout(timeoutId);
-        }
-        else if (!timeoutId && wait !== maxWait) {
-          timeoutId = setTimeout(delayed, wait);
-        }
-        if (leadingCall) {
-          isCalled = true;
-          result = func.apply(thisArg, args);
-        }
-        if (isCalled && !timeoutId && !maxTimeoutId) {
-          args = thisArg = null;
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Defers executing the `func` function until the current call stack has cleared.
-     * Additional arguments will be provided to `func` when it is invoked.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to defer.
-     * @param {...*} [arg] Arguments to invoke the function with.
-     * @returns {number} Returns the timer id.
-     * @example
-     *
-     * _.defer(function(text) { console.log(text); }, 'deferred');
-     * // logs 'deferred' after one or more milliseconds
-     */
-    function defer(func) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var args = slice(arguments, 1);
-      return setTimeout(function() { func.apply(undefined, args); }, 1);
-    }
-
-    /**
-     * Executes the `func` function after `wait` milliseconds. Additional arguments
-     * will be provided to `func` when it is invoked.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to delay.
-     * @param {number} wait The number of milliseconds to delay execution.
-     * @param {...*} [arg] Arguments to invoke the function with.
-     * @returns {number} Returns the timer id.
-     * @example
-     *
-     * _.delay(function(text) { console.log(text); }, 1000, 'later');
-     * // => logs 'later' after one second
-     */
-    function delay(func, wait) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var args = slice(arguments, 2);
-      return setTimeout(function() { func.apply(undefined, args); }, wait);
-    }
-
-    /**
-     * Creates a function that memoizes the result of `func`. If `resolver` is
-     * provided it will be used to determine the cache key for storing the result
-     * based on the arguments provided to the memoized function. By default, the
-     * first argument provided to the memoized function is used as the cache key.
-     * The `func` is executed with the `this` binding of the memoized function.
-     * The result cache is exposed as the `cache` property on the memoized function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to have its output memoized.
-     * @param {Function} [resolver] A function used to resolve the cache key.
-     * @returns {Function} Returns the new memoizing function.
-     * @example
-     *
-     * var fibonacci = _.memoize(function(n) {
-     *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
-     * });
-     *
-     * fibonacci(9)
-     * // => 34
-     *
-     * var data = {
-     *   'fred': { 'name': 'fred', 'age': 40 },
-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
-     * };
-     *
-     * // modifying the result cache
-     * var get = _.memoize(function(name) { return data[name]; }, _.identity);
-     * get('pebbles');
-     * // => { 'name': 'pebbles', 'age': 1 }
-     *
-     * get.cache.pebbles.name = 'penelope';
-     * get('pebbles');
-     * // => { 'name': 'penelope', 'age': 1 }
-     */
-    function memoize(func, resolver) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var memoized = function() {
-        var cache = memoized.cache,
-            key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
-
-        return hasOwnProperty.call(cache, key)
-          ? cache[key]
-          : (cache[key] = func.apply(this, arguments));
-      }
-      memoized.cache = {};
-      return memoized;
-    }
-
-    /**
-     * Creates a function that is restricted to execute `func` once. Repeat calls to
-     * the function will return the value of the first call. The `func` is executed
-     * with the `this` binding of the created function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to restrict.
-     * @returns {Function} Returns the new restricted function.
-     * @example
-     *
-     * var initialize = _.once(createApplication);
-     * initialize();
-     * initialize();
-     * // `initialize` executes `createApplication` once
-     */
-    function once(func) {
-      var ran,
-          result;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      return function() {
-        if (ran) {
-          return result;
-        }
-        ran = true;
-        result = func.apply(this, arguments);
-
-        // clear the `func` variable so the function may be garbage collected
-        func = null;
-        return result;
-      };
-    }
-
-    /**
-     * Creates a function that, when called, invokes `func` with any additional
-     * `partial` arguments prepended to those provided to the new function. This
-     * method is similar to `_.bind` except it does **not** alter the `this` binding.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to partially apply arguments to.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new partially applied function.
-     * @example
-     *
-     * var greet = function(greeting, name) { return greeting + ' ' + name; };
-     * var hi = _.partial(greet, 'hi');
-     * hi('fred');
-     * // => 'hi fred'
-     */
-    function partial(func) {
-      return createWrapper(func, 16, slice(arguments, 1));
-    }
-
-    /**
-     * This method is like `_.partial` except that `partial` arguments are
-     * appended to those provided to the new function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to partially apply arguments to.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new partially applied function.
-     * @example
-     *
-     * var defaultsDeep = _.partialRight(_.merge, _.defaults);
-     *
-     * var options = {
-     *   'variable': 'data',
-     *   'imports': { 'jq': $ }
-     * };
-     *
-     * defaultsDeep(options, _.templateSettings);
-     *
-     * options.variable
-     * // => 'data'
-     *
-     * options.imports
-     * // => { '_': _, 'jq': $ }
-     */
-    function partialRight(func) {
-      return createWrapper(func, 32, null, slice(arguments, 1));
-    }
-
-    /**
-     * Creates a function that, when executed, will only call the `func` function
-     * at most once per every `wait` milliseconds. Provide an options object to
-     * indicate that `func` should be invoked on the leading and/or trailing edge
-     * of the `wait` timeout. Subsequent calls to the throttled function will
-     * return the result of the last `func` call.
-     *
-     * Note: If `leading` and `trailing` options are `true` `func` will be called
-     * on the trailing edge of the timeout only if the the throttled function is
-     * invoked more than once during the `wait` timeout.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to throttle.
-     * @param {number} wait The number of milliseconds to throttle executions to.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
-     * @returns {Function} Returns the new throttled function.
-     * @example
-     *
-     * // avoid excessively updating the position while scrolling
-     * var throttled = _.throttle(updatePosition, 100);
-     * jQuery(window).on('scroll', throttled);
-     *
-     * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
-     * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
-     *   'trailing': false
-     * }));
-     */
-    function throttle(func, wait, options) {
-      var leading = true,
-          trailing = true;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      if (options === false) {
-        leading = false;
-      } else if (isObject(options)) {
-        leading = 'leading' in options ? options.leading : leading;
-        trailing = 'trailing' in options ? options.trailing : trailing;
-      }
-      debounceOptions.leading = leading;
-      debounceOptions.maxWait = wait;
-      debounceOptions.trailing = trailing;
-
-      return debounce(func, wait, debounceOptions);
-    }
-
-    /**
-     * Creates a function that provides `value` to the wrapper function as its
-     * first argument. Additional arguments provided to the function are appended
-     * to those provided to the wrapper function. The wrapper is executed with
-     * the `this` binding of the created function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {*} value The value to wrap.
-     * @param {Function} wrapper The wrapper function.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var p = _.wrap(_.escape, function(func, text) {
-     *   return '<p>' + func(text) + '</p>';
-     * });
-     *
-     * p('Fred, Wilma, & Pebbles');
-     * // => '<p>Fred, Wilma, & Pebbles</p>'
-     */
-    function wrap(value, wrapper) {
-      return createWrapper(wrapper, 16, [value]);
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a function that returns `value`.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} value The value to return from the new function.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * var getter = _.constant(object);
-     * getter() === object;
-     * // => true
-     */
-    function constant(value) {
-      return function() {
-        return value;
-      };
-    }
-
-    /**
-     * Produces a callback bound to an optional `thisArg`. If `func` is a property
-     * name the created callback will return the property value for a given element.
-     * If `func` is an object the created callback will return `true` for elements
-     * that contain the equivalent object properties, otherwise it will return `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} [func=identity] The value to convert to a callback.
-     * @param {*} [thisArg] The `this` binding of the created callback.
-     * @param {number} [argCount] The number of arguments the callback accepts.
-     * @returns {Function} Returns a callback function.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // wrap to create custom callback shorthands
-     * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
-     *   var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
-     *   return !match ? func(callback, thisArg) : function(object) {
-     *     return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
-     *   };
-     * });
-     *
-     * _.filter(characters, 'age__gt38');
-     * // => [{ 'name': 'fred', 'age': 40 }]
-     */
-    function createCallback(func, thisArg, argCount) {
-      var type = typeof func;
-      if (func == null || type == 'function') {
-        return baseCreateCallback(func, thisArg, argCount);
-      }
-      // handle "_.pluck" style callback shorthands
-      if (type != 'object') {
-        return property(func);
-      }
-      var props = keys(func),
-          key = props[0],
-          a = func[key];
-
-      // handle "_.where" style callback shorthands
-      if (props.length == 1 && a === a && !isObject(a)) {
-        // fast path the common case of providing an object with a single
-        // property containing a primitive value
-        return function(object) {
-          var b = object[key];
-          return a === b && (a !== 0 || (1 / a == 1 / b));
-        };
-      }
-      return function(object) {
-        var length = props.length,
-            result = false;
-
-        while (length--) {
-          if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
-            break;
-          }
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
-     * corresponding HTML entities.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} string The string to escape.
-     * @returns {string} Returns the escaped string.
-     * @example
-     *
-     * _.escape('Fred, Wilma, & Pebbles');
-     * // => 'Fred, Wilma, & Pebbles'
-     */
-    function escape(string) {
-      return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
-    }
-
-    /**
-     * This method returns the first argument provided to it.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} value Any value.
-     * @returns {*} Returns `value`.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * _.identity(object) === object;
-     * // => true
-     */
-    function identity(value) {
-      return value;
-    }
-
-    /**
-     * Adds function properties of a source object to the destination object.
-     * If `object` is a function methods will be added to its prototype as well.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {Function|Object} [object=lodash] object The destination object.
-     * @param {Object} source The object of functions to add.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
-     * @example
-     *
-     * function capitalize(string) {
-     *   return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
-     * }
-     *
-     * _.mixin({ 'capitalize': capitalize });
-     * _.capitalize('fred');
-     * // => 'Fred'
-     *
-     * _('fred').capitalize().value();
-     * // => 'Fred'
-     *
-     * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
-     * _('fred').capitalize();
-     * // => 'Fred'
-     */
-    function mixin(object, source, options) {
-      var chain = true,
-          methodNames = source && functions(source);
-
-      if (!source || (!options && !methodNames.length)) {
-        if (options == null) {
-          options = source;
-        }
-        ctor = lodashWrapper;
-        source = object;
-        object = lodash;
-        methodNames = functions(source);
-      }
-      if (options === false) {
-        chain = false;
-      } else if (isObject(options) && 'chain' in options) {
-        chain = options.chain;
-      }
-      var ctor = object,
-          isFunc = isFunction(ctor);
-
-      forEach(methodNames, function(methodName) {
-        var func = object[methodName] = source[methodName];
-        if (isFunc) {
-          ctor.prototype[methodName] = function() {
-            var chainAll = this.__chain__,
-                value = this.__wrapped__,
-                args = [value];
-
-            push.apply(args, arguments);
-            var result = func.apply(object, args);
-            if (chain || chainAll) {
-              if (value === result && isObject(result)) {
-                return this;
-              }
-              result = new ctor(result);
-              result.__chain__ = chainAll;
-            }
-            return result;
-          };
-        }
-      });
-    }
-
-    /**
-     * Reverts the '_' variable to its previous value and returns a reference to
-     * the `lodash` function.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @returns {Function} Returns the `lodash` function.
-     * @example
-     *
-     * var lodash = _.noConflict();
-     */
-    function noConflict() {
-      context._ = oldDash;
-      return this;
-    }
-
-    /**
-     * A no-operation function.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * _.noop(object) === undefined;
-     * // => true
-     */
-    function noop() {
-      // no operation performed
-    }
-
-    /**
-     * Gets the number of milliseconds that have elapsed since the Unix epoch
-     * (1 January 1970 00:00:00 UTC).
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @example
-     *
-     * var stamp = _.now();
-     * _.defer(function() { console.log(_.now() - stamp); });
-     * // => logs the number of milliseconds it took for the deferred function to be called
-     */
-    var now = isNative(now = Date.now) && now || function() {
-      return new Date().getTime();
-    };
-
-    /**
-     * Converts the given value into an integer of the specified radix.
-     * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
-     * `value` is a hexadecimal, in which case a `radix` of `16` is used.
-     *
-     * Note: This method avoids differences in native ES3 and ES5 `parseInt`
-     * implementations. See http://es5.github.io/#E.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} value The value to parse.
-     * @param {number} [radix] The radix used to interpret the value to parse.
-     * @returns {number} Returns the new integer value.
-     * @example
-     *
-     * _.parseInt('08');
-     * // => 8
-     */
-    var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
-      // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
-      return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
-    };
-
-    /**
-     * Creates a "_.pluck" style function, which returns the `key` value of a
-     * given object.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} key The name of the property to retrieve.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'fred',   'age': 40 },
-     *   { 'name': 'barney', 'age': 36 }
-     * ];
-     *
-     * var getName = _.property('name');
-     *
-     * _.map(characters, getName);
-     * // => ['barney', 'fred']
-     *
-     * _.sortBy(characters, getName);
-     * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred',   'age': 40 }]
-     */
-    function property(key) {
-      return function(object) {
-        return object[key];
-      };
-    }
-
-    /**
-     * Produces a random number between `min` and `max` (inclusive). If only one
-     * argument is provided a number between `0` and the given number will be
-     * returned. If `floating` is truey or either `min` or `max` are floats a
-     * floating-point number will be returned instead of an integer.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {number} [min=0] The minimum possible value.
-     * @param {number} [max=1] The maximum possible value.
-     * @param {boolean} [floating=false] Specify returning a floating-point number.
-     * @returns {number} Returns a random number.
-     * @example
-     *
-     * _.random(0, 5);
-     * // => an integer between 0 and 5
-     *
-     * _.random(5);
-     * // => also an integer between 0 and 5
-     *
-     * _.random(5, true);
-     * // => a floating-point number between 0 and 5
-     *
-     * _.random(1.2, 5.2);
-     * // => a floating-point number between 1.2 and 5.2
-     */
-    function random(min, max, floating) {
-      var noMin = min == null,
-          noMax = max == null;
-
-      if (floating == null) {
-        if (typeof min == 'boolean' && noMax) {
-          floating = min;
-          min = 1;
-        }
-        else if (!noMax && typeof max == 'boolean') {
-          floating = max;
-          noMax = true;
-        }
-      }
-      if (noMin && noMax) {
-        max = 1;
-      }
-      min = +min || 0;
-      if (noMax) {
-        max = min;
-        min = 0;
-      } else {
-        max = +max || 0;
-      }
-      if (floating || min % 1 || max % 1) {
-        var rand = nativeRandom();
-        return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
-      }
-      return baseRandom(min, max);
-    }
-
-    /**
-     * Resolves the value of property `key` on `object`. If `key` is a function
-     * it will be invoked with the `this` binding of `object` and its result returned,
-     * else the property value is returned. If `object` is falsey then `undefined`
-     * is returned.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {Object} object The object to inspect.
-     * @param {string} key The name of the property to resolve.
-     * @returns {*} Returns the resolved value.
-     * @example
-     *
-     * var object = {
-     *   'cheese': 'crumpets',
-     *   'stuff': function() {
-     *     return 'nonsense';
-     *   }
-     * };
-     *
-     * _.result(object, 'cheese');
-     * // => 'crumpets'
-     *
-     * _.result(object, 'stuff');
-     * // => 'nonsense'
-     */
-    function result(object, key) {
-      if (object) {
-        var value = object[key];
-        return isFunction(value) ? object[key]() : value;
-      }
-    }
-
-    /**
-     * A micro-templating method that handles arbitrary delimiters, preserves
-     * whitespace, and correctly escapes quotes within interpolated code.
-     *
-     * Note: In the development build, `_.template` utilizes sourceURLs for easier
-     * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-     *
-     * For more information on precompiling templates see:
-     * https://lodash.com/custom-builds
-     *
-     * For more information on Chrome extension sandboxes see:
-     * http://developer.chrome.com/stable/extensions/sandboxingEval.html
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} text The template text.
-     * @param {Object} data The data object used to populate the text.
-     * @param {Object} [options] The options object.
-     * @param {RegExp} [options.escape] The "escape" delimiter.
-     * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
-     * @param {Object} [options.imports] An object to import into the template as local variables.
-     * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
-     * @param {string} [sourceURL] The sourceURL of the template's compiled source.
-     * @param {string} [variable] The data object variable name.
-     * @returns {Function|string} Returns a compiled function when no `data` object
-     *  is given, else it returns the interpolated text.
-     * @example
-     *
-     * // using the "interpolate" delimiter to create a compiled template
-     * var compiled = _.template('hello <%= name %>');
-     * compiled({ 'name': 'fred' });
-     * // => 'hello fred'
-     *
-     * // using the "escape" delimiter to escape HTML in data property values
-     * _.template('<b><%- value %></b>', { 'value': '<script>' });
-     * // => '<b><script></b>'
-     *
-     * // using the "evaluate" delimiter to generate HTML
-     * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
-     * _.template(list, { 'people': ['fred', 'barney'] });
-     * // => '<li>fred</li><li>barney</li>'
-     *
-     * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
-     * _.template('hello ${ name }', { 'name': 'pebbles' });
-     * // => 'hello pebbles'
-     *
-     * // using the internal `print` function in "evaluate" delimiters
-     * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
-     * // => 'hello barney!'
-     *
-     * // using a custom template delimiters
-     * _.templateSettings = {
-     *   'interpolate': /{{([\s\S]+?)}}/g
-     * };
-     *
-     * _.template('hello {{ name }}!', { 'name': 'mustache' });
-     * // => 'hello mustache!'
-     *
-     * // using the `imports` option to import jQuery
-     * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
-     * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
-     * // => '<li>fred</li><li>barney</li>'
-     *
-     * // using the `sourceURL` option to specify a custom sourceURL for the template
-     * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
-     * compiled(data);
-     * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
-     *
-     * // using the `variable` option to ensure a with-statement isn't used in the compiled template
-     * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
-     * compiled.source;
-     * // => function(data) {
-     *   var __t, __p = '', __e = _.escape;
-     *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
-     *   return __p;
-     * }
-     *
-     * // using the `source` property to inline compiled templates for meaningful
-     * // line numbers in error messages and a stack trace
-     * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
-     *   var JST = {\
-     *     "main": ' + _.template(mainText).source + '\
-     *   };\
-     * ');
-     */
-    function template(text, data, options) {
-      // based on John Resig's `tmpl` implementation
-      // http://ejohn.org/blog/javascript-micro-templating/
-      // and Laura Doktorova's doT.js
-      // https://github.com/olado/doT
-      var settings = lodash.templateSettings;
-      text = String(text || '');
-
-      // avoid missing dependencies when `iteratorTemplate` is not defined
-      options = defaults({}, options, settings);
-
-      var imports = defaults({}, options.imports, settings.imports),
-          importsKeys = keys(imports),
-          importsValues = values(imports);
-
-      var isEvaluating,
-          index = 0,
-          interpolate = options.interpolate || reNoMatch,
-          source = "__p += '";
-
-      // compile the regexp to match each delimiter
-      var reDelimiters = RegExp(
-        (options.escape || reNoMatch).source + '|' +
-        interpolate.source + '|' +
-        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
-        (options.evaluate || reNoMatch).source + '|$'
-      , 'g');
-
-      text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
-        interpolateValue || (interpolateValue = esTemplateValue);
-
-        // escape characters that cannot be included in string literals
-        source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
-
-        // replace delimiters with snippets
-        if (escapeValue) {
-          source += "' +\n__e(" + escapeValue + ") +\n'";
-        }
-        if (evaluateValue) {
-          isEvaluating = true;
-          source += "';\n" + evaluateValue + ";\n__p += '";
-        }
-        if (interpolateValue) {
-          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
-        }
-        index = offset + match.length;
-
-        // the JS engine embedded in Adobe products requires returning the `match`
-        // string in order to produce the correct `offset` value
-        return match;
-      });
-
-      source += "';\n";
-
-      // if `variable` is not specified, wrap a with-statement around the generated
-      // code to add the data object to the top of the scope chain
-      var variable = options.variable,
-          hasVariable = variable;
-
-      if (!hasVariable) {
-        variable = 'obj';
-        source = 'with (' + variable + ') {\n' + source + '\n}\n';
-      }
-      // cleanup code by stripping empty strings
-      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
-        .replace(reEmptyStringMiddle, '$1')
-        .replace(reEmptyStringTrailing, '$1;');
-
-      // frame code as the function body
-      source = 'function(' + variable + ') {\n' +
-        (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
-        "var __t, __p = '', __e = _.escape" +
-        (isEvaluating
-          ? ', __j = Array.prototype.join;\n' +
-            "function print() { __p += __j.call(arguments, '') }\n"
-          : ';\n'
-        ) +
-        source +
-        'return __p\n}';
-
-      // Use a sourceURL for easier debugging.
-      // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-      var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
-
-      try {
-        var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
-      } catch(e) {
-        e.source = source;
-        throw e;
-      }
-      if (data) {
-        return result(data);
-      }
-      // provide the compiled function's source by its `toString` method, in
-      // supported environments, or the `source` property as a convenience for
-      // inlining compiled templates during the build process
-      result.source = source;
-      return result;
-    }
-
-    /**
-     * Executes the callback `n` times, returning an array of the results
-     * of each callback execution. The callback is bound to `thisArg` and invoked
-     * with one argument; (index).
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {number} n The number of times to execute the callback.
-     * @param {Function} callback The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns an array of the results of each `callback` execution.
-     * @example
-     *
-     * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
-     * // => [3, 6, 4]
-     *
-     * _.times(3, function(n) { mage.castSpell(n); });
-     * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
-     *
-     * _.times(3, function(n) { this.cast(n); }, mage);
-     * // => also calls `mage.castSpell(n)` three times
-     */
-    function times(n, callback, thisArg) {
-      n = (n = +n) > -1 ? n : 0;
-      var index = -1,
-          result = Array(n);
-
-      callback = baseCreateCallback(callback, thisArg, 1);
-      while (++index < n) {
-        result[index] = callback(index);
-      }
-      return result;
-    }
-
-    /**
-     * The inverse of `_.escape` this method converts the HTML entities
-     * `&`, `<`, `>`, `"`, and `'` in `string` to their
-     * corresponding characters.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} string The string to unescape.
-     * @returns {string} Returns the unescaped string.
-     * @example
-     *
-     * _.unescape('Fred, Barney & Pebbles');
-     * // => 'Fred, Barney & Pebbles'
-     */
-    function unescape(string) {
-      return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
-    }
-
-    /**
-     * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} [prefix] The value to prefix the ID with.
-     * @returns {string} Returns the unique ID.
-     * @example
-     *
-     * _.uniqueId('contact_');
-     * // => 'contact_104'
-     *
-     * _.uniqueId();
-     * // => '105'
-     */
-    function uniqueId(prefix) {
-      var id = ++idCounter;
-      return String(prefix == null ? '' : prefix) + id;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a `lodash` object that wraps the given value with explicit
-     * method chaining enabled.
-     *
-     * @static
-     * @memberOf _
-     * @category Chaining
-     * @param {*} value The value to wrap.
-     * @returns {Object} Returns the wrapper object.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36 },
-     *   { 'name': 'fred',    'age': 40 },
-     *   { 'name': 'pebbles', 'age': 1 }
-     * ];
-     *
-     * var youngest = _.chain(characters)
-     *     .sortBy('age')
-     *     .map(function(chr) { return chr.name + ' is ' + chr.age; })
-     *     .first()
-     *     .value();
-     * // => 'pebbles is 1'
-     */
-    function chain(value) {
-      value = new lodashWrapper(value);
-      value.__chain__ = true;
-      return value;
-    }
-
-    /**
-     * Invokes `interceptor` with the `value` as the first argument and then
-     * returns `value`. The purpose of this method is to "tap into" a method
-     * chain in order to perform operations on intermediate results within
-     * the chain.
-     *
-     * @static
-     * @memberOf _
-     * @category Chaining
-     * @param {*} value The value to provide to `interceptor`.
-     * @param {Function} interceptor The function to invoke.
-     * @returns {*} Returns `value`.
-     * @example
-     *
-     * _([1, 2, 3, 4])
-     *  .tap(function(array) { array.pop(); })
-     *  .reverse()
-     *  .value();
-     * // => [3, 2, 1]
-     */
-    function tap(value, interceptor) {
-      interceptor(value);
-      return value;
-    }
-
-    /**
-     * Enables explicit method chaining on the wrapper object.
-     *
-     * @name chain
-     * @memberOf _
-     * @category Chaining
-     * @returns {*} Returns the wrapper object.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // without explicit chaining
-     * _(characters).first();
-     * // => { 'name': 'barney', 'age': 36 }
-     *
-     * // with explicit chaining
-     * _(characters).chain()
-     *   .first()
-     *   .pick('age')
-     *   .value();
-     * // => { 'age': 36 }
-     */
-    function wrapperChain() {
-      this.__chain__ = true;
-      return this;
-    }
-
-    /**
-     * Produces the `toString` result of the wrapped value.
-     *
-     * @name toString
-     * @memberOf _
-     * @category Chaining
-     * @returns {string} Returns the string result.
-     * @example
-     *
-     * _([1, 2, 3]).toString();
-     * // => '1,2,3'
-     */
-    function wrapperToString() {
-      return String(this.__wrapped__);
-    }
-
-    /**
-     * Extracts the wrapped value.
-     *
-     * @name valueOf
-     * @memberOf _
-     * @alias value
-     * @category Chaining
-     * @returns {*} Returns the wrapped value.
-     * @example
-     *
-     * _([1, 2, 3]).valueOf();
-     * // => [1, 2, 3]
-     */
-    function wrapperValueOf() {
-      return this.__wrapped__;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions that return wrapped values when chaining
-    lodash.after = after;
-    lodash.assign = assign;
-    lodash.at = at;
-    lodash.bind = bind;
-    lodash.bindAll = bindAll;
-    lodash.bindKey = bindKey;
-    lodash.chain = chain;
-    lodash.compact = compact;
-    lodash.compose = compose;
-    lodash.constant = constant;
-    lodash.countBy = countBy;
-    lodash.create = create;
-    lodash.createCallback = createCallback;
-    lodash.curry = curry;
-    lodash.debounce = debounce;
-    lodash.defaults = defaults;
-    lodash.defer = defer;
-    lodash.delay = delay;
-    lodash.difference = difference;
-    lodash.filter = filter;
-    lodash.flatten = flatten;
-    lodash.forEach = forEach;
-    lodash.forEachRight = forEachRight;
-    lodash.forIn = forIn;
-    lodash.forInRight = forInRight;
-    lodash.forOwn = forOwn;
-    lodash.forOwnRight = forOwnRight;
-    lodash.functions = functions;
-    lodash.groupBy = groupBy;
-    lodash.indexBy = indexBy;
-    lodash.initial = initial;
-    lodash.intersection = intersection;
-    lodash.invert = invert;
-    lodash.invoke = invoke;
-    lodash.keys = keys;
-    lodash.map = map;
-    lodash.mapValues = mapValues;
-    lodash.max = max;
-    lodash.memoize = memoize;
-    lodash.merge = merge;
-    lodash.min = min;
-    lodash.omit = omit;
-    lodash.once = once;
-    lodash.pairs = pairs;
-    lodash.partial = partial;
-    lodash.partialRight = partialRight;
-    lodash.pick = pick;
-    lodash.pluck = pluck;
-    lodash.property = property;
-    lodash.pull = pull;
-    lodash.range = range;
-    lodash.reject = reject;
-    lodash.remove = remove;
-    lodash.rest = rest;
-    lodash.shuffle = shuffle;
-    lodash.sortBy = sortBy;
-    lodash.tap = tap;
-    lodash.throttle = throttle;
-    lodash.times = times;
-    lodash.toArray = toArray;
-    lodash.transform = transform;
-    lodash.union = union;
-    lodash.uniq = uniq;
-    lodash.values = values;
-    lodash.where = where;
-    lodash.without = without;
-    lodash.wrap = wrap;
-    lodash.xor = xor;
-    lodash.zip = zip;
-    lodash.zipObject = zipObject;
-
-    // add aliases
-    lodash.collect = map;
-    lodash.drop = rest;
-    lodash.each = forEach;
-    lodash.eachRight = forEachRight;
-    lodash.extend = assign;
-    lodash.methods = functions;
-    lodash.object = zipObject;
-    lodash.select = filter;
-    lodash.tail = rest;
-    lodash.unique = uniq;
-    lodash.unzip = zip;
-
-    // add functions to `lodash.prototype`
-    mixin(lodash);
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions that return unwrapped values when chaining
-    lodash.clone = clone;
-    lodash.cloneDeep = cloneDeep;
-    lodash.contains = contains;
-    lodash.escape = escape;
-    lodash.every = every;
-    lodash.find = find;
-    lodash.findIndex = findIndex;
-    lodash.findKey = findKey;
-    lodash.findLast = findLast;
-    lodash.findLastIndex = findLastIndex;
-    lodash.findLastKey = findLastKey;
-    lodash.has = has;
-    lodash.identity = identity;
-    lodash.indexOf = indexOf;
-    lodash.isArguments = isArguments;
-    lodash.isArray = isArray;
-    lodash.isBoolean = isBoolean;
-    lodash.isDate = isDate;
-    lodash.isElement = isElement;
-    lodash.isEmpty = isEmpty;
-    lodash.isEqual = isEqual;
-    lodash.isFinite = isFinite;
-    lodash.isFunction = isFunction;
-    lodash.isNaN = isNaN;
-    lodash.isNull = isNull;
-    lodash.isNumber = isNumber;
-    lodash.isObject = isObject;
-    lodash.isPlainObject = isPlainObject;
-    lodash.isRegExp = isRegExp;
-    lodash.isString = isString;
-    lodash.isUndefined = isUndefined;
-    lodash.lastIndexOf = lastIndexOf;
-    lodash.mixin = mixin;
-    lodash.noConflict = noConflict;
-    lodash.noop = noop;
-    lodash.now = now;
-    lodash.parseInt = parseInt;
-    lodash.random = random;
-    lodash.reduce = reduce;
-    lodash.reduceRight = reduceRight;
-    lodash.result = result;
-    lodash.runInContext = runInContext;
-    lodash.size = size;
-    lodash.some = some;
-    lodash.sortedIndex = sortedIndex;
-    lodash.template = template;
-    lodash.unescape = unescape;
-    lodash.uniqueId = uniqueId;
-
-    // add aliases
-    lodash.all = every;
-    lodash.any = some;
-    lodash.detect = find;
-    lodash.findWhere = find;
-    lodash.foldl = reduce;
-    lodash.foldr = reduceRight;
-    lodash.include = contains;
-    lodash.inject = reduce;
-
-    mixin(function() {
-      var source = {}
-      forOwn(lodash, function(func, methodName) {
-        if (!lodash.prototype[methodName]) {
-          source[methodName] = func;
-        }
-      });
-      return source;
-    }(), false);
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions capable of returning wrapped and unwrapped values when chaining
-    lodash.first = first;
-    lodash.last = last;
-    lodash.sample = sample;
-
-    // add aliases
-    lodash.take = first;
-    lodash.head = first;
-
-    forOwn(lodash, function(func, methodName) {
-      var callbackable = methodName !== 'sample';
-      if (!lodash.prototype[methodName]) {
-        lodash.prototype[methodName]= function(n, guard) {
-          var chainAll = this.__chain__,
-              result = func(this.__wrapped__, n, guard);
-
-          return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
-            ? result
-            : new lodashWrapper(result, chainAll);
-        };
-      }
-    });
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * The semantic version number.
-     *
-     * @static
-     * @memberOf _
-     * @type string
-     */
-    lodash.VERSION = '2.4.2';
-
-    // add "Chaining" functions to the wrapper
-    lodash.prototype.chain = wrapperChain;
-    lodash.prototype.toString = wrapperToString;
-    lodash.prototype.value = wrapperValueOf;
-    lodash.prototype.valueOf = wrapperValueOf;
-
-    // add `Array` functions that return unwrapped values
-    forEach(['join', 'pop', 'shift'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        var chainAll = this.__chain__,
-            result = func.apply(this.__wrapped__, arguments);
-
-        return chainAll
-          ? new lodashWrapper(result, chainAll)
-          : result;
-      };
-    });
-
-    // add `Array` functions that return the existing wrapped value
-    forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        func.apply(this.__wrapped__, arguments);
-        return this;
-      };
-    });
-
-    // add `Array` functions that return new wrapped values
-    forEach(['concat', 'slice', 'splice'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
-      };
-    });
-
-    return lodash;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  // expose Lo-Dash
-  var _ = runInContext();
-
-  // some AMD build optimizers like r.js check for condition patterns like the following:
-  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
-    // Expose Lo-Dash to the global object even when an AMD loader is present in
-    // case Lo-Dash is loaded with a RequireJS shim config.
-    // See http://requirejs.org/docs/api.html#config-shim
-    root._ = _;
-
-    // define as an anonymous module so, through path mapping, it can be
-    // referenced as the "underscore" module
-    define(function() {
-      return _;
-    });
-  }
-  // check for `exports` after `define` in case a build optimizer adds an `exports` object
-  else if (freeExports && freeModule) {
-    // in Node.js or RingoJS
-    if (moduleExports) {
-      (freeModule.exports = _)._ = _;
-    }
-    // in Narwhal or Rhino -require
-    else {
-      freeExports._ = _;
-    }
-  }
-  else {
-    // in a browser or Rhino
-    root._ = _;
-  }
-}.call(this));
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-
-},{}]},{},[1])(1)
-});
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJpbmRleC5qcyIsImxpYi9hcnJvd3MuanMiLCJsaWIvY3JlYXRlLWNsdXN0ZXJzLmpzIiwibGliL2NyZWF0ZS1lZGdlLWxhYmVscy5qcyIsImxpYi9jcmVhdGUtZWRnZS1wYXRocy5qcyIsImxpYi9jcmVhdGUtbm9kZXMuanMiLCJsaWIvZDMuanMiLCJsaWIvZGFncmUuanMiLCJsaWIvZ3JhcGhsaWIuanMiLCJsaWIvaW50ZXJzZWN0L2luZGV4LmpzIiwibGliL2ludGVyc2VjdC9pbnRlcnNlY3QtY2lyY2xlLmpzIiwibGliL2ludG [...]
diff --git a/debian/missing-source/dagre-d3/.gitignore b/debian/missing-source/dagre-d3/.gitignore
new file mode 100644
index 0000000..cfd9e0a
--- /dev/null
+++ b/debian/missing-source/dagre-d3/.gitignore
@@ -0,0 +1,6 @@
+/bower_components
+/build
+/node_modules
+.idea
+*.iml
+*.ipr
diff --git a/debian/missing-source/dagre-d3/.jscsrc b/debian/missing-source/dagre-d3/.jscsrc
new file mode 100644
index 0000000..a48833f
--- /dev/null
+++ b/debian/missing-source/dagre-d3/.jscsrc
@@ -0,0 +1,6 @@
+{
+  "disallowSpaceAfterPrefixUnaryOperators": true,
+  "disallowTrailingWhitespace": true,
+  "maximumLineLength": 100,
+  "validateQuoteMarks": true
+}
diff --git a/debian/missing-source/dagre-d3/.jshintrc b/debian/missing-source/dagre-d3/.jshintrc
new file mode 100644
index 0000000..39ee07e
--- /dev/null
+++ b/debian/missing-source/dagre-d3/.jshintrc
@@ -0,0 +1,13 @@
+{
+    "eqeqeq": true,
+    "newcap": true,
+    "quotmark": true,
+    "unused": true,
+    "trailing": true,
+    "laxbreak": true,
+    "node": true,
+    "expr": true,
+    "globals": {
+        "location": false
+    }
+}
diff --git a/debian/missing-source/dagre-d3/.npmignore b/debian/missing-source/dagre-d3/.npmignore
new file mode 100644
index 0000000..634ba91
--- /dev/null
+++ b/debian/missing-source/dagre-d3/.npmignore
@@ -0,0 +1,7 @@
+/browser.js
+/build
+/demo
+/Makefile
+/node_modules
+/src
+/test
diff --git a/debian/missing-source/dagre-d3/LICENSE b/debian/missing-source/dagre-d3/LICENSE
new file mode 100644
index 0000000..1d64ed6
--- /dev/null
+++ b/debian/missing-source/dagre-d3/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Chris Pettitt
+
+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/debian/missing-source/dagre-d3/README.md b/debian/missing-source/dagre-d3/README.md
new file mode 100644
index 0000000..5d6870b
--- /dev/null
+++ b/debian/missing-source/dagre-d3/README.md
@@ -0,0 +1,15 @@
+# dagre-d3 - A D3-based renderer for dagre
+
+[Dagre](https://github.com/cpettitt/dagre) is a JavaScript library that makes it easy to lay out directed graphs on
+the client-side. The dagre-d3 library acts as a front-end to dagre, providing
+actual rendering using [D3](http://d3js.org).
+
+For more details, including examples and configuration options, please see our
+[wiki](https://github.com/cpettitt/dagre-d3/wiki).
+
+**This project is not being actively developed; however, pull requests are still being accepted.**
+
+## License
+
+dagre-d3 is licensed under the terms of the MIT License. See the LICENSE file
+for details.
diff --git a/debian/missing-source/dagre-d3/bower.json b/debian/missing-source/dagre-d3/bower.json
new file mode 100644
index 0000000..8e168ea
--- /dev/null
+++ b/debian/missing-source/dagre-d3/bower.json
@@ -0,0 +1,31 @@
+{
+  "name": "dagre-d3",
+  "version": "0.4.17",
+  "main": [
+    "dist/dagre-d3.core.js"
+  ],
+  "ignore": [
+    ".*",
+    "README.md",
+    "CHANGELOG.md",
+    "Makefile",
+    "browser.js",
+    "build/**",
+    "dist/dagre-d3.js",
+    "dist/dagre-d3.min.js",
+    "dist/dagre-d3.min.js.map",
+    "dist/demo/**",
+    "index.js",
+    "karma*",
+    "lib/**",
+    "package.json",
+    "src/**",
+    "test/**"
+  ],
+  "dependencies": {
+    "d3": "^3.3.8",
+    "dagre": "^0.7.3",
+    "graphlib": "^1.0.5",
+    "lodash": "^3.10.0"
+  }
+}
\ No newline at end of file
diff --git a/debian/missing-source/dagre-d3/demo/arrows.html b/debian/missing-source/dagre-d3/demo/arrows.html
new file mode 100644
index 0000000..f6bdd8a
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/arrows.html
@@ -0,0 +1,76 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: Arrows</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<style id="css">
+body {
+  font: 300 14px 'Helvetica Neue', Helvetica;
+}
+
+.node rect,
+.node circle,
+.node ellipse {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1px;
+}
+
+.edgePath path {
+  stroke: #333;
+  fill: #333;
+  stroke-width: 1.5px;
+}
+</style>
+
+<h1>Dagre D3 Demo: Arrows</h1>
+
+<svg width=960 height=600><g/></svg>
+
+<section>
+<p>A sample that shows the different arrows available in dagre-d3.
+</section>
+
+<script id="js">
+// Create a new directed graph
+var g = new dagreD3.graphlib.Graph().setGraph({});
+
+["normal", "vee", "undirected"].forEach(function(arrowhead) {
+  g.setNode(arrowhead + "1", { label: " " });
+  g.setNode(arrowhead + "2", { label: " " });
+  g.setEdge(arrowhead + "1", arrowhead + "2", {
+    arrowhead: arrowhead,
+    label: arrowhead
+  });
+});
+
+var svg = d3.select("svg"),
+    inner = svg.select("g");
+
+// Set up zoom support
+var zoom = d3.behavior.zoom().on("zoom", function() {
+      inner.attr("transform", "translate(" + d3.event.translate + ")" +
+                                  "scale(" + d3.event.scale + ")");
+    });
+svg.call(zoom);
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Run the renderer. This is what draws the final graph.
+render(inner, g);
+
+// Center the graph
+var initialScale = 0.75;
+zoom
+  .translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
+  .scale(initialScale)
+  .event(svg);
+svg.attr('height', g.graph().height * initialScale + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/clusters.html b/debian/missing-source/dagre-d3/demo/clusters.html
new file mode 100644
index 0000000..36612a7
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/clusters.html
@@ -0,0 +1,102 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: Clusters</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<h1>Dagre D3 Demo: Clusters</h1>
+
+<style id="css">
+.clusters rect {
+  fill: #00ffd0;
+  stroke: #999;
+  stroke-width: 1.5px;
+}
+
+text {
+  font-weight: 300;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+  font-size: 14px;
+}
+
+.node rect {
+  stroke: #999;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.edgePath path {
+  stroke: #333;
+  stroke-width: 1.5px;
+}
+</style>
+
+<svg id="svg-canvas" width=960 height=600></svg>
+
+<section>
+<p>An example of visualizing clusters. This example shows
+how clusters can be applied to a rendered graph.
+</section>
+
+<script id="js">
+// Create the input graph
+var g = new dagreD3.graphlib.Graph({compound:true})
+  .setGraph({})
+  .setDefaultEdgeLabel(function() { return {}; });
+
+// Here we're setting the nodes
+g.setNode('a', {label: 'A'});
+g.setNode('b', {label: 'B'});
+g.setNode('c', {label: 'C'});
+g.setNode('d', {label: 'D'});
+g.setNode('e', {label: 'E'});
+g.setNode('f', {label: 'F'});
+g.setNode('g', {label: 'G'});
+g.setNode('group', {label: 'Group', clusterLabelPos: 'top', style: 'fill: #d3d7e8'});
+g.setNode('top_group', {label: 'Top Group', clusterLabelPos: 'bottom', style: 'fill: #ffd47f'});
+g.setNode('bottom_group', {label: 'Bottom Group', style: 'fill: #5f9488'});
+
+// Set the parents to define which nodes belong to which cluster
+g.setParent('top_group', 'group');
+g.setParent('bottom_group', 'group');
+g.setParent('b', 'top_group');
+g.setParent('c', 'bottom_group');
+g.setParent('d', 'bottom_group');
+g.setParent('e', 'bottom_group');
+g.setParent('f', 'bottom_group');
+
+// Set up edges, no special attributes.
+g.setEdge('a', 'b');
+g.setEdge('b', 'c');
+g.setEdge('b', 'd');
+g.setEdge('b', 'e');
+g.setEdge('b', 'f');
+g.setEdge('b', 'g');
+
+g.nodes().forEach(function(v) {
+  var node = g.node(v);
+  // Round the corners of the nodes
+  node.rx = node.ry = 5;
+});
+
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Set up an SVG group so that we can translate the final graph.
+var svg = d3.select("svg"),
+    svgGroup = svg.append("g");
+
+// Run the renderer. This is what draws the final graph.
+render(d3.select("svg g"), g);
+
+// Center the graph
+var xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
+svgGroup.attr("transform", "translate(" + xCenterOffset + ", 20)");
+svg.attr("height", g.graph().height + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/demo.css b/debian/missing-source/dagre-d3/demo/demo.css
new file mode 100644
index 0000000..06db0ca
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/demo.css
@@ -0,0 +1,35 @@
+body {
+  width: 960px;
+  margin: 0 auto;
+  color: #333;
+  font-weight: 300;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+}
+
+h1 {
+  font-size: 3em;
+  font-weight: 300;
+}
+
+h2 {
+  font-size: 1.5em;
+  font-weight: 300;
+}
+
+section {
+  margin-bottom: 3em;
+}
+
+section p {
+  text-align: justify;
+}
+
+svg {
+  border: 1px solid #ccc;
+  overflow: hidden;
+  margin: 0 auto;
+}
+
+pre {
+  border: 1px solid #ccc;
+}
diff --git a/debian/missing-source/dagre-d3/demo/demo.js b/debian/missing-source/dagre-d3/demo/demo.js
new file mode 100644
index 0000000..60f6b1c
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/demo.js
@@ -0,0 +1,25 @@
+var bodyElem = d3.select('body'),
+    jsElem = d3.select('#js'),
+    jsPanel = bodyElem.append('div').attr('id', 'jsPanel');
+    cssElem = d3.select('#css'),
+    cssPanel = bodyElem.append('div').attr('id', 'cssPanel');
+
+function setupPanel(panel, elem, title) {
+  panel.append('h2').text(title);
+  return panel.append('pre').append('code').text(elem.html().trim());
+}
+
+var jsCode = setupPanel(jsPanel, jsElem, 'JavaScript');
+var cssCode = setupPanel(cssPanel, cssElem, 'CSS');
+
+var hljsRoot = 'http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.1';
+
+bodyElem.append('link')
+  .attr('rel', 'stylesheet')
+  .attr('href', hljsRoot + '/styles/xcode.min.css');
+bodyElem.append('script')
+  .attr('src', hljsRoot + '/highlight.min.js')
+  .on('load', function() {
+    hljs.highlightBlock(jsCode.node());
+    hljs.highlightBlock(cssCode.node());
+  });
diff --git a/debian/missing-source/dagre-d3/demo/dom.html b/debian/missing-source/dagre-d3/demo/dom.html
new file mode 100644
index 0000000..2f52ff3
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/dom.html
@@ -0,0 +1,99 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: DOM Example</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<h1>Dagre D3 Demo: DOM Example</h1>
+
+<style id="css">
+text {
+  font-weight: 300;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+  font-size: 14px;
+}
+
+.node rect {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.edgePath path {
+  stroke: #333;
+  stroke-width: 1.5px;
+}
+
+table {
+  border-spacing: 0;
+}
+
+table td {
+  padding: 7px;
+}
+
+table td:first-child {
+  background-color: #afa;
+  border-top: 1px solid #333;
+  border-left: 1px solid #333;
+  border-bottom: 1px solid #333;
+  border-radius: 5px 0 0 5px;
+}
+
+table td:last-child {
+  background-color: #faa;
+  border-top: 1px solid #333;
+  border-right: 1px solid #333;
+  border-bottom: 1px solid #333;
+  border-radius: 0 5px 5px 0;
+}
+</style>
+
+<svg width=960 height=600></svg>
+
+<section>
+<p>A sample showing how to use DOM nodes in a graph. Note that IE does not
+support this technique.
+</section>
+
+<script id="js">
+// Create a new directed graph
+var g = new dagreD3.graphlib.Graph().setGraph({});
+
+g.setNode("root", {
+  label: function() {
+    var table = document.createElement("table"),
+        tr = d3.select(table).append("tr");
+    tr.append("td").text("A");
+    tr.append("td").text("B");
+    return table;
+  },
+  padding: 0,
+  rx: 5,
+  ry: 5
+});
+g.setNode("A", { label: "A", fill: "#afa" });
+g.setNode("B", { label: "B", fill: "#faa" });
+g.setEdge("root", "A", {});
+g.setEdge("root", "B", {});
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Set up an SVG group so that we can translate the final graph.
+var svg = d3.select('svg'),
+    svgGroup = svg.append('g');
+
+// Run the renderer. This is what draws the final graph.
+render(svgGroup, g);
+
+// Center the graph
+var xCenterOffset = (svg.attr('width') - g.graph().width) / 2;
+svgGroup.attr('transform', 'translate(' + xCenterOffset + ', 20)');
+svg.attr('height', g.graph().height + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/etl-status.html b/debian/missing-source/dagre-d3/demo/etl-status.html
new file mode 100644
index 0000000..ce4608b
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/etl-status.html
@@ -0,0 +1,284 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Renderer Demo</title>
+
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<style>
+
+  body {
+    position: fixed;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    margin: 0;
+    padding: 0;
+    font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+    background: #333;
+  }
+
+
+  @-webkit-keyframes flash {
+    0%, 50%, 100% {
+      opacity: 1;
+    }
+
+    25%, 75% {
+      opacity: 0.2;
+    }
+  }
+
+  @keyframes flash {
+    0%, 50%, 100% {
+      opacity: 1;
+    }
+
+    25%, 75% {
+      opacity: 0.2;
+    }
+  }
+
+  .warn {
+    -webkit-animation-duration: 5s;
+    animation-duration: 5s;
+    -webkit-animation-fill-mode: both;
+    animation-fill-mode: both;
+    -webkit-animation-iteration-count: 1;
+    animation-iteration-count: 1;
+  }
+
+  .live.map {
+    width: 100%;
+    height: 100%;
+  }
+
+  svg {
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+  }
+
+  .live.map text {
+    font-weight: 300;
+    font-size: 14px;
+  }
+
+  .live.map .node rect {
+    stroke-width: 1.5px;
+    stroke: #bbb;
+    fill: #666;
+  }
+
+  .live.map .status {
+    height: 100%;
+    width: 15px;
+    display: block;
+    float: left;
+    border-top-left-radius: 5px;
+    border-bottom-left-radius: 5px;
+    margin-right: 4px;
+  }
+
+  .live.map .running .status {
+    background-color: #7f7;
+  }
+
+  .live.map .running.warn .status {
+    background-color: #ffed68;
+  }
+
+  .live.map .stopped .status {
+    background-color: #f77;
+  }
+
+  .live.map .warn .queue {
+    color: #f77;
+  }
+
+  .warn {
+    -webkit-animation-name: flash;
+    animation-name: flash;
+  }
+
+  .live.map .consumers {
+    margin-right: 2px;
+  }
+
+  .live.map .consumers,
+  .live.map .name {
+    margin-top: 4px;
+  }
+
+  .live.map .consumers:after {
+    content: "x";
+  }
+
+  .live.map .queue {
+    display: block;
+    float: left;
+    width: 130px;
+    height: 20px;
+    font-size: 12px;
+    margin-top: 2px;
+  }
+
+  .live.map .node g div {
+    width: 200px;
+    height: 40px;
+    color: #fff;
+  }
+
+  .live.map .node g div span.consumers {
+    display: inline-block;
+    width: 20px;
+  }
+
+  .live.map .edgeLabel text {
+    width: 50px;
+    fill: #fff;
+  }
+
+  .live.map .edgePath path {
+    stroke: #999;
+    stroke-width: 1.5px;
+    fill: #999;
+  }
+</style>
+
+<body>
+<div class="live map">
+  <svg><g/></svg>
+</div>
+
+<script>
+
+  var workers = {
+    "identifier": {
+      "consumers": 2,
+      "count": 20
+    },
+    "lost-and-found": {
+      "consumers": 1,
+      "count": 1,
+      "inputQueue": "identifier",
+      "inputThroughput": 50
+    },
+    "monitor": {
+      "consumers": 1,
+      "count": 0,
+      "inputQueue": "identifier",
+      "inputThroughput": 50
+    },
+    "meta-enricher": {
+      "consumers": 4,
+      "count": 9900,
+      "inputQueue": "identifier",
+      "inputThroughput": 50
+    },
+    "geo-enricher": {
+      "consumers": 2,
+      "count": 1,
+      "inputQueue": "meta-enricher",
+      "inputThroughput": 50
+    },
+    "elasticsearch-writer": {
+      "consumers": 0,
+      "count": 9900,
+      "inputQueue": "geo-enricher",
+      "inputThroughput": 50
+    }
+  };
+
+  // Set up zoom support
+  var svg = d3.select("svg"),
+      inner = svg.select("g"),
+      zoom = d3.behavior.zoom().on("zoom", function() {
+        inner.attr("transform", "translate(" + d3.event.translate + ")" +
+                                    "scale(" + d3.event.scale + ")");
+      });
+  svg.call(zoom);
+
+  var render = new dagreD3.render();
+
+  // Left-to-right layout
+  var g = new dagreD3.graphlib.Graph();
+  g.setGraph({
+    nodesep: 70,
+    ranksep: 50,
+    rankdir: "LR",
+    marginx: 20,
+    marginy: 20
+  });
+
+  function draw(isUpdate) {
+    for (var id in workers) {
+      var worker = workers[id];
+      var className = worker.consumers ? "running" : "stopped";
+      if (worker.count > 10000) {
+        className += " warn";
+      }
+      var html = "<div>";
+      html += "<span class=status></span>";
+      html += "<span class=consumers>"+worker.consumers+"</span>";
+      html += "<span class=name>"+id+"</span>";
+      html += "<span class=queue><span class=counter>"+worker.count+"</span></span>";
+      html += "</div>";
+      g.setNode(id, {
+        labelType: "html",
+        label: html,
+        rx: 5,
+        ry: 5,
+        padding: 0,
+        class: className
+      });
+
+      if (worker.inputQueue) {
+        g.setEdge(worker.inputQueue, id, {
+          label: worker.inputThroughput + "/s",
+          width: 40
+        });
+      }
+    }
+
+    inner.call(render, g);
+
+    // Zoom and scale to fit
+    var graphWidth = g.graph().width + 80;
+    var graphHeight = g.graph().height + 40;
+    var width = parseInt(svg.style("width").replace(/px/, ""));
+    var height = parseInt(svg.style("height").replace(/px/, ""));
+    var zoomScale = Math.min(width / graphWidth, height / graphHeight);
+    var translate = [(width/2) - ((graphWidth*zoomScale)/2), (height/2) - ((graphHeight*zoomScale)/2)];
+    zoom.translate(translate);
+    zoom.scale(zoomScale);
+    zoom.event(isUpdate ? svg.transition().duration(500) : d3.select("svg"));
+  }
+
+  // Do some mock queue status updates
+  setInterval(function() {
+    var stoppedWorker1Count = workers["elasticsearch-writer"].count;
+    var stoppedWorker2Count = workers["meta-enricher"].count;
+    for (var id in workers) {
+      workers[id].count = Math.ceil(Math.random() * 3);
+      if (workers[id].inputThroughput) workers[id].inputThroughput = Math.ceil(Math.random() * 250);
+    }
+    workers["elasticsearch-writer"].count = stoppedWorker1Count + Math.ceil(Math.random() * 100);
+    workers["meta-enricher"].count = stoppedWorker2Count + Math.ceil(Math.random() * 100);
+    draw(true);
+  }, 1000);
+
+  // Do a mock change of worker configuration
+  setInterval(function() {
+    workers["elasticsearch-monitor"] = {
+      "consumers": 0,
+      "count": 0,
+      "inputQueue": "elasticsearch-writer",
+      "inputThroughput": 50
+    }
+  }, 5000);
+
+  draw();
+</script>
diff --git a/debian/missing-source/dagre-d3/demo/graph-story-board.html b/debian/missing-source/dagre-d3/demo/graph-story-board.html
new file mode 100644
index 0000000..529fff7
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/graph-story-board.html
@@ -0,0 +1,424 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Graph Storyboard. Add and Prune Dependencies Algorithm</title>
+
+<script src="http://d3js.org/d3.v3.js"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<style id="css">
+h1 {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+  margin-top: 0.8em;
+  margin-bottom: 0.2em;
+}
+
+text {
+  font-weight: 300;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+  font-size: 14px;
+}
+
+.node rect {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.node polygon {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.edgePath path.path {
+  stroke: #333;
+  fill: none;
+  stroke-width: 1.5px;
+}
+
+div#top-frame {
+  height: 350px;
+}
+
+div#WBS-frame {
+  float: left;
+  width: 50%;
+}
+
+div#dependencies-frame {
+  float: left;
+  width: 50%;
+}
+
+div#schedule-frame {
+  float: none;
+}
+</style>
+
+<script>
+// Polyfill for PhantomJS. This can be safely ignored if not using PhantomJS.
+// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
+if (!Function.prototype.bind) {
+  Function.prototype.bind = function(oThis) {
+    if (typeof this !== 'function') {
+      // closest thing possible to the ECMAScript 5
+      // internal IsCallable function
+      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
+    }
+
+    var aArgs   = Array.prototype.slice.call(arguments, 1),
+        fToBind = this,
+        fNOP    = function() {},
+        fBound  = function() {
+          return fToBind.apply(this instanceof fNOP && oThis
+                 ? this
+                 : oThis,
+                 aArgs.concat(Array.prototype.slice.call(arguments)));
+        };
+
+    fNOP.prototype = this.prototype;
+    fBound.prototype = new fNOP();
+
+    return fBound;
+  };
+}
+</script>
+
+<script>
+var dagred3Story = function(svgelement, graphType, interframetime) {
+	this.interframetime = interframetime;
+	this.lastrenderTime = null;
+	this.g = new dagreD3.graphlib.Graph().setGraph({});
+	//// Setup animation (if required)
+	//this.g.graph().transition = function(selection) {
+    //  return selection.transition().duration(50);
+    //}.bind(this);
+	this.g.setDefaultEdgeLabel(function() { return {}; });
+  this.g.graph().marginx = 10;
+  this.g.graph().marginy = 10;
+	switch(graphType) {
+	case 'Work Breakdown Structure':
+		this.WBS = true;
+		this.Schedule = false;
+		this.g.graph().ranksep = 30;
+		this.g.graph().nodesep = 30;
+		break;
+	case 'Schedule Network':
+		this.Schedule = true;
+		this.WBS = false;
+		this.g.graph().rankdir = "LR";
+		this.g.graph().ranksep = 15;
+		this.g.graph().nodesep = 15;
+		break;
+	default:
+		console.log ("graphType of "+x+" is not implemented")
+	}
+	this.svg = d3.select(svgelement);
+  this.inner = this.svg.append("g");
+	this.svg.call(d3.behavior.zoom().on("zoom", (function() {
+		this.inner.attr("transform", "translate(" + d3.event.translate + ")" +
+		                                 "scale(" + d3.event.scale + ")")
+  }).bind(this)));
+	
+	this.t = 0;
+
+	this.dagreD3render = new dagreD3.render();
+};
+
+dagred3Story.prototype.animateFrame = function(RenderAfter, Frame) {
+	this.t += RenderAfter
+	//var that = this;
+	setTimeout(function() {
+		Frame.forEach(function(x) {
+			if (this.Schedule) {
+				switch(x[0]) {
+				case 'setActivity':
+					this.g.setNode(x[1],{})
+					break;
+				case 'removeNode':
+					this.g.removeNode(x[1])
+					break;
+				case 'setMilestone':
+					this.g.setNode(x[1],{ shape: 'diamond', style: "fill: #fff; stroke: #000" })
+					break;
+				case 'AddCoherenceEdge':
+					this.g.setEdge(x[1], x[2], {
+						lineInterpolate: 'basis' 
+					});
+					break;
+				case 'AddDependencyEdge':
+					this.g.setEdge(x[1], x[2], {
+						lineInterpolate: 'basis'
+						,label: 'added'
+						,labeloffset: 5
+						,labelpos: 'l'
+					});
+					break;
+				case 'MakeRedundantEdge':
+					this.g.setEdge(x[1], x[2], {
+						style: "stroke: #aaa;   stroke-dasharray: 5, 10;" 
+						,lineInterpolate: 'basis'
+						,arrowheadStyle: "fill: #aaa"
+						,labelpos: 'c'
+						,label: 'pruned'
+						,labelStyle: 'stroke: #aaa'
+					});
+					break;
+				case 'RemoveEdge':
+					this.g.removeEdge(x[1], x[2]);
+					break;
+				default:
+					console.log ("Schedule Network element "+x+" is not implemented")
+				}
+			} else if (this.WBS ) {
+				switch(x[0]) {
+				case 'setComponent':
+					this.g.setNode(x[1],{})
+					break;
+				case 'AddWBSEdge':
+					this.g.setEdge(x[1], x[2], {
+						arrowhead: 'undirected'
+					});
+					break;
+				default:
+					console.log ("WBS element "+x+" is not implemented")
+				}
+			}
+		}.bind(this))
+		
+		if (this.g) {
+			// Render
+			this.dagreD3render(this.inner,this.g);
+		}
+	}.bind(this), this.t)
+};
+
+dagred3Story.prototype.animateStory = function(RenderAfter, Story) {
+	this.t += RenderAfter
+	setTimeout(function() {
+		Story.forEach(function(Frame) {
+			this.animateFrame(this.interframetime, Frame);
+		}.bind(this))
+	}.bind(this), this.t)
+};
+
+</script>
+
+<div id="top-frame">
+  <div id="WBS-frame">
+    <h1>WBS</h1>
+    <svg id="WBS" width=250 height=250></svg>
+  </div>
+
+  <div id="dependencies-frame">
+    <h1>Sequencing</h1>
+    <svg id="dependencies" width=300 height=250></svg>
+  </div>
+</div>
+
+<div id="schedule-frame">
+  <h1>Coherent Schedule Network</h1>
+  <svg id="schedule" width=1150 height=500></svg>
+</div>
+
+<script id="js">
+var framedelay = 2000;
+var dependenciesstory = new dagred3Story("#dependencies", "Schedule Network", framedelay);
+dependenciesstory.animateStory(0,
+[
+	[
+		
+	],[ 
+		
+	],[
+		
+	],[ 
+		
+	]
+	,[
+		["setActivity", "A.1"]
+		,
+		["setMilestone", "A.2 Start"]
+		,
+		["AddDependencyEdge", "A.1", "A.2 Start"]
+	],[
+		
+	],[
+		
+	],[
+		
+	],[
+		
+	],[
+		["setActivity", "A.2.2"]
+		,
+		["setActivity", "A.2.3"]
+		,
+		["AddDependencyEdge", "A.2.2", "A.2.3"]
+	],[
+		
+	],[
+		
+	],[
+		
+	],[
+		
+	],[
+		["setActivity", "A.2.1"]
+		,
+		["setActivity", "B"]
+		,
+		["AddDependencyEdge", "A.2.1", "B"]
+	],[
+		
+	],[
+		
+	]
+]);
+
+var WBSstory = new dagred3Story("#WBS", "Work Breakdown Structure", framedelay);
+
+WBSstory.animateStory(0,
+[
+	[
+		["setComponent", "Project"]
+	],[
+		["setComponent", "A"]
+		,
+		["AddWBSEdge", "Project", "A"]
+		,
+		["setComponent", "B"]
+		,
+		["AddWBSEdge", "Project", "B"]
+	],[
+		["setComponent", "A.1"]
+		, 
+		["AddWBSEdge", "A", "A.1"]
+		,
+		["setComponent", "A.2"]
+		, 
+		["AddWBSEdge",  "A", "A.2"]
+	],[
+		["setComponent", "A.2.1"]
+		, 
+		["AddWBSEdge", "A.2", "A.2.1"]
+		,
+		["setComponent", "A.2.2"]
+		, 
+		["AddWBSEdge",  "A.2", "A.2.2"]
+		,
+		["setComponent", "A.2.3"]
+		, 
+		["AddWBSEdge",  "A.2", "A.2.3"]
+	]
+]);
+
+var schedulestory = new dagred3Story("#schedule", "Schedule Network",framedelay);
+
+// Create the input graph
+
+schedulestory.animateStory(0,
+[
+	[
+		["setActivity", "Project"]
+	],[ 
+		["removeNode", "Project"]
+		,
+		["setMilestone", "Project Finish"]
+		, 
+		["setMilestone", "Project Start"]
+		,
+		["setActivity", "A"]
+		,
+		["setActivity", "B"]
+		,
+		["AddCoherenceEdge", "Project Start", "A"]
+		,
+		["AddCoherenceEdge", "Project Start", "B"]
+		,
+		["AddCoherenceEdge", "A", "Project Finish"]
+		,
+		["AddCoherenceEdge", "B", "Project Finish"]
+	],[
+		["removeNode", "A"]
+		,
+		["setMilestone", "A Start"]
+		, 
+		["setActivity", "A.1"]
+		,  
+		["setActivity", "A.2"]
+		,  
+		["setMilestone", "A Finish"]
+		,
+		["AddCoherenceEdge", "A Start", "A.1"]
+		,
+		["AddCoherenceEdge", "A Start", "A.2"]
+		,
+		["AddCoherenceEdge", "A.1", "A Finish"]
+		,
+		["AddCoherenceEdge", "A.2", "A Finish"]
+		,
+		["AddCoherenceEdge", "Project Start", "A Start"]
+		,
+		["AddCoherenceEdge", "A Finish", "Project Finish"]
+	],[ 
+		["removeNode", "A.2"]
+		,
+		["setMilestone", "A.2 Start"]
+		, 
+		["setActivity", "A.2.1"]
+		,  
+		["setActivity", "A.2.2"]
+		,  
+		["setActivity", "A.2.3"]
+		,  
+		["setMilestone", "A.2 Finish"]
+		,
+		["AddCoherenceEdge", "A.2 Start", "A.2.1"]
+		,
+		["AddCoherenceEdge", "A.2 Start", "A.2.2"]
+		,
+		["AddCoherenceEdge", "A.2 Start", "A.2.3"]
+		,
+		["AddCoherenceEdge", "A.2.1", "A.2 Finish"]
+		,
+		["AddCoherenceEdge", "A.2.2", "A.2 Finish"]
+		,
+		["AddCoherenceEdge", "A.2.3", "A.2 Finish"]
+		,
+		["AddCoherenceEdge", "A Start", "A.2 Start"]
+		,
+		["AddCoherenceEdge", "A.2 Finish", "A Finish"]
+	]
+	,[
+		["AddDependencyEdge", "A.1", "A.2 Start"]
+	],[
+		["MakeRedundantEdge", "A Start", "A.2 Start"]
+	],[
+		["MakeRedundantEdge", "A.1", "A Finish"]
+	],[
+		["RemoveEdge", "A Start", "A.2 Start"]
+	],[
+		["RemoveEdge", "A.1", "A Finish"]
+	],[
+		["AddDependencyEdge", "A.2.2", "A.2.3"]
+	],[
+		["MakeRedundantEdge", "A.2 Start", "A.2.3"]
+	],[
+		["MakeRedundantEdge", "A.2.2", "A.2 Finish"]
+	],[
+		["RemoveEdge", "A.2 Start", "A.2.3"]
+	],[
+		["RemoveEdge", "A.2.2", "A.2 Finish"]
+	],[
+		["AddDependencyEdge", "A.2.1", "B"]
+	],[
+		["MakeRedundantEdge", "Project Start", "B"]
+	],[
+		["RemoveEdge", "Project Start", "B"]
+	]
+]);
+</script>
+</body>
+</html>
diff --git a/debian/missing-source/dagre-d3/demo/hover.html b/debian/missing-source/dagre-d3/demo/hover.html
new file mode 100644
index 0000000..c9cabc3
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/hover.html
@@ -0,0 +1,197 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: Tooltip on Hover</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<!-- Pull in JQuery dependencies -->
+<link rel="stylesheet" href="tipsy.css">
+<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
+<script src="tipsy.js"></script>
+
+<h1>Dagre D3 Demo: Tooltip on Hover</h1>
+
+<style id="css">
+text {
+  font-weight: 300;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+  font-size: 14px;
+}
+
+.node rect {
+  stroke: #333;
+  fill: #fff;
+}
+
+.edgePath path {
+  stroke: #333;
+  fill: #333;
+  stroke-width: 1.5px;
+}
+
+.node text {
+  pointer-events: none;
+}
+
+/* This styles the title of the tooltip */
+.tipsy .name {
+  font-size: 1.5em;
+  font-weight: bold;
+  color: #60b1fc;
+  margin: 0;
+}
+
+/* This styles the body of the tooltip */
+.tipsy .description {
+  font-size: 1.2em;
+}
+</style>
+
+<svg width=960 height=600></svg>
+
+<section>
+<p>The TCP state diagram
+(<a href="http://www.rfc-editor.org/rfc/rfc793.txt">source: RFC 793</a>) with
+hover support. Uses <a href="http://bl.ocks.org/ilyabo/1373263">tipsy JS and CSS</a>
+for the tooltip.
+</section>
+
+<script id="js">
+// Create a new directed graph
+var g = new dagreD3.graphlib.Graph().setGraph({});
+
+// States and transitions from RFC 793
+var states = {
+  CLOSED: {
+    description: "represents no connection state at all.",
+    style: "fill: #f77"
+  },
+
+  LISTEN: {
+    description: "represents waiting for a connection request from any " +
+                 "remote TCP and port."
+  },
+
+  "SYN SENT": {
+    description: "represents waiting for a matching connection " +
+                 "request after having sent a connection request."
+  },
+
+  "SYN RCVD": {
+    description: "represents waiting for a confirming connection " +
+                 "request acknowledgment after having both received and sent a " +
+                 "connection request."
+  },
+
+
+  ESTAB: {
+    description: "represents an open connection, data received " +
+                 "can be delivered to the user.  The normal state for the data " +
+                 "transfer phase of the connection.",
+    style: "fill: #7f7"
+  },
+
+  "FINWAIT-1": {
+    description: "represents waiting for a connection termination " +
+                 "request from the remote TCP, or an acknowledgment of the " +
+                 "connection termination request previously sent."
+
+  },
+
+  "FINWAIT-2": {
+    description: "represents waiting for a connection termination " +
+                 "request from the remote TCP."
+  },
+
+
+  "CLOSE WAIT": {
+    description: "represents waiting for a connection termination " +
+                 "request from the local user."
+  },
+
+  CLOSING: {
+    description: "represents waiting for a connection termination " +
+                 "request acknowledgment from the remote TCP."
+  },
+
+  "LAST-ACK": {
+    description: "represents waiting for an acknowledgment of the " +
+                 "connection termination request previously sent to the remote " +
+                 "TCP (which includes an acknowledgment of its connection " +
+                 "termination request)."
+  },
+
+  "TIME WAIT": {
+    description: "represents waiting for enough time to pass to be " +
+                 "sure the remote TCP received the acknowledgment of its " +
+                 "connection termination request."
+  }
+};
+
+// Add states to the graph, set labels, and style
+Object.keys(states).forEach(function(state) {
+  var value = states[state];
+  value.label = state;
+  value.rx = value.ry = 5;
+  g.setNode(state, value);
+});
+
+// Set up the edges
+g.setEdge("CLOSED",     "LISTEN",     { label: "open" });
+g.setEdge("LISTEN",     "SYN RCVD",   { label: "rcv SYN" });
+g.setEdge("LISTEN",     "SYN SENT",   { label: "send" });
+g.setEdge("LISTEN",     "CLOSED",     { label: "close" });
+g.setEdge("SYN RCVD",   "FINWAIT-1",  { label: "close" });
+g.setEdge("SYN RCVD",   "ESTAB",      { label: "rcv ACK of SYN" });
+g.setEdge("SYN SENT",   "SYN RCVD",   { label: "rcv SYN" });
+g.setEdge("SYN SENT",   "ESTAB",      { label: "rcv SYN, ACK" });
+g.setEdge("SYN SENT",   "CLOSED",     { label: "close" });
+g.setEdge("ESTAB",      "FINWAIT-1",  { label: "close" });
+g.setEdge("ESTAB",      "CLOSE WAIT", { label: "rcv FIN" });
+g.setEdge("FINWAIT-1",  "FINWAIT-2",  { label: "rcv ACK of FIN" });
+g.setEdge("FINWAIT-1",  "CLOSING",    { label: "rcv FIN" });
+g.setEdge("CLOSE WAIT", "LAST-ACK",   { label: "close" });
+g.setEdge("FINWAIT-2",  "TIME WAIT",  { label: "rcv FIN" });
+g.setEdge("CLOSING",    "TIME WAIT",  { label: "rcv ACK of FIN" });
+g.setEdge("LAST-ACK",   "CLOSED",     { label: "rcv ACK of FIN" });
+g.setEdge("TIME WAIT",  "CLOSED",     { label: "timeout=2MSL" });
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Set up an SVG group so that we can translate the final graph.
+var svg = d3.select("svg"),
+    inner = svg.append("g");
+
+// Set up zoom support
+var zoom = d3.behavior.zoom().on("zoom", function() {
+    inner.attr("transform", "translate(" + d3.event.translate + ")" +
+                                "scale(" + d3.event.scale + ")");
+  });
+svg.call(zoom);
+
+// Simple function to style the tooltip for the given node.
+var styleTooltip = function(name, description) {
+  return "<p class='name'>" + name + "</p><p class='description'>" + description + "</p>";
+};
+
+// Run the renderer. This is what draws the final graph.
+render(inner, g);
+
+inner.selectAll("g.node")
+  .attr("title", function(v) { return styleTooltip(v, g.node(v).description) })
+  .each(function(v) { $(this).tipsy({ gravity: "w", opacity: 1, html: true }); });
+
+// Center the graph
+var initialScale = 0.75;
+zoom
+  .translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
+  .scale(initialScale)
+  .event(svg);
+svg.attr('height', g.graph().height * initialScale + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/interactive-demo.html b/debian/missing-source/dagre-d3/demo/interactive-demo.html
new file mode 100644
index 0000000..1d4ac95
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/interactive-demo.html
@@ -0,0 +1,173 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre Interactive Demo</title>
+
+<script src="http://d3js.org/d3.v3.js"></script>
+<script src="http://cpettitt.github.io/project/graphlib-dot/v0.5.2/graphlib-dot.js"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<style>
+svg {
+  border: 1px solid #999;
+  overflow: hidden;
+}
+
+.node {
+  white-space: nowrap;
+}
+
+.node rect,
+.node circle,
+.node ellipse {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.cluster rect {
+  stroke: #333;
+  fill: #000;
+  fill-opacity: 0.1;
+  stroke-width: 1.5px;
+}
+
+.edgePath path.path {
+  stroke: #333;
+  stroke-width: 1.5px;
+  fill: none;
+}
+</style>
+
+<style>
+h1, h2 {
+  color: #333;
+}
+
+textarea {
+  width: 800px;
+}
+
+label {
+  margin-top: 1em;
+  display: block;
+}
+
+.error {
+  color: red;
+}
+</style>
+
+<body onLoad="tryDraw();">
+
+<h1>Dagre Interactive Demo</h1>
+
+<h2>Input</h2>
+
+<form>
+  <label for="inputGraph">Graphviz Definition</label>
+  <textarea id="inputGraph" rows="5" style="display: block" onKeyUp="tryDraw();">
+/* Example */
+digraph {
+    /* Note: HTML labels do not work in IE, which lacks support for <foreignObject> tags. */
+    node [rx=5 ry=5 labelStyle="font: 300 14px 'Helvetica Neue', Helvetica"]
+    edge [labelStyle="font: 300 14px 'Helvetica Neue', Helvetica"]
+    A [labelType="html"
+       label="A <span style='font-size:32px'>Big</span> <span style='color:red;'>HTML</span> Source!"];
+    C;
+    E [label="Bold Red Sink" style="fill: #f77; font-weight: bold"];
+    A -> B -> C;
+    B -> D [label="A blue label" labelStyle="fill: #55f; font-weight: bold;"];
+    D -> E [label="A thick red edge" style="stroke: #f77; stroke-width: 2px;" arrowheadStyle="fill: #f77"];
+    C -> E;
+    A -> D [labelType="html" label="A multi-rank <span style='color:blue;'>HTML</span> edge!"];
+}
+  </textarea>
+
+  <a id="graphLink">Link for this graph</a>
+</form>
+
+<h2>Graph Visualization</h2>
+
+<svg width=800 height=600>
+  <g/>
+</svg>
+
+<script>
+// Input related code goes here
+
+function graphToURL() {
+  var elems = [window.location.protocol, '//',
+               window.location.host,
+               window.location.pathname,
+               '?'];
+
+  var queryParams = [];
+  if (debugAlignment) {
+    queryParams.push('alignment=' + debugAlignment);
+  }
+  queryParams.push('graph=' + encodeURIComponent(inputGraph.value));
+  elems.push(queryParams.join('&'));
+
+  return elems.join('');
+}
+
+var inputGraph = document.querySelector("#inputGraph");
+
+var graphLink = d3.select("#graphLink");
+
+var oldInputGraphValue;
+
+var graphRE = /[?&]graph=([^&]+)/;
+var graphMatch = window.location.search.match(graphRE);
+if (graphMatch) {
+  inputGraph.value = decodeURIComponent(graphMatch[1]);
+}
+var debugAlignmentRE = /[?&]alignment=([^&]+)/;
+var debugAlignmentMatch = window.location.search.match(debugAlignmentRE);
+var debugAlignment;
+if (debugAlignmentMatch) debugAlignment = debugAlignmentMatch[1];
+
+// Set up zoom support
+var svg = d3.select("svg"),
+    inner = d3.select("svg g"),
+    zoom = d3.behavior.zoom().on("zoom", function() {
+      inner.attr("transform", "translate(" + d3.event.translate + ")" +
+                                  "scale(" + d3.event.scale + ")");
+    });
+svg.call(zoom);
+
+// Create and configure the renderer
+var render = dagreD3.render();
+
+function tryDraw() {
+  var g;
+  if (oldInputGraphValue !== inputGraph.value) {
+    inputGraph.setAttribute("class", "");
+    oldInputGraphValue = inputGraph.value;
+    try {
+      g = graphlibDot.read(inputGraph.value);
+    } catch (e) {
+      inputGraph.setAttribute("class", "error");
+      throw e;
+    }
+
+    // Save link to new graph
+    graphLink.attr("href", graphToURL());
+
+    // Set margins, if not present
+    if (!g.graph().hasOwnProperty("marginx") &&
+        !g.graph().hasOwnProperty("marginy")) {
+      g.graph().marginx = 20;
+      g.graph().marginy = 20;
+    }
+
+    g.graph().transition = function(selection) {
+      return selection.transition().duration(500);
+    };
+
+    // Render the graph into svg g
+    d3.select("svg g").call(render, g);
+  }
+}
+</script>
diff --git a/debian/missing-source/dagre-d3/demo/sentence-tokenization.html b/debian/missing-source/dagre-d3/demo/sentence-tokenization.html
new file mode 100644
index 0000000..7e55951
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/sentence-tokenization.html
@@ -0,0 +1,105 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: Sentence Tokenization</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<h1>Dagre D3 Demo: Sentence Tokenization</h1>
+
+<style id="css">
+/* This sets the color for "TK" nodes to a light blue green. */
+g.type-TK > rect {
+  fill: #00ffd0;
+}
+
+text {
+  font-weight: 300;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+  font-size: 14px;
+}
+
+.node rect {
+  stroke: #999;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.edgePath path {
+  stroke: #333;
+  stroke-width: 1.5px;
+}
+</style>
+
+<svg id="svg-canvas" width=960 height=600></svg>
+
+<section>
+<p>An example of visualizing the tokenization of a sentence. This example shows
+how CSS classes can be applied to a rendered graph.
+</section>
+
+<script id="js">
+// Create the input graph
+var g = new dagreD3.graphlib.Graph()
+  .setGraph({})
+  .setDefaultEdgeLabel(function() { return {}; });
+
+// Here we"re setting nodeclass, which is used by our custom drawNodes function
+// below.
+g.setNode(0,  { label: "TOP",       class: "type-TOP" });
+g.setNode(1,  { label: "S",         class: "type-S" });
+g.setNode(2,  { label: "NP",        class: "type-NP" });
+g.setNode(3,  { label: "DT",        class: "type-DT" });
+g.setNode(4,  { label: "This",      class: "type-TK" });
+g.setNode(5,  { label: "VP",        class: "type-VP" });
+g.setNode(6,  { label: "VBZ",       class: "type-VBZ" });
+g.setNode(7,  { label: "is",        class: "type-TK" });
+g.setNode(8,  { label: "NP",        class: "type-NP" });
+g.setNode(9,  { label: "DT",        class: "type-DT" });
+g.setNode(10, { label: "an",        class: "type-TK" });
+g.setNode(11, { label: "NN",        class: "type-NN" });
+g.setNode(12, { label: "example",   class: "type-TK" });
+g.setNode(13, { label: ".",         class: "type-." });
+g.setNode(14, { label: "sentence",  class: "type-TK" });
+
+g.nodes().forEach(function(v) {
+  var node = g.node(v);
+  // Round the corners of the nodes
+  node.rx = node.ry = 5;
+});
+
+// Set up edges, no special attributes.
+g.setEdge(3, 4);
+g.setEdge(2, 3);
+g.setEdge(1, 2);
+g.setEdge(6, 7);
+g.setEdge(5, 6);
+g.setEdge(9, 10);
+g.setEdge(8, 9);
+g.setEdge(11,12);
+g.setEdge(8, 11);
+g.setEdge(5, 8);
+g.setEdge(1, 5);
+g.setEdge(13,14);
+g.setEdge(1, 13);
+g.setEdge(0, 1)
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Set up an SVG group so that we can translate the final graph.
+var svg = d3.select("svg"),
+    svgGroup = svg.append("g");
+
+// Run the renderer. This is what draws the final graph.
+render(d3.select("svg g"), g);
+
+// Center the graph
+var xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
+svgGroup.attr("transform", "translate(" + xCenterOffset + ", 20)");
+svg.attr("height", g.graph().height + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/shapes.html b/debian/missing-source/dagre-d3/demo/shapes.html
new file mode 100644
index 0000000..6f8a54f
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/shapes.html
@@ -0,0 +1,73 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: Shapes</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<style id="css">
+body {
+  font: 300 14px 'Helvetica Neue', Helvetica;
+}
+
+.node rect,
+.node circle,
+.node ellipse,
+.node polygon {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.edgePath path {
+  stroke: #333;
+  fill: #333;
+  stroke-width: 1.5px;
+}
+</style>
+
+<h1>Dagre D3 Demo: Shapes</h1>
+
+<svg width=960 height=600><g/></svg>
+
+<section>
+<p>A sample that shows the different node shapes available in dagre-d3.
+</section>
+
+<script id="js">
+// Create a new directed graph
+var g = new dagreD3.graphlib.Graph().setGraph({});
+
+g.setNode("rect", { shape: "rect" });
+g.setNode("circle", { shape: "circle" });
+g.setNode("ellipse", { shape: "ellipse" });
+g.setNode("diamond", { shape: "diamond" });
+
+var svg = d3.select("svg"),
+    inner = svg.select("g");
+
+// Set up zoom support
+var zoom = d3.behavior.zoom().on("zoom", function() {
+      inner.attr("transform", "translate(" + d3.event.translate + ")" +
+                                  "scale(" + d3.event.scale + ")");
+    });
+svg.call(zoom);
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Run the renderer. This is what draws the final graph.
+render(inner, g);
+
+// Center the graph
+var initialScale = 0.75;
+zoom
+  .translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
+  .scale(initialScale)
+  .event(svg);
+svg.attr('height', g.graph().height * initialScale + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/style-attrs.html b/debian/missing-source/dagre-d3/demo/style-attrs.html
new file mode 100644
index 0000000..e99b8ab
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/style-attrs.html
@@ -0,0 +1,106 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: Style Attributes</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<h1>Dagre D3 Demo: Style Attributes</h1>
+
+<style id="css">
+text {
+  font-weight: 300;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+  font-size: 14px;
+}
+
+.node rect {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.edgePath path.path {
+  stroke: #333;
+  fill: none;
+  stroke-width: 1.5px;
+}
+
+.arrowhead {
+ stroke: blue;
+ fill: blue;
+ stroke-width: 1.5px;
+}
+
+</style>
+
+<svg id="svg" width=960 height=600></svg>
+
+<section>
+<p>An example showing how styles that are set in the input graph can be applied
+to nodes, node labels, edges, and edge labels in the rendered graph.
+</section>
+
+<script id="js">
+// Create the input graph
+var g = new dagreD3.graphlib.Graph().setGraph({});
+
+// Fill node "A" with the color green
+g.setNode("A", { style: "fill: #afa" });
+
+// Make the label for node "B" bold
+g.setNode("B", { labelStyle: "font-weight: bold" });
+
+// Double the size of the font for node "C"
+g.setNode("C", { labelStyle: "font-size: 2em" });
+
+g.setNode("D", {});
+
+g.setNode("E", {});
+
+// Make the edge from "A" to "B" red, thick, and dashed
+g.setEdge("A", "B", {
+  style: "stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;",
+  arrowheadStyle: "fill: #f66"
+});
+
+// Make the label for the edge from "C" to "B" italic and underlined
+g.setEdge("C", "B", {
+  label: "A to C",
+  labelStyle: "font-style: italic; text-decoration: underline;"
+});
+
+// Make the edge between A and D smoother. 
+// see available options for lineInterpolate here: https://github.com/mbostock/d3/wiki/SVG-Shapes#line_interpolate
+g.setEdge("A", "D", {
+  label: "line interpolation different",
+  lineInterpolate: 'basis' 
+});
+
+g.setEdge("E", "D", {});
+
+// Make the arrowhead blue
+g.setEdge("A", "E", {
+  label: "Arrowhead class",
+  arrowheadClass: 'arrowhead'
+});
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Set up an SVG group so that we can translate the final graph.
+var svg = d3.select("svg"),
+    inner = svg.append("g");
+
+// Run the renderer. This is what draws the final graph.
+render(inner, g);
+
+// Center the graph
+var xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
+inner.attr("transform", "translate(" + xCenterOffset + ", 20)");
+svg.attr("height", g.graph().height + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/svg-labels.html b/debian/missing-source/dagre-d3/demo/svg-labels.html
new file mode 100644
index 0000000..cd2743c
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/svg-labels.html
@@ -0,0 +1,103 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: SVG Labels</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<h1>Dagre D3 Demo: SVG Labels</h1>
+
+<style id="css">
+    text {
+        font-weight: 300;
+        font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
+        font-size: 14px;
+    }
+
+    .node rect {
+        stroke: #999;
+        fill: #fff;
+        stroke-width: 1.5px;
+    }
+
+    .edgePath path {
+        stroke: #333;
+        stroke-width: 1.5px;
+    }
+</style>
+
+<svg id="svg-canvas" width=960 height=600></svg>
+
+<section>
+    <p>An example of adding SVG labels. This allows the user to add any svg
+        elements to the label. This allows for links to works in IE.</p>
+</section>
+
+<script id="js">
+    // Create the input graph
+    var g = new dagreD3.graphlib.Graph()
+            .setGraph({})
+            .setDefaultEdgeLabel(function() { return {}; });
+
+    // Create the SVG label to pass in
+    // Must create in SVG namespace
+    // http://stackoverflow.com/questions/7547117/add-a-new-line-in-svg-bug-cannot-see-the-line
+    // This mimics the same way string labels get added in Dagre-D3
+    svg_label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
+    tspan = document.createElementNS('http://www.w3.org/2000/svg','tspan');
+    tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
+    tspan.setAttribute('dy', '1em');
+    tspan.setAttribute('x', '1');
+    link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
+    link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://google.com/');
+    link.setAttribute('target', '_blank');
+    link.textContent = 'IE Capable link';
+    tspan.appendChild(link);
+    svg_label.appendChild(tspan);
+
+    g.setNode(0,  { label: svg_label, labelType: 'svg' });
+    g.setNode(1,  { label: "A" });
+    g.setNode(2,  { label: "B" });
+
+    g.nodes().forEach(function(v) {
+        var node = g.node(v);
+        // Round the corners of the nodes
+        node.rx = node.ry = 5;
+    });
+
+    svg_edge_label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
+    edge_tspan = document.createElementNS('http://www.w3.org/2000/svg','tspan');
+    edge_tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
+    edge_tspan.setAttribute('dy', '1em');
+    edge_tspan.setAttribute('x', '1');
+    edge_link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
+    edge_link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://google.com/');
+    edge_link.setAttribute('target', '_blank');
+    edge_link.textContent = 'IE Capable Edge link';
+    edge_tspan.appendChild(edge_link);
+    svg_edge_label.appendChild(edge_tspan);
+
+    // Set up edges, no special attributes.
+    g.setEdge(0, 1, { labelType: "svg", label: svg_edge_label });
+    g.setEdge(0, 2);
+    g.setEdge(1, 2);
+
+    // Create the renderer
+    var render = new dagreD3.render();
+
+    // Set up an SVG group so that we can translate the final graph.
+    var svg = d3.select("svg"),
+            svgGroup = svg.append("g");
+
+    // Run the renderer. This is what draws the final graph.
+    render(d3.select("svg g"), g);
+
+    // Center the graph
+    var xCenterOffset = (svg.attr("width") - g.graph().width) / 2;
+    svgGroup.attr("transform", "translate(" + xCenterOffset + ", 20)");
+    svg.attr("height", g.graph().height + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/tcp-state-diagram.html b/debian/missing-source/dagre-d3/demo/tcp-state-diagram.html
new file mode 100644
index 0000000..e4d5af6
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/tcp-state-diagram.html
@@ -0,0 +1,105 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: TCP State Diagram</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<style id="css">
+body {
+  font: 300 14px 'Helvetica Neue', Helvetica;
+}
+
+.node rect {
+  stroke: #333;
+  fill: #fff;
+}
+
+.edgePath path {
+  stroke: #333;
+  fill: #333;
+  stroke-width: 1.5px;
+}
+</style>
+
+<h1>Dagre D3 Demo: TCP State Diagram</h1>
+
+<svg width=960 height=600><g/></svg>
+
+<section>
+<p>A sample rendering of a TCP state diagram
+(<a href="http://www.rfc-editor.org/rfc/rfc793.txt">RFC 793</a>). This example
+shows how to set custom styles in the input graph and how to set a custom
+initial zoom.
+</section>
+
+<script id="js">
+// Create a new directed graph
+var g = new dagreD3.graphlib.Graph().setGraph({});
+
+// States and transitions from RFC 793
+var states = [ "CLOSED", "LISTEN", "SYN RCVD", "SYN SENT",
+               "ESTAB", "FINWAIT-1", "CLOSE WAIT", "FINWAIT-2",
+               "CLOSING", "LAST-ACK", "TIME WAIT" ];
+
+// Automatically label each of the nodes
+states.forEach(function(state) { g.setNode(state, { label: state }); });
+
+// Set up the edges
+g.setEdge("CLOSED",     "LISTEN",     { label: "open" });
+g.setEdge("LISTEN",     "SYN RCVD",   { label: "rcv SYN" });
+g.setEdge("LISTEN",     "SYN SENT",   { label: "send" });
+g.setEdge("LISTEN",     "CLOSED",     { label: "close" });
+g.setEdge("SYN RCVD",   "FINWAIT-1",  { label: "close" });
+g.setEdge("SYN RCVD",   "ESTAB",      { label: "rcv ACK of SYN" });
+g.setEdge("SYN SENT",   "SYN RCVD",   { label: "rcv SYN" });
+g.setEdge("SYN SENT",   "ESTAB",      { label: "rcv SYN, ACK" });
+g.setEdge("SYN SENT",   "CLOSED",     { label: "close" });
+g.setEdge("ESTAB",      "FINWAIT-1",  { label: "close" });
+g.setEdge("ESTAB",      "CLOSE WAIT", { label: "rcv FIN" });
+g.setEdge("FINWAIT-1",  "FINWAIT-2",  { label: "rcv ACK of FIN" });
+g.setEdge("FINWAIT-1",  "CLOSING",    { label: "rcv FIN" });
+g.setEdge("CLOSE WAIT", "LAST-ACK",   { label: "close" });
+g.setEdge("FINWAIT-2",  "TIME WAIT",  { label: "rcv FIN" });
+g.setEdge("CLOSING",    "TIME WAIT",  { label: "rcv ACK of FIN" });
+g.setEdge("LAST-ACK",   "CLOSED",     { label: "rcv ACK of FIN" });
+g.setEdge("TIME WAIT",  "CLOSED",     { label: "timeout=2MSL" });
+
+// Set some general styles
+g.nodes().forEach(function(v) {
+  var node = g.node(v);
+  node.rx = node.ry = 5;
+});
+
+// Add some custom colors based on state
+g.node('CLOSED').style = "fill: #f77";
+g.node('ESTAB').style = "fill: #7f7";
+
+var svg = d3.select("svg"),
+    inner = svg.select("g");
+
+// Set up zoom support
+var zoom = d3.behavior.zoom().on("zoom", function() {
+      inner.attr("transform", "translate(" + d3.event.translate + ")" +
+                                  "scale(" + d3.event.scale + ")");
+    });
+svg.call(zoom);
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Run the renderer. This is what draws the final graph.
+render(inner, g);
+
+// Center the graph
+var initialScale = 0.75;
+zoom
+  .translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
+  .scale(initialScale)
+  .event(svg);
+svg.attr('height', g.graph().height * initialScale + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/demo/tipsy.css b/debian/missing-source/dagre-d3/demo/tipsy.css
new file mode 100644
index 0000000..ca03976
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/tipsy.css
@@ -0,0 +1,25 @@
+.tipsy { font-size: 10px; position: absolute; padding: 5px; z-index: 100000; }
+  .tipsy-inner { background-color: #000; color: #FFF; max-width: 200px; padding: 5px 8px 4px 8px; text-align: center; }
+
+  /* Rounded corners */
+  .tipsy-inner { border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; }
+  
+  /* Uncomment for shadow */
+  .tipsy-inner { box-shadow: 0 0 5px #000000; -webkit-box-shadow: 0 0 5px #000000; -moz-box-shadow: 0 0 5px #000000; }
+  
+  .tipsy-arrow { position: absolute; width: 0; height: 0; line-height: 0; border: 5px dashed #000; }
+  
+  /* Rules to colour arrows */
+  .tipsy-arrow-n { border-bottom-color: #000; }
+  .tipsy-arrow-s { border-top-color: #000; }
+  .tipsy-arrow-e { border-left-color: #000; }
+  .tipsy-arrow-w { border-right-color: #000; }
+  
+	.tipsy-n .tipsy-arrow { top: 0px; left: 50%; margin-left: -5px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent; }
+    .tipsy-nw .tipsy-arrow { top: 0; left: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
+    .tipsy-ne .tipsy-arrow { top: 0; right: 10px; border-bottom-style: solid; border-top: none;  border-left-color: transparent; border-right-color: transparent;}
+  .tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-style: solid; border-bottom: none;  border-left-color: transparent; border-right-color: transparent; }
+    .tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; border-top-style: solid; border-bottom: none;  border-left-color: transparent; border-right-color: transparent; }
+    .tipsy-se .tipsy-arrow { bottom: 0; right: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
+  .tipsy-e .tipsy-arrow { right: 0; top: 50%; margin-top: -5px; border-left-style: solid; border-right: none; border-top-color: transparent; border-bottom-color: transparent; }
+  .tipsy-w .tipsy-arrow { left: 0; top: 50%; margin-top: -5px; border-right-style: solid; border-left: none; border-top-color: transparent; border-bottom-color: transparent; }
diff --git a/debian/missing-source/dagre-d3/demo/tipsy.js b/debian/missing-source/dagre-d3/demo/tipsy.js
new file mode 100644
index 0000000..9fd564d
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/tipsy.js
@@ -0,0 +1,288 @@
+// tipsy, facebook style tooltips for jquery
+// version 1.0.0a
+// (c) 2008-2010 jason frame [jason at onehackoranother.com]
+// released under the MIT license
+
+(function($) {
+    
+    function maybeCall(thing, ctx) {
+        return (typeof thing == 'function') ? (thing.call(ctx)) : thing;
+    }
+    
+    function Tipsy(element, options) {
+        this.$element = $(element);
+        this.options = options;
+        this.enabled = true;
+        this.fixTitle();
+    }
+    
+    Tipsy.prototype = {
+        show: function() {
+            var title = this.getTitle();
+            if (title && this.enabled) {
+                var $tip = this.tip();
+                
+                $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title);
+                $tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity
+                $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).prependTo(document.body);
+                
+                var pos = $.extend({}, this.$element.offset(), {
+                    width: this.$element[0].offsetWidth || 0,
+                    height: this.$element[0].offsetHeight || 0
+                });
+
+                if (typeof this.$element[0].nearestViewportElement == 'object') {
+                    // SVG
+					var el = this.$element[0];
+                    var rect = el.getBoundingClientRect();
+					pos.width = rect.width;
+					pos.height = rect.height;
+                }
+
+                
+                var actualWidth = $tip[0].offsetWidth,
+                    actualHeight = $tip[0].offsetHeight,
+                    gravity = maybeCall(this.options.gravity, this.$element[0]);
+                
+                var tp;
+                switch (gravity.charAt(0)) {
+                    case 'n':
+                        tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
+                        break;
+                    case 's':
+                        tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
+                        break;
+                    case 'e':
+                        tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset};
+                        break;
+                    case 'w':
+                        tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset};
+                        break;
+                }
+                
+                if (gravity.length == 2) {
+                    if (gravity.charAt(1) == 'w') {
+                        tp.left = pos.left + pos.width / 2 - 15;
+                    } else {
+                        tp.left = pos.left + pos.width / 2 - actualWidth + 15;
+                    }
+                }
+                
+                $tip.css(tp).addClass('tipsy-' + gravity);
+                $tip.find('.tipsy-arrow')[0].className = 'tipsy-arrow tipsy-arrow-' + gravity.charAt(0);
+                if (this.options.className) {
+                    $tip.addClass(maybeCall(this.options.className, this.$element[0]));
+                }
+                
+                if (this.options.fade) {
+                    $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity});
+                } else {
+                    $tip.css({visibility: 'visible', opacity: this.options.opacity});
+                }
+
+                var t = this;
+                var set_hovered  = function(set_hover){
+                    return function(){
+                        t.$tip.stop();
+                        t.tipHovered = set_hover;
+                        if (!set_hover){
+                            if (t.options.delayOut === 0) {
+                                t.hide();
+                            } else {
+                                setTimeout(function() { 
+                                    if (t.hoverState == 'out') t.hide(); }, t.options.delayOut);
+                            }
+                        }
+                    };
+                };
+               $tip.hover(set_hovered(true), set_hovered(false));
+            }
+        },
+        
+        hide: function() {
+            if (this.options.fade) {
+                this.tip().stop().fadeOut(function() { $(this).remove(); });
+            } else {
+                this.tip().remove();
+            }
+        },
+        
+        fixTitle: function() {
+            var $e = this.$element;
+            
+            if ($e.attr('title') || typeof($e.attr('original-title')) != 'string') {
+                $e.attr('original-title', $e.attr('title') || '').removeAttr('title');
+            }
+            if (typeof $e.context.nearestViewportElement == 'object'){                                                        
+                if ($e.children('title').length){
+                    $e.append('<original-title>' + ($e.children('title').text() || '') + '</original-title>')
+                        .children('title').remove();
+                }
+            }
+        },
+        
+        getTitle: function() {
+            
+            var title, $e = this.$element, o = this.options;
+            this.fixTitle();
+
+            if (typeof o.title == 'string') {
+                var title_name = o.title == 'title' ? 'original-title' : o.title;
+                if ($e.children(title_name).length){
+                    title = $e.children(title_name).html();
+                } else{
+                    title = $e.attr(title_name);
+                }
+                
+            } else if (typeof o.title == 'function') {
+                title = o.title.call($e[0]);
+            }
+            title = ('' + title).replace(/(^\s*|\s*$)/, "");
+            return title || o.fallback;
+        },
+        
+        tip: function() {
+            if (!this.$tip) {
+                this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
+            }
+            return this.$tip;
+        },
+        
+        validate: function() {
+            if (!this.$element[0].parentNode) {
+                this.hide();
+                this.$element = null;
+                this.options = null;
+            }
+        },
+        
+        enable: function() { this.enabled = true; },
+        disable: function() { this.enabled = false; },
+        toggleEnabled: function() { this.enabled = !this.enabled; }
+    };
+    
+    $.fn.tipsy = function(options) {
+        
+        if (options === true) {
+            return this.data('tipsy');
+        } else if (typeof options == 'string') {
+            var tipsy = this.data('tipsy');
+            if (tipsy) tipsy[options]();
+            return this;
+        }
+        
+        options = $.extend({}, $.fn.tipsy.defaults, options);
+
+        if (options.hoverlock && options.delayOut === 0) {
+	    options.delayOut = 100;
+	}
+        
+        function get(ele) {
+            var tipsy = $.data(ele, 'tipsy');
+            if (!tipsy) {
+                tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options));
+                $.data(ele, 'tipsy', tipsy);
+            }
+            return tipsy;
+        }
+        
+        function enter() {
+            var tipsy = get(this);
+            tipsy.hoverState = 'in';
+            if (options.delayIn === 0) {
+                tipsy.show();
+            } else {
+                tipsy.fixTitle();
+                setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn);
+            }
+        }
+        
+        function leave() {
+            var tipsy = get(this);
+            tipsy.hoverState = 'out';
+            if (options.delayOut === 0) {
+                tipsy.hide();
+            } else {
+                var to = function() {
+                    if (!tipsy.tipHovered || !options.hoverlock){
+                        if (tipsy.hoverState == 'out') tipsy.hide(); 
+                    }
+                };
+                setTimeout(to, options.delayOut);
+            }    
+        }
+
+        if (options.trigger != 'manual') {
+            var binder = options.live ? 'live' : 'bind',
+                eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus',
+                eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur';
+            this[binder](eventIn, enter)[binder](eventOut, leave);
+        }
+        
+        return this;
+        
+    };
+    
+    $.fn.tipsy.defaults = {
+        className: null,
+        delayIn: 0,
+        delayOut: 0,
+        fade: false,
+        fallback: '',
+        gravity: 'n',
+        html: false,
+        live: false,
+        offset: 0,
+        opacity: 0.8,
+        title: 'title',
+        trigger: 'hover',
+        hoverlock: false
+    };
+    
+    // Overwrite this method to provide options on a per-element basis.
+    // For example, you could store the gravity in a 'tipsy-gravity' attribute:
+    // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' });
+    // (remember - do not modify 'options' in place!)
+    $.fn.tipsy.elementOptions = function(ele, options) {
+        return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
+    };
+    
+    $.fn.tipsy.autoNS = function() {
+        return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n';
+    };
+    
+    $.fn.tipsy.autoWE = function() {
+        return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w';
+    };
+    
+    /**
+     * yields a closure of the supplied parameters, producing a function that takes
+     * no arguments and is suitable for use as an autogravity function like so:
+     *
+     * @param margin (int) - distance from the viewable region edge that an
+     *        element should be before setting its tooltip's gravity to be away
+     *        from that edge.
+     * @param prefer (string, e.g. 'n', 'sw', 'w') - the direction to prefer
+     *        if there are no viewable region edges effecting the tooltip's
+     *        gravity. It will try to vary from this minimally, for example,
+     *        if 'sw' is preferred and an element is near the right viewable 
+     *        region edge, but not the top edge, it will set the gravity for
+     *        that element's tooltip to be 'se', preserving the southern
+     *        component.
+     */
+     $.fn.tipsy.autoBounds = function(margin, prefer) {
+		return function() {
+			var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)},
+			    boundTop = $(document).scrollTop() + margin,
+			    boundLeft = $(document).scrollLeft() + margin,
+			    $this = $(this);
+
+			if ($this.offset().top < boundTop) dir.ns = 'n';
+			if ($this.offset().left < boundLeft) dir.ew = 'w';
+			if ($(window).width() + $(document).scrollLeft() - $this.offset().left < margin) dir.ew = 'e';
+			if ($(window).height() + $(document).scrollTop() - $this.offset().top < margin) dir.ns = 's';
+
+			return dir.ns + (dir.ew ? dir.ew : '');
+		};
+    };
+})(jQuery);
\ No newline at end of file
diff --git a/debian/missing-source/dagre-d3/demo/user-defined.html b/debian/missing-source/dagre-d3/demo/user-defined.html
new file mode 100644
index 0000000..1e80d4a
--- /dev/null
+++ b/debian/missing-source/dagre-d3/demo/user-defined.html
@@ -0,0 +1,115 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre D3 Demo: User-defined Shapes and Arrows</title>
+
+<link rel="stylesheet" href="demo.css">
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="../build/dist/dagre-d3.js"></script>
+
+<style id="css">
+body {
+  font: 300 14px 'Helvetica Neue', Helvetica;
+}
+
+.node rect,
+.node circle,
+.node ellipse,
+.node polygon {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.edgePath path.path {
+  stroke: #333;
+  fill: none;
+  stroke-width: 1.5px;
+}
+</style>
+
+<h1>Dagre D3 Demo: User-defined Shapes and Arrows</h1>
+
+<svg width=960 height=600><g/></svg>
+
+<section>
+<p>An example that shows how to create and use user-defined shapes and arrows.
+</section>
+
+<script id="js">
+// Create a new directed graph
+var g = new dagreD3.graphlib.Graph().setGraph({});
+
+g.setNode("house", { shape: "house", label: "house" });
+g.setNode("rect", { shape: "rect" });
+g.setEdge("house", "rect", { arrowhead: "hollowPoint" });
+
+var svg = d3.select("svg"),
+    inner = svg.select("g");
+
+// Set up zoom support
+var zoom = d3.behavior.zoom().on("zoom", function() {
+    inner.attr("transform", "translate(" + d3.event.translate + ")" +
+                                "scale(" + d3.event.scale + ")");
+  });
+svg.call(zoom);
+
+// Create the renderer
+var render = new dagreD3.render();
+
+// Add our custom shape (a house)
+render.shapes().house = function(parent, bbox, node) {
+  var w = bbox.width,
+      h = bbox.height,
+      points = [
+        { x:   0, y:        0 },
+        { x:   w, y:        0 },
+        { x:   w, y:       -h },
+        { x: w/2, y: -h * 3/2 },
+        { x:   0, y:       -h }
+      ];
+      shapeSvg = parent.insert("polygon", ":first-child")
+        .attr("points", points.map(function(d) { return d.x + "," + d.y; }).join(" "))
+        .attr("transform", "translate(" + (-w/2) + "," + (h * 3/4) + ")");
+
+  node.intersect = function(point) {
+    return dagreD3.intersect.polygon(node, points, point);
+  };
+
+  return shapeSvg;
+};
+
+// Add our custom arrow (a hollow-point)
+render.arrows().hollowPoint = function normal(parent, id, edge, type) {
+  var marker = parent.append("marker")
+    .attr("id", id)
+    .attr("viewBox", "0 0 10 10")
+    .attr("refX", 9)
+    .attr("refY", 5)
+    .attr("markerUnits", "strokeWidth")
+    .attr("markerWidth", 8)
+    .attr("markerHeight", 6)
+    .attr("orient", "auto");
+
+  var path = marker.append("path")
+    .attr("d", "M 0 0 L 10 5 L 0 10 z")
+    .style("stroke-width", 1)
+    .style("stroke-dasharray", "1,0")
+    .style("fill", "#fff")
+    .style("stroke", "#333");
+  dagreD3.util.applyStyle(path, edge[type + "Style"]);
+};
+
+// Run the renderer. This is what draws the final graph.
+render(inner, g);
+
+// Center the graph
+var initialScale = 0.75;
+zoom
+  .translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
+  .scale(initialScale)
+  .event(svg);
+svg.attr('height', g.graph().height * initialScale + 40);
+</script>
+
+<script src="demo.js"></script>
diff --git a/debian/missing-source/dagre-d3/gulpfile.js b/debian/missing-source/dagre-d3/gulpfile.js
new file mode 100644
index 0000000..cf2195e
--- /dev/null
+++ b/debian/missing-source/dagre-d3/gulpfile.js
@@ -0,0 +1,228 @@
+"use strict";
+
+var _ = require("lodash");
+var browserSync = require("browser-sync");
+var browserify = require("browserify");
+var buffer = require("vinyl-buffer");
+var changed = require("gulp-changed");
+var del = require("del");
+var fs = require("fs");
+var gulp = require("gulp");
+var gutil = require("gulp-util");
+var jshint = require("gulp-jshint");
+var jshintStylish = require("jshint-stylish");
+var karma = require("karma").server;
+var merge = require("merge-stream");
+var prettyTime = require("pretty-hrtime");
+var rename = require("gulp-rename");
+var replace = require("gulp-replace");
+var shell = require("gulp-shell");
+var source = require("vinyl-source-stream");
+var sourcemaps = require("gulp-sourcemaps");
+var uglify = require("gulp-uglify");
+var watch = require("gulp-watch");
+var watchify = require("watchify");
+
+var BUILD_DIR = "build";
+var BUILD_DIST_DIR = "build/dist";
+var DIST_DIR = "dist";
+var DEMO_SRC = "demo/**/*";
+var DEMO_BUILD = BUILD_DIST_DIR + "/demo";
+
+gulp.task("demo:build", function() {
+    return gulp.src(DEMO_SRC)
+        .pipe(replace("../" + BUILD_DIST_DIR + "/dagre-d3.js", "../dagre-d3.js"))
+        .pipe(gulp.dest(DEMO_BUILD));
+});
+
+gulp.task("demo:watch", ["demo:build"], function() {
+    gulp.src(DEMO_SRC)
+        .pipe(watch(DEMO_SRC), { verbose: true })
+        .pipe(changed(DEMO_BUILD))
+        .pipe(replace("../" + BUILD_DIST_DIR + "/dagre-d3.js", "../dagre-d3.js"))
+        .pipe(gulp.dest(DEMO_BUILD));
+});
+
+gulp.task("demo:test", ["demo:build"], function() {
+    return gulp.src("test/demo-test.js")
+        .pipe(shell("phantomjs <%= (file.path) %>"));
+});
+
+gulp.task("js:build", function() {
+    return makeJsBundleTask(false);
+});
+
+gulp.task("js:watch", function() {
+    return makeJsBundleTask(true);
+});
+
+gulp.task("js:test", ["js:build"], function(cb) {
+    karmaSingleRun(__dirname + "/karma.conf.js", cb);
+});
+
+gulp.task("js:test:watch", ["js:build"], function(cb) {
+    karma.start({
+        configFile: __dirname + "/karma.conf.js",
+        singleRun: false,
+        browsers: ["PhantomJS"]
+    });
+    cb();
+});
+
+gulp.task("core-js:build", function() {
+    return makeBundleTask("./index.js", "dagre-d3.core.js", false, {
+        standalone: "dagreD3",
+        bundleExternal: false,
+        debug: true
+    });
+});
+
+gulp.task("core-js:test", ["core-js:build"], function(cb) {
+    karmaSingleRun(__dirname + "/karma.core.conf.js", cb);
+});
+
+gulp.task("version:build", function() {
+    var pkg = readPackageJson();
+    fs.writeFileSync("lib/version.js", generateVersionJs(pkg));
+});
+
+gulp.task("bower:build", function() {
+    var pkg = readPackageJson();
+    fs.writeFileSync("bower.json", generateBowerJson(pkg));
+});
+
+gulp.task("build", ["demo:build", "js:build", "js:test", "core-js:build", "core-js:test", "demo:test"]);
+
+gulp.task("watch", ["demo:watch", "js:watch", "js:test:watch"]);
+
+gulp.task("serve", ["watch"], function() {
+    browserSync.init({
+        files: BUILD_DIST_DIR + "/**/*",
+        notify: false,
+        open: false,
+        reloadOnRestart: true,
+        server: {
+            baseDir: BUILD_DIST_DIR,
+            directory: true
+        }
+    });
+});
+
+gulp.task("dist", ["version:build", "bower:build", "build"], function() {
+    return gulp.src(BUILD_DIST_DIR + "/**/*")
+        .pipe(gulp.dest(DIST_DIR));
+});
+
+gulp.task("release", ["dist"], function() {
+    return gulp.src("src/release/release.sh")
+        .pipe(shell("<%= (file.path) %>"));
+});
+
+gulp.task("clean", function(cb) {
+    del(BUILD_DIR, cb);
+});
+
+gulp.task("default", ["build"]);
+
+function karmaSingleRun(conf, cb) {
+    var args = {
+        configFile: conf,
+        singleRun: true
+    };
+
+    if (process.env.BROWSERS) {
+        args.browsers = process.env.BROWSERS.split(",");
+    }
+
+    karma.start(args, cb);
+}
+
+function makeJsBundleTask(watch) {
+    return makeBundleTask("./index.js", "dagre-d3.js", watch, {
+        standalone: "dagreD3",
+        external: ["node_modules/d3/index.js", "node_modules/d3/d3.js"],
+        debug: true
+    });
+}
+
+function makeBundleTask(src, name, watch, args) {
+    var bundler = browserify(_.defaults(args, watchify.args))
+        .add(src);
+
+    function bundle(changedFiles) {
+        gutil.log("Starting '" + gutil.colors.cyan("browserify " + name) + "'...");
+        var start = process.hrtime();
+        var compileStream = bundler.bundle()
+            .on("error", function(err) {
+                gutil.log(gutil.colors.red("browserify error (" + name + "): " + err.message));
+                this.emit("end");
+            })
+            .on("end", function() {
+                var end = process.hrtime(start);
+                gutil.log("Finished '" + gutil.colors.cyan("browserify " + name) + "' after",
+                    gutil.colors.magenta(prettyTime(end)));
+            })
+            .pipe(source(name))
+            .pipe(gulp.dest(BUILD_DIST_DIR))
+            .pipe(buffer())
+            .pipe(sourcemaps.init({ loadMaps: true }))
+            .pipe(uglify({ preserveComments: "some" }))
+            .pipe(rename({ suffix: ".min" }))
+            .pipe(sourcemaps.write("./"))
+            .pipe(gulp.dest(BUILD_DIST_DIR));
+
+        var lintStream;
+        if (changedFiles) {
+            lintStream = gulp.src(changedFiles);
+        } else {
+            lintStream = gulp.src(["index.js", "lib/**/*.js"]);
+        }
+
+        lintStream = lintStream
+            .pipe(jshint())
+            .pipe(jshint.reporter(jshintStylish));
+        if (!watch) {
+            lintStream = lintStream.pipe(jshint.reporter("fail"));
+        }
+
+        return merge(lintStream, compileStream);
+    }
+
+    if (watch) {
+        bundler = watchify(bundler);
+        bundler.on("update", bundle);
+    }
+
+    return bundle();
+}
+
+function generateBowerJson(pkg) {
+    return prettifyJson(applyTemplate("src/bower.json.tmpl", { pkg: pkg }));
+}
+
+function generateVersionJs(pkg) {
+    return applyTemplate("src/version.js.tmpl", { pkg: pkg });
+}
+
+function applyTemplate(templateFile, props) {
+    var template = fs.readFileSync(templateFile);
+    var compiled = _.template(template);
+    return compiled(props);
+}
+
+/**
+ * Read the contents of package.json in as JSON. Do not cache package.json,
+ * because it may have changed (e.g. when running in watch mode).
+ */
+function readPackageJson() {
+    var packageText = fs.readFileSync("package.json");
+    return JSON.parse(packageText);
+}
+
+/**
+ * Given a JSON string return a prettified version of the string.
+ */
+function prettifyJson(str) {
+    var json = JSON.parse(str);
+    return JSON.stringify(json, null, 2);
+}
diff --git a/debian/missing-source/dagre-d3/index.js b/debian/missing-source/dagre-d3/index.js
new file mode 100644
index 0000000..8410d8f
--- /dev/null
+++ b/debian/missing-source/dagre-d3/index.js
@@ -0,0 +1,30 @@
+/**
+ * @license
+ * Copyright (c) 2012-2013 Chris Pettitt
+ *
+ * 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.
+ */
+module.exports =  {
+  graphlib: require("./lib/graphlib"),
+  dagre: require("./lib/dagre"),
+  intersect: require("./lib/intersect"),
+  render: require("./lib/render"),
+  util: require("./lib/util"),
+  version: require("./lib/version")
+};
diff --git a/debian/missing-source/dagre-d3/karma.conf.js b/debian/missing-source/dagre-d3/karma.conf.js
new file mode 100644
index 0000000..a292b8b
--- /dev/null
+++ b/debian/missing-source/dagre-d3/karma.conf.js
@@ -0,0 +1,71 @@
+// Karma configuration
+// Generated on Sat Oct 18 2014 14:34:48 GMT-0700 (PDT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['mocha'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      { pattern: 'test/*.css', included: false },
+
+      'node_modules/lodash/index.js',
+      'node_modules/d3/d3.js',
+      'build/dist/dagre-d3.js',
+
+      'node_modules/chai/chai.js',
+      'test/bundle-test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress'],
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome', 'Safari', 'Firefox', 'PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/debian/missing-source/dagre-d3/karma.core.conf.js b/debian/missing-source/dagre-d3/karma.core.conf.js
new file mode 100644
index 0000000..51bd6ff
--- /dev/null
+++ b/debian/missing-source/dagre-d3/karma.core.conf.js
@@ -0,0 +1,82 @@
+// Karma configuration
+// Generated on Sat Oct 18 2014 14:34:48 GMT-0700 (PDT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['mocha'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      { pattern: 'test/*.css', included: false },
+
+      'node_modules/lodash/index.js',
+      'node_modules/d3/d3.js',
+      'node_modules/graphlib/dist/graphlib.core.js',
+      'node_modules/dagre/dist/dagre.core.js',
+      'build/dist/dagre-d3.core.js',
+
+      'node_modules/chai/chai.js',
+      'test/bundle-test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'dist/dagre-d3.core.js': 'coverage'
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress', 'coverage'],
+
+    coverageReporter: {
+      dir: 'build/cov',
+      reporters: [
+        { type: 'html' },
+        { type: 'text-summary' }
+      ]
+    },
+
+    // web server port
+    port: 9877,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome', 'Safari', 'Firefox', 'PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/debian/missing-source/dagre-d3/lib/arrows.js b/debian/missing-source/dagre-d3/lib/arrows.js
new file mode 100644
index 0000000..e95cc62
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/arrows.js
@@ -0,0 +1,71 @@
+var util = require("./util");
+
+module.exports = {
+  "default": normal,
+  "normal": normal,
+  "vee": vee,
+  "undirected": undirected
+};
+
+function normal(parent, id, edge, type) {
+  var marker = parent.append("marker")
+    .attr("id", id)
+    .attr("viewBox", "0 0 10 10")
+    .attr("refX", 9)
+    .attr("refY", 5)
+    .attr("markerUnits", "strokeWidth")
+    .attr("markerWidth", 8)
+    .attr("markerHeight", 6)
+    .attr("orient", "auto");
+
+  var path = marker.append("path")
+    .attr("d", "M 0 0 L 10 5 L 0 10 z")
+    .style("stroke-width", 1)
+    .style("stroke-dasharray", "1,0");
+  util.applyStyle(path, edge[type + "Style"]);
+  if (edge[type + "Class"]) {
+    path.attr("class", edge[type + "Class"]);
+  }
+}
+
+function vee(parent, id, edge, type) {
+  var marker = parent.append("marker")
+    .attr("id", id)
+    .attr("viewBox", "0 0 10 10")
+    .attr("refX", 9)
+    .attr("refY", 5)
+    .attr("markerUnits", "strokeWidth")
+    .attr("markerWidth", 8)
+    .attr("markerHeight", 6)
+    .attr("orient", "auto");
+
+  var path = marker.append("path")
+    .attr("d", "M 0 0 L 10 5 L 0 10 L 4 5 z")
+    .style("stroke-width", 1)
+    .style("stroke-dasharray", "1,0");
+  util.applyStyle(path, edge[type + "Style"]);
+  if (edge[type + "Class"]) {
+    path.attr("class", edge[type + "Class"]);
+  }
+}
+
+function undirected(parent, id, edge, type) {
+  var marker = parent.append("marker")
+    .attr("id", id)
+    .attr("viewBox", "0 0 10 10")
+    .attr("refX", 9)
+    .attr("refY", 5)
+    .attr("markerUnits", "strokeWidth")
+    .attr("markerWidth", 8)
+    .attr("markerHeight", 6)
+    .attr("orient", "auto");
+
+  var path = marker.append("path")
+    .attr("d", "M 0 5 L 10 5")
+    .style("stroke-width", 1)
+    .style("stroke-dasharray", "1,0");
+  util.applyStyle(path, edge[type + "Style"]);
+  if (edge[type + "Class"]) {
+    path.attr("class", edge[type + "Class"]);
+  }
+}
diff --git a/debian/missing-source/dagre-d3/lib/create-clusters.js b/debian/missing-source/dagre-d3/lib/create-clusters.js
new file mode 100644
index 0000000..ce96b17
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/create-clusters.js
@@ -0,0 +1,43 @@
+var util = require("./util"),
+    addLabel = require("./label/add-label");
+
+module.exports = createClusters;
+
+function createClusters(selection, g) {
+  var clusters = g.nodes().filter(function(v) { return util.isSubgraph(g, v); }),
+      svgClusters = selection.selectAll("g.cluster")
+        .data(clusters, function(v) { return v; });
+
+  svgClusters.selectAll("*").remove();
+  svgClusters.enter()
+    .append("g")
+      .attr("class", "cluster")
+      .attr("id",function(v){
+          var node = g.node(v);
+          return node.id;
+      })
+      .style("opacity", 0);
+
+  util.applyTransition(svgClusters, g)
+    .style("opacity", 1);
+
+  svgClusters.each(function(v) {
+    var node = g.node(v),
+        thisGroup = d3.select(this);
+    d3.select(this).append("rect");
+    var labelGroup = thisGroup.append("g").attr("class", "label");
+    addLabel(labelGroup, node, node.clusterLabelPos);
+  });
+
+  svgClusters.selectAll("rect").each(function(c) {
+    var node = g.node(c);
+    var domCluster = d3.select(this);
+    util.applyStyle(domCluster, node.style);
+  });
+
+  util.applyTransition(svgClusters.exit(), g)
+    .style("opacity", 0)
+    .remove();
+
+  return svgClusters;
+}
diff --git a/debian/missing-source/dagre-d3/lib/create-edge-labels.js b/debian/missing-source/dagre-d3/lib/create-edge-labels.js
new file mode 100644
index 0000000..cc8afd6
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/create-edge-labels.js
@@ -0,0 +1,35 @@
+"use strict";
+
+var _ = require("./lodash"),
+    addLabel = require("./label/add-label"),
+    util = require("./util"),
+    d3 = require("./d3");
+
+module.exports = createEdgeLabels;
+
+function createEdgeLabels(selection, g) {
+  var svgEdgeLabels = selection.selectAll("g.edgeLabel")
+    .data(g.edges(), function(e) { return util.edgeToId(e); })
+    .classed("update", true);
+
+  svgEdgeLabels.selectAll("*").remove();
+  svgEdgeLabels.enter()
+    .append("g")
+      .classed("edgeLabel", true)
+      .style("opacity", 0);
+  svgEdgeLabels.each(function(e) {
+    var edge = g.edge(e),
+        label = addLabel(d3.select(this), g.edge(e), 0, 0).classed("label", true),
+        bbox = label.node().getBBox();
+
+    if (edge.labelId) { label.attr("id", edge.labelId); }
+    if (!_.has(edge, "width")) { edge.width = bbox.width; }
+    if (!_.has(edge, "height")) { edge.height = bbox.height; }
+  });
+
+  util.applyTransition(svgEdgeLabels.exit(), g)
+    .style("opacity", 0)
+    .remove();
+
+  return svgEdgeLabels;
+}
diff --git a/debian/missing-source/dagre-d3/lib/create-edge-paths.js b/debian/missing-source/dagre-d3/lib/create-edge-paths.js
new file mode 100644
index 0000000..d906ad6
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/create-edge-paths.js
@@ -0,0 +1,136 @@
+"use strict";
+
+var _ = require("./lodash"),
+    intersectNode = require("./intersect/intersect-node"),
+    util = require("./util"),
+    d3 = require("./d3");
+module.exports = createEdgePaths;
+
+function createEdgePaths(selection, g, arrows) {
+  var svgPaths = selection.selectAll("g.edgePath")
+    .data(g.edges(), function(e) { return util.edgeToId(e); })
+    .classed("update", true);
+
+  enter(svgPaths, g);
+  exit(svgPaths, g);
+
+  util.applyTransition(svgPaths, g)
+    .style("opacity", 1);
+
+  // Save DOM element in the path group, and set ID and class
+  svgPaths.each(function(e) {
+    var domEdge = d3.select(this);
+    var edge = g.edge(e);
+    edge.elem = this;
+
+    if (edge.id) {
+      domEdge.attr("id", edge.id);
+    }
+
+    util.applyClass(domEdge, edge["class"],
+      (domEdge.classed("update") ? "update " : "") + "edgePath");
+  });
+
+  svgPaths.selectAll("path.path")
+    .each(function(e) {
+      var edge = g.edge(e);
+      edge.arrowheadId = _.uniqueId("arrowhead");
+
+      var domEdge = d3.select(this)
+        .attr("marker-end", function() {
+            return "url(" + makeFragmentRef(location.href, edge.arrowheadId) + ")";
+        })
+        .style("fill", "none");
+
+      util.applyTransition(domEdge, g)
+        .attr("d", function(e) { return calcPoints(g, e); });
+
+      util.applyStyle(domEdge, edge.style);
+    });
+
+  svgPaths.selectAll("defs *").remove();
+  svgPaths.selectAll("defs")
+    .each(function(e) {
+      var edge = g.edge(e),
+          arrowhead = arrows[edge.arrowhead];
+      arrowhead(d3.select(this), edge.arrowheadId, edge, "arrowhead");
+    });
+
+  return svgPaths;
+}
+
+function makeFragmentRef(url, fragmentId) {
+  var baseUrl = url.split("#")[0];
+  return baseUrl + "#" + fragmentId;
+}
+
+function calcPoints(g, e) {
+  var edge = g.edge(e),
+      tail = g.node(e.v),
+      head = g.node(e.w),
+      points = edge.points.slice(1, edge.points.length - 1);
+  points.unshift(intersectNode(tail, points[0]));
+  points.push(intersectNode(head, points[points.length - 1]));
+
+  return createLine(edge, points);
+}
+
+function createLine(edge, points) {
+  var line = d3.svg.line()
+    .x(function(d) { return d.x; })
+    .y(function(d) { return d.y; });
+
+  if (_.has(edge, "lineInterpolate")) {
+    line.interpolate(edge.lineInterpolate);
+  }
+
+  if (_.has(edge, "lineTension")) {
+    line.tension(Number(edge.lineTension));
+  }
+
+  return line(points);
+}
+
+function getCoords(elem) {
+  var bbox = elem.getBBox(),
+      matrix = elem.ownerSVGElement.getScreenCTM()
+        .inverse()
+        .multiply(elem.getScreenCTM())
+        .translate(bbox.width / 2, bbox.height / 2);
+  return { x: matrix.e, y: matrix.f };
+}
+
+function enter(svgPaths, g) {
+  var svgPathsEnter = svgPaths.enter()
+    .append("g")
+      .attr("class", "edgePath")
+      .style("opacity", 0);
+  svgPathsEnter.append("path")
+    .attr("class", "path")
+    .attr("d", function(e) {
+      var edge = g.edge(e),
+          sourceElem = g.node(e.v).elem,
+          points = _.range(edge.points.length).map(function() { return getCoords(sourceElem); });
+      return createLine(edge, points);
+    });
+  svgPathsEnter.append("defs");
+}
+
+function exit(svgPaths, g) {
+  var svgPathExit = svgPaths.exit();
+  util.applyTransition(svgPathExit, g)
+    .style("opacity", 0)
+    .remove();
+
+  util.applyTransition(svgPathExit.select("path.path"), g)
+    .attr("d", function(e) {
+      var source = g.node(e.v);
+
+      if (source) {
+        var points = _.range(this.getTotalLength()).map(function() { return source; });
+        return createLine({}, points);
+      } else {
+        return d3.select(this).attr("d");
+      }
+    });
+}
diff --git a/debian/missing-source/dagre-d3/lib/create-nodes.js b/debian/missing-source/dagre-d3/lib/create-nodes.js
new file mode 100644
index 0000000..c255b18
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/create-nodes.js
@@ -0,0 +1,58 @@
+"use strict";
+
+var _ = require("./lodash"),
+    addLabel = require("./label/add-label"),
+    util = require("./util"),
+    d3 = require("./d3");
+
+module.exports = createNodes;
+
+function createNodes(selection, g, shapes) {
+  var simpleNodes = g.nodes().filter(function(v) { return !util.isSubgraph(g, v); });
+  var svgNodes = selection.selectAll("g.node")
+    .data(simpleNodes, function(v) { return v; })
+    .classed("update", true);
+
+  svgNodes.selectAll("*").remove();
+  svgNodes.enter()
+    .append("g")
+      .attr("class", "node")
+      .style("opacity", 0);
+  svgNodes.each(function(v) {
+    var node = g.node(v),
+        thisGroup = d3.select(this),
+        labelGroup = thisGroup.append("g").attr("class", "label"),
+        labelDom = addLabel(labelGroup, node),
+        shape = shapes[node.shape],
+        bbox = _.pick(labelDom.node().getBBox(), "width", "height");
+
+    node.elem = this;
+
+    if (node.id) { thisGroup.attr("id", node.id); }
+    if (node.labelId) { labelGroup.attr("id", node.labelId); }
+    util.applyClass(thisGroup, node["class"],
+      (thisGroup.classed("update") ? "update " : "") + "node");
+
+    if (_.has(node, "width")) { bbox.width = node.width; }
+    if (_.has(node, "height")) { bbox.height = node.height; }
+
+    bbox.width += node.paddingLeft + node.paddingRight;
+    bbox.height += node.paddingTop + node.paddingBottom;
+    labelGroup.attr("transform", "translate(" +
+      ((node.paddingLeft - node.paddingRight) / 2) + "," +
+      ((node.paddingTop - node.paddingBottom) / 2) + ")");
+
+    var shapeSvg = shape(d3.select(this), bbox, node);
+    util.applyStyle(shapeSvg, node.style);
+
+    var shapeBBox = shapeSvg.node().getBBox();
+    node.width = shapeBBox.width;
+    node.height = shapeBBox.height;
+  });
+
+  util.applyTransition(svgNodes.exit(), g)
+    .style("opacity", 0)
+    .remove();
+
+  return svgNodes;
+}
diff --git a/debian/missing-source/dagre-d3/lib/d3.js b/debian/missing-source/dagre-d3/lib/d3.js
new file mode 100644
index 0000000..c1a46ac
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/d3.js
@@ -0,0 +1,2 @@
+// Stub to get D3 either via NPM or from the global object
+module.exports = window.d3;
diff --git a/debian/missing-source/dagre-d3/lib/dagre.js b/debian/missing-source/dagre-d3/lib/dagre.js
new file mode 100644
index 0000000..82267e2
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/dagre.js
@@ -0,0 +1,15 @@
+/* global window */
+
+var dagre;
+
+if (require) {
+  try {
+    dagre = require("dagre");
+  } catch (e) {}
+}
+
+if (!dagre) {
+  dagre = window.dagre;
+}
+
+module.exports = dagre;
diff --git a/debian/missing-source/dagre-d3/lib/graphlib.js b/debian/missing-source/dagre-d3/lib/graphlib.js
new file mode 100644
index 0000000..df2a45a
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/graphlib.js
@@ -0,0 +1,15 @@
+/* global window */
+
+var graphlib;
+
+if (require) {
+  try {
+    graphlib = require("graphlib");
+  } catch (e) {}
+}
+
+if (!graphlib) {
+  graphlib = window.graphlib;
+}
+
+module.exports = graphlib;
diff --git a/debian/missing-source/dagre-d3/lib/intersect/index.js b/debian/missing-source/dagre-d3/lib/intersect/index.js
new file mode 100644
index 0000000..16c1638
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/intersect/index.js
@@ -0,0 +1,7 @@
+module.exports = {
+  node: require("./intersect-node"),
+  circle: require("./intersect-circle"),
+  ellipse: require("./intersect-ellipse"),
+  polygon: require("./intersect-polygon"),
+  rect: require("./intersect-rect")
+};
diff --git a/debian/missing-source/dagre-d3/lib/intersect/intersect-circle.js b/debian/missing-source/dagre-d3/lib/intersect/intersect-circle.js
new file mode 100644
index 0000000..051e441
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/intersect/intersect-circle.js
@@ -0,0 +1,7 @@
+var intersectEllipse = require("./intersect-ellipse");
+
+module.exports = intersectCircle;
+
+function intersectCircle(node, rx, point) {
+  return intersectEllipse(node, rx, rx, point);
+}
diff --git a/debian/missing-source/dagre-d3/lib/intersect/intersect-ellipse.js b/debian/missing-source/dagre-d3/lib/intersect/intersect-ellipse.js
new file mode 100644
index 0000000..f439c85
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/intersect/intersect-ellipse.js
@@ -0,0 +1,25 @@
+module.exports = intersectEllipse;
+
+function intersectEllipse(node, rx, ry, point) {
+  // Formulae from: http://mathworld.wolfram.com/Ellipse-LineIntersection.html
+
+  var cx = node.x;
+  var cy = node.y;
+
+  var px = cx - point.x;
+  var py = cy - point.y;
+
+  var det = Math.sqrt(rx * rx * py * py + ry * ry * px * px);
+
+  var dx = Math.abs(rx * ry * px / det);
+  if (point.x < cx) {
+    dx = -dx;
+  }
+  var dy = Math.abs(rx * ry * py / det);
+  if (point.y < cy) {
+    dy = -dy;
+  }
+
+  return {x: cx + dx, y: cy + dy};
+}
+
diff --git a/debian/missing-source/dagre-d3/lib/intersect/intersect-line.js b/debian/missing-source/dagre-d3/lib/intersect/intersect-line.js
new file mode 100644
index 0000000..dff1e2f
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/intersect/intersect-line.js
@@ -0,0 +1,70 @@
+module.exports = intersectLine;
+
+/*
+ * Returns the point at which two lines, p and q, intersect or returns
+ * undefined if they do not intersect.
+ */
+function intersectLine(p1, p2, q1, q2) {
+  // Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
+  // p7 and p473.
+
+  var a1, a2, b1, b2, c1, c2;
+  var r1, r2 , r3, r4;
+  var denom, offset, num;
+  var x, y;
+
+  // Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
+  // b1 y + c1 = 0.
+  a1 = p2.y - p1.y;
+  b1 = p1.x - p2.x;
+  c1 = (p2.x * p1.y) - (p1.x * p2.y);
+
+  // Compute r3 and r4.
+  r3 = ((a1 * q1.x) + (b1 * q1.y) + c1);
+  r4 = ((a1 * q2.x) + (b1 * q2.y) + c1);
+
+  // Check signs of r3 and r4. If both point 3 and point 4 lie on
+  // same side of line 1, the line segments do not intersect.
+  if ((r3 !== 0) && (r4 !== 0) && sameSign(r3, r4)) {
+    return /*DONT_INTERSECT*/;
+  }
+
+  // Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
+  a2 = q2.y - q1.y;
+  b2 = q1.x - q2.x;
+  c2 = (q2.x * q1.y) - (q1.x * q2.y);
+
+  // Compute r1 and r2
+  r1 = (a2 * p1.x) + (b2 * p1.y) + c2;
+  r2 = (a2 * p2.x) + (b2 * p2.y) + c2;
+
+  // Check signs of r1 and r2. If both point 1 and point 2 lie
+  // on same side of second line segment, the line segments do
+  // not intersect.
+  if ((r1 !== 0) && (r2 !== 0) && (sameSign(r1, r2))) {
+    return /*DONT_INTERSECT*/;
+  }
+
+  // Line segments intersect: compute intersection point.
+  denom = (a1 * b2) - (a2 * b1);
+  if (denom === 0) {
+    return /*COLLINEAR*/;
+  }
+
+  offset = Math.abs(denom / 2);
+
+  // The denom/2 is to get rounding instead of truncating. It
+  // is added or subtracted to the numerator, depending upon the
+  // sign of the numerator.
+  num = (b1 * c2) - (b2 * c1);
+  x = (num < 0) ? ((num - offset) / denom) : ((num + offset) / denom);
+
+  num = (a2 * c1) - (a1 * c2);
+  y = (num < 0) ? ((num - offset) / denom) : ((num + offset) / denom);
+
+  return { x: x, y: y };
+}
+
+function sameSign(r1, r2) {
+  return r1 * r2 > 0;
+}
diff --git a/debian/missing-source/dagre-d3/lib/intersect/intersect-node.js b/debian/missing-source/dagre-d3/lib/intersect/intersect-node.js
new file mode 100644
index 0000000..6e45299
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/intersect/intersect-node.js
@@ -0,0 +1,5 @@
+module.exports = intersectNode;
+
+function intersectNode(node, point) {
+  return node.intersect(point);
+}
diff --git a/debian/missing-source/dagre-d3/lib/intersect/intersect-polygon.js b/debian/missing-source/dagre-d3/lib/intersect/intersect-polygon.js
new file mode 100644
index 0000000..9206ecb
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/intersect/intersect-polygon.js
@@ -0,0 +1,55 @@
+var intersectLine = require("./intersect-line");
+
+module.exports = intersectPolygon;
+
+/*
+ * Returns the point ({x, y}) at which the point argument intersects with the
+ * node argument assuming that it has the shape specified by polygon.
+ */
+function intersectPolygon(node, polyPoints, point) {
+  var x1 = node.x;
+  var y1 = node.y;
+
+  var intersections = [];
+
+  var minX = Number.POSITIVE_INFINITY,
+      minY = Number.POSITIVE_INFINITY;
+  polyPoints.forEach(function(entry) {
+    minX = Math.min(minX, entry.x);
+    minY = Math.min(minY, entry.y);
+  });
+
+  var left = x1 - node.width / 2 - minX;
+  var top =  y1 - node.height / 2 - minY;
+
+  for (var i = 0; i < polyPoints.length; i++) {
+    var p1 = polyPoints[i];
+    var p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
+    var intersect = intersectLine(node, point,
+      {x: left + p1.x, y: top + p1.y}, {x: left + p2.x, y: top + p2.y});
+    if (intersect) {
+      intersections.push(intersect);
+    }
+  }
+
+  if (!intersections.length) {
+    console.log("NO INTERSECTION FOUND, RETURN NODE CENTER", node);
+    return node;
+  }
+
+  if (intersections.length > 1) {
+    // More intersections, find the one nearest to edge end point
+    intersections.sort(function(p, q) {
+      var pdx = p.x - point.x,
+          pdy = p.y - point.y,
+          distp = Math.sqrt(pdx * pdx + pdy * pdy),
+
+          qdx = q.x - point.x,
+          qdy = q.y - point.y,
+          distq = Math.sqrt(qdx * qdx + qdy * qdy);
+
+      return (distp < distq) ? -1 : (distp === distq ? 0 : 1);
+    });
+  }
+  return intersections[0];
+}
diff --git a/debian/missing-source/dagre-d3/lib/intersect/intersect-rect.js b/debian/missing-source/dagre-d3/lib/intersect/intersect-rect.js
new file mode 100644
index 0000000..663b80a
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/intersect/intersect-rect.js
@@ -0,0 +1,32 @@
+module.exports = intersectRect;
+
+function intersectRect(node, point) {
+  var x = node.x;
+  var y = node.y;
+
+  // Rectangle intersection algorithm from:
+  // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
+  var dx = point.x - x;
+  var dy = point.y - y;
+  var w = node.width / 2;
+  var h = node.height / 2;
+
+  var sx, sy;
+  if (Math.abs(dy) * w > Math.abs(dx) * h) {
+    // Intersection is top or bottom of rect.
+    if (dy < 0) {
+      h = -h;
+    }
+    sx = dy === 0 ? 0 : h * dx / dy;
+    sy = h;
+  } else {
+    // Intersection is left or right of rect.
+    if (dx < 0) {
+      w = -w;
+    }
+    sx = w;
+    sy = dx === 0 ? 0 : w * dy / dx;
+  }
+
+  return {x: x + sx, y: y + sy};
+}
diff --git a/debian/missing-source/dagre-d3/lib/label/add-html-label.js b/debian/missing-source/dagre-d3/lib/label/add-html-label.js
new file mode 100644
index 0000000..f62999a
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/label/add-html-label.js
@@ -0,0 +1,37 @@
+var util = require("../util");
+
+module.exports = addHtmlLabel;
+
+function addHtmlLabel(root, node) {
+  var fo = root
+    .append("foreignObject")
+      .attr("width", "100000");
+
+  var div = fo
+    .append("xhtml:div");
+  div.attr("xmlns", "http://www.w3.org/1999/xhtml");
+
+  var label = node.label;
+  switch(typeof label) {
+    case "function":
+      div.insert(label);
+      break;
+    case "object":
+      // Currently we assume this is a DOM object.
+      div.insert(function() { return label; });
+      break;
+    default: div.html(label);
+  }
+
+  util.applyStyle(div, node.labelStyle);
+  div.style("display", "inline-block");
+  // Fix for firefox
+  div.style("white-space", "nowrap");
+
+  var client = div[0][0].getBoundingClientRect();
+  fo
+    .attr("width", client.width)
+    .attr("height", client.height); 
+
+  return fo;
+}
diff --git a/debian/missing-source/dagre-d3/lib/label/add-label.js b/debian/missing-source/dagre-d3/lib/label/add-label.js
new file mode 100644
index 0000000..6446762
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/label/add-label.js
@@ -0,0 +1,37 @@
+var addTextLabel = require("./add-text-label"),
+    addHtmlLabel = require("./add-html-label"),
+    addSVGLabel  = require("./add-svg-label");
+
+module.exports = addLabel;
+
+function addLabel(root, node, location) {
+  var label = node.label;
+  var labelSvg = root.append("g");
+
+  // Allow the label to be a string, a function that returns a DOM element, or
+  // a DOM element itself.
+  if (node.labelType === "svg") {
+    addSVGLabel(labelSvg, node);
+  } else if (typeof label !== "string" || node.labelType === "html") {
+    addHtmlLabel(labelSvg, node);
+  } else {
+    addTextLabel(labelSvg, node);
+  }
+
+  var labelBBox = labelSvg.node().getBBox();
+  var y;
+  switch(location) {
+    case "top":
+      y = (-node.height / 2);
+      break;
+    case "bottom":
+      y = (node.height / 2) - labelBBox.height;
+      break;
+    default:
+      y = (-labelBBox.height / 2);
+  }
+  labelSvg.attr("transform",
+                "translate(" + (-labelBBox.width / 2) + "," + y + ")");
+
+  return labelSvg;
+}
diff --git a/debian/missing-source/dagre-d3/lib/label/add-svg-label.js b/debian/missing-source/dagre-d3/lib/label/add-svg-label.js
new file mode 100644
index 0000000..b1ab07f
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/label/add-svg-label.js
@@ -0,0 +1,13 @@
+var util = require("../util");
+
+module.exports = addSVGLabel;
+
+function addSVGLabel(root, node) {
+  var domNode = root;
+
+  domNode.node().appendChild(node.label);
+
+  util.applyStyle(domNode, node.labelStyle);
+
+  return domNode;
+}
diff --git a/debian/missing-source/dagre-d3/lib/label/add-text-label.js b/debian/missing-source/dagre-d3/lib/label/add-text-label.js
new file mode 100644
index 0000000..d6a8e5f
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/label/add-text-label.js
@@ -0,0 +1,45 @@
+var util = require("../util");
+
+module.exports = addTextLabel;
+
+/*
+ * Attaches a text label to the specified root. Handles escape sequences.
+ */
+function addTextLabel(root, node) {
+  var domNode = root.append("text");
+
+  var lines = processEscapeSequences(node.label).split("\n");
+  for (var i = 0; i < lines.length; i++) {
+    domNode
+      .append("tspan")
+        .attr("xml:space", "preserve")
+        .attr("dy", "1em")
+        .attr("x", "1")
+        .text(lines[i]);
+  }
+
+  util.applyStyle(domNode, node.labelStyle);
+
+  return domNode;
+}
+
+function processEscapeSequences(text) {
+  var newText = "",
+      escaped = false,
+      ch;
+  for (var i = 0; i < text.length; ++i) {
+    ch = text[i];
+    if (escaped) {
+      switch(ch) {
+        case "n": newText += "\n"; break;
+        default: newText += ch;
+      }
+      escaped = false;
+    } else if (ch === "\\") {
+      escaped = true;
+    } else {
+      newText += ch;
+    }
+  }
+  return newText;
+}
diff --git a/debian/missing-source/dagre-d3/lib/lodash.js b/debian/missing-source/dagre-d3/lib/lodash.js
new file mode 100644
index 0000000..915596b
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/lodash.js
@@ -0,0 +1,15 @@
+/* global window */
+
+var lodash;
+
+if (require) {
+  try {
+    lodash = require("lodash");
+  } catch (e) {}
+}
+
+if (!lodash) {
+  lodash = window._;
+}
+
+module.exports = lodash;
diff --git a/debian/missing-source/dagre-d3/lib/position-clusters.js b/debian/missing-source/dagre-d3/lib/position-clusters.js
new file mode 100644
index 0000000..21d4405
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/position-clusters.js
@@ -0,0 +1,34 @@
+"use strict";
+
+var util = require("./util"),
+    d3 = require("./d3");
+
+module.exports = positionClusters;
+
+function positionClusters(selection, g) {
+  var created = selection.filter(function() { return !d3.select(this).classed("update"); });
+
+  function translate(v) {
+    var node = g.node(v);
+    return "translate(" + node.x + "," + node.y + ")";
+  }
+
+  created.attr("transform", translate);
+
+  util.applyTransition(selection, g)
+      .style("opacity", 1)
+      .attr("transform", translate);
+
+  util.applyTransition(created.selectAll("rect"), g)
+      .attr("width", function(v) { return g.node(v).width; })
+      .attr("height", function(v) { return g.node(v).height; })
+      .attr("x", function(v) {
+        var node = g.node(v);
+        return -node.width / 2;
+      })
+      .attr("y", function(v) {
+        var node = g.node(v);
+        return -node.height / 2;
+      });
+
+}
diff --git a/debian/missing-source/dagre-d3/lib/position-edge-labels.js b/debian/missing-source/dagre-d3/lib/position-edge-labels.js
new file mode 100644
index 0000000..6dafb54
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/position-edge-labels.js
@@ -0,0 +1,22 @@
+"use strict";
+
+var util = require("./util"),
+    d3 = require("./d3"),
+    _ = require("./lodash");
+
+module.exports = positionEdgeLabels;
+
+function positionEdgeLabels(selection, g) {
+  var created = selection.filter(function() { return !d3.select(this).classed("update"); });
+
+  function translate(e) {
+    var edge = g.edge(e);
+    return _.has(edge, "x") ? "translate(" + edge.x + "," + edge.y + ")" : "";
+  }
+
+  created.attr("transform", translate);
+
+  util.applyTransition(selection, g)
+    .style("opacity", 1)
+    .attr("transform", translate);
+}
diff --git a/debian/missing-source/dagre-d3/lib/position-nodes.js b/debian/missing-source/dagre-d3/lib/position-nodes.js
new file mode 100644
index 0000000..cd3c349
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/position-nodes.js
@@ -0,0 +1,21 @@
+"use strict";
+
+var util = require("./util"),
+    d3 = require("./d3");
+
+module.exports = positionNodes;
+
+function positionNodes(selection, g) {
+  var created = selection.filter(function() { return !d3.select(this).classed("update"); });
+
+  function translate(v) {
+    var node = g.node(v);
+    return "translate(" + node.x + "," + node.y + ")";
+  }
+
+  created.attr("transform", translate);
+
+  util.applyTransition(selection, g)
+    .style("opacity", 1)
+    .attr("transform", translate);
+}
diff --git a/debian/missing-source/dagre-d3/lib/render.js b/debian/missing-source/dagre-d3/lib/render.js
new file mode 100644
index 0000000..eb7276a
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/render.js
@@ -0,0 +1,167 @@
+var _ = require("./lodash"),
+    layout = require("./dagre").layout;
+
+module.exports = render;
+
+// This design is based on http://bost.ocks.org/mike/chart/.
+function render() {
+  var createNodes = require("./create-nodes"),
+      createClusters = require("./create-clusters"),
+      createEdgeLabels = require("./create-edge-labels"),
+      createEdgePaths = require("./create-edge-paths"),
+      positionNodes = require("./position-nodes"),
+      positionEdgeLabels = require("./position-edge-labels"),
+      positionClusters = require("./position-clusters"),
+      shapes = require("./shapes"),
+      arrows = require("./arrows");
+
+  var fn = function(svg, g) {
+    preProcessGraph(g);
+
+    var outputGroup = createOrSelectGroup(svg, "output"),
+        clustersGroup = createOrSelectGroup(outputGroup, "clusters"),
+        edgePathsGroup = createOrSelectGroup(outputGroup, "edgePaths"),
+        edgeLabels = createEdgeLabels(createOrSelectGroup(outputGroup, "edgeLabels"), g),
+        nodes = createNodes(createOrSelectGroup(outputGroup, "nodes"), g, shapes);
+
+    layout(g);
+
+    positionNodes(nodes, g);
+    positionEdgeLabels(edgeLabels, g);
+    createEdgePaths(edgePathsGroup, g, arrows);
+
+    var clusters = createClusters(clustersGroup, g);
+    positionClusters(clusters, g);
+
+    postProcessGraph(g);
+  };
+
+  fn.createNodes = function(value) {
+    if (!arguments.length) return createNodes;
+    createNodes = value;
+    return fn;
+  };
+
+  fn.createClusters = function(value) {
+    if (!arguments.length) return createClusters;
+    createClusters = value;
+    return fn;
+  };
+
+  fn.createEdgeLabels = function(value) {
+    if (!arguments.length) return createEdgeLabels;
+    createEdgeLabels = value;
+    return fn;
+  };
+
+  fn.createEdgePaths = function(value) {
+    if (!arguments.length) return createEdgePaths;
+    createEdgePaths = value;
+    return fn;
+  };
+
+  fn.shapes = function(value) {
+    if (!arguments.length) return shapes;
+    shapes = value;
+    return fn;
+  };
+
+  fn.arrows = function(value) {
+    if (!arguments.length) return arrows;
+    arrows = value;
+    return fn;
+  };
+
+  return fn;
+}
+
+var NODE_DEFAULT_ATTRS = {
+  paddingLeft: 10,
+  paddingRight: 10,
+  paddingTop: 10,
+  paddingBottom: 10,
+  rx: 0,
+  ry: 0,
+  shape: "rect"
+};
+
+var EDGE_DEFAULT_ATTRS = {
+  arrowhead: "normal",
+  lineInterpolate: "linear"
+};
+
+function preProcessGraph(g) {
+  g.nodes().forEach(function(v) {
+    var node = g.node(v);
+    if (!_.has(node, "label") && !g.children(v).length) { node.label = v; }
+
+    if (_.has(node, "paddingX")) {
+      _.defaults(node, {
+        paddingLeft: node.paddingX,
+        paddingRight: node.paddingX
+      });
+    }
+
+    if (_.has(node, "paddingY")) {
+      _.defaults(node, {
+        paddingTop: node.paddingY,
+        paddingBottom: node.paddingY
+      });
+    }
+
+    if (_.has(node, "padding")) {
+      _.defaults(node, {
+        paddingLeft: node.padding,
+        paddingRight: node.padding,
+        paddingTop: node.padding,
+        paddingBottom: node.padding
+      });
+    }
+
+    _.defaults(node, NODE_DEFAULT_ATTRS);
+
+    _.each(["paddingLeft", "paddingRight", "paddingTop", "paddingBottom"], function(k) {
+      node[k] = Number(node[k]);
+    });
+
+    // Save dimensions for restore during post-processing
+    if (_.has(node, "width")) { node._prevWidth = node.width; }
+    if (_.has(node, "height")) { node._prevHeight = node.height; }
+  });
+
+  g.edges().forEach(function(e) {
+    var edge = g.edge(e);
+    if (!_.has(edge, "label")) { edge.label = ""; }
+    _.defaults(edge, EDGE_DEFAULT_ATTRS);
+  });
+}
+
+function postProcessGraph(g) {
+  _.each(g.nodes(), function(v) {
+    var node = g.node(v);
+
+    // Restore original dimensions
+    if (_.has(node, "_prevWidth")) {
+      node.width = node._prevWidth;
+    } else {
+      delete node.width;
+    }
+
+    if (_.has(node, "_prevHeight")) {
+      node.height = node._prevHeight;
+    } else {
+      delete node.height;
+    }
+
+    delete node._prevWidth;
+    delete node._prevHeight;
+  });
+}
+
+function createOrSelectGroup(root, name) {
+  var selection = root.select("g." + name);
+  if (selection.empty()) {
+    selection = root.append("g").attr("class", name);
+  }
+  return selection;
+}
diff --git a/debian/missing-source/dagre-d3/lib/shapes.js b/debian/missing-source/dagre-d3/lib/shapes.js
new file mode 100644
index 0000000..556c4e0
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/shapes.js
@@ -0,0 +1,81 @@
+"use strict";
+
+var intersectRect = require("./intersect/intersect-rect"),
+    intersectEllipse = require("./intersect/intersect-ellipse"),
+    intersectCircle = require("./intersect/intersect-circle"),
+    intersectPolygon = require("./intersect/intersect-polygon");
+
+module.exports = {
+  rect: rect,
+  ellipse: ellipse,
+  circle: circle,
+  diamond: diamond
+};
+
+function rect(parent, bbox, node) {
+  var shapeSvg = parent.insert("rect", ":first-child")
+        .attr("rx", node.rx)
+        .attr("ry", node.ry)
+        .attr("x", -bbox.width / 2)
+        .attr("y", -bbox.height / 2)
+        .attr("width", bbox.width)
+        .attr("height", bbox.height);
+
+  node.intersect = function(point) {
+    return intersectRect(node, point);
+  };
+
+  return shapeSvg;
+}
+
+function ellipse(parent, bbox, node) {
+  var rx = bbox.width / 2,
+      ry = bbox.height / 2,
+      shapeSvg = parent.insert("ellipse", ":first-child")
+        .attr("x", -bbox.width / 2)
+        .attr("y", -bbox.height / 2)
+        .attr("rx", rx)
+        .attr("ry", ry);
+
+  node.intersect = function(point) {
+    return intersectEllipse(node, rx, ry, point);
+  };
+
+  return shapeSvg;
+}
+
+function circle(parent, bbox, node) {
+  var r = Math.max(bbox.width, bbox.height) / 2,
+      shapeSvg = parent.insert("circle", ":first-child")
+        .attr("x", -bbox.width / 2)
+        .attr("y", -bbox.height / 2)
+        .attr("r", r);
+
+  node.intersect = function(point) {
+    return intersectCircle(node, r, point);
+  };
+
+  return shapeSvg;
+}
+
+// Circumscribe an ellipse for the bounding box with a diamond shape. I derived
+// the function to calculate the diamond shape from:
+// http://mathforum.org/kb/message.jspa?messageID=3750236
+function diamond(parent, bbox, node) {
+  var w = (bbox.width * Math.SQRT2) / 2,
+      h = (bbox.height * Math.SQRT2) / 2,
+      points = [
+        { x:  0, y: -h },
+        { x: -w, y:  0 },
+        { x:  0, y:  h },
+        { x:  w, y:  0 }
+      ],
+      shapeSvg = parent.insert("polygon", ":first-child")
+        .attr("points", points.map(function(p) { return p.x + "," + p.y; }).join(" "));
+
+  node.intersect = function(p) {
+    return intersectPolygon(node, points, p);
+  };
+
+  return shapeSvg;
+}
diff --git a/debian/missing-source/dagre-d3/lib/util.js b/debian/missing-source/dagre-d3/lib/util.js
new file mode 100644
index 0000000..a178e89
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/util.js
@@ -0,0 +1,54 @@
+var _ = require("./lodash");
+
+// Public utility functions
+module.exports = {
+  isSubgraph: isSubgraph,
+  edgeToId: edgeToId,
+  applyStyle: applyStyle,
+  applyClass: applyClass,
+  applyTransition: applyTransition
+};
+
+/*
+ * Returns true if the specified node in the graph is a subgraph node. A
+ * subgraph node is one that contains other nodes.
+ */
+function isSubgraph(g, v) {
+  return !!g.children(v).length;
+}
+
+function edgeToId(e) {
+  return escapeId(e.v) + ":" + escapeId(e.w) + ":" + escapeId(e.name);
+}
+
+var ID_DELIM = /:/g;
+function escapeId(str) {
+  return str ? String(str).replace(ID_DELIM, "\\:") : "";
+}
+
+function applyStyle(dom, styleFn) {
+  if (styleFn) {
+    dom.attr("style", styleFn);
+  }
+}
+
+function applyClass(dom, classFn, otherClasses) {
+  if (classFn) {
+    dom
+      .attr("class", classFn)
+      .attr("class", otherClasses + " " + dom.attr("class"));
+  }
+}
+
+function applyTransition(selection, g) {
+  var graph = g.graph();
+
+  if (_.isPlainObject(graph)) {
+    var transition = graph.transition;
+    if (_.isFunction(transition)) {
+      return transition(selection);
+    }
+  }
+
+  return selection;
+}
diff --git a/debian/missing-source/dagre-d3/lib/version.js b/debian/missing-source/dagre-d3/lib/version.js
new file mode 100644
index 0000000..64d9492
--- /dev/null
+++ b/debian/missing-source/dagre-d3/lib/version.js
@@ -0,0 +1 @@
+module.exports = "0.4.17";
diff --git a/debian/missing-source/dagre-d3/package.json b/debian/missing-source/dagre-d3/package.json
new file mode 100644
index 0000000..8ec3545
--- /dev/null
+++ b/debian/missing-source/dagre-d3/package.json
@@ -0,0 +1,57 @@
+{
+  "name": "dagre-d3",
+  "version": "0.4.17",
+  "description": "A D3-based renderer for Dagre",
+  "author": "Chris Pettitt <chris at samsarin.com>",
+  "keywords": [
+    "graph",
+    "dagre",
+    "graphlib",
+    "renderer"
+  ],
+  "dependencies": {
+    "d3": "^3.3.8",
+    "dagre": "^0.7.3",
+    "graphlib": "^1.0.5",
+    "lodash": "^3.10.0"
+  },
+  "devDependencies": {
+    "browser-sync": "^2.7.1",
+    "browserify": "^10.2.0",
+    "chai": "^1.9.2",
+    "del": "^1.1.1",
+    "gulp": "^3.8.11",
+    "gulp-changed": "^1.2.1",
+    "gulp-jshint": "^1.10.0",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.3",
+    "gulp-shell": "^0.4.1",
+    "gulp-sourcemaps": "^1.5.2",
+    "gulp-uglify": "^1.2.0",
+    "gulp-util": "^3.0.4",
+    "gulp-watch": "^4.2.4",
+    "jshint": "^2.5.6",
+    "jshint-stylish": "^1.0.2",
+    "karma": "^0.12.37",
+    "karma-chrome-launcher": "^0.2.0",
+    "karma-coverage": "^0.4.2",
+    "karma-firefox-launcher": "^0.1.6",
+    "karma-mocha": "^0.2.0",
+    "karma-phantomjs-launcher": "^0.2.0",
+    "karma-safari-launcher": "^0.1.1",
+    "merge-stream": "^0.1.7",
+    "mocha": "^1.21.5",
+    "phantomjs": "^1.9.12",
+    "pretty-hrtime": "^1.0.0",
+    "semver": "^4.1.0",
+    "uglify-js": "^2.4.15",
+    "vinyl-buffer": "^1.0.0",
+    "vinyl-source-stream": "^1.1.0",
+    "watchify": "^3.2.1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/cpettitt/dagre-d3.git"
+  },
+  "license": "MIT"
+}
diff --git a/debian/missing-source/dagre-d3/src/bower.json.tmpl b/debian/missing-source/dagre-d3/src/bower.json.tmpl
new file mode 100644
index 0000000..a758057
--- /dev/null
+++ b/debian/missing-source/dagre-d3/src/bower.json.tmpl
@@ -0,0 +1,26 @@
+{
+  "name": "${pkg.name}",
+  "version": "${pkg.version}",
+  "main": [
+    "dist/${pkg.name}.core.js"
+  ],
+  "ignore": [
+    ".*",
+    "README.md",
+    "CHANGELOG.md",
+    "Makefile",
+    "browser.js",
+    "build/**",
+    "dist/${pkg.name}.js",
+    "dist/${pkg.name}.min.js",
+    "dist/${pkg.name}.min.js.map",
+    "dist/demo/**",
+    "index.js",
+    "karma*",
+    "lib/**",
+    "package.json",
+    "src/**",
+    "test/**"
+  ],
+  "dependencies": ${ JSON.stringify(pkg.dependencies, null, 2) }
+}
diff --git a/debian/missing-source/dagre-d3/src/release/bump-version.js b/debian/missing-source/dagre-d3/src/release/bump-version.js
new file mode 100755
index 0000000..fe5ed24
--- /dev/null
+++ b/debian/missing-source/dagre-d3/src/release/bump-version.js
@@ -0,0 +1,24 @@
+/*
+ * Bumps the minor version and sets the prelease tag.
+ */
+
+var fs = require("fs"),
+    semver = require("semver");
+
+var packageFile = fs.readFileSync("package.json");
+var packageJson = JSON.parse(packageFile);
+
+if (!("version" in packageJson)) {
+  bail("ERROR: Could not find version in package.json");
+}
+
+var ver = semver.parse(packageJson.version);
+packageJson.version = ver.inc("patch").toString() + "-pre";
+
+fs.writeFileSync("package.json", JSON.stringify(packageJson, undefined, 2));
+
+// Write an error message to stderr and then exit immediately with an error.
+function bail(msg) {
+  stderr.write(msg + "\n");
+  process.exit(1);
+}
diff --git a/debian/missing-source/dagre-d3/src/release/check-version.js b/debian/missing-source/dagre-d3/src/release/check-version.js
new file mode 100755
index 0000000..4e5c702
--- /dev/null
+++ b/debian/missing-source/dagre-d3/src/release/check-version.js
@@ -0,0 +1,29 @@
+/*
+ * Prints the current version from the specified package-file to stdout or
+ * fails with an error if either the version cannot be determined or it is
+ * a pre-release.
+ */
+
+var fs = require("fs"),
+    semver = require("semver");
+
+var packageFile = fs.readFileSync("package.json");
+var packageJson = JSON.parse(packageFile);
+
+if (!("version" in packageJson)) {
+  bail("ERROR: Could not find version in package.json");
+}
+
+var ver = semver.parse(packageJson.version);
+
+if (ver.prerelease.length > 0) {
+  bail("ERROR: version is a pre-release: " + ver);
+}
+
+console.log(ver.toString());
+
+// Write an error message to stderr and then exit immediately with an error.
+function bail(msg) {
+  process.stderr.write(msg + "\n");
+  process.exit(1);
+}
diff --git a/debian/missing-source/dagre-d3/src/release/release.sh b/debian/missing-source/dagre-d3/src/release/release.sh
new file mode 100755
index 0000000..074e632
--- /dev/null
+++ b/debian/missing-source/dagre-d3/src/release/release.sh
@@ -0,0 +1,66 @@
+# Fail on error
+set -e
+[ -n "$DEBUG"] && set -x
+
+bail() {
+    echo $1 >&2
+    exit 1
+}
+
+# Initial config
+PROJECT=dagre-d3
+PROJECT_ROOT=`pwd`
+DOC_DIR=/tmp/dagre-d3-doc
+DIST_DIR=dist
+
+# Check version. Is this a release? If not abort
+VERSION=$(node src/release/check-version.js)
+
+echo Attemping to publish version: $VERSION
+
+# Preflight checks
+[ -z "`git tag -l v$VERSION`"] || bail "Version already published. Skipping publish."
+[ "`git rev-parse HEAD`" = "`git rev-parse master`" ] || bail "ERROR: You must release from the master branch"
+[ -z "`git status --porcelain`" ] || bail "ERROR: Dirty index on working tree. Use git status to check"
+
+# Pull remote repos
+rm -rf $DOC_DIR
+git clone git at github.com:cpettitt/cpettitt.github.com.git $DOC_DIR
+
+# Publish docs
+echo Preparing to publish docs
+cd $DOC_DIR
+mkdir -p project/$PROJECT
+TARGET=project/$PROJECT/latest
+git rm -r $TARGET || true
+cp -r $PROJECT_ROOT/$DIST_DIR $TARGET
+git add $TARGET
+
+TARGET=project/$PROJECT/v$VERSION
+cp -r $PROJECT_ROOT/$DIST_DIR $TARGET
+git add $TARGET
+
+git commit -m "Publish docs for $PROJECT v$VERSION"
+git push origin
+
+cd $PROJECT_ROOT
+echo Done with docs
+
+# Publish tag
+git tag v$VERSION
+git push origin
+git push origin v$VERSION
+echo Published dagre-d3 v$VERSION
+
+# Publish to npm
+npm publish
+echo Published to npm
+
+# Update patch level version + commit
+node src/release/bump-version.js
+make lib/version.js
+git commit package.json lib/version.js -m "Bump version and set as pre-release"
+git push origin
+echo Updated patch version
+
+echo Release complete!
diff --git a/debian/missing-source/dagre-d3/src/version.js.tmpl b/debian/missing-source/dagre-d3/src/version.js.tmpl
new file mode 100644
index 0000000..9677daf
--- /dev/null
+++ b/debian/missing-source/dagre-d3/src/version.js.tmpl
@@ -0,0 +1 @@
+module.exports = "${pkg.version}";
diff --git a/debian/missing-source/dagre-d3/test/bundle-test.css b/debian/missing-source/dagre-d3/test/bundle-test.css
new file mode 100644
index 0000000..8319704
--- /dev/null
+++ b/debian/missing-source/dagre-d3/test/bundle-test.css
@@ -0,0 +1,29 @@
+svg {
+  border: 1px solid #999;
+  overflow: hidden;
+}
+
+.node {
+  white-space: nowrap;
+}
+
+.node rect,
+.node circle,
+.node ellipse {
+  stroke: #333;
+  fill: #fff;
+  stroke-width: 1.5px;
+}
+
+.cluster rect {
+  stroke: #333;
+  fill: #000;
+  fill-opacity: 0.1;
+  stroke-width: 1.5px;
+}
+
+.edgePath path.path {
+  stroke: #333;
+  stroke-width: 1.5px;
+  fill: none;
+}
diff --git a/debian/missing-source/dagre-d3/test/bundle-test.js b/debian/missing-source/dagre-d3/test/bundle-test.js
new file mode 100644
index 0000000..38c80dc
--- /dev/null
+++ b/debian/missing-source/dagre-d3/test/bundle-test.js
@@ -0,0 +1,325 @@
+var expect = chai.expect;
+
+d3.select("body").append("link")
+  .attr("rel", "stylesheet")
+  .attr("href", "/base/test/bundle-test.css");
+
+describe("dagreD3", function() {
+  var svg,
+      g;
+
+  beforeEach(function() {
+    svg = d3.select("body").append("svg");
+    g = new dagreD3.graphlib.Graph()
+      .setGraph({})
+      .setDefaultNodeLabel(function() { return {}; })
+      .setDefaultEdgeLabel(function() { return {}; });
+  });
+
+  afterEach(function() {
+    svg.remove();
+  });
+
+  describe("exports", function() {
+    _.each(["graphlib", "dagre", "intersect", "util"], function(lib) {
+      it(lib, function() {
+        expect(dagreD3[lib]).to.be.an("object");
+      });
+    });
+
+    it("render", function() {
+      expect(dagreD3.render).to.be.a("function");
+    });
+
+    it("version", function() {
+      expect(dagreD3.version).to.be.a("string");
+    });
+  });
+
+  describe("DOM elements", function() {
+    it("are created for each node", function() {
+      g.setNode("a", { id: "a" });
+      g.setNode("b", { id: "b" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a").datum()).to.equal("a");
+      expect(d3.select("#b").datum()).to.equal("b");
+
+      // We should also be able to get to the element from the node object.
+      expect(g.node("a").elem).to.equal(d3.select("#a").node());
+      expect(g.node("b").elem).to.equal(d3.select("#b").node());
+    });
+
+    it("are created for each node label", function() {
+      g.setNode("a", { labelId: "a-lab" });
+      g.setNode("b", { labelId: "b-lab" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a-lab").datum()).to.equal("a");
+      expect(d3.select("#b-lab").datum()).to.equal("b");
+    });
+
+    it("are created for each edge", function() {
+      g.setNode("a", {});
+      g.setNode("b", {});
+      g.setEdge("a", "b", { id: "ab" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#ab").datum()).eqls({ v: "a", w: "b" });
+
+      // We should also be able to get to the element from the edge object.
+      expect(g.edge("a", "b").elem).to.equal(d3.select("#ab").node());
+    });
+
+    it("preserve link to the elem even after re-rendering", function() {
+      g.setNode("a", {});
+      g.setNode("b", {});
+      g.setEdge("a", "b", { id: "ab" });
+      dagreD3.render()(svg, g);
+
+      // Remove elem from edge object and re-render
+      g.setEdge("a", "b", { id: "ab" });
+      dagreD3.render()(svg, g);
+
+      expect(g.edge("a", "b").elem).to.equal(d3.select("#ab").node());
+    });
+
+    it("are created for each edge label", function() {
+      g.setNode("a", {});
+      g.setNode("b", {});
+      g.setEdge("a", "b", { labelId: "ab-lab" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#ab-lab").datum()).eqls({ v: "a", w: "b" });
+    });
+  });
+
+  it("uses node's width and height if specified", function() {
+    g.setNode("a", { id: "a", width: 1000, height: 2000, padding: 0 });
+    dagreD3.render()(svg, g);
+
+    expect(d3.select("#a").node().getBBox().width).to.equal(1000);
+    expect(d3.select("#a").node().getBBox().height).to.equal(2000);
+  });
+
+  it("does not grow node dimensions when re-rendering", function() {
+    g.setNode("a", { id: "a" });
+    dagreD3.render()(svg, g);
+    var bbox = svg.select("#a rect").node().getBBox();
+
+    dagreD3.render()(svg, g);
+    var bbox2 = svg.select("#a rect").node().getBBox();
+
+    expect(bbox.width).equals(bbox2.width);
+    expect(bbox.height).equals(bbox2.height);
+  });
+
+  it("does not grow edge dimensions when re-rendering", function() {
+    g.setNode("a");
+    g.setNode("b");
+    g.setEdge("a", "b", { labelId: "ab", label: "foo" });
+    dagreD3.render()(svg, g);
+    var bbox = svg.select("#ab").node().getBBox();
+
+    dagreD3.render()(svg, g);
+    var bbox2 = svg.select("#ab").node().getBBox();
+
+    expect(bbox.width).equals(bbox2.width);
+    expect(bbox.height).equals(bbox2.height);
+  });
+
+  describe("HTML labels", function() {
+    it("can be created for a node", function() {
+      g.setNode("a", { labelType: "html", label: "<p id='a-lab'>Hello</p>" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a-lab").empty()).to.be.false;
+      expect(d3.select("#a-lab").text()).equals("Hello");
+    });
+
+    it("can use an existing DOM element", function() {
+      var elem = document.createElement("p");
+      elem.setAttribute("id", "a-lab");
+      elem.innerHTML = "Hello";
+
+      g.setNode("a", { id: "a", labelType: "html", label: elem });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a #a-lab").empty()).to.be.false;
+      expect(d3.select("#a #a-lab").text()).equals("Hello");
+    });
+
+    it("can use an function that returns a DOM element", function() {
+      var elem = document.createElement("p");
+      elem.setAttribute("id", "a-lab");
+      elem.innerHTML = "Hello";
+
+      g.setNode("a", { id: "a", labelType: "html", label: function() { return elem; } });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a #a-lab").empty()).to.be.false;
+      expect(d3.select("#a #a-lab").text()).equals("Hello");
+    });
+
+    it("can be created for an edge", function() {
+      g.setNode("a", {});
+      g.setNode("b", {});
+      g.setEdge("a", "b", { labelType: "html", label: "<p id='ab-lab'>Hello</p>" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#ab-lab").empty()).to.be.false;
+      expect(d3.select("#ab-lab").text()).equals("Hello");
+    });
+  });
+
+  describe("SVG labels", function() {
+    it("can be created for a node", function() {
+      link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
+      link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://google.com/');
+      link.setAttribute('target', '_blank');
+      link.setAttribute('id', 'a-lab');
+      link.textContent = 'Google';
+
+      g.setNode("a", { labelType: "svg", label: link });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a-lab").empty()).to.be.false;
+      expect(d3.select("#a-lab").text()).equals("Google");
+    });
+
+    it("can be created for an edge", function() {
+      link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
+      link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://yahoo.com/');
+      link.setAttribute('target', '_blank');
+      link.setAttribute('id', 'ab-lab');
+      link.textContent = 'Yahoo';
+
+      g.setNode("a", {});
+      g.setNode("b", {});
+      g.setEdge("a", "b", { labelType: "svg", label: link });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#ab-lab").empty()).to.be.false;
+      expect(d3.select("#ab-lab").text()).equals("Yahoo");
+    });
+  });
+
+  describe("breaks label lines", function() {
+    it("on '\\n'", function() {
+      g.setNode("a", { id: "a", label: "multi\nline" });
+      dagreD3.render()(svg, g);
+
+      var text = d3.select("#a text");
+      expect(text.empty()).to.be.false;
+      expect(d3.select(text.selectAll("tspan")[0][0]).text()).equals("multi");
+      expect(d3.select(text.selectAll("tspan")[0][1]).text()).equals("line");
+    });
+
+    it("on '\\\\n'", function() {
+      g.setNode("a", { id: "a", label: "multi\\nline" });
+      dagreD3.render()(svg, g);
+
+      var text = d3.select("#a text");
+      expect(text.empty()).to.be.false;
+      expect(d3.select(text.selectAll("tspan")[0][0]).text()).equals("multi");
+      expect(d3.select(text.selectAll("tspan")[0][1]).text()).equals("line");
+    });
+  });
+
+  describe("styles", function() {
+    var canonicalRed;
+
+    beforeEach(function() {
+      // Each browser has a different way to represent colors canonically. We
+      // create a dummy object here to get the canonical representation for the
+      // color red.
+      canonicalRed = svg.append("rect").style("fill", "#ff0000").style("fill");
+    });
+
+    it("can be applied to a node", function() {
+      g.setNode("a", { id: "a", style: "fill: #ff0000", shape: "rect" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a rect").style("fill")).to.equal(canonicalRed);
+    });
+
+    it("can be applied to a node label", function() {
+      g.setNode("a", { labelId: "a-lab", labelStyle: "stroke: #ff0000" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a-lab text").style("stroke")).to.equal(canonicalRed);
+    });
+
+    it("can be applied to an edge", function() {
+      g.setNode("a", {});
+      g.setNode("b", {});
+      g.setEdge("a", "b", { id: "ab", style: "stroke: #ff0000" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#ab path").style("stroke")).to.equal(canonicalRed);
+    });
+
+    it("can be applied to an edge label", function() {
+      g.setNode("a", {});
+      g.setNode("b", {});
+      g.setEdge("a", "b", { labelId: "ab-lab", labelStyle: "stroke: #ff0000" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#ab-lab text").style("stroke")).to.equal(canonicalRed);
+    });
+  });
+
+  describe("shapes", function() {
+    it("include a rect", function() {
+      g.setNode("a", { id: "a", shape: "rect", width: 100, height: 200, padding: 0 });
+      dagreD3.render()(svg, g);
+
+      var rect = d3.select("#a rect");
+      expect(rect.empty()).to.be.false;
+      expect(rect.node().getBBox().width).to.equal(100);
+      expect(rect.node().getBBox().height).to.equal(200);
+    });
+
+    it("include a circle", function() {
+      g.setNode("a", { id: "a", shape: "circle", width: 100, height: 250, padding: 0 });
+      dagreD3.render()(svg, g);
+
+      var circle = d3.select("#a circle");
+      expect(circle.empty()).to.be.false;
+      // Should be half of greater of width, height
+      expect(circle.attr("r") * 2).to.equal(250);
+    });
+
+    it("include an ellipse", function() {
+      g.setNode("a", { id: "a", shape: "ellipse", width: 100, height: 250, padding: 0 });
+      dagreD3.render()(svg, g);
+
+      var ellipse = d3.select("#a ellipse");
+      expect(ellipse.empty()).to.be.false;
+      expect(ellipse.attr("rx") * 2).to.equal(100);
+      expect(ellipse.attr("ry") * 2).to.equal(250);
+    });
+  });
+
+  describe("class", function() {
+    it("can be set for nodes", function() {
+      g.setNode("a", { id: "a", class: function(d) { return d + "-class"; } });
+      g.setNode("b", { id: "b", class: "b-class" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#a").classed("a-class")).to.be.true;
+      expect(d3.select("#b").classed("b-class")).to.be.true;
+    });
+
+    it("can be set for edges", function() {
+      g.setNode("a", { id: "a" });
+      g.setNode("b", { id: "b" });
+      g.setEdge("a", "b", { id: "c", class: function(d) { return d.v + d.w + "-class"; } });
+      g.setEdge("b", "a", { id: "d", class: "d-class" });
+      dagreD3.render()(svg, g);
+
+      expect(d3.select("#c").classed("ab-class")).to.be.true;
+      expect(d3.select("#d").classed("d-class")).to.be.true;
+    });
+  });
+});
diff --git a/debian/missing-source/dagre-d3/test/demo-test.js b/debian/missing-source/dagre-d3/test/demo-test.js
new file mode 100644
index 0000000..368bb8d
--- /dev/null
+++ b/debian/missing-source/dagre-d3/test/demo-test.js
@@ -0,0 +1,76 @@
+// A *very* simple test runner to ensure that the demos work as expected.
+var webpage = require("webpage"),
+    system = require("system"),
+    stdout = system.stdout,
+    stderr = system.stderr,
+    // Too bad this replaces the more function fs module from nodejs...
+    fs = require("fs"),
+    start = new Date();
+
+var red = "\033[31m";
+var green = "\033[32m";
+var grey = "\033[30;1m";
+var reset = "\033[0m";
+
+function htmlFile(file) { return file.match(/.*\.html/); }
+
+var remaining =  {};
+ls("./demo", htmlFile).forEach(function(f) { remaining[f] = true; });
+ls("./build/dist/demo", htmlFile).forEach(function(f) { remaining[f] = true; });
+var testCount = Object.keys(remaining).length;
+var failures = [];
+
+stdout.write("\n");
+stdout.write(grey + "  ");
+
+Object.keys(remaining).forEach(function(url) {
+  stdout.write(".");
+  var page = webpage.create();
+  page.onError = function(msg, trace) {
+    failures.push({ url: url, msg: msg, trace: trace });
+    testDone(url);
+  };
+  page.onLoadFinished = function(status) {
+    if (status !== "success") {
+      failures.push({ url: url, msg: "Could not load page" });
+    }
+    testDone(url);
+  };
+  page.open(url, function() {});
+});
+
+function ls(dir, filter) {
+  var set = [];
+  fs.list(dir).forEach(function(file) {
+    if (filter(file)) {
+      set.push(dir + "/" + file);
+    }
+  });
+  return set;
+}
+
+function testDone(url) {
+  delete remaining[url];
+  if (!Object.keys(remaining).length) {
+    stdout.write(reset + "\n");
+    stdout.write("\n");
+    failures.forEach(function(failure) {
+      stderr.write(red + "FAILED: " + failure.url + reset + "\n");
+      stderr.write(grey);
+      stderr.write("  " + failure.msg + "\n");
+      if (failure.trace) {
+        failure.trace.forEach(function(t) {
+          stderr.write("    " + t.file + ": " + t.line + (t.function ? " (in function '" + t.function + "')" : "") + "\n");
+        });
+      }
+      stderr.write(reset);
+      stderr.write("\n");
+    });
+    stdout.write("  " + green + (testCount - failures.length) + " passing" + reset);
+    if (failures.length) {
+      stdout.write(" " + red + (failures.length) + " failing" + reset);
+    }
+    stdout.write(grey + " (" + (new Date() - start) + "ms)" + reset + "\n\n");
+    phantom.exit(failures.length);
+  }
+}
diff --git a/debian/missing-source/dagre/.gitignore b/debian/missing-source/dagre/.gitignore
new file mode 100644
index 0000000..5965641
--- /dev/null
+++ b/debian/missing-source/dagre/.gitignore
@@ -0,0 +1,3 @@
+/build
+/node_modules
+/tmp
diff --git a/debian/missing-source/dagre/.jscsrc b/debian/missing-source/dagre/.jscsrc
new file mode 100644
index 0000000..a48833f
--- /dev/null
+++ b/debian/missing-source/dagre/.jscsrc
@@ -0,0 +1,6 @@
+{
+  "disallowSpaceAfterPrefixUnaryOperators": true,
+  "disallowTrailingWhitespace": true,
+  "maximumLineLength": 100,
+  "validateQuoteMarks": true
+}
diff --git a/debian/missing-source/dagre/.jshintrc b/debian/missing-source/dagre/.jshintrc
new file mode 100644
index 0000000..ff29dc0
--- /dev/null
+++ b/debian/missing-source/dagre/.jshintrc
@@ -0,0 +1,24 @@
+{
+  "camelcase": true,
+  "eqeqeq": true,
+  "expr": true,
+  "freeze": true,
+  "immed": true,
+  "newcap": true,
+  "noarg": true,
+  "quotmark": "double",
+  "trailing": true,
+  "undef": true,
+  "unused": true,
+
+  "laxbreak": true,
+
+  "node": true,
+
+  "globals": {
+      "afterEach": false,
+      "beforeEach": false,
+      "describe": false,
+      "it": false
+  }
+}
diff --git a/debian/missing-source/dagre/.npmignore b/debian/missing-source/dagre/.npmignore
new file mode 100644
index 0000000..91e816c
--- /dev/null
+++ b/debian/missing-source/dagre/.npmignore
@@ -0,0 +1,7 @@
+/bench
+/build
+/Makefile
+/node_modules
+/src
+/test
+/tmp
diff --git a/debian/missing-source/dagre/.travis.yml b/debian/missing-source/dagre/.travis.yml
new file mode 100644
index 0000000..0842667
--- /dev/null
+++ b/debian/missing-source/dagre/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - "0.10"
+script: KARMA_OPTS="--browsers Firefox,PhantomJS" make -e test
+before_script:
+  - export DISPLAY=:99.0        
+  - sh -e /etc/init.d/xvfb start
diff --git a/debian/missing-source/dagre/LICENSE b/debian/missing-source/dagre/LICENSE
new file mode 100644
index 0000000..7d7dd94
--- /dev/null
+++ b/debian/missing-source/dagre/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012-2014 Chris Pettitt
+
+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/debian/missing-source/dagre/Makefile b/debian/missing-source/dagre/Makefile
new file mode 100644
index 0000000..200e650
--- /dev/null
+++ b/debian/missing-source/dagre/Makefile
@@ -0,0 +1,83 @@
+MOD = dagre
+
+NPM = npm
+BROWSERIFY = ./node_modules/browserify/bin/cmd.js
+ISTANBUL = ./node_modules/istanbul/lib/cli.js
+JSHINT = ./node_modules/jshint/bin/jshint
+JSCS = ./node_modules/jscs/bin/jscs
+KARMA = ./node_modules/karma/bin/karma
+MOCHA = ./node_modules/mocha/bin/_mocha
+UGLIFY = ./node_modules/uglify-js/bin/uglifyjs
+
+ISTANBUL_OPTS = --dir $(COVERAGE_DIR) --report html
+JSHINT_OPTS = --reporter node_modules/jshint-stylish/stylish.js
+MOCHA_OPTS = -R dot
+
+BUILD_DIR = build
+COVERAGE_DIR = $(BUILD_DIR)/cov
+DIST_DIR = dist
+
+SRC_FILES = index.js lib/version.js $(shell find lib -type f -name '*.js')
+TEST_FILES = $(shell find test -type f -name '*.js' | grep -v 'bundle-test.js')
+BUILD_FILES = $(addprefix $(BUILD_DIR)/, \
+						$(MOD).js $(MOD).min.js \
+						$(MOD).core.js $(MOD).core.min.js)
+
+DIRS = $(BUILD_DIR)
+
+.PHONY: all bench clean browser-test unit-test test dist
+
+all: unit-test
+
+bench: test
+	@src/bench.js
+
+lib/version.js: package.json
+	@src/release/make-version.js > $@
+
+$(DIRS):
+	@mkdir -p $@
+
+test: unit-test browser-test
+
+unit-test: $(SRC_FILES) $(TEST_FILES) node_modules | $(BUILD_DIR)
+	@$(ISTANBUL) cover $(ISTANBUL_OPTS) $(MOCHA) --dir $(COVERAGE_DIR) -- $(MOCHA_OPTS) $(TEST_FILES) || $(MOCHA) $(MOCHA_OPTS) $(TEST_FILES)
+	@$(JSHINT) $(JSHINT_OPTS) $(filter-out node_modules, $?)
+	@$(JSCS) $(filter-out node_modules, $?)
+
+browser-test: $(BUILD_DIR)/$(MOD).js $(BUILD_DIR)/$(MOD).core.js
+	$(KARMA) start --single-run $(KARMA_OPTS)
+	$(KARMA) start karma.core.conf.js --single-run $(KARMA_OPTS)
+
+bower.json: package.json src/release/make-bower.json.js
+	@src/release/make-bower.json.js > $@
+
+$(BUILD_DIR)/$(MOD).js: index.js $(SRC_FILES) | unit-test
+	@$(BROWSERIFY) $< > $@ -s dagre
+
+$(BUILD_DIR)/$(MOD).min.js: $(BUILD_DIR)/$(MOD).js
+	@$(UGLIFY) $< --comments '@license' > $@
+
+$(BUILD_DIR)/$(MOD).core.js: index.js $(SRC_FILES) | unit-test
+	@$(BROWSERIFY) $< > $@ --no-bundle-external -s dagre
+
+$(BUILD_DIR)/$(MOD).core.min.js: $(BUILD_DIR)/$(MOD).core.js
+	@$(UGLIFY) $< --comments '@license' > $@
+
+dist: $(BUILD_FILES) | bower.json test
+	@rm -rf $@
+	@mkdir -p $@
+	@cp $^ dist
+
+release: dist
+	@echo
+	@echo Starting release...
+	@echo
+	@src/release/release.sh $(MOD) dist
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+node_modules: package.json
+	@$(NPM) install
+	@touch $@
diff --git a/debian/missing-source/dagre/README.md b/debian/missing-source/dagre/README.md
new file mode 100644
index 0000000..4384d0c
--- /dev/null
+++ b/debian/missing-source/dagre/README.md
@@ -0,0 +1,16 @@
+# dagre - Graph layout for JavaScript
+
+[![Build Status](https://secure.travis-ci.org/cpettitt/dagre.png?branch=master)](http://travis-ci.org/cpettitt/dagre)
+
+Dagre is a JavaScript library that makes it easy to lay out directed graphs on
+the client-side.
+
+For more details, including examples and configuration options, please see our
+[wiki](https://github.com/cpettitt/dagre/wiki).
+
+**This project is not being actively developed; however, pull requests are still being accepted.**
+
+## License
+
+dagre is licensed under the terms of the MIT License. See the LICENSE file
+for details.
diff --git a/debian/missing-source/dagre/bower.json b/debian/missing-source/dagre/bower.json
new file mode 100644
index 0000000..a03fc9b
--- /dev/null
+++ b/debian/missing-source/dagre/bower.json
@@ -0,0 +1,26 @@
+{
+  "name": "dagre",
+  "version": "0.7.4",
+  "main": [
+    "dist/dagre.core.js",
+    "dist/dagre.core.min.js"
+  ],
+  "ignore": [
+    ".*",
+    "README.md",
+    "CHANGELOG.md",
+    "Makefile",
+    "dist/dagre.js",
+    "dist/dagre.min.js",
+    "index.js",
+    "karma*",
+    "lib/**",
+    "package.json",
+    "src/**",
+    "test/**"
+  ],
+  "dependencies": {
+    "graphlib": "^1.0.5",
+    "lodash": "^3.10.0"
+  }
+}
diff --git a/debian/missing-source/dagre/index.js b/debian/missing-source/dagre/index.js
new file mode 100644
index 0000000..625910c
--- /dev/null
+++ b/debian/missing-source/dagre/index.js
@@ -0,0 +1,33 @@
+/*
+Copyright (c) 2012-2014 Chris Pettitt
+
+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.
+*/
+
+module.exports = {
+  graphlib: require("./lib/graphlib"),
+
+  layout: require("./lib/layout"),
+  debug: require("./lib/debug"),
+  util: {
+    time: require("./lib/util").time,
+    notime: require("./lib/util").notime
+  },
+  version: require("./lib/version")
+};
diff --git a/debian/missing-source/dagre/karma.conf.js b/debian/missing-source/dagre/karma.conf.js
new file mode 100644
index 0000000..983dab6
--- /dev/null
+++ b/debian/missing-source/dagre/karma.conf.js
@@ -0,0 +1,68 @@
+// Karma configuration
+// Generated on Sat Oct 18 2014 17:38:05 GMT-0700 (PDT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['mocha'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      'build/dagre.js',
+
+      'node_modules/chai/chai.js',
+      'test/bundle-test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome', 'Firefox', 'PhantomJS', 'Safari'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/debian/missing-source/dagre/karma.core.conf.js b/debian/missing-source/dagre/karma.core.conf.js
new file mode 100644
index 0000000..237ee30
--- /dev/null
+++ b/debian/missing-source/dagre/karma.core.conf.js
@@ -0,0 +1,70 @@
+// Karma configuration
+// Generated on Sat Oct 18 2014 17:38:05 GMT-0700 (PDT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['mocha'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      'node_modules/lodash/index.js',
+      'node_modules/graphlib/dist/graphlib.core.js',
+      'build/dagre.core.js',
+
+      'node_modules/chai/chai.js',
+      'test/bundle-test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome', 'Firefox', 'PhantomJS', 'Safari'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/debian/missing-source/dagre/lib/acyclic.js b/debian/missing-source/dagre/lib/acyclic.js
new file mode 100644
index 0000000..5b0c56f
--- /dev/null
+++ b/debian/missing-source/dagre/lib/acyclic.js
@@ -0,0 +1,67 @@
+"use strict";
+
+var _ = require("./lodash"),
+    greedyFAS = require("./greedy-fas");
+
+module.exports = {
+  run: run,
+  undo: undo
+};
+
+function run(g) {
+  var fas = (g.graph().acyclicer === "greedy"
+                ? greedyFAS(g, weightFn(g))
+                : dfsFAS(g));
+  _.each(fas, function(e) {
+    var label = g.edge(e);
+    g.removeEdge(e);
+    label.forwardName = e.name;
+    label.reversed = true;
+    g.setEdge(e.w, e.v, label, _.uniqueId("rev"));
+  });
+
+  function weightFn(g) {
+    return function(e) {
+      return g.edge(e).weight;
+    };
+  }
+}
+
+function dfsFAS(g) {
+  var fas = [],
+      stack = {},
+      visited = {};
+
+  function dfs(v) {
+    if (_.has(visited, v)) {
+      return;
+    }
+    visited[v] = true;
+    stack[v] = true;
+    _.each(g.outEdges(v), function(e) {
+      if (_.has(stack, e.w)) {
+        fas.push(e);
+      } else {
+        dfs(e.w);
+      }
+    });
+    delete stack[v];
+  }
+
+  _.each(g.nodes(), dfs);
+  return fas;
+}
+
+function undo(g) {
+  _.each(g.edges(), function(e) {
+    var label = g.edge(e);
+    if (label.reversed) {
+      g.removeEdge(e);
+
+      var forwardName = label.forwardName;
+      delete label.reversed;
+      delete label.forwardName;
+      g.setEdge(e.w, e.v, label, forwardName);
+    }
+  });
+}
diff --git a/debian/missing-source/dagre/lib/add-border-segments.js b/debian/missing-source/dagre/lib/add-border-segments.js
new file mode 100644
index 0000000..f453330
--- /dev/null
+++ b/debian/missing-source/dagre/lib/add-border-segments.js
@@ -0,0 +1,38 @@
+var _ = require("./lodash"),
+    util = require("./util");
+
+module.exports = addBorderSegments;
+
+function addBorderSegments(g) {
+  function dfs(v) {
+    var children = g.children(v),
+        node = g.node(v);
+    if (children.length) {
+      _.each(children, dfs);
+    }
+
+    if (_.has(node, "minRank")) {
+      node.borderLeft = [];
+      node.borderRight = [];
+      for (var rank = node.minRank, maxRank = node.maxRank + 1;
+           rank < maxRank;
+           ++rank) {
+        addBorderNode(g, "borderLeft", "_bl", v, node, rank);
+        addBorderNode(g, "borderRight", "_br", v, node, rank);
+      }
+    }
+  }
+
+  _.each(g.children(), dfs);
+}
+
+function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
+  var label = { width: 0, height: 0, rank: rank, borderType: prop },
+      prev = sgNode[prop][rank - 1],
+      curr = util.addDummyNode(g, "border", label, prefix);
+  sgNode[prop][rank] = curr;
+  g.setParent(curr, sg);
+  if (prev) {
+    g.setEdge(prev, curr, { weight: 1 });
+  }
+}
diff --git a/debian/missing-source/dagre/lib/coordinate-system.js b/debian/missing-source/dagre/lib/coordinate-system.js
new file mode 100644
index 0000000..6068b03
--- /dev/null
+++ b/debian/missing-source/dagre/lib/coordinate-system.js
@@ -0,0 +1,72 @@
+"use strict";
+
+var _ = require("./lodash");
+
+module.exports = {
+  adjust: adjust,
+  undo: undo
+};
+
+function adjust(g) {
+  var rankDir = g.graph().rankdir.toLowerCase();
+  if (rankDir === "lr" || rankDir === "rl") {
+    swapWidthHeight(g);
+  }
+}
+
+function undo(g) {
+  var rankDir = g.graph().rankdir.toLowerCase();
+  if (rankDir === "bt" || rankDir === "rl") {
+    reverseY(g);
+  }
+
+  if (rankDir === "lr" || rankDir === "rl") {
+    swapXY(g);
+    swapWidthHeight(g);
+  }
+}
+
+function swapWidthHeight(g) {
+  _.each(g.nodes(), function(v) { swapWidthHeightOne(g.node(v)); });
+  _.each(g.edges(), function(e) { swapWidthHeightOne(g.edge(e)); });
+}
+
+function swapWidthHeightOne(attrs) {
+  var w = attrs.width;
+  attrs.width = attrs.height;
+  attrs.height = w;
+}
+
+function reverseY(g) {
+  _.each(g.nodes(), function(v) { reverseYOne(g.node(v)); });
+
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    _.each(edge.points, reverseYOne);
+    if (_.has(edge, "y")) {
+      reverseYOne(edge);
+    }
+  });
+}
+
+function reverseYOne(attrs) {
+  attrs.y = -attrs.y;
+}
+
+function swapXY(g) {
+  _.each(g.nodes(), function(v) { swapXYOne(g.node(v)); });
+
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    _.each(edge.points, swapXYOne);
+    if (_.has(edge, "x")) {
+      swapXYOne(edge);
+    }
+  });
+}
+
+function swapXYOne(attrs) {
+  var x = attrs.x;
+  attrs.x = attrs.y;
+  attrs.y = x;
+}
diff --git a/debian/missing-source/dagre/lib/data/list.js b/debian/missing-source/dagre/lib/data/list.js
new file mode 100644
index 0000000..39dd772
--- /dev/null
+++ b/debian/missing-source/dagre/lib/data/list.js
@@ -0,0 +1,56 @@
+/*
+ * Simple doubly linked list implementation derived from Cormen, et al.,
+ * "Introduction to Algorithms".
+ */
+
+module.exports = List;
+
+function List() {
+  var sentinel = {};
+  sentinel._next = sentinel._prev = sentinel;
+  this._sentinel = sentinel;
+}
+
+List.prototype.dequeue = function() {
+  var sentinel = this._sentinel,
+      entry = sentinel._prev;
+  if (entry !== sentinel) {
+    unlink(entry);
+    return entry;
+  }
+};
+
+List.prototype.enqueue = function(entry) {
+  var sentinel = this._sentinel;
+  if (entry._prev && entry._next) {
+    unlink(entry);
+  }
+  entry._next = sentinel._next;
+  sentinel._next._prev = entry;
+  sentinel._next = entry;
+  entry._prev = sentinel;
+};
+
+List.prototype.toString = function() {
+  var strs = [],
+      sentinel = this._sentinel,
+      curr = sentinel._prev;
+  while (curr !== sentinel) {
+    strs.push(JSON.stringify(curr, filterOutLinks));
+    curr = curr._prev;
+  }
+  return "[" + strs.join(", ") + "]";
+};
+
+function unlink(entry) {
+  entry._prev._next = entry._next;
+  entry._next._prev = entry._prev;
+  delete entry._next;
+  delete entry._prev;
+}
+
+function filterOutLinks(k, v) {
+  if (k !== "_next" && k !== "_prev") {
+    return v;
+  }
+}
diff --git a/debian/missing-source/dagre/lib/debug.js b/debian/missing-source/dagre/lib/debug.js
new file mode 100644
index 0000000..4ab95bb
--- /dev/null
+++ b/debian/missing-source/dagre/lib/debug.js
@@ -0,0 +1,34 @@
+var _ = require("./lodash"),
+    util = require("./util"),
+    Graph = require("./graphlib").Graph;
+
+module.exports = {
+  debugOrdering: debugOrdering
+};
+
+/* istanbul ignore next */
+function debugOrdering(g) {
+  var layerMatrix = util.buildLayerMatrix(g);
+
+  var h = new Graph({ compound: true, multigraph: true }).setGraph({});
+
+  _.each(g.nodes(), function(v) {
+    h.setNode(v, { label: v });
+    h.setParent(v, "layer" + g.node(v).rank);
+  });
+
+  _.each(g.edges(), function(e) {
+    h.setEdge(e.v, e.w, {}, e.name);
+  });
+
+  _.each(layerMatrix, function(layer, i) {
+    var layerV = "layer" + i;
+    h.setNode(layerV, { rank: "same" });
+    _.reduce(layer, function(u, v) {
+      h.setEdge(u, v, { style: "invis" });
+      return v;
+    });
+  });
+
+  return h;
+}
diff --git a/debian/missing-source/dagre/lib/graphlib.js b/debian/missing-source/dagre/lib/graphlib.js
new file mode 100644
index 0000000..e161cf2
--- /dev/null
+++ b/debian/missing-source/dagre/lib/graphlib.js
@@ -0,0 +1,15 @@
+/* global window */
+
+var graphlib;
+
+if (typeof require === "function") {
+  try {
+    graphlib = require("graphlib");
+  } catch (e) {}
+}
+
+if (!graphlib) {
+  graphlib = window.graphlib;
+}
+
+module.exports = graphlib;
diff --git a/debian/missing-source/dagre/lib/greedy-fas.js b/debian/missing-source/dagre/lib/greedy-fas.js
new file mode 100644
index 0000000..499a052
--- /dev/null
+++ b/debian/missing-source/dagre/lib/greedy-fas.js
@@ -0,0 +1,118 @@
+var _ = require("./lodash"),
+    Graph = require("./graphlib").Graph,
+    List = require("./data/list");
+
+/*
+ * A greedy heuristic for finding a feedback arc set for a graph. A feedback
+ * arc set is a set of edges that can be removed to make a graph acyclic.
+ * The algorithm comes from: P. Eades, X. Lin, and W. F. Smyth, "A fast and
+ * effective heuristic for the feedback arc set problem." This implementation
+ * adjusts that from the paper to allow for weighted edges.
+ */
+module.exports = greedyFAS;
+
+var DEFAULT_WEIGHT_FN = _.constant(1);
+
+function greedyFAS(g, weightFn) {
+  if (g.nodeCount() <= 1) {
+    return [];
+  }
+  var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
+  var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
+
+  // Expand multi-edges
+  return _.flatten(_.map(results, function(e) {
+    return g.outEdges(e.v, e.w);
+  }), true);
+}
+
+function doGreedyFAS(g, buckets, zeroIdx) {
+  var results = [],
+      sources = buckets[buckets.length - 1],
+      sinks = buckets[0];
+
+  var entry;
+  while (g.nodeCount()) {
+    while ((entry = sinks.dequeue()))   { removeNode(g, buckets, zeroIdx, entry); }
+    while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
+    if (g.nodeCount()) {
+      for (var i = buckets.length - 2; i > 0; --i) {
+        entry = buckets[i].dequeue();
+        if (entry) {
+          results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
+          break;
+        }
+      }
+    }
+  }
+
+  return results;
+}
+
+function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
+  var results = collectPredecessors ? [] : undefined;
+
+  _.each(g.inEdges(entry.v), function(edge) {
+    var weight = g.edge(edge),
+        uEntry = g.node(edge.v);
+
+    if (collectPredecessors) {
+      results.push({ v: edge.v, w: edge.w });
+    }
+
+    uEntry.out -= weight;
+    assignBucket(buckets, zeroIdx, uEntry);
+  });
+
+  _.each(g.outEdges(entry.v), function(edge) {
+    var weight = g.edge(edge),
+        w = edge.w,
+        wEntry = g.node(w);
+    wEntry["in"] -= weight;
+    assignBucket(buckets, zeroIdx, wEntry);
+  });
+
+  g.removeNode(entry.v);
+
+  return results;
+}
+
+function buildState(g, weightFn) {
+  var fasGraph = new Graph(),
+      maxIn = 0,
+      maxOut = 0;
+
+  _.each(g.nodes(), function(v) {
+    fasGraph.setNode(v, { v: v, "in": 0, out: 0 });
+  });
+
+  // Aggregate weights on nodes, but also sum the weights across multi-edges
+  // into a single edge for the fasGraph.
+  _.each(g.edges(), function(e) {
+    var prevWeight = fasGraph.edge(e.v, e.w) || 0,
+        weight = weightFn(e),
+        edgeWeight = prevWeight + weight;
+    fasGraph.setEdge(e.v, e.w, edgeWeight);
+    maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
+    maxIn  = Math.max(maxIn,  fasGraph.node(e.w)["in"]  += weight);
+  });
+
+  var buckets = _.range(maxOut + maxIn + 3).map(function() { return new List(); });
+  var zeroIdx = maxIn + 1;
+
+  _.each(fasGraph.nodes(), function(v) {
+    assignBucket(buckets, zeroIdx, fasGraph.node(v));
+  });
+
+  return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
+}
+
+function assignBucket(buckets, zeroIdx, entry) {
+  if (!entry.out) {
+    buckets[0].enqueue(entry);
+  } else if (!entry["in"]) {
+    buckets[buckets.length - 1].enqueue(entry);
+  } else {
+    buckets[entry.out - entry["in"] + zeroIdx].enqueue(entry);
+  }
+}
diff --git a/debian/missing-source/dagre/lib/layout.js b/debian/missing-source/dagre/lib/layout.js
new file mode 100644
index 0000000..f83d509
--- /dev/null
+++ b/debian/missing-source/dagre/lib/layout.js
@@ -0,0 +1,392 @@
+"use strict";
+
+var _ = require("./lodash"),
+    acyclic = require("./acyclic"),
+    normalize = require("./normalize"),
+    rank = require("./rank"),
+    normalizeRanks = require("./util").normalizeRanks,
+    parentDummyChains = require("./parent-dummy-chains"),
+    removeEmptyRanks = require("./util").removeEmptyRanks,
+    nestingGraph = require("./nesting-graph"),
+    addBorderSegments = require("./add-border-segments"),
+    coordinateSystem = require("./coordinate-system"),
+    order = require("./order"),
+    position = require("./position"),
+    util = require("./util"),
+    Graph = require("./graphlib").Graph;
+
+module.exports = layout;
+
+function layout(g, opts) {
+  var time = opts && opts.debugTiming ? util.time : util.notime;
+  time("layout", function() {
+    var layoutGraph = time("  buildLayoutGraph",
+                               function() { return buildLayoutGraph(g); });
+    time("  runLayout",        function() { runLayout(layoutGraph, time); });
+    time("  updateInputGraph", function() { updateInputGraph(g, layoutGraph); });
+  });
+}
+
+function runLayout(g, time) {
+  time("    makeSpaceForEdgeLabels", function() { makeSpaceForEdgeLabels(g); });
+  time("    removeSelfEdges",        function() { removeSelfEdges(g); });
+  time("    acyclic",                function() { acyclic.run(g); });
+  time("    nestingGraph.run",       function() { nestingGraph.run(g); });
+  time("    rank",                   function() { rank(util.asNonCompoundGraph(g)); });
+  time("    injectEdgeLabelProxies", function() { injectEdgeLabelProxies(g); });
+  time("    removeEmptyRanks",       function() { removeEmptyRanks(g); });
+  time("    nestingGraph.cleanup",   function() { nestingGraph.cleanup(g); });
+  time("    normalizeRanks",         function() { normalizeRanks(g); });
+  time("    assignRankMinMax",       function() { assignRankMinMax(g); });
+  time("    removeEdgeLabelProxies", function() { removeEdgeLabelProxies(g); });
+  time("    normalize.run",          function() { normalize.run(g); });
+  time("    parentDummyChains",      function() { parentDummyChains(g); });
+  time("    addBorderSegments",      function() { addBorderSegments(g); });
+  time("    order",                  function() { order(g); });
+  time("    insertSelfEdges",        function() { insertSelfEdges(g); });
+  time("    adjustCoordinateSystem", function() { coordinateSystem.adjust(g); });
+  time("    position",               function() { position(g); });
+  time("    positionSelfEdges",      function() { positionSelfEdges(g); });
+  time("    removeBorderNodes",      function() { removeBorderNodes(g); });
+  time("    normalize.undo",         function() { normalize.undo(g); });
+  time("    fixupEdgeLabelCoords",   function() { fixupEdgeLabelCoords(g); });
+  time("    undoCoordinateSystem",   function() { coordinateSystem.undo(g); });
+  time("    translateGraph",         function() { translateGraph(g); });
+  time("    assignNodeIntersects",   function() { assignNodeIntersects(g); });
+  time("    reversePoints",          function() { reversePointsForReversedEdges(g); });
+  time("    acyclic.undo",           function() { acyclic.undo(g); });
+}
+
+/*
+ * Copies final layout information from the layout graph back to the input
+ * graph. This process only copies whitelisted attributes from the layout graph
+ * to the input graph, so it serves as a good place to determine what
+ * attributes can influence layout.
+ */
+function updateInputGraph(inputGraph, layoutGraph) {
+  _.each(inputGraph.nodes(), function(v) {
+    var inputLabel = inputGraph.node(v),
+        layoutLabel = layoutGraph.node(v);
+
+    if (inputLabel) {
+      inputLabel.x = layoutLabel.x;
+      inputLabel.y = layoutLabel.y;
+
+      if (layoutGraph.children(v).length) {
+        inputLabel.width = layoutLabel.width;
+        inputLabel.height = layoutLabel.height;
+      }
+    }
+  });
+
+  _.each(inputGraph.edges(), function(e) {
+    var inputLabel = inputGraph.edge(e),
+        layoutLabel = layoutGraph.edge(e);
+
+    inputLabel.points = layoutLabel.points;
+    if (_.has(layoutLabel, "x")) {
+      inputLabel.x = layoutLabel.x;
+      inputLabel.y = layoutLabel.y;
+    }
+  });
+
+  inputGraph.graph().width = layoutGraph.graph().width;
+  inputGraph.graph().height = layoutGraph.graph().height;
+}
+
+var graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"],
+    graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" },
+    graphAttrs = ["acyclicer", "ranker", "rankdir", "align"],
+    nodeNumAttrs = ["width", "height"],
+    nodeDefaults = { width: 0, height: 0 },
+    edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"],
+    edgeDefaults = {
+      minlen: 1, weight: 1, width: 0, height: 0,
+      labeloffset: 10, labelpos: "r"
+    },
+    edgeAttrs = ["labelpos"];
+
+/*
+ * Constructs a new graph from the input graph, which can be used for layout.
+ * This process copies only whitelisted attributes from the input graph to the
+ * layout graph. Thus this function serves as a good place to determine what
+ * attributes can influence layout.
+ */
+function buildLayoutGraph(inputGraph) {
+  var g = new Graph({ multigraph: true, compound: true }),
+      graph = canonicalize(inputGraph.graph());
+
+  g.setGraph(_.merge({},
+    graphDefaults,
+    selectNumberAttrs(graph, graphNumAttrs),
+    _.pick(graph, graphAttrs)));
+
+  _.each(inputGraph.nodes(), function(v) {
+    var node = canonicalize(inputGraph.node(v));
+    g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults));
+    g.setParent(v, inputGraph.parent(v));
+  });
+
+  _.each(inputGraph.edges(), function(e) {
+    var edge = canonicalize(inputGraph.edge(e));
+    g.setEdge(e, _.merge({},
+      edgeDefaults,
+      selectNumberAttrs(edge, edgeNumAttrs),
+      _.pick(edge, edgeAttrs)));
+  });
+
+  return g;
+}
+
+/*
+ * This idea comes from the Gansner paper: to account for edge labels in our
+ * layout we split each rank in half by doubling minlen and halving ranksep.
+ * Then we can place labels at these mid-points between nodes.
+ *
+ * We also add some minimal padding to the width to push the label for the edge
+ * away from the edge itself a bit.
+ */
+function makeSpaceForEdgeLabels(g) {
+  var graph = g.graph();
+  graph.ranksep /= 2;
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    edge.minlen *= 2;
+    if (edge.labelpos.toLowerCase() !== "c") {
+      if (graph.rankdir === "TB" || graph.rankdir === "BT") {
+        edge.width += edge.labeloffset;
+      } else {
+        edge.height += edge.labeloffset;
+      }
+    }
+  });
+}
+
+/*
+ * Creates temporary dummy nodes that capture the rank in which each edge's
+ * label is going to, if it has one of non-zero width and height. We do this
+ * so that we can safely remove empty ranks while preserving balance for the
+ * label's position.
+ */
+function injectEdgeLabelProxies(g) {
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    if (edge.width && edge.height) {
+      var v = g.node(e.v),
+          w = g.node(e.w),
+          label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e };
+      util.addDummyNode(g, "edge-proxy", label, "_ep");
+    }
+  });
+}
+
+function assignRankMinMax(g) {
+  var maxRank = 0;
+  _.each(g.nodes(), function(v) {
+    var node = g.node(v);
+    if (node.borderTop) {
+      node.minRank = g.node(node.borderTop).rank;
+      node.maxRank = g.node(node.borderBottom).rank;
+      maxRank = _.max(maxRank, node.maxRank);
+    }
+  });
+  g.graph().maxRank = maxRank;
+}
+
+function removeEdgeLabelProxies(g) {
+  _.each(g.nodes(), function(v) {
+    var node = g.node(v);
+    if (node.dummy === "edge-proxy") {
+      g.edge(node.e).labelRank = node.rank;
+      g.removeNode(v);
+    }
+  });
+}
+
+function translateGraph(g) {
+  var minX = Number.POSITIVE_INFINITY,
+      maxX = 0,
+      minY = Number.POSITIVE_INFINITY,
+      maxY = 0,
+      graphLabel = g.graph(),
+      marginX = graphLabel.marginx || 0,
+      marginY = graphLabel.marginy || 0;
+
+  function getExtremes(attrs) {
+    var x = attrs.x,
+        y = attrs.y,
+        w = attrs.width,
+        h = attrs.height;
+    minX = Math.min(minX, x - w / 2);
+    maxX = Math.max(maxX, x + w / 2);
+    minY = Math.min(minY, y - h / 2);
+    maxY = Math.max(maxY, y + h / 2);
+  }
+
+  _.each(g.nodes(), function(v) { getExtremes(g.node(v)); });
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    if (_.has(edge, "x")) {
+      getExtremes(edge);
+    }
+  });
+
+  minX -= marginX;
+  minY -= marginY;
+
+  _.each(g.nodes(), function(v) {
+    var node = g.node(v);
+    node.x -= minX;
+    node.y -= minY;
+  });
+
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    _.each(edge.points, function(p) {
+      p.x -= minX;
+      p.y -= minY;
+    });
+    if (_.has(edge, "x")) { edge.x -= minX; }
+    if (_.has(edge, "y")) { edge.y -= minY; }
+  });
+
+  graphLabel.width = maxX - minX + marginX;
+  graphLabel.height = maxY - minY + marginY;
+}
+
+function assignNodeIntersects(g) {
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e),
+        nodeV = g.node(e.v),
+        nodeW = g.node(e.w),
+        p1, p2;
+    if (!edge.points) {
+      edge.points = [];
+      p1 = nodeW;
+      p2 = nodeV;
+    } else {
+      p1 = edge.points[0];
+      p2 = edge.points[edge.points.length - 1];
+    }
+    edge.points.unshift(util.intersectRect(nodeV, p1));
+    edge.points.push(util.intersectRect(nodeW, p2));
+  });
+}
+
+function fixupEdgeLabelCoords(g) {
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    if (_.has(edge, "x")) {
+      if (edge.labelpos === "l" || edge.labelpos === "r") {
+        edge.width -= edge.labeloffset;
+      }
+      switch (edge.labelpos) {
+        case "l": edge.x -= edge.width / 2 + edge.labeloffset; break;
+        case "r": edge.x += edge.width / 2 + edge.labeloffset; break;
+      }
+    }
+  });
+}
+
+function reversePointsForReversedEdges(g) {
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    if (edge.reversed) {
+      edge.points.reverse();
+    }
+  });
+}
+
+function removeBorderNodes(g) {
+  _.each(g.nodes(), function(v) {
+    if (g.children(v).length) {
+      var node = g.node(v),
+          t = g.node(node.borderTop),
+          b = g.node(node.borderBottom),
+          l = g.node(_.last(node.borderLeft)),
+          r = g.node(_.last(node.borderRight));
+
+      node.width = Math.abs(r.x - l.x);
+      node.height = Math.abs(b.y - t.y);
+      node.x = l.x + node.width / 2;
+      node.y = t.y + node.height / 2;
+    }
+  });
+
+  _.each(g.nodes(), function(v) {
+    if (g.node(v).dummy === "border") {
+      g.removeNode(v);
+    }
+  });
+}
+
+function removeSelfEdges(g) {
+  _.each(g.edges(), function(e) {
+    if (e.v === e.w) {
+      var node = g.node(e.v);
+      if (!node.selfEdges) {
+        node.selfEdges = [];
+      }
+      node.selfEdges.push({ e: e, label: g.edge(e) });
+      g.removeEdge(e);
+    }
+  });
+}
+
+function insertSelfEdges(g) {
+  var layers = util.buildLayerMatrix(g);
+  _.each(layers, function(layer) {
+    var orderShift = 0;
+    _.each(layer, function(v, i) {
+      var node = g.node(v);
+      node.order = i + orderShift;
+      _.each(node.selfEdges, function(selfEdge) {
+        util.addDummyNode(g, "selfedge", {
+          width: selfEdge.label.width,
+          height: selfEdge.label.height,
+          rank: node.rank,
+          order: i + (++orderShift),
+          e: selfEdge.e,
+          label: selfEdge.label
+        }, "_se");
+      });
+      delete node.selfEdges;
+    });
+  });
+}
+
+function positionSelfEdges(g) {
+  _.each(g.nodes(), function(v) {
+    var node = g.node(v);
+    if (node.dummy === "selfedge") {
+      var selfNode = g.node(node.e.v),
+          x = selfNode.x + selfNode.width / 2,
+          y = selfNode.y,
+          dx = node.x - x,
+          dy = selfNode.height / 2;
+      g.setEdge(node.e, node.label);
+      g.removeNode(v);
+      node.label.points = [
+        { x: x + 2 * dx / 3, y: y - dy },
+        { x: x + 5 * dx / 6, y: y - dy },
+        { x: x +     dx    , y: y },
+        { x: x + 5 * dx / 6, y: y + dy },
+        { x: x + 2 * dx / 3, y: y + dy },
+      ];
+      node.label.x = node.x;
+      node.label.y = node.y;
+    }
+  });
+}
+
+function selectNumberAttrs(obj, attrs) {
+  return _.mapValues(_.pick(obj, attrs), Number);
+}
+
+function canonicalize(attrs) {
+  var newAttrs = {};
+  _.each(attrs, function(v, k) {
+    newAttrs[k.toLowerCase()] = v;
+  });
+  return newAttrs;
+}
diff --git a/debian/missing-source/dagre/lib/lodash.js b/debian/missing-source/dagre/lib/lodash.js
new file mode 100644
index 0000000..c27a416
--- /dev/null
+++ b/debian/missing-source/dagre/lib/lodash.js
@@ -0,0 +1,15 @@
+/* global window */
+
+var lodash;
+
+if (typeof require === "function") {
+  try {
+    lodash = require("lodash");
+  } catch (e) {}
+}
+
+if (!lodash) {
+  lodash = window._;
+}
+
+module.exports = lodash;
diff --git a/debian/missing-source/dagre/lib/nesting-graph.js b/debian/missing-source/dagre/lib/nesting-graph.js
new file mode 100644
index 0000000..957b918
--- /dev/null
+++ b/debian/missing-source/dagre/lib/nesting-graph.js
@@ -0,0 +1,132 @@
+var _ = require("./lodash"),
+    util = require("./util");
+
+module.exports = {
+  run: run,
+  cleanup: cleanup
+};
+
+/*
+ * A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
+ * adds appropriate edges to ensure that all cluster nodes are placed between
+ * these boundries, and ensures that the graph is connected.
+ *
+ * In addition we ensure, through the use of the minlen property, that nodes
+ * and subgraph border nodes to not end up on the same rank.
+ *
+ * Preconditions:
+ *
+ *    1. Input graph is a DAG
+ *    2. Nodes in the input graph has a minlen attribute
+ *
+ * Postconditions:
+ *
+ *    1. Input graph is connected.
+ *    2. Dummy nodes are added for the tops and bottoms of subgraphs.
+ *    3. The minlen attribute for nodes is adjusted to ensure nodes do not
+ *       get placed on the same rank as subgraph border nodes.
+ *
+ * The nesting graph idea comes from Sander, "Layout of Compound Directed
+ * Graphs."
+ */
+function run(g) {
+  var root = util.addDummyNode(g, "root", {}, "_root"),
+      depths = treeDepths(g),
+      height = _.max(depths) - 1,
+      nodeSep = 2 * height + 1;
+
+  g.graph().nestingRoot = root;
+
+  // Multiply minlen by nodeSep to align nodes on non-border ranks.
+  _.each(g.edges(), function(e) { g.edge(e).minlen *= nodeSep; });
+
+  // Calculate a weight that is sufficient to keep subgraphs vertically compact
+  var weight = sumWeights(g) + 1;
+
+  // Create border nodes and link them up
+  _.each(g.children(), function(child) {
+    dfs(g, root, nodeSep, weight, height, depths, child);
+  });
+
+  // Save the multiplier for node layers for later removal of empty border
+  // layers.
+  g.graph().nodeRankFactor = nodeSep;
+}
+
+function dfs(g, root, nodeSep, weight, height, depths, v) {
+  var children = g.children(v);
+  if (!children.length) {
+    if (v !== root) {
+      g.setEdge(root, v, { weight: 0, minlen: nodeSep });
+    }
+    return;
+  }
+
+  var top = util.addBorderNode(g, "_bt"),
+      bottom = util.addBorderNode(g, "_bb"),
+      label = g.node(v);
+
+  g.setParent(top, v);
+  label.borderTop = top;
+  g.setParent(bottom, v);
+  label.borderBottom = bottom;
+
+  _.each(children, function(child) {
+    dfs(g, root, nodeSep, weight, height, depths, child);
+
+    var childNode = g.node(child),
+        childTop = childNode.borderTop ? childNode.borderTop : child,
+        childBottom = childNode.borderBottom ? childNode.borderBottom : child,
+        thisWeight = childNode.borderTop ? weight : 2 * weight,
+        minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
+
+    g.setEdge(top, childTop, {
+      weight: thisWeight,
+      minlen: minlen,
+      nestingEdge: true
+    });
+
+    g.setEdge(childBottom, bottom, {
+      weight: thisWeight,
+      minlen: minlen,
+      nestingEdge: true
+    });
+  });
+
+  if (!g.parent(v)) {
+    g.setEdge(root, top, { weight: 0, minlen: height + depths[v] });
+  }
+}
+
+function treeDepths(g) {
+  var depths = {};
+  function dfs(v, depth) {
+    var children = g.children(v);
+    if (children && children.length) {
+      _.each(children, function(child) {
+        dfs(child, depth + 1);
+      });
+    }
+    depths[v] = depth;
+  }
+  _.each(g.children(), function(v) { dfs(v, 1); });
+  return depths;
+}
+
+function sumWeights(g) {
+  return _.reduce(g.edges(), function(acc, e) {
+    return acc + g.edge(e).weight;
+  }, 0);
+}
+
+function cleanup(g) {
+  var graphLabel = g.graph();
+  g.removeNode(graphLabel.nestingRoot);
+  delete graphLabel.nestingRoot;
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    if (edge.nestingEdge) {
+      g.removeEdge(e);
+    }
+  });
+}
diff --git a/debian/missing-source/dagre/lib/normalize.js b/debian/missing-source/dagre/lib/normalize.js
new file mode 100644
index 0000000..ab83d91
--- /dev/null
+++ b/debian/missing-source/dagre/lib/normalize.js
@@ -0,0 +1,90 @@
+"use strict";
+
+var _ = require("./lodash"),
+    util = require("./util");
+
+module.exports = {
+  run: run,
+  undo: undo
+};
+
+/*
+ * Breaks any long edges in the graph into short segments that span 1 layer
+ * each. This operation is undoable with the denormalize function.
+ *
+ * Pre-conditions:
+ *
+ *    1. The input graph is a DAG.
+ *    2. Each node in the graph has a "rank" property.
+ *
+ * Post-condition:
+ *
+ *    1. All edges in the graph have a length of 1.
+ *    2. Dummy nodes are added where edges have been split into segments.
+ *    3. The graph is augmented with a "dummyChains" attribute which contains
+ *       the first dummy in each chain of dummy nodes produced.
+ */
+function run(g) {
+  g.graph().dummyChains = [];
+  _.each(g.edges(), function(edge) { normalizeEdge(g, edge); });
+}
+
+function normalizeEdge(g, e) {
+  var v = e.v,
+      vRank = g.node(v).rank,
+      w = e.w,
+      wRank = g.node(w).rank,
+      name = e.name,
+      edgeLabel = g.edge(e),
+      labelRank = edgeLabel.labelRank;
+
+  if (wRank === vRank + 1) return;
+
+  g.removeEdge(e);
+
+  var dummy, attrs, i;
+  for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
+    edgeLabel.points = [];
+    attrs = {
+      width: 0, height: 0,
+      edgeLabel: edgeLabel, edgeObj: e,
+      rank: vRank
+    };
+    dummy = util.addDummyNode(g, "edge", attrs, "_d");
+    if (vRank === labelRank) {
+      attrs.width = edgeLabel.width;
+      attrs.height = edgeLabel.height;
+      attrs.dummy = "edge-label";
+      attrs.labelpos = edgeLabel.labelpos;
+    }
+    g.setEdge(v, dummy, { weight: edgeLabel.weight }, name);
+    if (i === 0) {
+      g.graph().dummyChains.push(dummy);
+    }
+    v = dummy;
+  }
+
+  g.setEdge(v, w, { weight: edgeLabel.weight }, name);
+}
+
+function undo(g) {
+  _.each(g.graph().dummyChains, function(v) {
+    var node = g.node(v),
+        origLabel = node.edgeLabel,
+        w;
+    g.setEdge(node.edgeObj, origLabel);
+    while (node.dummy) {
+      w = g.successors(v)[0];
+      g.removeNode(v);
+      origLabel.points.push({ x: node.x, y: node.y });
+      if (node.dummy === "edge-label") {
+        origLabel.x = node.x;
+        origLabel.y = node.y;
+        origLabel.width = node.width;
+        origLabel.height = node.height;
+      }
+      v = w;
+      node = g.node(v);
+    }
+  });
+}
diff --git a/debian/missing-source/dagre/lib/order/add-subgraph-constraints.js b/debian/missing-source/dagre/lib/order/add-subgraph-constraints.js
new file mode 100644
index 0000000..a52bf5f
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/add-subgraph-constraints.js
@@ -0,0 +1,53 @@
+var _ = require("../lodash");
+
+module.exports = addSubgraphConstraints;
+
+function addSubgraphConstraints(g, cg, vs) {
+  var prev = {},
+      rootPrev;
+
+  _.each(vs, function(v) {
+    var child = g.parent(v),
+        parent,
+        prevChild;
+    while (child) {
+      parent = g.parent(child);
+      if (parent) {
+        prevChild = prev[parent];
+        prev[parent] = child;
+      } else {
+        prevChild = rootPrev;
+        rootPrev = child;
+      }
+      if (prevChild && prevChild !== child) {
+        cg.setEdge(prevChild, child);
+        return;
+      }
+      child = parent;
+    }
+  });
+
+  /*
+  function dfs(v) {
+    var children = v ? g.children(v) : g.children();
+    if (children.length) {
+      var min = Number.POSITIVE_INFINITY,
+          subgraphs = [];
+      _.each(children, function(child) {
+        var childMin = dfs(child);
+        if (g.children(child).length) {
+          subgraphs.push({ v: child, order: childMin });
+        }
+        min = Math.min(min, childMin);
+      });
+      _.reduce(_.sortBy(subgraphs, "order"), function(prev, curr) {
+        cg.setEdge(prev.v, curr.v);
+        return curr;
+      });
+      return min;
+    }
+    return g.node(v).order;
+  }
+  dfs(undefined);
+  */
+}
diff --git a/debian/missing-source/dagre/lib/order/barycenter.js b/debian/missing-source/dagre/lib/order/barycenter.js
new file mode 100644
index 0000000..d3d3484
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/barycenter.js
@@ -0,0 +1,28 @@
+var _ = require("../lodash");
+
+module.exports = barycenter;
+
+function barycenter(g, movable) {
+  return _.map(movable, function(v) {
+    var inV = g.inEdges(v);
+    if (!inV.length) {
+      return { v: v };
+    } else {
+      var result = _.reduce(inV, function(acc, e) {
+        var edge = g.edge(e),
+            nodeU = g.node(e.v);
+        return {
+          sum: acc.sum + (edge.weight * nodeU.order),
+          weight: acc.weight + edge.weight
+        };
+      }, { sum: 0, weight: 0 });
+
+      return {
+        v: v,
+        barycenter: result.sum / result.weight,
+        weight: result.weight
+      };
+    }
+  });
+}
+
diff --git a/debian/missing-source/dagre/lib/order/build-layer-graph.js b/debian/missing-source/dagre/lib/order/build-layer-graph.js
new file mode 100644
index 0000000..3a9e418
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/build-layer-graph.js
@@ -0,0 +1,73 @@
+var _ = require("../lodash"),
+    Graph = require("../graphlib").Graph;
+
+module.exports = buildLayerGraph;
+
+/*
+ * Constructs a graph that can be used to sort a layer of nodes. The graph will
+ * contain all base and subgraph nodes from the request layer in their original
+ * hierarchy and any edges that are incident on these nodes and are of the type
+ * requested by the "relationship" parameter.
+ *
+ * Nodes from the requested rank that do not have parents are assigned a root
+ * node in the output graph, which is set in the root graph attribute. This
+ * makes it easy to walk the hierarchy of movable nodes during ordering.
+ *
+ * Pre-conditions:
+ *
+ *    1. Input graph is a DAG
+ *    2. Base nodes in the input graph have a rank attribute
+ *    3. Subgraph nodes in the input graph has minRank and maxRank attributes
+ *    4. Edges have an assigned weight
+ *
+ * Post-conditions:
+ *
+ *    1. Output graph has all nodes in the movable rank with preserved
+ *       hierarchy.
+ *    2. Root nodes in the movable layer are made children of the node
+ *       indicated by the root attribute of the graph.
+ *    3. Non-movable nodes incident on movable nodes, selected by the
+ *       relationship parameter, are included in the graph (without hierarchy).
+ *    4. Edges incident on movable nodes, selected by the relationship
+ *       parameter, are added to the output graph.
+ *    5. The weights for copied edges are aggregated as need, since the output
+ *       graph is not a multi-graph.
+ */
+function buildLayerGraph(g, rank, relationship) {
+  var root = createRootNode(g),
+      result = new Graph({ compound: true }).setGraph({ root: root })
+                  .setDefaultNodeLabel(function(v) { return g.node(v); });
+
+  _.each(g.nodes(), function(v) {
+    var node = g.node(v),
+        parent = g.parent(v);
+
+    if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
+      result.setNode(v);
+      result.setParent(v, parent || root);
+
+      // This assumes we have only short edges!
+      _.each(g[relationship](v), function(e) {
+        var u = e.v === v ? e.w : e.v,
+            edge = result.edge(u, v),
+            weight = !_.isUndefined(edge) ? edge.weight : 0;
+        result.setEdge(u, v, { weight: g.edge(e).weight + weight });
+      });
+
+      if (_.has(node, "minRank")) {
+        result.setNode(v, {
+          borderLeft: node.borderLeft[rank],
+          borderRight: node.borderRight[rank]
+        });
+      }
+    }
+  });
+
+  return result;
+}
+
+function createRootNode(g) {
+  var v;
+  while (g.hasNode((v = _.uniqueId("_root"))));
+  return v;
+}
diff --git a/debian/missing-source/dagre/lib/order/cross-count.js b/debian/missing-source/dagre/lib/order/cross-count.js
new file mode 100644
index 0000000..4eff1f2
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/cross-count.js
@@ -0,0 +1,70 @@
+"use strict";
+
+var _ = require("../lodash");
+
+module.exports = crossCount;
+
+/*
+ * A function that takes a layering (an array of layers, each with an array of
+ * ordererd nodes) and a graph and returns a weighted crossing count.
+ *
+ * Pre-conditions:
+ *
+ *    1. Input graph must be simple (not a multigraph), directed, and include
+ *       only simple edges.
+ *    2. Edges in the input graph must have assigned weights.
+ *
+ * Post-conditions:
+ *
+ *    1. The graph and layering matrix are left unchanged.
+ *
+ * This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
+ */
+function crossCount(g, layering) {
+  var cc = 0;
+  for (var i = 1; i < layering.length; ++i) {
+    cc += twoLayerCrossCount(g, layering[i-1], layering[i]);
+  }
+  return cc;
+}
+
+function twoLayerCrossCount(g, northLayer, southLayer) {
+  // Sort all of the edges between the north and south layers by their position
+  // in the north layer and then the south. Map these edges to the position of
+  // their head in the south layer.
+  var southPos = _.zipObject(southLayer,
+                             _.map(southLayer, function (v, i) { return i; }));
+  var southEntries = _.flatten(_.map(northLayer, function(v) {
+    return _.chain(g.outEdges(v))
+            .map(function(e) {
+              return { pos: southPos[e.w], weight: g.edge(e).weight };
+            })
+            .sortBy("pos")
+            .value();
+  }), true);
+
+  // Build the accumulator tree
+  var firstIndex = 1;
+  while (firstIndex < southLayer.length) firstIndex <<= 1;
+  var treeSize = 2 * firstIndex - 1;
+  firstIndex -= 1;
+  var tree = _.map(new Array(treeSize), function() { return 0; });
+
+  // Calculate the weighted crossings
+  var cc = 0;
+  _.each(southEntries.forEach(function(entry) {
+    var index = entry.pos + firstIndex;
+    tree[index] += entry.weight;
+    var weightSum = 0;
+    while (index > 0) {
+      if (index % 2) {
+        weightSum += tree[index + 1];
+      }
+      index = (index - 1) >> 1;
+      tree[index] += entry.weight;
+    }
+    cc += entry.weight * weightSum;
+  }));
+
+  return cc;
+}
diff --git a/debian/missing-source/dagre/lib/order/index.js b/debian/missing-source/dagre/lib/order/index.js
new file mode 100644
index 0000000..7e61d54
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/index.js
@@ -0,0 +1,79 @@
+"use strict";
+
+var _ = require("../lodash"),
+    initOrder = require("./init-order"),
+    crossCount = require("./cross-count"),
+    sortSubgraph = require("./sort-subgraph"),
+    buildLayerGraph = require("./build-layer-graph"),
+    addSubgraphConstraints = require("./add-subgraph-constraints"),
+    Graph = require("../graphlib").Graph,
+    util = require("../util");
+
+module.exports = order;
+
+/*
+ * Applies heuristics to minimize edge crossings in the graph and sets the best
+ * order solution as an order attribute on each node.
+ *
+ * Pre-conditions:
+ *
+ *    1. Graph must be DAG
+ *    2. Graph nodes must be objects with a "rank" attribute
+ *    3. Graph edges must have the "weight" attribute
+ *
+ * Post-conditions:
+ *
+ *    1. Graph nodes will have an "order" attribute based on the results of the
+ *       algorithm.
+ */
+function order(g) {
+  var maxRank = util.maxRank(g),
+      downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank + 1), "inEdges"),
+      upLayerGraphs = buildLayerGraphs(g, _.range(maxRank - 1, -1, -1), "outEdges");
+
+  var layering = initOrder(g);
+  assignOrder(g, layering);
+
+  var bestCC = Number.POSITIVE_INFINITY,
+      best;
+
+  for (var i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
+    sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
+
+    layering = util.buildLayerMatrix(g);
+    var cc = crossCount(g, layering);
+    if (cc < bestCC) {
+      lastBest = 0;
+      best = _.cloneDeep(layering);
+      bestCC = cc;
+    }
+  }
+
+  assignOrder(g, best);
+}
+
+function buildLayerGraphs(g, ranks, relationship) {
+  return _.map(ranks, function(rank) {
+    return buildLayerGraph(g, rank, relationship);
+  });
+}
+
+function sweepLayerGraphs(layerGraphs, biasRight) {
+  var cg = new Graph();
+  _.each(layerGraphs, function(lg) {
+    var root = lg.graph().root;
+    var sorted = sortSubgraph(lg, root, cg, biasRight);
+    _.each(sorted.vs, function(v, i) {
+      lg.node(v).order = i;
+    });
+    addSubgraphConstraints(lg, cg, sorted.vs);
+  });
+}
+
+function assignOrder(g, layering) {
+  _.each(layering, function(layer) {
+    _.each(layer, function(v, i) {
+      g.node(v).order = i;
+    });
+  });
+}
diff --git a/debian/missing-source/dagre/lib/order/init-order.js b/debian/missing-source/dagre/lib/order/init-order.js
new file mode 100644
index 0000000..530a84b
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/init-order.js
@@ -0,0 +1,38 @@
+"use strict";
+
+var _ = require("../lodash");
+
+module.exports = initOrder;
+
+/*
+ * Assigns an initial order value for each node by performing a DFS search
+ * starting from nodes in the first rank. Nodes are assigned an order in their
+ * rank as they are first visited.
+ *
+ * This approach comes from Gansner, et al., "A Technique for Drawing Directed
+ * Graphs."
+ *
+ * Returns a layering matrix with an array per layer and each layer sorted by
+ * the order of its nodes.
+ */
+function initOrder(g) {
+  var visited = {},
+      simpleNodes = _.filter(g.nodes(), function(v) {
+        return !g.children(v).length;
+      }),
+      maxRank = _.max(_.map(simpleNodes, function(v) { return g.node(v).rank; })),
+      layers = _.map(_.range(maxRank + 1), function() { return []; });
+
+  function dfs(v) {
+    if (_.has(visited, v)) return;
+    visited[v] = true;
+    var node = g.node(v);
+    layers[node.rank].push(v);
+    _.each(g.successors(v), dfs);
+  }
+
+  var orderedVs = _.sortBy(simpleNodes, function(v) { return g.node(v).rank; });
+  _.each(orderedVs, dfs);
+
+  return layers;
+}
diff --git a/debian/missing-source/dagre/lib/order/resolve-conflicts.js b/debian/missing-source/dagre/lib/order/resolve-conflicts.js
new file mode 100644
index 0000000..9efc0a0
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/resolve-conflicts.js
@@ -0,0 +1,123 @@
+"use strict";
+
+var _ = require("../lodash");
+
+module.exports = resolveConflicts;
+
+/*
+ * Given a list of entries of the form {v, barycenter, weight} and a
+ * constraint graph this function will resolve any conflicts between the
+ * constraint graph and the barycenters for the entries. If the barycenters for
+ * an entry would violate a constraint in the constraint graph then we coalesce
+ * the nodes in the conflict into a new node that respects the contraint and
+ * aggregates barycenter and weight information.
+ *
+ * This implementation is based on the description in Forster, "A Fast and
+ * Simple Hueristic for Constrained Two-Level Crossing Reduction," thought it
+ * differs in some specific details.
+ *
+ * Pre-conditions:
+ *
+ *    1. Each entry has the form {v, barycenter, weight}, or if the node has
+ *       no barycenter, then {v}.
+ *
+ * Returns:
+ *
+ *    A new list of entries of the form {vs, i, barycenter, weight}. The list
+ *    `vs` may either be a singleton or it may be an aggregation of nodes
+ *    ordered such that they do not violate constraints from the constraint
+ *    graph. The property `i` is the lowest original index of any of the
+ *    elements in `vs`.
+ */
+function resolveConflicts(entries, cg) {
+  var mappedEntries = {};
+  _.each(entries, function(entry, i) {
+    var tmp = mappedEntries[entry.v] = {
+      indegree: 0,
+      "in": [],
+      out: [],
+      vs: [entry.v],
+      i: i
+    };
+    if (!_.isUndefined(entry.barycenter)) {
+      tmp.barycenter = entry.barycenter;
+      tmp.weight = entry.weight;
+    }
+  });
+
+  _.each(cg.edges(), function(e) {
+    var entryV = mappedEntries[e.v],
+        entryW = mappedEntries[e.w];
+    if (!_.isUndefined(entryV) && !_.isUndefined(entryW)) {
+      entryW.indegree++;
+      entryV.out.push(mappedEntries[e.w]);
+    }
+  });
+
+  var sourceSet = _.filter(mappedEntries, function(entry) {
+    return !entry.indegree;
+  });
+
+  return doResolveConflicts(sourceSet);
+}
+
+function doResolveConflicts(sourceSet) {
+  var entries = [];
+
+  function handleIn(vEntry) {
+    return function(uEntry) {
+      if (uEntry.merged) {
+        return;
+      }
+      if (_.isUndefined(uEntry.barycenter) ||
+          _.isUndefined(vEntry.barycenter) ||
+          uEntry.barycenter >= vEntry.barycenter) {
+        mergeEntries(vEntry, uEntry);
+      }
+    };
+  }
+
+  function handleOut(vEntry) {
+    return function(wEntry) {
+      wEntry["in"].push(vEntry);
+      if (--wEntry.indegree === 0) {
+        sourceSet.push(wEntry);
+      }
+    };
+  }
+
+  while (sourceSet.length) {
+    var entry = sourceSet.pop();
+    entries.push(entry);
+    _.each(entry["in"].reverse(), handleIn(entry));
+    _.each(entry.out, handleOut(entry));
+  }
+
+  return _.chain(entries)
+          .filter(function(entry) { return !entry.merged; })
+          .map(function(entry) {
+            return _.pick(entry, ["vs", "i", "barycenter", "weight"]);
+          })
+          .value();
+}
+
+function mergeEntries(target, source) {
+  var sum = 0,
+      weight = 0;
+
+  if (target.weight) {
+    sum += target.barycenter * target.weight;
+    weight += target.weight;
+  }
+
+  if (source.weight) {
+    sum += source.barycenter * source.weight;
+    weight += source.weight;
+  }
+
+  target.vs = source.vs.concat(target.vs);
+  target.barycenter = sum / weight;
+  target.weight = weight;
+  target.i = Math.min(source.i, target.i);
+  source.merged = true;
+}
diff --git a/debian/missing-source/dagre/lib/order/sort-subgraph.js b/debian/missing-source/dagre/lib/order/sort-subgraph.js
new file mode 100644
index 0000000..4727358
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/sort-subgraph.js
@@ -0,0 +1,76 @@
+var _ = require("../lodash"),
+    barycenter = require("./barycenter"),
+    resolveConflicts = require("./resolve-conflicts"),
+    sort = require("./sort");
+
+module.exports = sortSubgraph;
+
+function sortSubgraph(g, v, cg, biasRight) {
+  var movable = g.children(v),
+      node = g.node(v),
+      bl = node ? node.borderLeft : undefined,
+      br = node ? node.borderRight: undefined,
+      subgraphs = {};
+
+  if (bl) {
+    movable = _.filter(movable, function(w) {
+      return w !== bl && w !== br;
+    });
+  }
+
+  var barycenters = barycenter(g, movable);
+  _.each(barycenters, function(entry) {
+    if (g.children(entry.v).length) {
+      var subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
+      subgraphs[entry.v] = subgraphResult;
+      if (_.has(subgraphResult, "barycenter")) {
+        mergeBarycenters(entry, subgraphResult);
+      }
+    }
+  });
+
+  var entries = resolveConflicts(barycenters, cg);
+  expandSubgraphs(entries, subgraphs);
+
+  var result = sort(entries, biasRight);
+
+  if (bl) {
+    result.vs = _.flatten([bl, result.vs, br], true);
+    if (g.predecessors(bl).length) {
+      var blPred = g.node(g.predecessors(bl)[0]),
+          brPred = g.node(g.predecessors(br)[0]);
+      if (!_.has(result, "barycenter")) {
+        result.barycenter = 0;
+        result.weight = 0;
+      }
+      result.barycenter = (result.barycenter * result.weight +
+                           blPred.order + brPred.order) / (result.weight + 2);
+      result.weight += 2;
+    }
+  }
+
+  return result;
+}
+
+function expandSubgraphs(entries, subgraphs) {
+  _.each(entries, function(entry) {
+    entry.vs = _.flatten(entry.vs.map(function(v) {
+      if (subgraphs[v]) {
+        return subgraphs[v].vs;
+      }
+      return v;
+    }), true);
+  });
+}
+
+function mergeBarycenters(target, other) {
+  if (!_.isUndefined(target.barycenter)) {
+    target.barycenter = (target.barycenter * target.weight +
+                         other.barycenter * other.weight) /
+                        (target.weight + other.weight);
+    target.weight += other.weight;
+  } else {
+    target.barycenter = other.barycenter;
+    target.weight = other.weight;
+  }
+}
diff --git a/debian/missing-source/dagre/lib/order/sort.js b/debian/missing-source/dagre/lib/order/sort.js
new file mode 100644
index 0000000..b8ea6f1
--- /dev/null
+++ b/debian/missing-source/dagre/lib/order/sort.js
@@ -0,0 +1,57 @@
+var _ = require("../lodash"),
+    util = require("../util");
+
+module.exports = sort;
+
+function sort(entries, biasRight) {
+  var parts = util.partition(entries, function(entry) {
+    return _.has(entry, "barycenter");
+  });
+  var sortable = parts.lhs,
+      unsortable = _.sortBy(parts.rhs, function(entry) { return -entry.i; }),
+      vs = [],
+      sum = 0,
+      weight = 0,
+      vsIndex = 0;
+
+  sortable.sort(compareWithBias(!!biasRight));
+
+  vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
+
+  _.each(sortable, function (entry) {
+    vsIndex += entry.vs.length;
+    vs.push(entry.vs);
+    sum += entry.barycenter * entry.weight;
+    weight += entry.weight;
+    vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
+  });
+
+  var result = { vs: _.flatten(vs, true) };
+  if (weight) {
+    result.barycenter = sum / weight;
+    result.weight = weight;
+  }
+  return result;
+}
+
+function consumeUnsortable(vs, unsortable, index) {
+  var last;
+  while (unsortable.length && (last = _.last(unsortable)).i <= index) {
+    unsortable.pop();
+    vs.push(last.vs);
+    index++;
+  }
+  return index;
+}
+
+function compareWithBias(bias) {
+  return function(entryV, entryW) {
+    if (entryV.barycenter < entryW.barycenter) {
+      return -1;
+    } else if (entryV.barycenter > entryW.barycenter) {
+      return 1;
+    }
+
+    return !bias ? entryV.i - entryW.i : entryW.i - entryV.i;
+  };
+}
diff --git a/debian/missing-source/dagre/lib/parent-dummy-chains.js b/debian/missing-source/dagre/lib/parent-dummy-chains.js
new file mode 100644
index 0000000..b651692
--- /dev/null
+++ b/debian/missing-source/dagre/lib/parent-dummy-chains.js
@@ -0,0 +1,86 @@
+var _ = require("./lodash");
+
+module.exports = parentDummyChains;
+
+function parentDummyChains(g) {
+  var postorderNums = postorder(g);
+
+  _.each(g.graph().dummyChains, function(v) {
+    var node = g.node(v),
+        edgeObj = node.edgeObj,
+        pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w),
+        path = pathData.path,
+        lca = pathData.lca,
+        pathIdx = 0,
+        pathV = path[pathIdx],
+        ascending = true;
+
+    while (v !== edgeObj.w) {
+      node = g.node(v);
+
+      if (ascending) {
+        while ((pathV = path[pathIdx]) !== lca &&
+               g.node(pathV).maxRank < node.rank) {
+          pathIdx++;
+        }
+
+        if (pathV === lca) {
+          ascending = false;
+        }
+      }
+
+      if (!ascending) {
+        while (pathIdx < path.length - 1 &&
+               g.node(pathV = path[pathIdx + 1]).minRank <= node.rank) {
+          pathIdx++;
+        }
+        pathV = path[pathIdx];
+      }
+
+      g.setParent(v, pathV);
+      v = g.successors(v)[0];
+    }
+  });
+}
+
+// Find a path from v to w through the lowest common ancestor (LCA). Return the
+// full path and the LCA.
+function findPath(g, postorderNums, v, w) {
+  var vPath = [],
+      wPath = [],
+      low = Math.min(postorderNums[v].low, postorderNums[w].low),
+      lim = Math.max(postorderNums[v].lim, postorderNums[w].lim),
+      parent,
+      lca;
+
+  // Traverse up from v to find the LCA
+  parent = v;
+  do {
+    parent = g.parent(parent);
+    vPath.push(parent);
+  } while (parent &&
+           (postorderNums[parent].low > low || lim > postorderNums[parent].lim));
+  lca = parent;
+
+  // Traverse from w to LCA
+  parent = w;
+  while ((parent = g.parent(parent)) !== lca) {
+    wPath.push(parent);
+  }
+
+  return { path: vPath.concat(wPath.reverse()), lca: lca };
+}
+
+function postorder(g) {
+  var result = {},
+      lim = 0;
+
+  function dfs(v) {
+    var low = lim;
+    _.each(g.children(v), dfs);
+    result[v] = { low: low, lim: lim++ };
+  }
+  _.each(g.children(), dfs);
+
+  return result;
+}
diff --git a/debian/missing-source/dagre/lib/position/bk.js b/debian/missing-source/dagre/lib/position/bk.js
new file mode 100644
index 0000000..131cec4
--- /dev/null
+++ b/debian/missing-source/dagre/lib/position/bk.js
@@ -0,0 +1,398 @@
+"use strict";
+
+var _ = require("../lodash"),
+    Graph = require("../graphlib").Graph,
+    util = require("../util");
+
+/*
+ * This module provides coordinate assignment based on Brandes and Köpf, "Fast
+ * and Simple Horizontal Coordinate Assignment."
+ */
+
+module.exports = {
+  positionX: positionX,
+  findType1Conflicts: findType1Conflicts,
+  findType2Conflicts: findType2Conflicts,
+  addConflict: addConflict,
+  hasConflict: hasConflict,
+  verticalAlignment: verticalAlignment,
+  horizontalCompaction: horizontalCompaction,
+  alignCoordinates: alignCoordinates,
+  findSmallestWidthAlignment: findSmallestWidthAlignment,
+  balance: balance
+};
+
+/*
+ * Marks all edges in the graph with a type-1 conflict with the "type1Conflict"
+ * property. A type-1 conflict is one where a non-inner segment crosses an
+ * inner segment. An inner segment is an edge with both incident nodes marked
+ * with the "dummy" property.
+ *
+ * This algorithm scans layer by layer, starting with the second, for type-1
+ * conflicts between the current layer and the previous layer. For each layer
+ * it scans the nodes from left to right until it reaches one that is incident
+ * on an inner segment. It then scans predecessors to determine if they have
+ * edges that cross that inner segment. At the end a final scan is done for all
+ * nodes on the current rank to see if they cross the last visited inner
+ * segment.
+ *
+ * This algorithm (safely) assumes that a dummy node will only be incident on a
+ * single node in the layers being scanned.
+ */
+function findType1Conflicts(g, layering) {
+  var conflicts = {};
+
+  function visitLayer(prevLayer, layer) {
+    var
+      // last visited node in the previous layer that is incident on an inner
+      // segment.
+      k0 = 0,
+      // Tracks the last node in this layer scanned for crossings with a type-1
+      // segment.
+      scanPos = 0,
+      prevLayerLength = prevLayer.length,
+      lastNode = _.last(layer);
+
+    _.each(layer, function(v, i) {
+      var w = findOtherInnerSegmentNode(g, v),
+          k1 = w ? g.node(w).order : prevLayerLength;
+
+      if (w || v === lastNode) {
+        _.each(layer.slice(scanPos, i +1), function(scanNode) {
+          _.each(g.predecessors(scanNode), function(u) {
+            var uLabel = g.node(u),
+                uPos = uLabel.order;
+            if ((uPos < k0 || k1 < uPos) &&
+                !(uLabel.dummy && g.node(scanNode).dummy)) {
+              addConflict(conflicts, u, scanNode);
+            }
+          });
+        });
+        scanPos = i + 1;
+        k0 = k1;
+      }
+    });
+
+    return layer;
+  }
+
+  _.reduce(layering, visitLayer);
+  return conflicts;
+}
+
+function findType2Conflicts(g, layering) {
+  var conflicts = {};
+
+  function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
+    var v;
+    _.each(_.range(southPos, southEnd), function(i) {
+      v = south[i];
+      if (g.node(v).dummy) {
+        _.each(g.predecessors(v), function(u) {
+          var uNode = g.node(u);
+          if (uNode.dummy &&
+              (uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
+            addConflict(conflicts, u, v);
+          }
+        });
+      }
+    });
+  }
+
+
+  function visitLayer(north, south) {
+    var prevNorthPos = -1,
+        nextNorthPos,
+        southPos = 0;
+
+    _.each(south, function(v, southLookahead) {
+      if (g.node(v).dummy === "border") {
+        var predecessors = g.predecessors(v);
+        if (predecessors.length) {
+          nextNorthPos = g.node(predecessors[0]).order;
+          scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
+          southPos = southLookahead;
+          prevNorthPos = nextNorthPos;
+        }
+      }
+      scan(south, southPos, south.length, nextNorthPos, north.length);
+    });
+
+    return south;
+  }
+
+  _.reduce(layering, visitLayer);
+  return conflicts;
+}
+
+function findOtherInnerSegmentNode(g, v) {
+  if (g.node(v).dummy) {
+    return _.find(g.predecessors(v), function(u) {
+      return g.node(u).dummy;
+    });
+  }
+}
+
+function addConflict(conflicts, v, w) {
+  if (v > w) {
+    var tmp = v;
+    v = w;
+    w = tmp;
+  }
+
+  var conflictsV = conflicts[v];
+  if (!conflictsV) {
+    conflicts[v] = conflictsV = {};
+  }
+  conflictsV[w] = true;
+}
+
+function hasConflict(conflicts, v, w) {
+  if (v > w) {
+    var tmp = v;
+    v = w;
+    w = tmp;
+  }
+  return _.has(conflicts[v], w);
+}
+
+/*
+ * Try to align nodes into vertical "blocks" where possible. This algorithm
+ * attempts to align a node with one of its median neighbors. If the edge
+ * connecting a neighbor is a type-1 conflict then we ignore that possibility.
+ * If a previous node has already formed a block with a node after the node
+ * we're trying to form a block with, we also ignore that possibility - our
+ * blocks would be split in that scenario.
+ */
+function verticalAlignment(g, layering, conflicts, neighborFn) {
+  var root = {},
+      align = {},
+      pos = {};
+
+  // We cache the position here based on the layering because the graph and
+  // layering may be out of sync. The layering matrix is manipulated to
+  // generate different extreme alignments.
+  _.each(layering, function(layer) {
+    _.each(layer, function(v, order) {
+      root[v] = v;
+      align[v] = v;
+      pos[v] = order;
+    });
+  });
+
+  _.each(layering, function(layer) {
+    var prevIdx = -1;
+    _.each(layer, function(v) {
+      var ws = neighborFn(v);
+      if (ws.length) {
+        ws = _.sortBy(ws, function(w) { return pos[w]; });
+        var mp = (ws.length - 1) / 2;
+        for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
+          var w = ws[i];
+          if (align[v] === v &&
+              prevIdx < pos[w] &&
+              !hasConflict(conflicts, v, w)) {
+            align[w] = v;
+            align[v] = root[v] = root[w];
+            prevIdx = pos[w];
+          }
+        }
+      }
+    });
+  });
+
+  return { root: root, align: align };
+}
+
+function horizontalCompaction(g, layering, root, align, reverseSep) {
+  // This portion of the algorithm differs from BK due to a number of problems.
+  // Instead of their algorithm we construct a new block graph and do two
+  // sweeps. The first sweep places blocks with the smallest possible
+  // coordinates. The second sweep removes unused space by moving blocks to the
+  // greatest coordinates without violating separation.
+  var xs = {},
+      blockG = buildBlockGraph(g, layering, root, reverseSep);
+
+  // First pass, assign smallest coordinates via DFS
+  var visited = {};
+  function pass1(v) {
+    if (!_.has(visited, v)) {
+      visited[v] = true;
+      xs[v] = _.reduce(blockG.inEdges(v), function(max, e) {
+        pass1(e.v);
+        return Math.max(max, xs[e.v] + blockG.edge(e));
+      }, 0);
+    }
+  }
+  _.each(blockG.nodes(), pass1);
+
+  var borderType = reverseSep ? "borderLeft" : "borderRight";
+  function pass2(v) {
+    if (visited[v] !== 2) {
+      visited[v]++;
+      var node = g.node(v);
+      var min = _.reduce(blockG.outEdges(v), function(min, e) {
+        pass2(e.w);
+        return Math.min(min, xs[e.w] - blockG.edge(e));
+      }, Number.POSITIVE_INFINITY);
+      if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
+        xs[v] = Math.max(xs[v], min);
+      }
+    }
+  }
+  _.each(blockG.nodes(), pass2);
+
+  // Assign x coordinates to all nodes
+  _.each(align, function(v) {
+    xs[v] = xs[root[v]];
+  });
+
+  return xs;
+}
+
+
+function buildBlockGraph(g, layering, root, reverseSep) {
+  var blockGraph = new Graph(),
+      graphLabel = g.graph(),
+      sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
+
+  _.each(layering, function(layer) {
+    var u;
+    _.each(layer, function(v) {
+      var vRoot = root[v];
+      blockGraph.setNode(vRoot);
+      if (u) {
+        var uRoot = root[u],
+            prevMax = blockGraph.edge(uRoot, vRoot);
+        blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
+      }
+      u = v;
+    });
+  });
+
+  return blockGraph;
+}
+
+/*
+ * Returns the alignment that has the smallest width of the given alignments.
+ */
+function findSmallestWidthAlignment(g, xss) {
+  return _.min(xss, function(xs) {
+    var min = _.min(xs, function(x, v) { return x - width(g, v) / 2; }),
+        max = _.max(xs, function(x, v) { return x + width(g, v) / 2; });
+    return max - min;
+  });
+}
+
+/*
+ * Align the coordinates of each of the layout alignments such that
+ * left-biased alignments have their minimum coordinate at the same point as
+ * the minimum coordinate of the smallest width alignment and right-biased
+ * alignments have their maximum coordinate at the same point as the maximum
+ * coordinate of the smallest width alignment.
+ */
+function alignCoordinates(xss, alignTo) {
+  var alignToMin = _.min(alignTo),
+      alignToMax = _.max(alignTo);
+
+  _.each(["u", "d"], function(vert) {
+    _.each(["l", "r"], function(horiz) {
+      var alignment = vert + horiz,
+          xs = xss[alignment],
+          delta;
+      if (xs === alignTo) return;
+
+      delta = horiz === "l" ? alignToMin - _.min(xs) : alignToMax - _.max(xs);
+
+      if (delta) {
+        xss[alignment] = _.mapValues(xs, function(x) { return x + delta; });
+      }
+    });
+  });
+}
+
+function balance(xss, align) {
+  return _.mapValues(xss.ul, function(ignore, v) {
+    if (align) {
+      return xss[align.toLowerCase()][v];
+    } else {
+      var xs = _.sortBy(_.pluck(xss, v));
+      return (xs[1] + xs[2]) / 2;
+    }
+  });
+}
+
+function positionX(g) {
+  var layering = util.buildLayerMatrix(g),
+      conflicts = _.merge(findType1Conflicts(g, layering),
+                          findType2Conflicts(g, layering));
+
+  var xss = {},
+      adjustedLayering;
+  _.each(["u", "d"], function(vert) {
+    adjustedLayering = vert === "u" ? layering : _.values(layering).reverse();
+    _.each(["l", "r"], function(horiz) {
+      if (horiz === "r") {
+        adjustedLayering = _.map(adjustedLayering, function(inner) {
+          return _.values(inner).reverse();
+        });
+      }
+
+      var neighborFn = _.bind(vert === "u" ? g.predecessors : g.successors, g);
+      var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
+      var xs = horizontalCompaction(g, adjustedLayering,
+                                    align.root, align.align,
+                                    horiz === "r");
+      if (horiz === "r") {
+        xs = _.mapValues(xs, function(x) { return -x; });
+      }
+      xss[vert + horiz] = xs;
+    });
+  });
+
+  var smallestWidth = findSmallestWidthAlignment(g, xss);
+  alignCoordinates(xss, smallestWidth);
+  return balance(xss, g.graph().align);
+}
+
+function sep(nodeSep, edgeSep, reverseSep) {
+  return function(g, v, w) {
+    var vLabel = g.node(v),
+        wLabel = g.node(w),
+        sum = 0,
+        delta;
+
+    sum += vLabel.width / 2;
+    if (_.has(vLabel, "labelpos")) {
+      switch (vLabel.labelpos.toLowerCase()) {
+        case "l": delta = -vLabel.width / 2; break;
+        case "r": delta = vLabel.width / 2; break;
+      }
+    }
+    if (delta) {
+      sum += reverseSep ? delta : -delta;
+    }
+    delta = 0;
+
+    sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
+    sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
+
+    sum += wLabel.width / 2;
+    if (_.has(wLabel, "labelpos")) {
+      switch (wLabel.labelpos.toLowerCase()) {
+        case "l": delta = wLabel.width / 2; break;
+        case "r": delta = -wLabel.width / 2; break;
+      }
+    }
+    if (delta) {
+      sum += reverseSep ? delta : -delta;
+    }
+    delta = 0;
+
+    return sum;
+  };
+}
+
+function width(g, v) {
+  return g.node(v).width;
+}
diff --git a/debian/missing-source/dagre/lib/position/index.js b/debian/missing-source/dagre/lib/position/index.js
new file mode 100644
index 0000000..8e91eb3
--- /dev/null
+++ b/debian/missing-source/dagre/lib/position/index.js
@@ -0,0 +1,30 @@
+"use strict";
+
+var _ = require("../lodash"),
+    util = require("../util"),
+    positionX = require("./bk").positionX;
+
+module.exports = position;
+
+function position(g) {
+  g = util.asNonCompoundGraph(g);
+
+  positionY(g);
+  _.each(positionX(g), function(x, v) {
+    g.node(v).x = x;
+  });
+}
+
+function positionY(g) {
+  var layering = util.buildLayerMatrix(g),
+      rankSep = g.graph().ranksep,
+      prevY = 0;
+  _.each(layering, function(layer) {
+    var maxHeight = _.max(_.map(layer, function(v) { return g.node(v).height; }));
+    _.each(layer, function(v) {
+      g.node(v).y = prevY + maxHeight / 2;
+    });
+    prevY += maxHeight + rankSep;
+  });
+}
+
diff --git a/debian/missing-source/dagre/lib/rank/feasible-tree.js b/debian/missing-source/dagre/lib/rank/feasible-tree.js
new file mode 100644
index 0000000..a90a1bb
--- /dev/null
+++ b/debian/missing-source/dagre/lib/rank/feasible-tree.js
@@ -0,0 +1,89 @@
+"use strict";
+
+var _ = require("../lodash"),
+    Graph = require("../graphlib").Graph,
+    slack = require("./util").slack;
+
+module.exports = feasibleTree;
+
+/*
+ * Constructs a spanning tree with tight edges and adjusted the input node's
+ * ranks to achieve this. A tight edge is one that is has a length that matches
+ * its "minlen" attribute.
+ *
+ * The basic structure for this function is derived from Gansner, et al., "A
+ * Technique for Drawing Directed Graphs."
+ *
+ * Pre-conditions:
+ *
+ *    1. Graph must be a DAG.
+ *    2. Graph must be connected.
+ *    3. Graph must have at least one node.
+ *    5. Graph nodes must have been previously assigned a "rank" property that
+ *       respects the "minlen" property of incident edges.
+ *    6. Graph edges must have a "minlen" property.
+ *
+ * Post-conditions:
+ *
+ *    - Graph nodes will have their rank adjusted to ensure that all edges are
+ *      tight.
+ *
+ * Returns a tree (undirected graph) that is constructed using only "tight"
+ * edges.
+ */
+function feasibleTree(g) {
+  var t = new Graph({ directed: false });
+
+  // Choose arbitrary node from which to start our tree
+  var start = g.nodes()[0],
+      size = g.nodeCount();
+  t.setNode(start, {});
+
+  var edge, delta;
+  while (tightTree(t, g) < size) {
+    edge = findMinSlackEdge(t, g);
+    delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
+    shiftRanks(t, g, delta);
+  }
+
+  return t;
+}
+
+/*
+ * Finds a maximal tree of tight edges and returns the number of nodes in the
+ * tree.
+ */
+function tightTree(t, g) {
+  function dfs(v) {
+    _.each(g.nodeEdges(v), function(e) {
+      var edgeV = e.v,
+          w = (v === edgeV) ? e.w : edgeV;
+      if (!t.hasNode(w) && !slack(g, e)) {
+        t.setNode(w, {});
+        t.setEdge(v, w, {});
+        dfs(w);
+      }
+    });
+  }
+
+  _.each(t.nodes(), dfs);
+  return t.nodeCount();
+}
+
+/*
+ * Finds the edge with the smallest slack that is incident on tree and returns
+ * it.
+ */
+function findMinSlackEdge(t, g) {
+  return _.min(g.edges(), function(e) {
+    if (t.hasNode(e.v) !== t.hasNode(e.w)) {
+      return slack(g, e);
+    }
+  });
+}
+
+function shiftRanks(t, g, delta) {
+  _.each(t.nodes(), function(v) {
+    g.node(v).rank += delta;
+  });
+}
diff --git a/debian/missing-source/dagre/lib/rank/index.js b/debian/missing-source/dagre/lib/rank/index.js
new file mode 100644
index 0000000..9cf55dc
--- /dev/null
+++ b/debian/missing-source/dagre/lib/rank/index.js
@@ -0,0 +1,48 @@
+"use strict";
+
+var rankUtil = require("./util"),
+    longestPath = rankUtil.longestPath,
+    feasibleTree = require("./feasible-tree"),
+    networkSimplex = require("./network-simplex");
+
+module.exports = rank;
+
+/*
+ * Assigns a rank to each node in the input graph that respects the "minlen"
+ * constraint specified on edges between nodes.
+ *
+ * This basic structure is derived from Gansner, et al., "A Technique for
+ * Drawing Directed Graphs."
+ *
+ * Pre-conditions:
+ *
+ *    1. Graph must be a connected DAG
+ *    2. Graph nodes must be objects
+ *    3. Graph edges must have "weight" and "minlen" attributes
+ *
+ * Post-conditions:
+ *
+ *    1. Graph nodes will have a "rank" attribute based on the results of the
+ *       algorithm. Ranks can start at any index (including negative), we'll
+ *       fix them up later.
+ */
+function rank(g) {
+  switch(g.graph().ranker) {
+    case "network-simplex": networkSimplexRanker(g); break;
+    case "tight-tree": tightTreeRanker(g); break;
+    case "longest-path": longestPathRanker(g); break;
+    default: networkSimplexRanker(g);
+  }
+}
+
+// A fast and simple ranker, but results are far from optimal.
+var longestPathRanker = longestPath;
+
+function tightTreeRanker(g) {
+  longestPath(g);
+  feasibleTree(g);
+}
+
+function networkSimplexRanker(g) {
+  networkSimplex(g);
+}
diff --git a/debian/missing-source/dagre/lib/rank/network-simplex.js b/debian/missing-source/dagre/lib/rank/network-simplex.js
new file mode 100644
index 0000000..8d27843
--- /dev/null
+++ b/debian/missing-source/dagre/lib/rank/network-simplex.js
@@ -0,0 +1,234 @@
+"use strict";
+
+var _ = require("../lodash"),
+    feasibleTree = require("./feasible-tree"),
+    slack = require("./util").slack,
+    initRank = require("./util").longestPath,
+    preorder = require("../graphlib").alg.preorder,
+    postorder = require("../graphlib").alg.postorder,
+    simplify = require("../util").simplify;
+
+module.exports = networkSimplex;
+
+// Expose some internals for testing purposes
+networkSimplex.initLowLimValues = initLowLimValues;
+networkSimplex.initCutValues = initCutValues;
+networkSimplex.calcCutValue = calcCutValue;
+networkSimplex.leaveEdge = leaveEdge;
+networkSimplex.enterEdge = enterEdge;
+networkSimplex.exchangeEdges = exchangeEdges;
+
+/*
+ * The network simplex algorithm assigns ranks to each node in the input graph
+ * and iteratively improves the ranking to reduce the length of edges.
+ *
+ * Preconditions:
+ *
+ *    1. The input graph must be a DAG.
+ *    2. All nodes in the graph must have an object value.
+ *    3. All edges in the graph must have "minlen" and "weight" attributes.
+ *
+ * Postconditions:
+ *
+ *    1. All nodes in the graph will have an assigned "rank" attribute that has
+ *       been optimized by the network simplex algorithm. Ranks start at 0.
+ *
+ *
+ * A rough sketch of the algorithm is as follows:
+ *
+ *    1. Assign initial ranks to each node. We use the longest path algorithm,
+ *       which assigns ranks to the lowest position possible. In general this
+ *       leads to very wide bottom ranks and unnecessarily long edges.
+ *    2. Construct a feasible tight tree. A tight tree is one such that all
+ *       edges in the tree have no slack (difference between length of edge
+ *       and minlen for the edge). This by itself greatly improves the assigned
+ *       rankings by shorting edges.
+ *    3. Iteratively find edges that have negative cut values. Generally a
+ *       negative cut value indicates that the edge could be removed and a new
+ *       tree edge could be added to produce a more compact graph.
+ *
+ * Much of the algorithms here are derived from Gansner, et al., "A Technique
+ * for Drawing Directed Graphs." The structure of the file roughly follows the
+ * structure of the overall algorithm.
+ */
+function networkSimplex(g) {
+  g = simplify(g);
+  initRank(g);
+  var t = feasibleTree(g);
+  initLowLimValues(t);
+  initCutValues(t, g);
+
+  var e, f;
+  while ((e = leaveEdge(t))) {
+    f = enterEdge(t, g, e);
+    exchangeEdges(t, g, e, f);
+  }
+}
+
+/*
+ * Initializes cut values for all edges in the tree.
+ */
+function initCutValues(t, g) {
+  var vs = postorder(t, t.nodes());
+  vs = vs.slice(0, vs.length - 1);
+  _.each(vs, function(v) {
+    assignCutValue(t, g, v);
+  });
+}
+
+function assignCutValue(t, g, child) {
+  var childLab = t.node(child),
+      parent = childLab.parent;
+  t.edge(child, parent).cutvalue = calcCutValue(t, g, child);
+}
+
+/*
+ * Given the tight tree, its graph, and a child in the graph calculate and
+ * return the cut value for the edge between the child and its parent.
+ */
+function calcCutValue(t, g, child) {
+  var childLab = t.node(child),
+      parent = childLab.parent,
+      // True if the child is on the tail end of the edge in the directed graph
+      childIsTail = true,
+      // The graph's view of the tree edge we're inspecting
+      graphEdge = g.edge(child, parent),
+      // The accumulated cut value for the edge between this node and its parent
+      cutValue = 0;
+
+  if (!graphEdge) {
+    childIsTail = false;
+    graphEdge = g.edge(parent, child);
+  }
+
+  cutValue = graphEdge.weight;
+
+  _.each(g.nodeEdges(child), function(e) {
+    var isOutEdge = e.v === child,
+        other = isOutEdge ? e.w : e.v;
+
+    if (other !== parent) {
+      var pointsToHead = isOutEdge === childIsTail,
+          otherWeight = g.edge(e).weight;
+
+      cutValue += pointsToHead ? otherWeight : -otherWeight;
+      if (isTreeEdge(t, child, other)) {
+        var otherCutValue = t.edge(child, other).cutvalue;
+        cutValue += pointsToHead ? -otherCutValue : otherCutValue;
+      }
+    }
+  });
+
+  return cutValue;
+}
+
+function initLowLimValues(tree, root) {
+  if (arguments.length < 2) {
+    root = tree.nodes()[0];
+  }
+  dfsAssignLowLim(tree, {}, 1, root);
+}
+
+function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
+  var low = nextLim,
+      label = tree.node(v);
+
+  visited[v] = true;
+  _.each(tree.neighbors(v), function(w) {
+    if (!_.has(visited, w)) {
+      nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
+    }
+  });
+
+  label.low = low;
+  label.lim = nextLim++;
+  if (parent) {
+    label.parent = parent;
+  } else {
+    // TODO should be able to remove this when we incrementally update low lim
+    delete label.parent;
+  }
+
+  return nextLim;
+}
+
+function leaveEdge(tree) {
+  return _.find(tree.edges(), function(e) {
+    return tree.edge(e).cutvalue < 0;
+  });
+}
+
+function enterEdge(t, g, edge) {
+  var v = edge.v,
+      w = edge.w;
+
+  // For the rest of this function we assume that v is the tail and w is the
+  // head, so if we don't have this edge in the graph we should flip it to
+  // match the correct orientation.
+  if (!g.hasEdge(v, w)) {
+    v = edge.w;
+    w = edge.v;
+  }
+
+  var vLabel = t.node(v),
+      wLabel = t.node(w),
+      tailLabel = vLabel,
+      flip = false;
+
+  // If the root is in the tail of the edge then we need to flip the logic that
+  // checks for the head and tail nodes in the candidates function below.
+  if (vLabel.lim > wLabel.lim) {
+    tailLabel = wLabel;
+    flip = true;
+  }
+
+  var candidates = _.filter(g.edges(), function(edge) {
+    return flip === isDescendant(t, t.node(edge.v), tailLabel) &&
+           flip !== isDescendant(t, t.node(edge.w), tailLabel);
+  });
+
+  return _.min(candidates, function(edge) { return slack(g, edge); });
+}
+
+function exchangeEdges(t, g, e, f) {
+  var v = e.v,
+      w = e.w;
+  t.removeEdge(v, w);
+  t.setEdge(f.v, f.w, {});
+  initLowLimValues(t);
+  initCutValues(t, g);
+  updateRanks(t, g);
+}
+
+function updateRanks(t, g) {
+  var root = _.find(t.nodes(), function(v) { return !g.node(v).parent; }),
+      vs = preorder(t, root);
+  vs = vs.slice(1);
+  _.each(vs, function(v) {
+    var parent = t.node(v).parent,
+        edge = g.edge(v, parent),
+        flipped = false;
+
+    if (!edge) {
+      edge = g.edge(parent, v);
+      flipped = true;
+    }
+
+    g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen);
+  });
+}
+
+/*
+ * Returns true if the edge is in the tree.
+ */
+function isTreeEdge(tree, u, v) {
+  return tree.hasEdge(u, v);
+}
+
+/*
+ * Returns true if the specified node is descendant of the root node per the
+ * assigned low and lim attributes in the tree.
+ */
+function isDescendant(tree, vLabel, rootLabel) {
+  return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim;
+}
diff --git a/debian/missing-source/dagre/lib/rank/util.js b/debian/missing-source/dagre/lib/rank/util.js
new file mode 100644
index 0000000..05b6888
--- /dev/null
+++ b/debian/missing-source/dagre/lib/rank/util.js
@@ -0,0 +1,61 @@
+"use strict";
+
+var _ = require("../lodash");
+
+module.exports = {
+  longestPath: longestPath,
+  slack: slack
+};
+
+/*
+ * Initializes ranks for the input graph using the longest path algorithm. This
+ * algorithm scales well and is fast in practice, it yields rather poor
+ * solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
+ * ranks wide and leaving edges longer than necessary. However, due to its
+ * speed, this algorithm is good for getting an initial ranking that can be fed
+ * into other algorithms.
+ *
+ * This algorithm does not normalize layers because it will be used by other
+ * algorithms in most cases. If using this algorithm directly, be sure to
+ * run normalize at the end.
+ *
+ * Pre-conditions:
+ *
+ *    1. Input graph is a DAG.
+ *    2. Input graph node labels can be assigned properties.
+ *
+ * Post-conditions:
+ *
+ *    1. Each node will be assign an (unnormalized) "rank" property.
+ */
+function longestPath(g) {
+  var visited = {};
+
+  function dfs(v) {
+    var label = g.node(v);
+    if (_.has(visited, v)) {
+      return label.rank;
+    }
+    visited[v] = true;
+
+    var rank = _.min(_.map(g.outEdges(v), function(e) {
+      return dfs(e.w) - g.edge(e).minlen;
+    }));
+
+    if (rank === Number.POSITIVE_INFINITY) {
+      rank = 0;
+    }
+
+    return (label.rank = rank);
+  }
+
+  _.each(g.sources(), dfs);
+}
+
+/*
+ * Returns the amount of slack for the given edge. The slack is defined as the
+ * difference between the length of the edge and its minimum length.
+ */
+function slack(g, e) {
+  return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
+}
diff --git a/debian/missing-source/dagre/lib/util.js b/debian/missing-source/dagre/lib/util.js
new file mode 100644
index 0000000..82058d3
--- /dev/null
+++ b/debian/missing-source/dagre/lib/util.js
@@ -0,0 +1,236 @@
+"use strict";
+
+var _ = require("./lodash"),
+    Graph = require("./graphlib").Graph;
+
+module.exports = {
+  addDummyNode: addDummyNode,
+  simplify: simplify,
+  asNonCompoundGraph: asNonCompoundGraph,
+  successorWeights: successorWeights,
+  predecessorWeights: predecessorWeights,
+  intersectRect: intersectRect,
+  buildLayerMatrix: buildLayerMatrix,
+  normalizeRanks: normalizeRanks,
+  removeEmptyRanks: removeEmptyRanks,
+  addBorderNode: addBorderNode,
+  maxRank: maxRank,
+  partition: partition,
+  time: time,
+  notime: notime
+};
+
+/*
+ * Adds a dummy node to the graph and return v.
+ */
+function addDummyNode(g, type, attrs, name) {
+  var v;
+  do {
+    v = _.uniqueId(name);
+  } while (g.hasNode(v));
+
+  attrs.dummy = type;
+  g.setNode(v, attrs);
+  return v;
+}
+
+/*
+ * Returns a new graph with only simple edges. Handles aggregation of data
+ * associated with multi-edges.
+ */
+function simplify(g) {
+  var simplified = new Graph().setGraph(g.graph());
+  _.each(g.nodes(), function(v) { simplified.setNode(v, g.node(v)); });
+  _.each(g.edges(), function(e) {
+    var simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 },
+        label = g.edge(e);
+    simplified.setEdge(e.v, e.w, {
+      weight: simpleLabel.weight + label.weight,
+      minlen: Math.max(simpleLabel.minlen, label.minlen)
+    });
+  });
+  return simplified;
+}
+
+function asNonCompoundGraph(g) {
+  var simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
+  _.each(g.nodes(), function(v) {
+    if (!g.children(v).length) {
+      simplified.setNode(v, g.node(v));
+    }
+  });
+  _.each(g.edges(), function(e) {
+    simplified.setEdge(e, g.edge(e));
+  });
+  return simplified;
+}
+
+function successorWeights(g) {
+  var weightMap = _.map(g.nodes(), function(v) {
+    var sucs = {};
+    _.each(g.outEdges(v), function(e) {
+      sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight;
+    });
+    return sucs;
+  });
+  return _.zipObject(g.nodes(), weightMap);
+}
+
+function predecessorWeights(g) {
+  var weightMap = _.map(g.nodes(), function(v) {
+    var preds = {};
+    _.each(g.inEdges(v), function(e) {
+      preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight;
+    });
+    return preds;
+  });
+  return _.zipObject(g.nodes(), weightMap);
+}
+
+/*
+ * Finds where a line starting at point ({x, y}) would intersect a rectangle
+ * ({x, y, width, height}) if it were pointing at the rectangle's center.
+ */
+function intersectRect(rect, point) {
+  var x = rect.x;
+  var y = rect.y;
+
+  // Rectangle intersection algorithm from:
+  // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
+  var dx = point.x - x;
+  var dy = point.y - y;
+  var w = rect.width / 2;
+  var h = rect.height / 2;
+
+  if (!dx && !dy) {
+    throw new Error("Not possible to find intersection inside of the rectangle");
+  }
+
+  var sx, sy;
+  if (Math.abs(dy) * w > Math.abs(dx) * h) {
+    // Intersection is top or bottom of rect.
+    if (dy < 0) {
+      h = -h;
+    }
+    sx = h * dx / dy;
+    sy = h;
+  } else {
+    // Intersection is left or right of rect.
+    if (dx < 0) {
+      w = -w;
+    }
+    sx = w;
+    sy = w * dy / dx;
+  }
+
+  return { x: x + sx, y: y + sy };
+}
+
+/*
+ * Given a DAG with each node assigned "rank" and "order" properties, this
+ * function will produce a matrix with the ids of each node.
+ */
+function buildLayerMatrix(g) {
+  var layering = _.map(_.range(maxRank(g) + 1), function() { return []; });
+  _.each(g.nodes(), function(v) {
+    var node = g.node(v),
+        rank = node.rank;
+    if (!_.isUndefined(rank)) {
+      layering[rank][node.order] = v;
+    }
+  });
+  return layering;
+}
+
+/*
+ * Adjusts the ranks for all nodes in the graph such that all nodes v have
+ * rank(v) >= 0 and at least one node w has rank(w) = 0.
+ */
+function normalizeRanks(g) {
+  var min = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
+  _.each(g.nodes(), function(v) {
+    var node = g.node(v);
+    if (_.has(node, "rank")) {
+      node.rank -= min;
+    }
+  });
+}
+
+function removeEmptyRanks(g) {
+  // Ranks may not start at 0, so we need to offset them
+  var offset = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
+
+  var layers = [];
+  _.each(g.nodes(), function(v) {
+    var rank = g.node(v).rank - offset;
+    if (!layers[rank]) {
+      layers[rank] = [];
+    }
+    layers[rank].push(v);
+  });
+
+  var delta = 0,
+      nodeRankFactor = g.graph().nodeRankFactor;
+  _.each(layers, function(vs, i) {
+    if (_.isUndefined(vs) && i % nodeRankFactor !== 0) {
+      --delta;
+    } else if (delta) {
+      _.each(vs, function(v) { g.node(v).rank += delta; });
+    }
+  });
+}
+
+function addBorderNode(g, prefix, rank, order) {
+  var node = {
+    width: 0,
+    height: 0
+  };
+  if (arguments.length >= 4) {
+    node.rank = rank;
+    node.order = order;
+  }
+  return addDummyNode(g, "border", node, prefix);
+}
+
+function maxRank(g) {
+  return _.max(_.map(g.nodes(), function(v) {
+    var rank = g.node(v).rank;
+    if (!_.isUndefined(rank)) {
+      return rank;
+    }
+  }));
+}
+
+/*
+ * Partition a collection into two groups: `lhs` and `rhs`. If the supplied
+ * function returns true for an entry it goes into `lhs`. Otherwise it goes
+ * into `rhs.
+ */
+function partition(collection, fn) {
+  var result = { lhs: [], rhs: [] };
+  _.each(collection, function(value) {
+    if (fn(value)) {
+      result.lhs.push(value);
+    } else {
+      result.rhs.push(value);
+    }
+  });
+  return result;
+}
+
+/*
+ * Returns a new function that wraps `fn` with a timer. The wrapper logs the
+ * time it takes to execute the function.
+ */
+function time(name, fn) {
+  var start = _.now();
+  try {
+    return fn();
+  } finally {
+    console.log(name + " time: " + (_.now() - start) + "ms");
+  }
+}
+
+function notime(name, fn) {
+  return fn();
+}
diff --git a/debian/missing-source/dagre/lib/version.js b/debian/missing-source/dagre/lib/version.js
new file mode 100644
index 0000000..027cb04
--- /dev/null
+++ b/debian/missing-source/dagre/lib/version.js
@@ -0,0 +1 @@
+module.exports = "0.7.4";
diff --git a/debian/missing-source/dagre/package.json b/debian/missing-source/dagre/package.json
new file mode 100644
index 0000000..d26ae94
--- /dev/null
+++ b/debian/missing-source/dagre/package.json
@@ -0,0 +1,40 @@
+{
+  "name": "dagre",
+  "version": "0.7.4",
+  "description": "Graph layout for JavaScript",
+  "author": "Chris Pettitt <cpettitt at gmail.com>",
+  "main": "index.js",
+  "keywords": [
+    "graph",
+    "layout"
+  ],
+  "dependencies": {
+    "graphlib": "^1.0.5",
+    "lodash": "^3.10.0"
+  },
+  "devDependencies": {
+    "benchmark": "^1.0.0",
+    "browserify": "^6.1.0",
+    "chai": "^1.9.2",
+    "istanbul": "^0.3.2",
+    "jscs": "^1.7.3",
+    "jshint": "^2.5.6",
+    "jshint-stylish": "^1.0.0",
+    "karma": "^0.12.37",
+    "karma-chrome-launcher": "^0.2.0",
+    "karma-firefox-launcher": "^0.1.6",
+    "karma-mocha": "^0.2.0",
+    "karma-phantomjs-launcher": "^0.2.0",
+    "karma-safari-launcher": "^0.1.1",
+    "mocha": "^1.21.5",
+    "phantomjs": "^1.9.17",
+    "semver": "^4.1.0",
+    "sprintf": "^0.1.4",
+    "uglify-js": "^2.4.15"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/cpettitt/dagre.git"
+  },
+  "license": "MIT"
+}
diff --git a/debian/missing-source/dagre/src/bench.js b/debian/missing-source/dagre/src/bench.js
new file mode 100755
index 0000000..27139cb
--- /dev/null
+++ b/debian/missing-source/dagre/src/bench.js
@@ -0,0 +1,63 @@
+#!/usr/bin/env node
+
+var Benchmark = require("benchmark"),
+    sprintf = require("sprintf").sprintf;
+
+var Graph = require("graphlib").Graph,
+    rank = require("../lib/rank"),
+    layout = require("..").layout;
+
+function runBenchmark(name, fn) {
+  var options = {};
+  options.onComplete = function(bench) {
+    var target = bench.target,
+        hz = target.hz,
+        stats = target.stats,
+        rme = stats.rme,
+        samples = stats.sample.length,
+        msg = sprintf("    %25s: %13s ops/sec \xb1 %s%% (%3d run(s) sampled)",
+                      target.name,
+                      Benchmark.formatNumber(hz.toFixed(2)),
+                      rme.toFixed(2),
+                      samples);
+    console.log(msg);
+  };
+  options.onError = function(bench) {
+    console.error("    " + bench.target.error);
+  };
+  options.setup = function() {
+    this.count = Math.random() * 1000;
+    this.nextInt = function(range) {
+      return Math.floor(this.count++ % range );
+    };
+  };
+  new Benchmark(name, fn, options).run();
+}
+
+var g = new Graph()
+  .setGraph({})
+  .setDefaultNodeLabel(function() { return { width: 1, height: 1}; })
+  .setDefaultEdgeLabel(function() { return { minlen: 1, weight: 1 }; })
+  .setPath(["a", "b", "c", "d", "h"])
+  .setPath(["a", "e", "g", "h"])
+  .setPath(["a", "f", "g"]);
+
+runBenchmark("longest-path ranker", function() {
+  g.graph().ranker = "longest-path";
+  rank(g);
+});
+
+runBenchmark("tight-tree ranker", function() {
+  g.graph().ranker = "tight-tree";
+  rank(g);
+});
+
+runBenchmark("network-simplex ranker", function() {
+  g.graph().ranker = "network-simplex";
+  rank(g);
+});
+
+runBenchmark("layout", function() {
+  delete g.graph().ranker;
+  layout(g);
+});
diff --git a/debian/missing-source/dagre/src/release/bump-version.js b/debian/missing-source/dagre/src/release/bump-version.js
new file mode 100755
index 0000000..80f7b3d
--- /dev/null
+++ b/debian/missing-source/dagre/src/release/bump-version.js
@@ -0,0 +1,26 @@
+#!/usr/bin/env node
+
+/*
+ * Bumps the minor version and sets the prelease tag.
+ */
+
+var fs = require("fs"),
+    semver = require("semver");
+
+var packageFile = fs.readFileSync("package.json");
+var packageJson = JSON.parse(packageFile);
+
+if (!("version" in packageJson)) {
+  bail("ERROR: Could not find version in package.json");
+}
+
+var ver = semver.parse(packageJson.version);
+packageJson.version = ver.inc("patch").toString() + "-pre";
+
+fs.writeFileSync("package.json", JSON.stringify(packageJson, undefined, 2));
+
+// Write an error message to stderr and then exit immediately with an error.
+function bail(msg) {
+  stderr.write(msg + "\n");
+  process.exit(1);
+}
diff --git a/debian/missing-source/dagre/src/release/check-version.js b/debian/missing-source/dagre/src/release/check-version.js
new file mode 100755
index 0000000..1890158
--- /dev/null
+++ b/debian/missing-source/dagre/src/release/check-version.js
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+
+/*
+ * Prints the current version from the specified package-file to stdout or
+ * fails with an error if either the version cannot be determined or it is
+ * a pre-release.
+ */
+
+var fs = require("fs"),
+    semver = require("semver");
+
+var packageFile = fs.readFileSync("package.json");
+var packageJson = JSON.parse(packageFile);
+
+if (!("version" in packageJson)) {
+  bail("ERROR: Could not find version in package.json");
+}
+
+var ver = semver.parse(packageJson.version),
+    preRelease = process.env.PRE_RELEASE;
+
+if (ver.prerelease.length > 0 && !preRelease) {
+  bail("ERROR: version is a pre-release: " + ver);
+}
+
+console.log(ver.toString());
+
+// Write an error message to stderr and then exit immediately with an error.
+function bail(msg) {
+  process.stderr.write(msg + "\n");
+  process.exit(1);
+}
diff --git a/debian/missing-source/dagre/src/release/make-bower.json.js b/debian/missing-source/dagre/src/release/make-bower.json.js
new file mode 100755
index 0000000..81549fc
--- /dev/null
+++ b/debian/missing-source/dagre/src/release/make-bower.json.js
@@ -0,0 +1,28 @@
+#!/usr/bin/env node
+
+// Renders the bower.json template and prints it to stdout
+
+var packageJson = require("../../package.json");
+
+var template = {
+  name: packageJson.name,
+  version: packageJson.version,
+  main: ["dist/" + packageJson.name + ".core.js", "dist/" + packageJson.name + ".core.min.js"],
+  ignore: [
+    ".*",
+    "README.md",
+    "CHANGELOG.md",
+    "Makefile",
+    "dist/" + packageJson.name + ".js",
+    "dist/" + packageJson.name + ".min.js",
+    "index.js",
+    "karma*",
+    "lib/**",
+    "package.json",
+    "src/**",
+    "test/**"
+  ],
+  dependencies: packageJson.dependencies
+};
+
+console.log(JSON.stringify(template, null, 2));
diff --git a/debian/missing-source/dagre/src/release/make-version.js b/debian/missing-source/dagre/src/release/make-version.js
new file mode 100755
index 0000000..8027ccf
--- /dev/null
+++ b/debian/missing-source/dagre/src/release/make-version.js
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+var package = require("../../package.json");
+console.log("module.exports = \"" + package.version + "\";");
diff --git a/debian/missing-source/dagre/src/release/release.sh b/debian/missing-source/dagre/src/release/release.sh
new file mode 100755
index 0000000..106a9a3
--- /dev/null
+++ b/debian/missing-source/dagre/src/release/release.sh
@@ -0,0 +1,67 @@
+# Fail on error
+set -e
+[ -n "$DEBUG"] && set -x
+
+bail() {
+    echo $1 >&2
+    exit 1
+}
+
+# Initial config
+PROJECT=$1
+PROJECT_ROOT=`pwd`
+PAGES_DIR=/tmp/$PROJECT-pages
+DIST_DIR=$2
+
+# Check version. Is this a release? If not abort
+VERSION=$(./src/release/check-version.js)
+SHORT_VERSION=$(echo $VERSION | cut -f1 -d-)
+
+echo Attemping to publish version: $VERSION
+
+# Preflight checks
+[ -n "$PROJECT" ] || bail "No project name was specified."
+[ -n "$DIST_DIR" ] || bail "No dist dir was specified."
+[ -z "`git tag -l v$VERSION`" ] || bail "Version already published. Skipping publish."
+[ "`git rev-parse HEAD`" = "`git rev-parse master`" ] || [ -n "$PRE_RELEASE" ] || bail "ERROR: You must release from the master branch"
+[ -z "`git status --porcelain`" ] || bail "ERROR: Dirty index on working tree. Use git status to check"
+
+# Publish to pages
+rm -rf $PAGES_DIR
+git clone git at github.com:cpettitt/cpettitt.github.com.git $PAGES_DIR
+
+TMP_TARGET=$PAGES_DIR/project/$PROJECT/latest
+rm -rf $TMP_TARGET
+mkdir -p $TMP_TARGET
+cp -r $DIST_DIR/*.js $TMP_TARGET
+
+TMP_TARGET=$PAGES_DIR/project/$PROJECT/v$VERSION
+rm -rf $TMP_TARGET
+mkdir -p $TMP_TARGET
+cp -r $DIST_DIR/*.js $TMP_TARGET
+
+cd $PAGES_DIR/project/$PROJECT
+git add -A
+git commit -m "Publishing $PROJECT v$VERSION"
+git push -f origin master
+cd $PROJECT_ROOT
+echo "Published $PROJECT to pages"
+
+# Publish tag
+git tag v$VERSION
+git push origin
+git push origin v$VERSION
+echo Published $PROJECT v$VERSION
+
+# Publish to npm
+npm publish
+echo Published to npm
+
+# Update patch level version + commit
+./src/release/bump-version.js
+make lib/version.js
+git commit package.json lib/version.js -m "Bump version and set as pre-release"
+git push origin
+echo Updated patch version
+
+echo Release complete!
diff --git a/debian/missing-source/dagre/test/acyclic-test.js b/debian/missing-source/dagre/test/acyclic-test.js
new file mode 100644
index 0000000..c67a94a
--- /dev/null
+++ b/debian/missing-source/dagre/test/acyclic-test.js
@@ -0,0 +1,98 @@
+var _ = require("lodash"),
+    expect = require("./chai").expect,
+    acyclic = require("../lib/acyclic"),
+    Graph = require("graphlib").Graph,
+    findCycles = require("graphlib").alg.findCycles;
+
+describe("acyclic", function() {
+  var ACYCLICERS = [
+    "greedy",
+    "dfs",
+    "unknown-should-still-work"
+  ];
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ multigraph: true })
+      .setDefaultEdgeLabel(function() { return { minlen: 1, weight: 1 }; });
+  });
+
+  _.each(ACYCLICERS, function(acyclicer) {
+    describe(acyclicer, function() {
+      beforeEach(function() {
+        g.setGraph({ acyclicer: acyclicer });
+      });
+
+      describe("run", function() {
+        it("does not change an already acyclic graph", function() {
+          g.setPath(["a", "b", "d"]);
+          g.setPath(["a", "c", "d"]);
+          acyclic.run(g);
+          var results = _.map(g.edges(), stripLabel);
+          expect(_.sortByAll(results, ["v", "w"])).to.eql([
+            { v: "a", w: "b" },
+            { v: "a", w: "c" },
+            { v: "b", w: "d" },
+            { v: "c", w: "d" }
+          ]);
+        });
+
+        it("breaks cycles in the input graph", function() {
+          g.setPath(["a", "b", "c", "d", "a"]);
+          acyclic.run(g);
+          expect(findCycles(g)).to.eql([]);
+        });
+
+        it("creates a multi-edge where necessary", function() {
+          g.setPath(["a", "b", "a"]);
+          acyclic.run(g);
+          expect(findCycles(g)).to.eql([]);
+          if (g.hasEdge("a", "b")) {
+            expect(g.outEdges("a", "b")).to.have.length(2);
+          } else {
+            expect(g.outEdges("b", "a")).to.have.length(2);
+          }
+          expect(g.edgeCount()).to.equal(2);
+        });
+      });
+
+      describe("undo", function() {
+        it("does not change edges where the original graph was acyclic", function() {
+          g.setEdge("a", "b", { minlen: 2, weight: 3 });
+          acyclic.run(g);
+          acyclic.undo(g);
+          expect(g.edge("a", "b")).to.eql({ minlen: 2, weight: 3 });
+          expect(g.edges()).to.have.length(1);
+        });
+
+        it("can restore previosuly reversed edges", function() {
+          g.setEdge("a", "b", { minlen: 2, weight: 3 });
+          g.setEdge("b", "a", { minlen: 3, weight: 4 });
+          acyclic.run(g);
+          acyclic.undo(g);
+          expect(g.edge("a", "b")).to.eql({ minlen: 2, weight: 3 });
+          expect(g.edge("b", "a")).to.eql({ minlen: 3, weight: 4 });
+          expect(g.edges()).to.have.length(2);
+        });
+      });
+    });
+  });
+
+  describe("greedy-specific functionality", function() {
+    it("prefers to break cycles at low-weight edges", function() {
+      g.setGraph({ acyclicer: "greedy" });
+      g.setDefaultEdgeLabel(function() { return { minlen: 1, weight: 2 }; });
+      g.setPath(["a", "b", "c", "d", "a"]);
+      g.setEdge("c", "d", { weight: 1 });
+      acyclic.run(g);
+      expect(findCycles(g)).to.eql([]);
+      expect(g.hasEdge("c", "d")).to.be.false;
+    });
+  });
+});
+
+function stripLabel(edge) {
+  var c = _.clone(edge);
+  delete c.label;
+  return c;
+}
diff --git a/debian/missing-source/dagre/test/add-border-segments-test.js b/debian/missing-source/dagre/test/add-border-segments-test.js
new file mode 100644
index 0000000..8270f49
--- /dev/null
+++ b/debian/missing-source/dagre/test/add-border-segments-test.js
@@ -0,0 +1,92 @@
+var expect = require("./chai").expect,
+    addBorderSegments = require("../lib/add-border-segments"),
+    Graph = require("graphlib").Graph;
+
+describe("addBorderSegments", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ compound: true });
+  });
+
+  it("does not add border nodes for a non-compound graph", function() {
+    var g = new Graph();
+    g.setNode("a", { rank: 0 });
+    addBorderSegments(g);
+    expect(g.nodeCount()).to.equal(1);
+    expect(g.node("a")).to.eql({ rank: 0 });
+  });
+
+  it("does not add border nodes for a graph with no clusters", function() {
+    g.setNode("a", { rank: 0 });
+    addBorderSegments(g);
+    expect(g.nodeCount()).to.equal(1);
+    expect(g.node("a")).to.eql({ rank: 0 });
+  });
+
+  it("adds a border for a single-rank subgraph", function() {
+    g.setNode("sg", { minRank: 1, maxRank: 1 });
+    addBorderSegments(g);
+
+    var bl = g.node("sg").borderLeft[1],
+        br = g.node("sg").borderRight[1];
+    expect(g.node(bl)).eqls({ dummy: "border", borderType: "borderLeft",
+                              rank: 1, width: 0, height: 0 });
+    expect(g.parent(bl)).equals("sg");
+    expect(g.node(br)).eqls({ dummy: "border", borderType: "borderRight",
+                              rank: 1, width: 0, height: 0 });
+    expect(g.parent(br)).equals("sg");
+  });
+
+  it("adds a border for a multi-rank subgraph", function() {
+    g.setNode("sg", { minRank: 1, maxRank: 2 });
+    addBorderSegments(g);
+
+    var sgNode = g.node("sg");
+    var bl2 = sgNode.borderLeft[1],
+        br2 = sgNode.borderRight[1];
+    expect(g.node(bl2)).eqls({ dummy: "border", borderType: "borderLeft",
+                               rank: 1, width: 0, height: 0 });
+    expect(g.parent(bl2)).equals("sg");
+    expect(g.node(br2)).eqls({ dummy: "border", borderType: "borderRight",
+                               rank: 1, width: 0, height: 0 });
+    expect(g.parent(br2)).equals("sg");
+
+    var bl1 = sgNode.borderLeft[2],
+        br1 = sgNode.borderRight[2];
+    expect(g.node(bl1)).eqls({ dummy: "border", borderType: "borderLeft",
+                               rank: 2, width: 0, height: 0 });
+    expect(g.parent(bl1)).equals("sg");
+    expect(g.node(br1)).eqls({ dummy: "border", borderType: "borderRight",
+                               rank: 2, width: 0, height: 0 });
+    expect(g.parent(br1)).equals("sg");
+
+    expect(g.hasEdge(sgNode.borderLeft[1], sgNode.borderLeft[2])).to.be.true;
+    expect(g.hasEdge(sgNode.borderRight[1], sgNode.borderRight[2])).to.be.true;
+  });
+
+  it("adds borders for nested subgraphs", function() {
+    g.setNode("sg1", { minRank: 1, maxRank: 1 });
+    g.setNode("sg2", { minRank: 1, maxRank: 1 });
+    g.setParent("sg2", "sg1");
+    addBorderSegments(g);
+
+    var bl1 = g.node("sg1").borderLeft[1],
+        br1 = g.node("sg1").borderRight[1];
+    expect(g.node(bl1)).eqls({ dummy: "border", borderType: "borderLeft",
+                              rank: 1, width: 0, height: 0 });
+    expect(g.parent(bl1)).equals("sg1");
+    expect(g.node(br1)).eqls({ dummy: "border", borderType: "borderRight",
+                               rank: 1, width: 0, height: 0 });
+    expect(g.parent(br1)).equals("sg1");
+
+    var bl2 = g.node("sg2").borderLeft[1],
+        br2 = g.node("sg2").borderRight[1];
+    expect(g.node(bl2)).eqls({ dummy: "border", borderType: "borderLeft",
+                               rank: 1, width: 0, height: 0 });
+    expect(g.parent(bl2)).equals("sg2");
+    expect(g.node(br2)).eqls({ dummy: "border", borderType: "borderRight",
+                               rank: 1, width: 0, height: 0 });
+    expect(g.parent(br2)).equals("sg2");
+  });
+});
diff --git a/debian/missing-source/dagre/test/bundle-test.js b/debian/missing-source/dagre/test/bundle-test.js
new file mode 100644
index 0000000..d8e82e5
--- /dev/null
+++ b/debian/missing-source/dagre/test/bundle-test.js
@@ -0,0 +1,34 @@
+/* global chai, dagre */
+
+// These are smoke tests to make sure the bundles look like they are working
+// correctly.
+
+var expect = chai.expect,
+    graphlib = dagre.graphlib;
+
+describe("bundle", function() {
+  it("exports dagre", function() {
+    expect(dagre).to.be.an("object");
+    expect(dagre.graphlib).to.be.an("object");
+    expect(dagre.layout).to.be.a("function");
+    expect(dagre.util).to.be.an("object");
+    expect(dagre.version).to.be.a("string");
+  });
+
+  it("can do trivial layout", function() {
+    var g = new graphlib.Graph().setGraph({});
+    g.setNode("a", { label: "a", width: 50, height: 100 });
+    g.setNode("b", { label: "b", width: 50, height: 100 });
+    g.setEdge("a", "b", { label: "ab", width: 50, height: 100 });
+
+    dagre.layout(g);
+    expect(g.node("a")).to.have.property("x");
+    expect(g.node("a")).to.have.property("y");
+    expect(g.node("a").x).to.be.gte(0);
+    expect(g.node("a").y).to.be.gte(0);
+    expect(g.edge("a", "b")).to.have.property("x");
+    expect(g.edge("a", "b")).to.have.property("y");
+    expect(g.edge("a", "b").x).to.be.gte(0);
+    expect(g.edge("a", "b").y).to.be.gte(0);
+  });
+});
diff --git a/debian/missing-source/dagre/test/chai.js b/debian/missing-source/dagre/test/chai.js
new file mode 100644
index 0000000..5f4ec38
--- /dev/null
+++ b/debian/missing-source/dagre/test/chai.js
@@ -0,0 +1,13 @@
+var chai = require("chai");
+
+module.exports = chai;
+
+chai.config.includeStack = true;
+
+/*
+ * Fix Chai"s `notProperty` which passes when an object has a property but its
+ * value is undefined.
+ */
+chai.assert.notProperty = function(obj, prop) {
+  chai.assert(!(prop in obj), "Found prop " + prop + " in " + obj + " with value " + obj[prop]);
+};
diff --git a/debian/missing-source/dagre/test/console.html b/debian/missing-source/dagre/test/console.html
new file mode 100644
index 0000000..1c6625f
--- /dev/null
+++ b/debian/missing-source/dagre/test/console.html
@@ -0,0 +1,244 @@
+<!doctype html>
+
+<meta charset="utf-8">
+<title>Dagre Debug Console</title>
+
+<script src="../build/dagre.js"></script>
+<script src="http://cpettitt.github.io/project/graphlib-dot/latest/graphlib-dot.js"></script>
+<script src="http://d3js.org/d3.v3.js" charset="utf-8"></script>
+<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
+
+<style>
+body {
+  color: #333;
+}
+
+#wrapper {
+  width: 1000px;
+  margin: 0 auto;
+}
+
+#inputPanel {
+  width: 350px;
+  float: left;
+  padding-right: 10%
+}
+
+#inputPanel textarea {
+  width: 100%;
+  resize: vertical;
+}
+
+textarea.error {
+  color: #f33;
+  border: 1px solid #f33;
+}
+
+#resultPanel {
+  width: 550px;
+  float: left;
+}
+
+#resultPanel svg {
+  border: 1px solid #333;
+}
+</style>
+
+<style>
+.node rect {
+  stroke: #333;
+  fill: #fff;
+}
+
+.subgraph rect {
+  stroke: #333;
+  fill: #333;
+  fill-opacity: 0.15;
+}
+
+.edge rect {
+  fill: #fff;
+}
+
+path.edge {
+  stroke: #333;
+  fill: none;
+}
+</style>
+
+<div id="wrapper">
+  <h1>Dagre Debug Console</h1>
+
+  <div id="inputPanel">
+    <textarea rows=25 onkeyup="renderDot();"></textarea>
+    <input type="checkbox" id="timing" name="timing">Enable timing instrumentation</input>
+  </div>
+
+  <div id="resultPanel">
+    <svg id="svg" width="550px" height="550px">
+      <defs>
+        <marker id="arrowhead" viewBox="0 0 10 10" refx=8 refy=5
+                markerUnits="strokeWidth" markerWidth=8 markerHeight=5
+                orient="auto">
+          <path d="M 0 0 L 10 5 L 0 10 z"/>
+        </marker>
+      </defs>
+    </svg>
+  </div>
+</div>
+
+<script>
+var debugTiming = false,
+    time = dagre.util.notime,
+    lastDotStr = "",
+    input = document.querySelector("#inputPanel textarea");
+function renderDot() {
+  debugTiming = d3.select("#timing").property("checked"),
+  time = debugTiming ? dagre.util.time : dagre.util.notime;
+
+  var dotStr = input.value;
+  if (dotStr !== lastDotStr) {
+    lastDotStr = dotStr;
+    input.className = "";
+    try {
+      var g = time("DOT parsing", function() { return graphlibDot.read(dotStr); });
+      time("render", function() { render(g); });
+    } catch (e) {
+      input.className = "error";
+      throw e;
+    }
+  }
+}
+
+input.onkeydown = function(e) {
+  if (e.keyCode === 9) {
+    e.preventDefault();
+    var s = this.selectionStart;
+    this.value = this.value.substring(0,this.selectionStart) + "    " +
+                 this.value.substring(this.selectionEnd);
+    this.selectionEnd = s + 4;
+  }
+}
+
+function render(g) {
+  var svg = d3.select("svg");
+  svg.selectAll("g").remove();
+  var group = svg.append("g");
+  time("preLayout", function() { preLayout(g, group) });
+  dagre.layout(g, { debugTiming: debugTiming });
+  time("postLayout", function() { postLayout(g, svg, group); });
+}
+
+function preLayout(g, svg) {
+  _.each(g.edges(), function(e) {
+    var edge = g.edge(e);
+    if (edge.label) {
+      var group = appendLabel(svg, edge.label, edge, 0, 0);
+      group.attr("id", "edge-" + edgeObjToId(e)).classed("edge", true);
+    }
+  });
+
+  _.each(g.nodes(), function(v) {
+    if (g.children(v).length) {
+      return;
+    }
+    var node = g.node(v),
+        group = appendLabel(svg, node.label || v, node, 10, 10);
+    group.attr("id", "node-" + id(v)).classed("node", true);
+  });
+}
+
+function appendLabel(target, label, graphObj, marginX, marginY) {
+  var group = target.append("g"),
+      rect = group.append("rect"),
+      text = group.append("text").attr("text-anchor", "left");
+  text
+    .append("tspan")
+    .attr("dy", "1em")
+    .text(label);
+
+  var textBBox = text.node().getBBox();
+  text.attr("transform",
+            "translate(" + (-textBBox.width / 2) + "," +
+                           (-textBBox.height / 2) + ")");
+
+  var bbox = group.node().getBBox();
+  rect
+    .attr("rx", 5)
+    .attr("ry", 5)
+    .attr("x", -(bbox.width / 2 + marginX))
+    .attr("y", -(bbox.height / 2 + marginY))
+    .attr("width", bbox.width + 2 * marginX)
+    .attr("height", bbox.height + 2 * marginY)
+    .attr("fill", "#fff");
+  bbox = group.node().getBBox();
+
+  graphObj.width = bbox.width;
+  graphObj.height = bbox.height;
+
+  return group;
+}
+
+function postLayout(g, root, svg) {
+  root.insert("rect", ":first-child")
+    .attr("width", "100%")
+    .attr("height", "100%")
+    .style("fill", "none")
+    .style("pointer-events", "all");
+  root.call(d3.behavior.zoom().on("zoom", function() {
+    svg.attr("transform", "translate(" + d3.event.translate + ")" +
+                            "scale(" + d3.event.scale + ")");
+  }));
+
+  _.each(g.edges(), function(e) {
+    var group = svg.select("g#edge-" + edgeObjToId(e));
+    if (!group.empty()) {
+      var edge = g.edge(e);
+      group.attr("transform", "translate(" + edge.x + "," + edge.y + ")");
+    }
+  });
+
+  _.each(g.nodes(), function(v) {
+    var group = svg.select("g#node-" + id(v)),
+        node = g.node(v);
+    group.attr("transform", "translate(" + node.x + "," + node.y + ")");
+  });
+
+  _.each(g.edges(), function(e) {
+    var points = g.edge(e).points,
+        path = svg.insert("path", ":first-child")
+                .classed("edge", true)
+                .attr("marker-end", "url(#arrowhead)"),
+        line = d3.svg.line()
+                .x(function(d) { return d.x; })
+                .y(function(d) { return d.y; });
+    path.attr("d", line(points));
+  });
+
+  function dfsChildren(v) {
+    var children = g.children(v);
+    if (children.length) {
+      _.each(children, dfsChildren);
+
+      var node = g.node(v);
+      svg.insert("g", ":first-child")
+         .classed("subgraph", true)
+         .attr("transform", "translate(" + (node.x - node.width / 2) + "," +
+                                       (node.y - node.height / 2) + ")")
+         .append("rect")
+           .attr("width", node.width)
+           .attr("height", node.height);
+    }
+  };
+  _.each(g.children(), dfsChildren);
+}
+
+function edgeObjToId(e) {
+  // Not particularly safe, but good enough for our needs.
+  return id(e.v) + "-" + id(e.w) + "-" + id(e.name);
+}
+
+function id(str) {
+  return str ? str.replace(/[^a-zA-z0-9-]/g, "_") : "";
+}
+</script>
diff --git a/debian/missing-source/dagre/test/coordinate-system-test.js b/debian/missing-source/dagre/test/coordinate-system-test.js
new file mode 100644
index 0000000..5253ca1
--- /dev/null
+++ b/debian/missing-source/dagre/test/coordinate-system-test.js
@@ -0,0 +1,71 @@
+var Graph = require("graphlib").Graph,
+    coordinateSystem = require("../lib/coordinate-system"),
+    expect = require("./chai").expect;
+
+describe("coordinateSystem", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph();
+  });
+
+  describe("coordinateSystem.adjust", function() {
+    beforeEach(function() {
+      g.setNode("a", { width: 100, height: 200 });
+    });
+
+    it("does nothing to node dimensions with rankdir = TB", function() {
+      g.setGraph({ rankdir: "TB" });
+      coordinateSystem.adjust(g);
+      expect(g.node("a")).eqls({ width: 100, height: 200 });
+    });
+
+    it("does nothing to node dimensions with rankdir = BT", function() {
+      g.setGraph({ rankdir: "BT" });
+      coordinateSystem.adjust(g);
+      expect(g.node("a")).eqls({ width: 100, height: 200 });
+    });
+
+    it("swaps width and height for nodes with rankdir = LR", function() {
+      g.setGraph({ rankdir: "LR" });
+      coordinateSystem.adjust(g);
+      expect(g.node("a")).eqls({ width: 200, height: 100 });
+    });
+
+    it("swaps width and height for nodes with rankdir = RL", function() {
+      g.setGraph({ rankdir: "RL" });
+      coordinateSystem.adjust(g);
+      expect(g.node("a")).eqls({ width: 200, height: 100 });
+    });
+  });
+
+  describe("coordinateSystem.undo", function() {
+    beforeEach(function() {
+      g.setNode("a", { width: 100, height: 200, x: 20, y: 40 });
+    });
+
+    it("does nothing to points with rankdir = TB", function() {
+      g.setGraph({ rankdir: "TB" });
+      coordinateSystem.undo(g);
+      expect(g.node("a")).eqls({ x: 20, y: 40, width: 100, height: 200 });
+    });
+
+    it("flips the y coordinate for points with rankdir = BT", function() {
+      g.setGraph({ rankdir: "BT" });
+      coordinateSystem.undo(g);
+      expect(g.node("a")).eqls({ x: 20, y: -40, width: 100, height: 200 });
+    });
+
+    it("swaps dimensions and coordinates for points with rankdir = LR", function() {
+      g.setGraph({ rankdir: "LR" });
+      coordinateSystem.undo(g);
+      expect(g.node("a")).eqls({ x: 40, y: 20, width: 200, height: 100 });
+    });
+
+    it("swaps dims and coords and flips x for points with rankdir = RL", function() {
+      g.setGraph({ rankdir: "RL" });
+      coordinateSystem.undo(g);
+      expect(g.node("a")).eqls({ x: -40, y: 20, width: 200, height: 100 });
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/data/list-test.js b/debian/missing-source/dagre/test/data/list-test.js
new file mode 100644
index 0000000..6892f21
--- /dev/null
+++ b/debian/missing-source/dagre/test/data/list-test.js
@@ -0,0 +1,60 @@
+var expect = require("../chai").expect,
+    List = require("../../lib/data/list");
+
+describe("data.List", function() {
+  var list;
+
+  beforeEach(function() {
+    list = new List();
+  });
+
+  describe("dequeue", function() {
+    it("returns undefined with an empty list", function() {
+      expect(list.dequeue()).to.be.undefined;
+    });
+
+    it("unlinks and returns the first entry", function() {
+      var obj = {};
+      list.enqueue(obj);
+      expect(list.dequeue()).to.equal(obj);
+    });
+
+    it("unlinks and returns multiple entries in FIFO order", function() {
+      var obj1 = {},
+          obj2 = {};
+      list.enqueue(obj1);
+      list.enqueue(obj2);
+
+      expect(list.dequeue()).to.equal(obj1);
+      expect(list.dequeue()).to.equal(obj2);
+    });
+
+    it("unlinks and relinks an entry if it is re-enqueued", function() {
+      var obj1 = {},
+          obj2 = {};
+      list.enqueue(obj1);
+      list.enqueue(obj2);
+      list.enqueue(obj1);
+
+      expect(list.dequeue()).to.equal(obj2);
+      expect(list.dequeue()).to.equal(obj1);
+    });
+
+    it("unlinks and relinks an entry if it is enqueued on another list", function() {
+      var obj = {},
+          list2 = new List();
+      list.enqueue(obj);
+      list2.enqueue(obj);
+
+      expect(list.dequeue()).to.be.undefined;
+      expect(list2.dequeue()).to.equal(obj);
+    });
+
+    it("can return a string representation", function() {
+      list.enqueue({ entry: 1 });
+      list.enqueue({ entry: 2 });
+
+      expect(list.toString()).to.equal("[{\"entry\":1}, {\"entry\":2}]");
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/greedy-fas-test.js b/debian/missing-source/dagre/test/greedy-fas-test.js
new file mode 100644
index 0000000..62c0c01
--- /dev/null
+++ b/debian/missing-source/dagre/test/greedy-fas-test.js
@@ -0,0 +1,109 @@
+var _ = require("lodash"),
+    expect = require("./chai").expect,
+    Graph = require("graphlib").Graph,
+    findCycles = require("graphlib").alg.findCycles,
+    greedyFAS = require("../lib/greedy-fas");
+
+describe("greedyFAS", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph();
+  });
+
+  it("returns the empty set for empty graphs", function() {
+    expect(greedyFAS(g)).to.eql([]);
+  });
+
+  it("returns the empty set for single-node graphs", function() {
+    g.setNode("a");
+    expect(greedyFAS(g)).to.eql([]);
+  });
+
+  it("returns an empty set if the input graph is acyclic", function() {
+    var g = new Graph();
+    g.setEdge("a", "b");
+    g.setEdge("b", "c");
+    g.setEdge("b", "d");
+    g.setEdge("a", "e");
+    expect(greedyFAS(g)).to.eql([]);
+  });
+
+  it("returns a single edge with a simple cycle", function() {
+    var g = new Graph();
+    g.setEdge("a", "b");
+    g.setEdge("b", "a");
+    checkFAS(g, greedyFAS(g));
+  });
+
+  it("returns a single edge in a 4-node cycle", function() {
+    var g = new Graph();
+    g.setEdge("n1", "n2");
+    g.setPath(["n2", "n3", "n4", "n5", "n2"]);
+    g.setEdge("n3", "n5");
+    g.setEdge("n4", "n2");
+    g.setEdge("n4", "n6");
+    checkFAS(g, greedyFAS(g));
+  });
+
+  it("returns two edges for two 4-node cycles", function() {
+    var g = new Graph();
+    g.setEdge("n1", "n2");
+    g.setPath(["n2", "n3", "n4", "n5", "n2"]);
+    g.setEdge("n3", "n5");
+    g.setEdge("n4", "n2");
+    g.setEdge("n4", "n6");
+    g.setPath(["n6", "n7", "n8", "n9", "n6"]);
+    g.setEdge("n7", "n9");
+    g.setEdge("n8", "n6");
+    g.setEdge("n8", "n10");
+    checkFAS(g, greedyFAS(g));
+  });
+
+  it("works with arbitrarily weighted edges", function() {
+    // Our algorithm should also work for graphs with multi-edges, a graph
+    // where more than one edge can be pointing in the same direction between
+    // the same pair of incident nodes. We try this by assigning weights to
+    // our edges representing the number of edges from one node to the other.
+
+    var g1 = new Graph();
+    g1.setEdge("n1", "n2", 2);
+    g1.setEdge("n2", "n1", 1);
+    expect(greedyFAS(g1, weightFn(g1))).to.eql([{v: "n2", w: "n1"}]);
+
+    var g2 = new Graph();
+    g2.setEdge("n1", "n2", 1);
+    g2.setEdge("n2", "n1", 2);
+    expect(greedyFAS(g2, weightFn(g2))).to.eql([{v: "n1", w: "n2"}]);
+  });
+
+  it("works for multigraphs", function() {
+    var g = new Graph({ multigraph: true });
+    g.setEdge("a", "b", 5, "foo");
+    g.setEdge("b", "a", 2, "bar");
+    g.setEdge("b", "a", 2, "baz");
+    expect(_.sortBy(greedyFAS(g, weightFn(g)), "name")).to.eql([
+      { v: "b", w: "a", name: "bar" },
+      { v: "b", w: "a", name: "baz" }
+    ]);
+  });
+});
+
+function checkFAS(g, fas) {
+  var n = g.nodeCount(),
+      m = g.edgeCount();
+  _.each(fas, function(edge) {
+    g.removeEdge(edge.v, edge.w);
+  });
+  expect(findCycles(g)).to.eql([]);
+  // The more direct m/2 - n/6 fails for the simple cycle A <-> B, where one
+  // edge must be reversed, but the performance bound implies that only 2/3rds
+  // of an edge can be reversed. I'm using floors to acount for this.
+  expect(fas.length).to.be.lte(Math.floor(m/2) - Math.floor(n/6));
+}
+
+function weightFn(g) {
+  return function(e) {
+    return g.edge(e);
+  };
+}
diff --git a/debian/missing-source/dagre/test/layout-test.js b/debian/missing-source/dagre/test/layout-test.js
new file mode 100644
index 0000000..cdd5a74
--- /dev/null
+++ b/debian/missing-source/dagre/test/layout-test.js
@@ -0,0 +1,298 @@
+var _ = require("lodash"),
+    expect = require("./chai").expect,
+    layout = require("..").layout,
+    Graph = require("graphlib").Graph;
+
+describe("layout", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ multigraph: true, compound: true })
+          .setGraph({})
+          .setDefaultEdgeLabel(function() { return {}; });
+  });
+
+  it("can layout a single node", function() {
+    g.setNode("a", { width: 50, height: 100 });
+    layout(g);
+    expect(extractCoordinates(g)).to.eql({
+      a: { x: 50 / 2, y: 100 / 2 }
+    });
+    expect(g.node("a").x).to.equal(50 / 2);
+    expect(g.node("a").y).to.equal(100 / 2);
+  });
+
+  it("can layout two nodes on the same rank", function() {
+    g.graph().nodesep = 200;
+    g.setNode("a", { width: 50, height: 100 });
+    g.setNode("b", { width: 75, height: 200 });
+    layout(g);
+    expect(extractCoordinates(g)).to.eql({
+      a: { x: 50 / 2,            y: 200 / 2 },
+      b: { x: 50 + 200 + 75 / 2, y: 200 / 2 }
+    });
+  });
+
+  it("can layout two nodes connected by an edge", function() {
+    g.graph().ranksep = 300;
+    g.setNode("a", { width: 50, height: 100 });
+    g.setNode("b", { width: 75, height: 200 });
+    g.setEdge("a", "b");
+    layout(g);
+    expect(extractCoordinates(g)).to.eql({
+      a: { x: 75 / 2, y: 100 / 2 },
+      b: { x: 75 / 2, y: 100 + 300 + 200 / 2 }
+    });
+
+    // We should not get x, y coordinates if the edge has no label
+    expect(g.edge("a", "b")).to.not.have.property("x");
+    expect(g.edge("a", "b")).to.not.have.property("y");
+  });
+
+  it("can layout an edge with a label", function() {
+    g.graph().ranksep = 300;
+    g.setNode("a", { width: 50, height: 100 });
+    g.setNode("b", { width: 75, height: 200 });
+    g.setEdge("a", "b", { width: 60, height: 70, labelpos: "c" });
+    layout(g);
+    expect(extractCoordinates(g)).to.eql({
+      a: { x: 75 / 2, y: 100 / 2 },
+      b: { x: 75 / 2, y: 100 + 150 + 70 + 150 + 200 / 2 }
+    });
+    expect(_.pick(g.edge("a", "b"), ["x", "y"]))
+      .eqls({ x: 75 / 2, y: 100  + 150 + 70 / 2 });
+  });
+
+  describe("can layout an edge with a long label, with rankdir =", function() {
+    _.each(["TB", "BT", "LR", "RL"], function(rankdir) {
+      it(rankdir, function() {
+        g.graph().nodesep = g.graph().edgesep = 10;
+        g.graph().rankdir = rankdir;
+        _.each(["a", "b", "c", "d"], function(v) {
+          g.setNode(v, { width: 10, height: 10 });
+        });
+        g.setEdge("a", "c", { width: 2000, height: 10, labelpos: "c" });
+        g.setEdge("b", "d", { width: 1, height: 1 });
+        layout(g);
+
+        var p1, p2;
+        if (rankdir === "TB" || rankdir === "BT") {
+          p1 = g.edge("a", "c");
+          p2 = g.edge("b", "d");
+        } else {
+          p1 = g.node("a");
+          p2 = g.node("c");
+        }
+
+        expect(Math.abs(p1.x - p2.x)).gt(1000);
+      });
+    });
+  });
+
+  describe("can apply an offset, with rankdir =", function() {
+    _.each(["TB", "BT", "LR", "RL"], function(rankdir) {
+      it(rankdir, function() {
+        g.graph().nodesep = g.graph().edgesep = 10;
+        g.graph().rankdir = rankdir;
+        _.each(["a", "b", "c", "d"], function(v) {
+          g.setNode(v, { width: 10, height: 10 });
+        });
+        g.setEdge("a", "b", { width: 10, height: 10, labelpos: "l", labeloffset: 1000 });
+        g.setEdge("c", "d", { width: 10, height: 10, labelpos: "r", labeloffset: 1000 });
+        layout(g);
+
+        if (rankdir === "TB" || rankdir === "BT") {
+          expect(g.edge("a", "b").x - g.edge("a", "b").points[0].x).equals(-1000 - 10 / 2);
+          expect(g.edge("c", "d").x - g.edge("c", "d").points[0].x).equals(1000 + 10 / 2);
+        } else {
+          expect(g.edge("a", "b").y - g.edge("a", "b").points[0].y).equals(-1000 - 10 / 2);
+          expect(g.edge("c", "d").y - g.edge("c", "d").points[0].y).equals(1000 + 10 / 2);
+        }
+      });
+    });
+  });
+
+  it("can layout a long edge with a label", function() {
+    g.graph().ranksep = 300;
+    g.setNode("a", { width: 50, height: 100 });
+    g.setNode("b", { width: 75, height: 200 });
+    g.setEdge("a", "b", { width: 60, height: 70, minlen: 2, labelpos: "c" });
+    layout(g);
+    expect(g.edge("a", "b").x).to.equal(75 / 2);
+    expect(g.edge("a", "b").y)
+      .to.be.gt(g.node("a").y)
+      .to.be.lt(g.node("b").y);
+  });
+
+  it("can layout out a short cycle", function() {
+    g.graph().ranksep = 200;
+    g.setNode("a", { width: 100, height: 100 });
+    g.setNode("b", { width: 100, height: 100 });
+    g.setEdge("a", "b", { weight: 2 });
+    g.setEdge("b", "a");
+    layout(g);
+    expect(extractCoordinates(g)).to.eql({
+      a: { x: 100 / 2, y: 100 / 2 },
+      b: { x: 100 / 2, y: 100 + 200 + 100 / 2}
+    });
+    // One arrow should point down, one up
+    expect(g.edge("a", "b").points[1].y).gt(g.edge("a", "b").points[0].y);
+    expect(g.edge("b", "a").points[0].y).gt(g.edge("b", "a").points[1].y);
+  });
+
+  it("adds rectangle intersects for edges", function() {
+    g.graph().ranksep = 200;
+    g.setNode("a", { width: 100, height: 100 });
+    g.setNode("b", { width: 100, height: 100 });
+    g.setEdge("a", "b");
+    layout(g);
+    var points = g.edge("a", "b").points;
+    expect(points).to.have.length(3);
+    expect(points).eqls([
+      { x: 100 / 2, y: 100 },           // intersect with bottom of a
+      { x: 100 / 2, y: 100 + 200 / 2 }, // point for edge label
+      { x: 100 / 2, y: 100 + 200 }      // intersect with top of b
+    ]);
+  });
+
+  it("adds rectangle intersects for edges spanning multiple ranks", function() {
+    g.graph().ranksep = 200;
+    g.setNode("a", { width: 100, height: 100 });
+    g.setNode("b", { width: 100, height: 100 });
+    g.setEdge("a", "b", { minlen: 2 });
+    layout(g);
+    var points = g.edge("a", "b").points;
+    expect(points).to.have.length(5);
+    expect(points).eqls([
+      { x: 100 / 2, y: 100 },           // intersect with bottom of a
+      { x: 100 / 2, y: 100 + 200 / 2 }, // bend #1
+      { x: 100 / 2, y: 100 + 400 / 2 }, // point for edge label
+      { x: 100 / 2, y: 100 + 600 / 2 }, // bend #2
+      { x: 100 / 2, y: 100 + 800 / 2 }  // intersect with top of b
+    ]);
+  });
+
+  describe("can layout a self loop", function() {
+    _.each(["TB", "BT", "LR", "RL"], function(rankdir) {
+      it ("in rankdir = " + rankdir, function() {
+        g.graph().edgesep = 75;
+        g.graph().rankdir = rankdir;
+        g.setNode("a", { width: 100, height: 100 });
+        g.setEdge("a", "a", { width: 50, height: 50 });
+        layout(g);
+        var nodeA = g.node("a"),
+            points = g.edge("a", "a").points;
+        expect(points).to.have.length(7);
+        _.each(points, function(point) {
+          if (rankdir !== "LR" && rankdir !== "RL") {
+            expect(point.x).gt(nodeA.x);
+            expect(Math.abs(point.y - nodeA.y)).lte(nodeA.height / 2);
+          } else {
+            expect(point.y).gt(nodeA.y);
+            expect(Math.abs(point.x - nodeA.x)).lte(nodeA.width / 2);
+          }
+        });
+      });
+    });
+  });
+
+  it("can layout a graph with subgraphs", function() {
+    // To be expanded, this primarily ensures nothing blows up for the moment.
+    g.setNode("a", { width: 50, height: 50 });
+    g.setParent("a", "sg1");
+    layout(g);
+  });
+
+  it("minimizes the height of subgraphs", function() {
+    _.each(["a", "b", "c", "d", "x", "y"], function(v) {
+      g.setNode(v, { width: 50, height: 50 });
+    });
+    g.setPath(["a", "b", "c", "d"]);
+    g.setEdge("a", "x", { weight: 100 });
+    g.setEdge("y", "d", { weight: 100 });
+    g.setParent("x", "sg");
+    g.setParent("y", "sg");
+
+    // We did not set up an edge (x, y), and we set up high-weight edges from
+    // outside of the subgraph to nodes in the subgraph. This is to try to
+    // force nodes x and y to be on different ranks, which we want our ranker
+    // to avoid.
+    layout(g);
+    expect(g.node("x").y).to.equal(g.node("y").y);
+  });
+
+  it("can layout subgraphs with different rankdirs", function() {
+    g.setNode("a", { width: 50, height: 50 });
+    g.setNode("sg", {});
+    g.setParent("a", "sg");
+
+    function check(rankdir) {
+      expect(g.node("sg").width, "width " + rankdir).gt(50);
+      expect(g.node("sg").height, "height " + rankdir).gt(50);
+      expect(g.node("sg").x, "x " + rankdir).gt(50 / 2);
+      expect(g.node("sg").y, "y " + rankdir).gt(50 / 2);
+    }
+
+    _.each(["tb", "bt", "lr", "rl"], function(rankdir) {
+      g.graph().rankdir = rankdir;
+      layout(g);
+      check(rankdir);
+    });
+  });
+
+  it("adds dimensions to the graph", function() {
+    g.setNode("a", { width: 100, height: 50 });
+    layout(g);
+    expect(g.graph().width).equals(100);
+    expect(g.graph().height).equals(50);
+  });
+
+  describe("ensures all coordinates are in the bounding box for the graph", function() {
+    _.each(["TB", "BT", "LR", "RL"], function(rankdir) {
+      describe(rankdir, function() {
+        beforeEach(function() {
+          g.graph().rankdir = rankdir;
+        });
+
+        it("node", function() {
+          g.setNode("a", { width: 100, height: 200 });
+          layout(g);
+          expect(g.node("a").x).equals(100 / 2);
+          expect(g.node("a").y).equals(200 / 2);
+        });
+
+        it("edge, labelpos = l", function() {
+          g.setNode("a", { width: 100, height: 100 });
+          g.setNode("b", { width: 100, height: 100 });
+          g.setEdge("a", "b", {
+            width: 1000, height: 2000, labelpos: "l", labeloffset: 0
+          });
+          layout(g);
+          if (rankdir === "TB" || rankdir === "BT") {
+            expect(g.edge("a", "b").x).equals(1000 / 2);
+          } else {
+            expect(g.edge("a", "b").y).equals(2000 / 2);
+          }
+        });
+      });
+    });
+  });
+
+  it("treats attributes with case-insensitivity", function() {
+    g.graph().nodeSep = 200; // note the capital S
+    g.setNode("a", { width: 50, height: 100 });
+    g.setNode("b", { width: 75, height: 200 });
+    layout(g);
+    expect(extractCoordinates(g)).to.eql({
+      a: { x: 50 / 2,            y: 200 / 2 },
+      b: { x: 50 + 200 + 75 / 2, y: 200 / 2 }
+    });
+  });
+});
+
+function extractCoordinates(g) {
+  var nodes = g.nodes();
+  return _.zipObject(nodes, _.map(nodes, function(v) {
+    return _.pick(g.node(v), ["x", "y"]);
+  }));
+}
diff --git a/debian/missing-source/dagre/test/nesting-graph-test.js b/debian/missing-source/dagre/test/nesting-graph-test.js
new file mode 100644
index 0000000..6613233
--- /dev/null
+++ b/debian/missing-source/dagre/test/nesting-graph-test.js
@@ -0,0 +1,199 @@
+var expect = require("./chai").expect,
+    Graph = require("graphlib").Graph,
+    components = require("graphlib").alg.components,
+    nestingGraph = require("../lib/nesting-graph");
+
+describe("rank/nestingGraph", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ compound: true })
+          .setGraph({})
+          .setDefaultNodeLabel(function() { return {}; });
+  });
+
+  describe("run", function() {
+    it("connects a disconnected graph", function() {
+      g.setNode("a");
+      g.setNode("b");
+      expect(components(g)).to.have.length(2);
+      nestingGraph.run(g);
+      expect(components(g)).to.have.length(1);
+      expect(g.hasNode("a"));
+      expect(g.hasNode("b"));
+    });
+
+    it("adds border nodes to the top and bottom of a subgraph", function() {
+      g.setParent("a", "sg1");
+      nestingGraph.run(g);
+
+      var borderTop = g.node("sg1").borderTop,
+          borderBottom = g.node("sg1").borderBottom;
+      expect(borderTop).to.exist;
+      expect(borderBottom).to.exist;
+      expect(g.parent(borderTop)).to.equal("sg1");
+      expect(g.parent(borderBottom)).to.equal("sg1");
+      expect(g.outEdges(borderTop, "a")).to.have.length(1);
+      expect(g.edge(g.outEdges(borderTop, "a")[0]).minlen).equals(1);
+      expect(g.outEdges("a", borderBottom)).to.have.length(1);
+      expect(g.edge(g.outEdges("a", borderBottom)[0]).minlen).equals(1);
+      expect(g.node(borderTop)).eqls({ width: 0, height: 0, dummy: "border" });
+      expect(g.node(borderBottom)).eqls({ width: 0, height: 0, dummy: "border" });
+    });
+
+    it("adds edges between borders of nested subgraphs", function() {
+      g.setParent("sg2", "sg1");
+      g.setParent("a", "sg2");
+      nestingGraph.run(g);
+
+      var sg1Top = g.node("sg1").borderTop,
+          sg1Bottom = g.node("sg1").borderBottom,
+          sg2Top = g.node("sg2").borderTop,
+          sg2Bottom = g.node("sg2").borderBottom;
+      expect(sg1Top).to.exist;
+      expect(sg1Bottom).to.exist;
+      expect(sg2Top).to.exist;
+      expect(sg2Bottom).to.exist;
+      expect(g.outEdges(sg1Top, sg2Top)).to.have.length(1);
+      expect(g.edge(g.outEdges(sg1Top, sg2Top)[0]).minlen).equals(1);
+      expect(g.outEdges(sg2Bottom, sg1Bottom)).to.have.length(1);
+      expect(g.edge(g.outEdges(sg2Bottom, sg1Bottom)[0]).minlen).equals(1);
+    });
+
+    it("adds sufficient weight to border to node edges", function() {
+      // We want to keep subgraphs tight, so we should ensure that the weight for
+      // the edge between the top (and bottom) border nodes and nodes in the
+      // subgraph have weights exceeding anything in the graph.
+      g.setParent("x", "sg");
+      g.setEdge("a", "x", { weight: 100 });
+      g.setEdge("x", "b", { weight: 200 });
+      nestingGraph.run(g);
+
+      var top = g.node("sg").borderTop,
+          bot = g.node("sg").borderBottom;
+      expect(g.edge(top, "x").weight).to.be.gt(300);
+      expect(g.edge("x", bot).weight).to.be.gt(300);
+    });
+
+    it("adds an edge from the root to the tops of top-level subgraphs", function() {
+      g.setParent("a", "sg1");
+      nestingGraph.run(g);
+
+      var root = g.graph().nestingRoot,
+          borderTop = g.node("sg1").borderTop;
+      expect(root).to.exist;
+      expect(borderTop).to.exist;
+      expect(g.outEdges(root, borderTop)).to.have.length(1);
+      expect(g.hasEdge(g.outEdges(root, borderTop)[0])).to.be.true;
+    });
+
+    it("adds an edge from root to each node with the correct minlen #1", function() {
+      g.setNode("a");
+      nestingGraph.run(g);
+
+      var root = g.graph().nestingRoot;
+      expect(root).to.exist;
+      expect(g.outEdges(root, "a")).to.have.length(1);
+      expect(g.edge(g.outEdges(root, "a")[0])).eqls({ weight: 0, minlen: 1 });
+    });
+
+    it("adds an edge from root to each node with the correct minlen #2", function() {
+      g.setParent("a", "sg1");
+      nestingGraph.run(g);
+
+      var root = g.graph().nestingRoot;
+      expect(root).to.exist;
+      expect(g.outEdges(root, "a")).to.have.length(1);
+      expect(g.edge(g.outEdges(root, "a")[0])).eqls({ weight: 0, minlen: 3 });
+    });
+
+    it("adds an edge from root to each node with the correct minlen #3", function() {
+      g.setParent("sg2", "sg1");
+      g.setParent("a", "sg2");
+      nestingGraph.run(g);
+
+      var root = g.graph().nestingRoot;
+      expect(root).to.exist;
+      expect(g.outEdges(root, "a")).to.have.length(1);
+      expect(g.edge(g.outEdges(root, "a")[0])).eqls({ weight: 0, minlen: 5 });
+    });
+
+    it("does not add an edge from the root to itself", function() {
+      g.setNode("a");
+      nestingGraph.run(g);
+
+      var root = g.graph().nestingRoot;
+      expect(g.outEdges(root, root)).eqls([]);
+    });
+
+    it("expands inter-node edges to separate SG border and nodes #1", function() {
+      g.setEdge("a", "b", { minlen: 1 });
+      nestingGraph.run(g);
+      expect(g.edge("a", "b").minlen).equals(1);
+    });
+
+    it("expands inter-node edges to separate SG border and nodes #2", function() {
+      g.setParent("a", "sg1");
+      g.setEdge("a", "b", { minlen: 1 });
+      nestingGraph.run(g);
+      expect(g.edge("a", "b").minlen).equals(3);
+    });
+
+    it("expands inter-node edges to separate SG border and nodes #3", function() {
+      g.setParent("sg2", "sg1");
+      g.setParent("a", "sg2");
+      g.setEdge("a", "b", { minlen: 1 });
+      nestingGraph.run(g);
+      expect(g.edge("a", "b").minlen).equals(5);
+    });
+
+    it("sets minlen correctly for nested SG boder to children", function() {
+      g.setParent("a", "sg1");
+      g.setParent("sg2", "sg1");
+      g.setParent("b", "sg2");
+      nestingGraph.run(g);
+
+      // We expect the following layering:
+      //
+      // 0: root
+      // 1: empty (close sg2)
+      // 2: empty (close sg1)
+      // 3: open sg1
+      // 4: open sg2
+      // 5: a, b
+      // 6: close sg2
+      // 7: close sg1
+
+      var root = g.graph().nestingRoot,
+          sg1Top = g.node("sg1").borderTop,
+          sg1Bot = g.node("sg1").borderBottom,
+          sg2Top = g.node("sg2").borderTop,
+          sg2Bot = g.node("sg2").borderBottom;
+
+      expect(g.edge(root, sg1Top).minlen).equals(3);
+      expect(g.edge(sg1Top, sg2Top).minlen).equals(1);
+      expect(g.edge(sg1Top, "a").minlen).equals(2);
+      expect(g.edge("a", sg1Bot).minlen).equals(2);
+      expect(g.edge(sg2Top, "b").minlen).equals(1);
+      expect(g.edge("b", sg2Bot).minlen).equals(1);
+      expect(g.edge(sg2Bot, sg1Bot).minlen).equals(1);
+    });
+  });
+
+  describe("cleanup", function() {
+    it("removes nesting graph edges", function() {
+      g.setParent("a", "sg1");
+      g.setEdge("a", "b", { minlen: 1 });
+      nestingGraph.run(g);
+      nestingGraph.cleanup(g);
+      expect(g.successors("a")).eqls(["b"]);
+    });
+
+    it("removes the root node", function() {
+      g.setParent("a", "sg1");
+      nestingGraph.run(g);
+      nestingGraph.cleanup(g);
+      expect(g.nodeCount()).to.equal(4); // sg1 + sg1Top + sg1Bottom + "a"
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/normalize-test.js b/debian/missing-source/dagre/test/normalize-test.js
new file mode 100644
index 0000000..feb70e5
--- /dev/null
+++ b/debian/missing-source/dagre/test/normalize-test.js
@@ -0,0 +1,219 @@
+var _ = require("lodash"),
+    expect = require("./chai").expect,
+    normalize = require("../lib/normalize"),
+    Graph = require("graphlib").Graph;
+
+describe("normalize", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ multigraph: true, compound: true }).setGraph({});
+  });
+
+  describe("run", function() {
+    it("does not change a short edge", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 1 });
+      g.setEdge("a", "b", {});
+
+      normalize.run(g);
+
+      expect(_.map(g.edges(), incidentNodes)).to.eql([{ v: "a", w: "b" }]);
+      expect(g.node("a").rank).to.equal(0);
+      expect(g.node("b").rank).to.equal(1);
+    });
+
+    it("splits a two layer edge into two segments", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 2 });
+      g.setEdge("a", "b", {});
+
+      normalize.run(g);
+
+      expect(g.successors("a")).to.have.length(1);
+      var successor = g.successors("a")[0];
+      expect(g.node(successor).dummy).to.equal("edge");
+      expect(g.node(successor).rank).to.equal(1);
+      expect(g.successors(successor)).to.eql(["b"]);
+      expect(g.node("a").rank).to.equal(0);
+      expect(g.node("b").rank).to.equal(2);
+
+      expect(g.graph().dummyChains).to.have.length(1);
+      expect(g.graph().dummyChains[0]).to.equal(successor);
+    });
+
+    it("assigns width = 0, height = 0 to dummy nodes by default", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 2 });
+      g.setEdge("a", "b", { width: 10, height: 10 });
+
+      normalize.run(g);
+
+      expect(g.successors("a")).to.have.length(1);
+      var successor = g.successors("a")[0];
+      expect(g.node(successor).width).to.equal(0);
+      expect(g.node(successor).height).to.equal(0);
+    });
+
+    it("assigns width and height from the edge for the node on labelRank", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 4 });
+      g.setEdge("a", "b", { width: 20, height: 10, labelRank: 2 });
+
+      normalize.run(g);
+
+      var labelV = g.successors(g.successors("a")[0])[0],
+          labelNode = g.node(labelV);
+      expect(labelNode.width).to.equal(20);
+      expect(labelNode.height).to.equal(10);
+    });
+
+    it("preserves the weight for the edge", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 2 });
+      g.setEdge("a", "b", { weight: 2 });
+
+      normalize.run(g);
+
+      expect(g.successors("a")).to.have.length(1);
+      expect(g.edge("a", g.successors("a")[0]).weight).to.equal(2);
+    });
+  });
+
+  describe("undo", function() {
+    it("reverses the run operation", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 2 });
+      g.setEdge("a", "b", {});
+
+      normalize.run(g);
+      normalize.undo(g);
+
+      expect(_.map(g.edges(), incidentNodes)).to.eql([{ v: "a", w: "b" }]);
+      expect(g.node("a").rank).to.equal(0);
+      expect(g.node("b").rank).to.equal(2);
+    });
+
+    it("restores previous edge labels", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 2 });
+      g.setEdge("a", "b", { foo: "bar" });
+
+      normalize.run(g);
+      normalize.undo(g);
+
+      expect(g.edge("a", "b").foo).equals("bar");
+    });
+
+    it("collects assigned coordinates into the 'points' attribute", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 2 });
+      g.setEdge("a", "b", {});
+
+      normalize.run(g);
+
+      var dummyLabel = g.node(g.neighbors("a")[0]);
+      dummyLabel.x = 5;
+      dummyLabel.y = 10;
+
+      normalize.undo(g);
+
+      expect(g.edge("a", "b").points).eqls([{ x: 5, y: 10 }]);
+    });
+
+    it("merges assigned coordinates into the 'points' attribute", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 4 });
+      g.setEdge("a", "b", {});
+
+      normalize.run(g);
+
+      var aSucLabel = g.node(g.neighbors("a")[0]);
+      aSucLabel.x = 5;
+      aSucLabel.y = 10;
+
+      var midLabel = g.node(g.successors(g.successors("a")[0])[0]);
+      midLabel.x = 20;
+      midLabel.y = 25;
+
+      var bPredLabel = g.node(g.neighbors("b")[0]);
+      bPredLabel.x = 100;
+      bPredLabel.y = 200;
+
+      normalize.undo(g);
+
+      expect(g.edge("a", "b").points)
+        .eqls([{ x: 5, y: 10 }, { x: 20, y: 25 }, { x: 100, y: 200 }]);
+    });
+
+    it("sets coords and dims for the label, if the edge has one", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 2 });
+      g.setEdge("a", "b", { width: 10, height: 20, labelRank: 1 });
+
+      normalize.run(g);
+
+      var labelNode = g.node(g.successors("a")[0]);
+      labelNode.x = 50;
+      labelNode.y = 60;
+      labelNode.width = 20;
+      labelNode.height = 10;
+
+      normalize.undo(g);
+
+      expect(_.pick(g.edge("a", "b"), ["x", "y", "width", "height"])).eqls({
+        x: 50, y: 60, width: 20, height: 10
+      });
+    });
+
+    it("sets coords and dims for the label, if the long edge has one", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 4 });
+      g.setEdge("a", "b", { width: 10, height: 20, labelRank: 2 });
+
+      normalize.run(g);
+
+      var labelNode = g.node(g.successors(g.successors("a")[0])[0]);
+      labelNode.x = 50;
+      labelNode.y = 60;
+      labelNode.width = 20;
+      labelNode.height = 10;
+
+      normalize.undo(g);
+
+      expect(_.pick(g.edge("a", "b"), ["x", "y", "width", "height"])).eqls({
+        x: 50, y: 60, width: 20, height: 10
+      });
+    });
+
+    it("restores multi-edges", function() {
+      g.setNode("a", { rank: 0 });
+      g.setNode("b", { rank: 2 });
+      g.setEdge("a", "b", {}, "bar");
+      g.setEdge("a", "b", {}, "foo");
+
+      normalize.run(g);
+
+      var outEdges = _.sortBy(g.outEdges("a"), "name");
+      expect(outEdges).to.have.length(2);
+
+      var barDummy = g.node(outEdges[0].w);
+      barDummy.x = 5;
+      barDummy.y = 10;
+
+      var fooDummy = g.node(outEdges[1].w);
+      fooDummy.x = 15;
+      fooDummy.y = 20;
+
+      normalize.undo(g);
+
+      expect(g.hasEdge("a", "b")).to.be.false;
+      expect(g.edge("a", "b", "bar").points).eqls([{ x: 5, y: 10 }]);
+      expect(g.edge("a", "b", "foo").points).eqls([{ x: 15, y: 20 }]);
+    });
+  });
+});
+
+function incidentNodes(edge) {
+  return { v: edge.v, w: edge.w };
+}
diff --git a/debian/missing-source/dagre/test/order/add-subgraph-constraints-test.js b/debian/missing-source/dagre/test/order/add-subgraph-constraints-test.js
new file mode 100644
index 0000000..f294db8
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/add-subgraph-constraints-test.js
@@ -0,0 +1,59 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    addSubgraphConstraints = require("../../lib/order/add-subgraph-constraints");
+
+describe("order/addSubgraphConstraints", function() {
+  var g, cg;
+
+  beforeEach(function() {
+    g = new Graph({ compound: true });
+    cg = new Graph();
+  });
+
+  it("does not change CG for a flat set of nodes", function() {
+    var vs = ["a", "b", "c", "d"];
+    _.each(vs, function(v) { g.setNode(v); });
+    addSubgraphConstraints(g, cg, vs);
+    expect(cg.nodeCount()).equals(0);
+    expect(cg.edgeCount()).equals(0);
+  });
+
+  it("doesn't create a constraint for contiguous subgraph nodes", function() {
+    var vs = ["a", "b", "c"];
+    _.each(vs, function(v) {
+      g.setParent(v, "sg");
+    });
+    addSubgraphConstraints(g, cg, vs);
+    expect(cg.nodeCount()).equals(0);
+    expect(cg.edgeCount()).equals(0);
+  });
+
+  it("adds a constraint when the parents for adjacent nodes are different", function() {
+    var vs = ["a", "b"];
+    g.setParent("a", "sg1");
+    g.setParent("b", "sg2");
+    addSubgraphConstraints(g, cg, vs);
+    expect(cg.edges()).eqls([{ v: "sg1", w: "sg2" }]);
+  });
+
+  it("works for multiple levels", function() {
+    var vs = ["a", "b", "c", "d", "e", "f", "g", "h"];
+    _.each(vs, function(v) {
+      g.setNode(v);
+    });
+    g.setParent("b", "sg2");
+    g.setParent("sg2", "sg1");
+    g.setParent("c", "sg1");
+    g.setParent("d", "sg3");
+    g.setParent("sg3", "sg1");
+    g.setParent("f", "sg4");
+    g.setParent("g", "sg5");
+    g.setParent("sg5", "sg4");
+    addSubgraphConstraints(g, cg, vs);
+    expect(_.sortBy(cg.edges(), "v")).eqls([
+      { v: "sg1", w: "sg4" },
+      { v: "sg2", w: "sg3" }
+    ]);
+  });
+});
diff --git a/debian/missing-source/dagre/test/order/barycenter-test.js b/debian/missing-source/dagre/test/order/barycenter-test.js
new file mode 100644
index 0000000..5a1a324
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/barycenter-test.js
@@ -0,0 +1,69 @@
+var expect = require("../chai").expect,
+    barycenter = require("../../lib/order/barycenter"),
+    Graph = require("graphlib").Graph;
+
+describe("order/barycenter", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph()
+      .setDefaultNodeLabel(function() { return {}; })
+      .setDefaultEdgeLabel(function() { return { weight: 1 }; });
+  });
+
+  it("assigns an undefined barycenter for a node with no predecessors", function() {
+    g.setNode("x", {});
+
+    var results = barycenter(g, ["x"]);
+    expect(results).to.have.length(1);
+    expect(results[0]).to.eql({ v: "x" });
+  });
+
+  it("assigns the position of the sole predecessors", function() {
+    g.setNode("a", { order: 2 });
+    g.setEdge("a", "x");
+
+    var results = barycenter(g, ["x"]);
+    expect(results).to.have.length(1);
+    expect(results[0]).eqls({ v: "x", barycenter: 2, weight: 1 });
+  });
+
+  it("assigns the average of multiple predecessors", function() {
+    g.setNode("a", { order: 2 });
+    g.setNode("b", { order: 4 });
+    g.setEdge("a", "x");
+    g.setEdge("b", "x");
+
+    var results = barycenter(g, ["x"]);
+    expect(results).to.have.length(1);
+    expect(results[0]).eqls({ v: "x", barycenter: 3, weight: 2 });
+  });
+
+  it("takes into account the weight of edges", function() {
+    g.setNode("a", { order: 2 });
+    g.setNode("b", { order: 4 });
+    g.setEdge("a", "x", { weight: 3 });
+    g.setEdge("b", "x");
+
+    var results = barycenter(g, ["x"]);
+    expect(results).to.have.length(1);
+    expect(results[0]).eqls({ v: "x", barycenter: 2.5, weight: 4 });
+  });
+
+  it("calculates barycenters for all nodes in the movable layer", function() {
+    g.setNode("a", { order: 1 });
+    g.setNode("b", { order: 2 });
+    g.setNode("c", { order: 4 });
+    g.setEdge("a", "x");
+    g.setEdge("b", "x");
+    g.setNode("y");
+    g.setEdge("a", "z", { weight: 2 });
+    g.setEdge("c", "z");
+
+    var results = barycenter(g, ["x", "y", "z"]);
+    expect(results).to.have.length(3);
+    expect(results[0]).eqls({ v: "x", barycenter: 1.5, weight: 2 });
+    expect(results[1]).eqls({ v: "y" });
+    expect(results[2]).eqls({ v: "z", barycenter: 2, weight: 3 });
+  });
+});
diff --git a/debian/missing-source/dagre/test/order/build-layer-graph-test.js b/debian/missing-source/dagre/test/order/build-layer-graph-test.js
new file mode 100644
index 0000000..b3a5184
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/build-layer-graph-test.js
@@ -0,0 +1,117 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    buildLayerGraph = require("../../lib/order/build-layer-graph");
+
+describe("order/buildLayerGraph", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ compound: true, multigraph: true });
+  });
+
+  it("places movable nodes with no parents under the root node", function() {
+    g.setNode("a", { rank: 1 });
+    g.setNode("b", { rank: 1 });
+    g.setNode("c", { rank: 2 });
+    g.setNode("d", { rank: 3 });
+
+    var lg;
+    lg = buildLayerGraph(g, 1, "inEdges");
+    expect(lg.hasNode(lg.graph().root));
+    expect(lg.children()).eqls([lg.graph().root]);
+    expect(lg.children(lg.graph().root)).eqls(["a", "b"]);
+  });
+
+  it("copies flat nodes from the layer to the graph", function() {
+    g.setNode("a", { rank: 1 });
+    g.setNode("b", { rank: 1 });
+    g.setNode("c", { rank: 2 });
+    g.setNode("d", { rank: 3 });
+
+    expect(buildLayerGraph(g, 1, "inEdges").nodes()).to.include("a");
+    expect(buildLayerGraph(g, 1, "inEdges").nodes()).to.include("b");
+    expect(buildLayerGraph(g, 2, "inEdges").nodes()).to.include("c");
+    expect(buildLayerGraph(g, 3, "inEdges").nodes()).to.include("d");
+  });
+
+  it("uses the original node label for copied nodes", function() {
+    // This allows us to make updates to the original graph and have them
+    // be available automatically in the layer graph.
+    g.setNode("a", { foo: 1, rank: 1 });
+    g.setNode("b", { foo: 2, rank: 2 });
+    g.setEdge("a", "b", { weight: 1 });
+
+    var lg = buildLayerGraph(g, 2, "inEdges");
+
+    expect(lg.node("a").foo).equals(1);
+    g.node("a").foo = "updated";
+    expect(lg.node("a").foo).equals("updated");
+
+    expect(lg.node("b").foo).equals(2);
+    g.node("b").foo = "updated";
+    expect(lg.node("b").foo).equals("updated");
+  });
+
+  it("copies edges incident on rank nodes to the graph (inEdges)", function() {
+    g.setNode("a", { rank: 1 });
+    g.setNode("b", { rank: 1 });
+    g.setNode("c", { rank: 2 });
+    g.setNode("d", { rank: 3 });
+    g.setEdge("a", "c", { weight: 2 });
+    g.setEdge("b", "c", { weight: 3 });
+    g.setEdge("c", "d", { weight: 4 });
+
+    expect(buildLayerGraph(g, 1, "inEdges").edgeCount()).to.equal(0);
+    expect(buildLayerGraph(g, 2, "inEdges").edgeCount()).to.equal(2);
+    expect(buildLayerGraph(g, 2, "inEdges").edge("a", "c")).eqls({ weight: 2 });
+    expect(buildLayerGraph(g, 2, "inEdges").edge("b", "c")).eqls({ weight: 3 });
+    expect(buildLayerGraph(g, 3, "inEdges").edgeCount()).to.equal(1);
+    expect(buildLayerGraph(g, 3, "inEdges").edge("c", "d")).eqls({ weight: 4 });
+  });
+
+  it("copies edges incident on rank nodes to the graph (outEdges)", function() {
+    g.setNode("a", { rank: 1 });
+    g.setNode("b", { rank: 1 });
+    g.setNode("c", { rank: 2 });
+    g.setNode("d", { rank: 3 });
+    g.setEdge("a", "c", { weight: 2 });
+    g.setEdge("b", "c", { weight: 3 });
+    g.setEdge("c", "d", { weight: 4 });
+
+    expect(buildLayerGraph(g, 1, "outEdges").edgeCount()).to.equal(2);
+    expect(buildLayerGraph(g, 1, "outEdges").edge("c", "a")).eqls({ weight: 2 });
+    expect(buildLayerGraph(g, 1, "outEdges").edge("c", "b")).eqls({ weight: 3 });
+    expect(buildLayerGraph(g, 2, "outEdges").edgeCount()).to.equal(1);
+    expect(buildLayerGraph(g, 2, "outEdges").edge("d", "c")).eqls({ weight: 4 });
+    expect(buildLayerGraph(g, 3, "outEdges").edgeCount()).to.equal(0);
+  });
+
+  it("collapses multi-edges", function() {
+    g.setNode("a", { rank: 1 });
+    g.setNode("b", { rank: 2 });
+    g.setEdge("a", "b", { weight: 2 });
+    g.setEdge("a", "b", { weight: 3 }, "multi");
+
+    expect(buildLayerGraph(g, 2, "inEdges").edge("a", "b")).eqls({ weight: 5 });
+  });
+
+  it("preserves hierarchy for the movable layer", function() {
+    g.setNode("a", { rank: 0 });
+    g.setNode("b", { rank: 0 });
+    g.setNode("c", { rank: 0 });
+    g.setNode("sg", {
+      minRank: 0,
+      maxRank: 0,
+      borderLeft: ["bl"],
+      borderRight: ["br"]
+    });
+    _.each(["a", "b"], function(v) { g.setParent(v, "sg"); });
+
+    var lg = buildLayerGraph(g, 0, "inEdges"),
+        root = lg.graph().root;
+    expect(_.sortBy(lg.children(root))).eqls(["c", "sg"]);
+    expect(lg.parent("a")).equals("sg");
+    expect(lg.parent("b")).equals("sg");
+  });
+});
diff --git a/debian/missing-source/dagre/test/order/cross-count-test.js b/debian/missing-source/dagre/test/order/cross-count-test.js
new file mode 100644
index 0000000..320d5fc
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/cross-count-test.js
@@ -0,0 +1,49 @@
+var expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    crossCount = require("../../lib/order/cross-count");
+
+describe("crossCount", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph()
+      .setDefaultEdgeLabel(function() { return { weight: 1 }; });
+  });
+
+  it("returns 0 for an empty layering", function() {
+    expect(crossCount(g, [])).equals(0);
+  });
+
+  it("returns 0 for a layering with no crossings", function() {
+    g.setEdge("a1", "b1");
+    g.setEdge("a2", "b2");
+    expect(crossCount(g, [["a1", "a2"], ["b1", "b2"]])).equals(0);
+  });
+
+  it("returns 1 for a layering with 1 crossing", function() {
+    g.setEdge("a1", "b1");
+    g.setEdge("a2", "b2");
+    expect(crossCount(g, [["a1", "a2"], ["b2", "b1"]])).equals(1);
+  });
+
+  it("returns a weighted crossing count for a layering with 1 crossing", function() {
+    g.setEdge("a1", "b1", { weight: 2 });
+    g.setEdge("a2", "b2", { weight: 3 });
+    expect(crossCount(g, [["a1", "a2"], ["b2", "b1"]])).equals(6);
+  });
+
+  it("calculates crossings across layers", function() {
+    g.setPath(["a1", "b1", "c1"]);
+    g.setPath(["a2", "b2", "c2"]);
+    expect(crossCount(g, [["a1", "a2"], ["b2", "b1"], ["c1", "c2"]])).equals(2);
+  });
+
+  it("works for graph #1", function() {
+    g.setPath(["a", "b", "c"]);
+    g.setPath(["d", "e", "c"]);
+    g.setPath(["a", "f", "i"]);
+    g.setEdge("a", "e");
+    expect(crossCount(g, [["a", "d"], ["b", "e", "f"], ["c", "i"]])).equals(1);
+    expect(crossCount(g, [["d", "a"], ["e", "b", "f"], ["c", "i"]])).equals(0);
+  });
+});
diff --git a/debian/missing-source/dagre/test/order/init-order-test.js b/debian/missing-source/dagre/test/order/init-order-test.js
new file mode 100644
index 0000000..da03c95
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/init-order-test.js
@@ -0,0 +1,49 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    initOrder = require("../../lib/order/init-order");
+
+describe("order/initOrder", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ compound: true })
+      .setDefaultEdgeLabel(function() { return { weight: 1 }; });
+  });
+
+  it("assigns non-overlapping orders for each rank in a tree", function() {
+    _.each({ a: 0, b: 1, c: 2, d: 2, e: 1 }, function(rank, v) {
+      g.setNode(v, { rank: rank });
+    });
+    g.setPath(["a", "b", "c"]);
+    g.setEdge("b", "d");
+    g.setEdge("a", "e");
+
+    var layering = initOrder(g);
+    expect(layering[0]).to.eql(["a"]);
+    expect(_.sortBy(layering[1])).to.eql(["b", "e"]);
+    expect(_.sortBy(layering[2])).to.eql(["c", "d"]);
+  });
+
+  it("assigns non-overlapping orders for each rank in a DAG", function() {
+    _.each({ a: 0, b: 1, c: 1, d: 2 }, function(rank, v) {
+      g.setNode(v, { rank: rank });
+    });
+    g.setPath(["a", "b", "d"]);
+    g.setPath(["a", "c", "d"]);
+
+    var layering = initOrder(g);
+    expect(layering[0]).to.eql(["a"]);
+    expect(_.sortBy(layering[1])).to.eql(["b", "c"]);
+    expect(_.sortBy(layering[2])).to.eql(["d"]);
+  });
+
+  it("does not assign an order to subgraph nodes", function() {
+    g.setNode("a", { rank: 0 });
+    g.setNode("sg1", {});
+    g.setParent("a", "sg1");
+
+    var layering = initOrder(g);
+    expect(layering).to.eql([["a"]]);
+  });
+});
diff --git a/debian/missing-source/dagre/test/order/order-test.js b/debian/missing-source/dagre/test/order/order-test.js
new file mode 100644
index 0000000..be23889
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/order-test.js
@@ -0,0 +1,47 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    order = require("../../lib/order"),
+    crossCount = require("../../lib/order/cross-count"),
+    util = require("../../lib/util");
+
+describe("order", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph()
+      .setDefaultEdgeLabel({ weight: 1 });
+  });
+
+  it("does not add crossings to a tree structure", function() {
+    g.setNode("a", { rank: 1 });
+    _.each(["b", "e"], function(v) { g.setNode(v, { rank: 2 }); });
+    _.each(["c", "d", "f"], function(v) { g.setNode(v, { rank: 3 }); });
+    g.setPath(["a", "b", "c"]);
+    g.setEdge("b", "d");
+    g.setPath(["a", "e", "f"]);
+    order(g);
+    var layering = util.buildLayerMatrix(g);
+    expect(crossCount(g, layering)).to.equal(0);
+  });
+
+  it("can solve a simple graph", function() {
+    // This graph resulted in a single crossing for previous versions of dagre.
+    _.each(["a", "d"], function(v) { g.setNode(v, { rank: 1 }); });
+    _.each(["b", "f", "e"], function(v) { g.setNode(v, { rank: 2 }); });
+    _.each(["c", "g"], function(v) { g.setNode(v, { rank: 3 }); });
+    order(g);
+    var layering = util.buildLayerMatrix(g);
+    expect(crossCount(g, layering)).to.equal(0);
+  });
+
+  it("can minimize crossings", function() {
+    g.setNode("a", { rank: 1 });
+    _.each(["b", "e", "g"], function(v) { g.setNode(v, { rank: 2 }); });
+    _.each(["c", "f", "h"], function(v) { g.setNode(v, { rank: 3 }); });
+    g.setNode("d", { rank: 4 });
+    order(g);
+    var layering = util.buildLayerMatrix(g);
+    expect(crossCount(g, layering)).to.be.lte(1);
+  });
+});
diff --git a/debian/missing-source/dagre/test/order/resolve-conflicts-test.js b/debian/missing-source/dagre/test/order/resolve-conflicts-test.js
new file mode 100644
index 0000000..c42df5e
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/resolve-conflicts-test.js
@@ -0,0 +1,150 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    resolveConflicts = require("../../lib/order/resolve-conflicts");
+
+describe("order/resolveConflicts", function() {
+  var cg;
+
+  beforeEach(function() {
+    cg = new Graph();
+  });
+
+  it("returns back nodes unchanged when no constraints exist", function() {
+    var input = [
+      { v: "a", barycenter: 2, weight: 3 },
+      { v: "b", barycenter: 1, weight: 2 }
+    ];
+    expect(_.sortBy(resolveConflicts(input, cg), "vs")).eqls([
+      { vs: ["a"], i: 0, barycenter: 2, weight: 3 },
+      { vs: ["b"], i: 1, barycenter: 1, weight: 2 }
+    ]);
+  });
+
+  it("returns back nodes unchanged when no conflicts exist", function() {
+    var input = [
+      { v: "a", barycenter: 2, weight: 3 },
+      { v: "b", barycenter: 1, weight: 2 }
+    ];
+    cg.setEdge("b", "a");
+    expect(_.sortBy(resolveConflicts(input, cg), "vs")).eqls([
+      { vs: ["a"], i: 0, barycenter: 2, weight: 3 },
+      { vs: ["b"], i: 1, barycenter: 1, weight: 2 }
+    ]);
+  });
+
+  it("coalesces nodes when there is a conflict", function() {
+    var input = [
+      { v: "a", barycenter: 2, weight: 3 },
+      { v: "b", barycenter: 1, weight: 2 }
+    ];
+    cg.setEdge("a", "b");
+    expect(_.sortBy(resolveConflicts(input, cg), "vs")).eqls([
+      { vs: ["a", "b"],
+        i: 0,
+        barycenter: (3 * 2 + 2 * 1) / (3 + 2),
+        weight: 3 + 2
+      }
+    ]);
+  });
+
+  it("coalesces nodes when there is a conflict #2", function() {
+    var input = [
+      { v: "a", barycenter: 4, weight: 1 },
+      { v: "b", barycenter: 3, weight: 1 },
+      { v: "c", barycenter: 2, weight: 1 },
+      { v: "d", barycenter: 1, weight: 1 }
+    ];
+    cg.setPath(["a", "b", "c", "d"]);
+    expect(_.sortBy(resolveConflicts(input, cg), "vs")).eqls([
+      { vs: ["a", "b", "c", "d"],
+        i: 0,
+        barycenter: (4 + 3 + 2 + 1) / 4,
+        weight: 4
+      }
+    ]);
+  });
+
+  it("works with multiple constraints for the same target #1", function() {
+    var input = [
+      { v: "a", barycenter: 4, weight: 1 },
+      { v: "b", barycenter: 3, weight: 1 },
+      { v: "c", barycenter: 2, weight: 1 },
+    ];
+    cg.setEdge("a", "c");
+    cg.setEdge("b", "c");
+    var results = resolveConflicts(input, cg);
+    expect(results).to.have.length(1);
+    expect(_.indexOf(results[0].vs, "c")).to.be.gt(_.indexOf(results[0].vs, "a"));
+    expect(_.indexOf(results[0].vs, "c")).to.be.gt(_.indexOf(results[0].vs, "b"));
+    expect(results[0].i).equals(0);
+    expect(results[0].barycenter).equals((4 + 3 + 2) / 3);
+    expect(results[0].weight).equals(3);
+  });
+
+  it("works with multiple constraints for the same target #2", function() {
+    var input = [
+      { v: "a", barycenter: 4, weight: 1 },
+      { v: "b", barycenter: 3, weight: 1 },
+      { v: "c", barycenter: 2, weight: 1 },
+      { v: "d", barycenter: 1, weight: 1 },
+    ];
+    cg.setEdge("a", "c");
+    cg.setEdge("a", "d");
+    cg.setEdge("b", "c");
+    cg.setEdge("c", "d");
+    var results = resolveConflicts(input, cg);
+    expect(results).to.have.length(1);
+    expect(_.indexOf(results[0].vs, "c")).to.be.gt(_.indexOf(results[0].vs, "a"));
+    expect(_.indexOf(results[0].vs, "c")).to.be.gt(_.indexOf(results[0].vs, "b"));
+    expect(_.indexOf(results[0].vs, "d")).to.be.gt(_.indexOf(results[0].vs, "c"));
+    expect(results[0].i).equals(0);
+    expect(results[0].barycenter).equals((4 + 3 + 2 + 1) / 4);
+    expect(results[0].weight).equals(4);
+  });
+
+  it("does nothing to a node lacking both a barycenter and a constraint", function() {
+    var input = [
+      { v: "a" },
+      { v: "b", barycenter: 1, weight: 2 }
+    ];
+    expect(_.sortBy(resolveConflicts(input, cg), "vs")).eqls([
+      { vs: ["a"], i: 0 },
+      { vs: ["b"], i: 1, barycenter: 1, weight: 2 }
+    ]);
+  });
+
+  it("treats a node w/o a barycenter as always violating constraints #1", function() {
+    var input = [
+      { v: "a" },
+      { v: "b", barycenter: 1, weight: 2 }
+    ];
+    cg.setEdge("a", "b");
+    expect(_.sortBy(resolveConflicts(input, cg), "vs")).eqls([
+      { vs: ["a", "b"], i: 0, barycenter: 1, weight: 2 }
+    ]);
+  });
+
+  it("treats a node w/o a barycenter as always violating constraints #2", function() {
+    var input = [
+      { v: "a" },
+      { v: "b", barycenter: 1, weight: 2 }
+    ];
+    cg.setEdge("b", "a");
+    expect(_.sortBy(resolveConflicts(input, cg), "vs")).eqls([
+      { vs: ["b", "a"], i: 0, barycenter: 1, weight: 2 }
+    ]);
+  });
+
+  it("ignores edges not related to entries", function() {
+    var input = [
+      { v: "a", barycenter: 2, weight: 3 },
+      { v: "b", barycenter: 1, weight: 2 }
+    ];
+    cg.setEdge("c", "d");
+    expect(_.sortBy(resolveConflicts(input, cg), "vs")).eqls([
+      { vs: ["a"], i: 0, barycenter: 2, weight: 3 },
+      { vs: ["b"], i: 1, barycenter: 1, weight: 2 }
+    ]);
+  });
+});
diff --git a/debian/missing-source/dagre/test/order/sort-subgraph-test.js b/debian/missing-source/dagre/test/order/sort-subgraph-test.js
new file mode 100644
index 0000000..b984d80
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/sort-subgraph-test.js
@@ -0,0 +1,126 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    sortSubgraph = require("../../lib/order/sort-subgraph"),
+    Graph = require("graphlib").Graph;
+
+describe("order/sortSubgraph", function() {
+  var g, cg;
+
+  beforeEach(function() {
+    g = new Graph({ compound: true })
+      .setDefaultNodeLabel(function() { return {}; })
+      .setDefaultEdgeLabel(function() { return { weight: 1 }; });
+    _.each(_.range(5), function(v) { g.setNode(v, { order: v }); });
+    cg = new Graph();
+  });
+
+  it("sorts a flat subgraph based on barycenter", function() {
+    g.setEdge(3, "x");
+    g.setEdge(1, "y", { weight: 2 });
+    g.setEdge(4, "y");
+    _.each(["x", "y"], function(v) { g.setParent(v, "movable"); });
+
+    expect(sortSubgraph(g, "movable", cg).vs).eqls(["y", "x"]);
+  });
+
+  it("preserves the pos of a node (y) w/o neighbors in a flat subgraph", function() {
+    g.setEdge(3, "x");
+    g.setNode("y");
+    g.setEdge(1, "z", { weight: 2 });
+    g.setEdge(4, "z");
+    _.each(["x", "y", "z"], function(v) { g.setParent(v, "movable"); });
+
+    expect(sortSubgraph(g, "movable", cg).vs).eqls(["z", "y", "x"]);
+  });
+
+  it("biases to the left without reverse bias", function() {
+    g.setEdge(1, "x");
+    g.setEdge(1, "y");
+    _.each(["x", "y"], function(v) { g.setParent(v, "movable"); });
+
+    expect(sortSubgraph(g, "movable", cg).vs).eqls(["x", "y"]);
+  });
+
+  it("biases to the right with reverse bias", function() {
+    g.setEdge(1, "x");
+    g.setEdge(1, "y");
+    _.each(["x", "y"], function(v) { g.setParent(v, "movable"); });
+
+    expect(sortSubgraph(g, "movable", cg, true).vs).eqls(["y", "x"]);
+  });
+
+  it("aggregates stats about the subgraph", function() {
+    g.setEdge(3, "x");
+    g.setEdge(1, "y", { weight: 2 });
+    g.setEdge(4, "y");
+    _.each(["x", "y"], function(v) { g.setParent(v, "movable"); });
+
+    var results = sortSubgraph(g, "movable", cg);
+    expect(results.barycenter).to.equal(2.25);
+    expect(results.weight).to.equal(4);
+  });
+
+  it("can sort a nested subgraph with no barycenter", function() {
+    g.setNodes(["a", "b", "c"]);
+    g.setParent("a", "y");
+    g.setParent("b", "y");
+    g.setParent("c", "y");
+    g.setEdge(0, "x");
+    g.setEdge(1, "z");
+    g.setEdge(2, "y");
+    _.each(["x", "y", "z"], function(v) { g.setParent(v, "movable"); });
+
+    expect(sortSubgraph(g, "movable", cg).vs).eqls(["x", "z", "a", "b", "c"]);
+  });
+
+  it("can sort a nested subgraph with a barycenter", function() {
+    g.setNodes(["a", "b", "c"]);
+    g.setParent("a", "y");
+    g.setParent("b", "y");
+    g.setParent("c", "y");
+    g.setEdge(0, "a", { weight: 3 });
+    g.setEdge(0, "x");
+    g.setEdge(1, "z");
+    g.setEdge(2, "y");
+    _.each(["x", "y", "z"], function(v) { g.setParent(v, "movable"); });
+
+    expect(sortSubgraph(g, "movable", cg).vs).eqls(["x", "a", "b", "c", "z"]);
+  });
+
+  it("can sort a nested subgraph with no in-edges", function() {
+    g.setNodes(["a", "b", "c"]);
+    g.setParent("a", "y");
+    g.setParent("b", "y");
+    g.setParent("c", "y");
+    g.setEdge(0, "a");
+    g.setEdge(1, "b");
+    g.setEdge(0, "x");
+    g.setEdge(1, "z");
+    _.each(["x", "y", "z"], function(v) { g.setParent(v, "movable"); });
+
+    expect(sortSubgraph(g, "movable", cg).vs).eqls(["x", "a", "b", "c", "z"]);
+  });
+
+  it("sorts border nodes to the extremes of the subgraph", function() {
+    g.setEdge(0, "x");
+    g.setEdge(1, "y");
+    g.setEdge(2, "z");
+    g.setNode("sg1", { borderLeft: "bl", borderRight: "br" });
+    _.each(["x", "y", "z", "bl", "br"], function(v) { g.setParent(v, "sg1"); });
+    expect(sortSubgraph(g, "sg1", cg).vs).eqls(["bl", "x", "y", "z", "br"]);
+  });
+
+  it("assigns a barycenter to a subgraph based on previous border nodes", function() {
+    g.setNode("bl1", { order: 0 });
+    g.setNode("br1", { order: 1 });
+    g.setEdge("bl1", "bl2");
+    g.setEdge("br1", "br2");
+    _.each(["bl2", "br2"], function(v) { g.setParent(v, "sg"); });
+    g.setNode("sg", { borderLeft: "bl2", borderRight: "br2" });
+    expect(sortSubgraph(g, "sg", cg)).eqls({
+      barycenter: 0.5,
+      weight: 2,
+      vs: ["bl2", "br2"]
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/order/sort-test.js b/debian/missing-source/dagre/test/order/sort-test.js
new file mode 100644
index 0000000..b9ef471
--- /dev/null
+++ b/debian/missing-source/dagre/test/order/sort-test.js
@@ -0,0 +1,86 @@
+var expect = require("../chai").expect,
+    sort = require("../../lib/order/sort");
+
+describe("sort", function() {
+  it("sorts nodes by barycenter", function() {
+    var input = [
+      { vs: ["a"], i: 0, barycenter: 2, weight: 3 },
+      { vs: ["b"], i: 1, barycenter: 1, weight: 2 }
+    ];
+    expect(sort(input)).eqls({
+      vs: ["b", "a"],
+      barycenter: (2 * 3 + 1 * 2) / (3 + 2),
+      weight: 3 + 2 });
+  });
+
+  it("can sort super-nodes", function() {
+    var input = [
+      { vs: ["a", "c", "d"], i: 0, barycenter: 2, weight: 3 },
+      { vs: ["b"], i: 1, barycenter: 1, weight: 2 }
+    ];
+    expect(sort(input)).eqls({
+      vs: ["b", "a", "c", "d"],
+      barycenter: (2 * 3 + 1 * 2) / (3 + 2),
+      weight: 3 + 2 });
+  });
+
+  it("biases to the left by default", function() {
+    var input = [
+      { vs: ["a"], i: 0, barycenter: 1, weight: 1 },
+      { vs: ["b"], i: 1, barycenter: 1, weight: 1 }
+    ];
+    expect(sort(input)).eqls({
+      vs: ["a", "b"],
+      barycenter: 1,
+      weight: 2 });
+  });
+
+  it("biases to the right if biasRight = true", function() {
+    var input = [
+      { vs: ["a"], i: 0, barycenter: 1, weight: 1 },
+      { vs: ["b"], i: 1, barycenter: 1, weight: 1 }
+    ];
+    expect(sort(input, true)).eqls({
+      vs: ["b", "a"],
+      barycenter: 1,
+      weight: 2 });
+  });
+
+  it("can sort nodes without a barycenter", function() {
+    var input = [
+      { vs: ["a"], i: 0, barycenter: 2, weight: 1 },
+      { vs: ["b"], i: 1, barycenter: 6, weight: 1 },
+      { vs: ["c"], i: 2 },
+      { vs: ["d"], i: 3, barycenter: 3, weight: 1 }
+    ];
+    expect(sort(input)).eqls({
+      vs: ["a", "d", "c", "b"],
+      barycenter: (2 + 6 + 3) / 3,
+      weight: 3
+    });
+  });
+
+  it("can handle no barycenters for any nodes", function() {
+    var input = [
+      { vs: ["a"], i: 0 },
+      { vs: ["b"], i: 3 },
+      { vs: ["c"], i: 2 },
+      { vs: ["d"], i: 1 }
+    ];
+    expect(sort(input)).eqls({ vs: ["a", "d", "c", "b"] });
+  });
+
+  it("can handle a barycenter of 0", function() {
+    var input = [
+      { vs: ["a"], i: 0, barycenter: 0, weight: 1 },
+      { vs: ["b"], i: 3 },
+      { vs: ["c"], i: 2 },
+      { vs: ["d"], i: 1 }
+    ];
+    expect(sort(input)).eqls({
+      vs: ["a", "d", "c", "b"],
+      barycenter: 0,
+      weight: 1
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/parent-dummy-chains-test.js b/debian/missing-source/dagre/test/parent-dummy-chains-test.js
new file mode 100644
index 0000000..d9653c2
--- /dev/null
+++ b/debian/missing-source/dagre/test/parent-dummy-chains-test.js
@@ -0,0 +1,147 @@
+var expect = require("./chai").expect,
+    Graph = require("graphlib").Graph,
+    parentDummyChains = require("../lib/parent-dummy-chains");
+
+describe("parentDummyChains", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ compound: true }).setGraph({});
+  });
+
+  it("does not set a parent if both the tail and head have no parent", function() {
+    g.setNode("a");
+    g.setNode("b");
+    g.setNode("d1", { edgeObj: { v: "a", w: "b" } });
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).to.be.undefined;
+  });
+
+  it("uses the tail's parent for the first node if it is not the root", function() {
+    g.setParent("a", "sg1");
+    g.setNode("sg1", { minRank: 0, maxRank: 2 });
+    g.setNode("d1", { edgeObj: { v: "a", w: "b" }, rank: 2 });
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).equals("sg1");
+  });
+
+  it("uses the heads's parent for the first node if tail's is root", function() {
+    g.setParent("b", "sg1");
+    g.setNode("sg1", { minRank: 1, maxRank: 3 });
+    g.setNode("d1", { edgeObj: { v: "a", w: "b" }, rank: 1 });
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).equals("sg1");
+  });
+
+  it("handles a long chain starting in a subgraph", function() {
+    g.setParent("a", "sg1");
+    g.setNode("sg1", { minRank: 0, maxRank: 2 });
+    g.setNode("d1", { edgeObj: { v: "a", w: "b" }, rank: 2 });
+    g.setNode("d2", { rank: 3 });
+    g.setNode("d3", { rank: 4 });
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "d2", "d3", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).equals("sg1");
+    expect(g.parent("d2")).to.be.undefined;
+    expect(g.parent("d3")).to.be.undefined;
+  });
+
+  it("handles a long chain ending in a subgraph", function() {
+    g.setParent("b", "sg1");
+    g.setNode("sg1", { minRank: 3, maxRank: 5 });
+    g.setNode("d1", { edgeObj: { v: "a", w: "b" }, rank: 1 });
+    g.setNode("d2", { rank: 2 });
+    g.setNode("d3", { rank: 3 });
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "d2", "d3", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).to.be.undefined;
+    expect(g.parent("d2")).to.be.undefined;
+    expect(g.parent("d3")).equals("sg1");
+  });
+
+  it("handles nested subgraphs", function() {
+    g.setParent("a", "sg2");
+    g.setParent("sg2", "sg1");
+    g.setNode("sg1", { minRank: 0, maxRank: 4 });
+    g.setNode("sg2", { minRank: 1, maxRank: 3 });
+    g.setParent("b", "sg4");
+    g.setParent("sg4", "sg3");
+    g.setNode("sg3", { minRank: 6, maxRank: 10 });
+    g.setNode("sg4", { minRank: 7, maxRank:  9 });
+    for (var i = 0; i < 5; ++i) {
+      g.setNode("d" + (i + 1), { rank: i + 3  });
+    }
+    g.node("d1").edgeObj = { v: "a", w: "b" };
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "d2", "d3", "d4", "d5", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).equals("sg2");
+    expect(g.parent("d2")).equals("sg1");
+    expect(g.parent("d3")).to.be.undefined;
+    expect(g.parent("d4")).equals("sg3");
+    expect(g.parent("d5")).equals("sg4");
+  });
+
+  it("handles overlapping rank ranges", function() {
+    g.setParent("a", "sg1");
+    g.setNode("sg1", { minRank: 0, maxRank: 3 });
+    g.setParent("b", "sg2");
+    g.setNode("sg2", { minRank: 2, maxRank: 6 });
+    g.setNode("d1", { edgeObj: { v: "a", w: "b" }, rank: 2 });
+    g.setNode("d2", { rank: 3 });
+    g.setNode("d3", { rank: 4 });
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "d2", "d3", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).equals("sg1");
+    expect(g.parent("d2")).equals("sg1");
+    expect(g.parent("d3")).equals("sg2");
+  });
+
+  it("handles an LCA that is not the root of the graph #1", function() {
+    g.setParent("a", "sg1");
+    g.setParent("sg2", "sg1");
+    g.setNode("sg1", { minRank: 0, maxRank: 6 });
+    g.setParent("b", "sg2");
+    g.setNode("sg2", { minRank: 3, maxRank: 5 });
+    g.setNode("d1", { edgeObj: { v: "a", w: "b" }, rank: 2 });
+    g.setNode("d2", { rank: 3 });
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "d2", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).equals("sg1");
+    expect(g.parent("d2")).equals("sg2");
+  });
+
+  it("handles an LCA that is not the root of the graph #2", function() {
+    g.setParent("a", "sg2");
+    g.setParent("sg2", "sg1");
+    g.setNode("sg1", { minRank: 0, maxRank: 6 });
+    g.setParent("b", "sg1");
+    g.setNode("sg2", { minRank: 1, maxRank: 3 });
+    g.setNode("d1", { edgeObj: { v: "a", w: "b" }, rank: 3 });
+    g.setNode("d2", { rank: 4 });
+    g.graph().dummyChains = ["d1"];
+    g.setPath(["a", "d1", "d2", "b"]);
+
+    parentDummyChains(g);
+    expect(g.parent("d1")).equals("sg2");
+    expect(g.parent("d2")).equals("sg1");
+  });
+});
diff --git a/debian/missing-source/dagre/test/position-test.js b/debian/missing-source/dagre/test/position-test.js
new file mode 100644
index 0000000..f36782d
--- /dev/null
+++ b/debian/missing-source/dagre/test/position-test.js
@@ -0,0 +1,54 @@
+var expect = require("./chai").expect,
+    position = require("../lib/position"),
+    Graph = require("graphlib").Graph;
+
+describe("position", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph({ compound: true })
+      .setGraph({
+        ranksep: 50,
+        nodesep: 50,
+        edgesep: 10
+      });
+  });
+
+  it("respects ranksep", function() {
+    g.graph().ranksep = 1000;
+    g.setNode("a", { width: 50, height: 100, rank: 0, order: 0 });
+    g.setNode("b", { width: 50, height:  80, rank: 1, order: 0 });
+    g.setEdge("a", "b");
+    position(g);
+    expect(g.node("b").y).to.equal(100 + 1000 + 80 / 2);
+  });
+
+  it("use the largest height in each rank with ranksep", function() {
+    g.graph().ranksep = 1000;
+    g.setNode("a", { width: 50, height: 100, rank: 0, order: 0 });
+    g.setNode("b", { width: 50, height:  80, rank: 0, order: 1 });
+    g.setNode("c", { width: 50, height:  90, rank: 1, order: 0 });
+    g.setEdge("a", "c");
+    position(g);
+    expect(g.node("a").y).to.equal(100 / 2);
+    expect(g.node("b").y).to.equal(100 / 2); // Note we used 100 and not 80 here
+    expect(g.node("c").y).to.equal(100 + 1000 + 90 / 2);
+  });
+
+  it("respects nodesep", function() {
+    g.graph().nodesep = 1000;
+    g.setNode("a", { width: 50, height: 100, rank: 0, order: 0 });
+    g.setNode("b", { width: 70, height:  80, rank: 0, order: 1 });
+    position(g);
+    expect(g.node("b").x).to.equal(g.node("a").x + 50 / 2 + 1000 + 70 / 2);
+  });
+
+  it("should not try to position the subgraph node itself", function() {
+    g.setNode("a", { width: 50, height: 50, rank: 0, order: 0 });
+    g.setNode("sg1", {});
+    g.setParent("a", "sg1");
+    position(g);
+    expect(g.node("sg1")).to.not.have.property("x");
+    expect(g.node("sg1")).to.not.have.property("y");
+  });
+});
diff --git a/debian/missing-source/dagre/test/position/bk-test.js b/debian/missing-source/dagre/test/position/bk-test.js
new file mode 100644
index 0000000..a109bcf
--- /dev/null
+++ b/debian/missing-source/dagre/test/position/bk-test.js
@@ -0,0 +1,667 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    buildLayerMatrix = require("../../lib/util").buildLayerMatrix,
+    bk = require("../../lib/position/bk"),
+    findType1Conflicts = bk.findType1Conflicts,
+    findType2Conflicts = bk.findType2Conflicts,
+    addConflict = bk.addConflict,
+    hasConflict = bk.hasConflict,
+    verticalAlignment = bk.verticalAlignment,
+    horizontalCompaction = bk.horizontalCompaction,
+    alignCoordinates = bk.alignCoordinates,
+    balance = bk.balance,
+    findSmallestWidthAlignment = bk.findSmallestWidthAlignment,
+    positionX = bk.positionX,
+    Graph = require("graphlib").Graph;
+
+describe("position/bk", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph().setGraph({});
+  });
+
+  describe("findType1Conflicts", function() {
+    var layering;
+
+    beforeEach(function() {
+      g
+        .setDefaultEdgeLabel(function() { return {}; })
+        .setNode("a", { rank: 0, order: 0 })
+        .setNode("b", { rank: 0, order: 1 })
+        .setNode("c", { rank: 1, order: 0 })
+        .setNode("d", { rank: 1, order: 1 })
+        // Set up crossing
+        .setEdge("a", "d")
+        .setEdge("b", "c");
+
+      layering = buildLayerMatrix(g);
+    });
+
+    it("does not mark edges that have no conflict", function() {
+      g.removeEdge("a", "d");
+      g.removeEdge("b", "c");
+      g.setEdge("a", "c");
+      g.setEdge("b", "d");
+
+      var conflicts = findType1Conflicts(g, layering);
+      expect(hasConflict(conflicts, "a", "c")).to.be.false;
+      expect(hasConflict(conflicts, "b", "d")).to.be.false;
+    });
+
+    it("does not mark type-0 conflicts (no dummies)", function() {
+      var conflicts = findType1Conflicts(g, layering);
+      expect(hasConflict(conflicts, "a", "d")).to.be.false;
+      expect(hasConflict(conflicts, "b", "c")).to.be.false;
+    });
+
+    _.each(["a", "b", "c", "d"], function(v) {
+      it("does not mark type-0 conflicts (" + v + " is dummy)", function() {
+        g.node(v).dummy = true;
+
+        var conflicts = findType1Conflicts(g, layering);
+        expect(hasConflict(conflicts, "a", "d")).to.be.false;
+        expect(hasConflict(conflicts, "b", "c")).to.be.false;
+      });
+    });
+
+    _.each(["a", "b", "c", "d"], function(v) {
+      it("does mark type-1 conflicts (" + v + " is non-dummy)", function() {
+        _.each(["a", "b", "c", "d"], function(w) {
+          if (v !== w) {
+            g.node(w).dummy = true;
+          }
+        });
+
+        var conflicts = findType1Conflicts(g, layering);
+        if (v === "a" || v === "d") {
+          expect(hasConflict(conflicts, "a", "d")).to.be.true;
+          expect(hasConflict(conflicts, "b", "c")).to.be.false;
+        } else {
+          expect(hasConflict(conflicts, "a", "d")).to.be.false;
+          expect(hasConflict(conflicts, "b", "c")).to.be.true;
+        }
+      });
+    });
+
+    it("does not mark type-2 conflicts (all dummies)", function() {
+      _.each(["a", "b", "c", "d"], function(v) {
+        g.node(v).dummy = true;
+      });
+
+      var conflicts = findType1Conflicts(g, layering);
+      expect(hasConflict(conflicts, "a", "d")).to.be.false;
+      expect(hasConflict(conflicts, "b", "c")).to.be.false;
+      findType1Conflicts(g, layering);
+    });
+  });
+
+  describe("findType2Conflicts", function() {
+    var layering;
+
+    beforeEach(function() {
+      g
+        .setDefaultEdgeLabel(function() { return {}; })
+        .setNode("a", { rank: 0, order: 0 })
+        .setNode("b", { rank: 0, order: 1 })
+        .setNode("c", { rank: 1, order: 0 })
+        .setNode("d", { rank: 1, order: 1 })
+        // Set up crossing
+        .setEdge("a", "d")
+        .setEdge("b", "c");
+
+      layering = buildLayerMatrix(g);
+    });
+
+    it("marks type-2 conflicts favoring border segments #1", function() {
+      _.each(["a", "d"], function(v) {
+        g.node(v).dummy = true;
+      });
+
+      _.each(["b", "c"], function(v) {
+        g.node(v).dummy = "border";
+      });
+
+      var conflicts = findType2Conflicts(g, layering);
+      expect(hasConflict(conflicts, "a", "d")).to.be.true;
+      expect(hasConflict(conflicts, "b", "c")).to.be.false;
+      findType1Conflicts(g, layering);
+    });
+
+    it("marks type-2 conflicts favoring border segments #2", function() {
+      _.each(["b", "c"], function(v) {
+        g.node(v).dummy = true;
+      });
+
+      _.each(["a", "d"], function(v) {
+        g.node(v).dummy = "border";
+      });
+
+      var conflicts = findType2Conflicts(g, layering);
+      expect(hasConflict(conflicts, "a", "d")).to.be.false;
+      expect(hasConflict(conflicts, "b", "c")).to.be.true;
+      findType1Conflicts(g, layering);
+    });
+
+  });
+
+  describe("hasConflict", function() {
+    it("can test for a type-1 conflict regardless of edge orientation", function() {
+      var conflicts = {};
+      addConflict(conflicts, "b", "a");
+      expect(hasConflict(conflicts, "a", "b")).to.be.true;
+      expect(hasConflict(conflicts, "b", "a")).to.be.true;
+    });
+
+    it("works for multiple conflicts with the same node", function() {
+      var conflicts = {};
+      addConflict(conflicts, "a", "b");
+      addConflict(conflicts, "a", "c");
+      expect(hasConflict(conflicts, "a", "b")).to.be.true;
+      expect(hasConflict(conflicts, "a", "c")).to.be.true;
+    });
+  });
+
+  describe("verticalAlignment", function() {
+    it("Aligns with itself if the node has no adjacencies", function() {
+      g.setNode("a", { rank: 0, order: 0 });
+      g.setNode("b", { rank: 1, order: 0 });
+
+      var layering = buildLayerMatrix(g),
+          conflicts = {};
+
+      var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
+      expect(result).to.eql({
+        root:  { a: "a", b: "b" },
+        align: { a: "a", b: "b" }
+      });
+    });
+
+    it("Aligns with its sole adjacency", function() {
+      g.setNode("a", { rank: 0, order: 0 });
+      g.setNode("b", { rank: 1, order: 0 });
+      g.setEdge("a", "b");
+
+      var layering = buildLayerMatrix(g),
+          conflicts = {};
+
+      var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
+      expect(result).to.eql({
+        root:  { a: "a", b: "a" },
+        align: { a: "b", b: "a" }
+      });
+    });
+
+    it("aligns with its left median when possible", function() {
+      g.setNode("a", { rank: 0, order: 0 });
+      g.setNode("b", { rank: 0, order: 1 });
+      g.setNode("c", { rank: 1, order: 0 });
+      g.setEdge("a", "c");
+      g.setEdge("b", "c");
+
+      var layering = buildLayerMatrix(g),
+          conflicts = {};
+
+      var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
+      expect(result).to.eql({
+        root:  { a: "a", b: "b", c: "a" },
+        align: { a: "c", b: "b", c: "a" }
+      });
+    });
+
+    it("aligns correctly even regardless of node name / insertion order", function() {
+      // This test ensures that we're actually properly sorting nodes by
+      // position when searching for candidates. Many of these tests previously
+      // passed because the node insertion order matched the order of the nodes
+      // in the layering.
+      g.setNode("b", { rank: 0, order: 1 });
+      g.setNode("c", { rank: 1, order: 0 });
+      g.setNode("z", { rank: 0, order: 0 });
+      g.setEdge("z", "c");
+      g.setEdge("b", "c");
+
+      var layering = buildLayerMatrix(g),
+          conflicts = {};
+
+      var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
+      expect(result).to.eql({
+        root:  { z: "z", b: "b", c: "z" },
+        align: { z: "c", b: "b", c: "z" }
+      });
+    });
+
+
+    it("aligns with its right median when left is unavailable", function() {
+      g.setNode("a", { rank: 0, order: 0 });
+      g.setNode("b", { rank: 0, order: 1 });
+      g.setNode("c", { rank: 1, order: 0 });
+      g.setEdge("a", "c");
+      g.setEdge("b", "c");
+
+      var layering = buildLayerMatrix(g),
+          conflicts = {};
+
+      addConflict(conflicts, "a", "c");
+
+      var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
+      expect(result).to.eql({
+        root:  { a: "a", b: "b", c: "b" },
+        align: { a: "a", b: "c", c: "b" }
+      });
+    });
+
+    it("aligns with neither median if both are unavailable", function() {
+      g.setNode("a", { rank: 0, order: 0 });
+      g.setNode("b", { rank: 0, order: 1 });
+      g.setNode("c", { rank: 1, order: 0 });
+      g.setNode("d", { rank: 1, order: 1 });
+      g.setEdge("a", "d");
+      g.setEdge("b", "c");
+      g.setEdge("b", "d");
+
+      var layering = buildLayerMatrix(g),
+          conflicts = {};
+
+      var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
+      // c will align with b, so d will not be able to align with a, because
+      // (a,d) and (c,b) cross.
+      expect(result).to.eql({
+        root:  { a: "a", b: "b", c: "b", d: "d" },
+        align: { a: "a", b: "c", c: "b", d: "d" }
+      });
+    });
+
+    it("aligns with the single median for an odd number of adjacencies", function() {
+      g.setNode("a", { rank: 0, order: 0 });
+      g.setNode("b", { rank: 0, order: 1 });
+      g.setNode("c", { rank: 0, order: 2 });
+      g.setNode("d", { rank: 1, order: 0 });
+      g.setEdge("a", "d");
+      g.setEdge("b", "d");
+      g.setEdge("c", "d");
+
+      var layering = buildLayerMatrix(g),
+          conflicts = {};
+
+      var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
+      expect(result).to.eql({
+        root:  { a: "a", b: "b", c: "c", d: "b" },
+        align: { a: "a", b: "d", c: "c", d: "b" }
+      });
+    });
+
+    it("aligns blocks across multiple layers", function() {
+      g.setNode("a", { rank: 0, order: 0 });
+      g.setNode("b", { rank: 1, order: 0 });
+      g.setNode("c", { rank: 1, order: 1 });
+      g.setNode("d", { rank: 2, order: 0 });
+      g.setPath(["a", "b", "d"]);
+      g.setPath(["a", "c", "d"]);
+
+      var layering = buildLayerMatrix(g),
+          conflicts = {};
+
+      var result = verticalAlignment(g, layering, conflicts, g.predecessors.bind(g));
+      expect(result).to.eql({
+        root:  { a: "a", b: "a", c: "c", d: "a" },
+        align: { a: "b", b: "d", c: "c", d: "a" }
+      });
+    });
+  });
+
+  describe("horizonalCompaction", function() {
+    it("places the center of a single node graph at origin (0,0)", function() {
+      var root =  { a: "a" },
+          align = { a: "a" };
+      g.setNode("a", { rank: 0, order: 0 });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+    });
+
+    it("separates adjacent nodes by specified node separation", function() {
+      var root =  { a: "a", b: "b" },
+          align = { a: "a", b: "b" };
+      g.graph().nodesep = 100;
+      g.setNode("a", { rank: 0, order: 0, width: 100 });
+      g.setNode("b", { rank: 0, order: 1, width: 200 });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(100 / 2 + 100 + 200 / 2);
+    });
+
+    it("separates adjacent edges by specified node separation", function() {
+      var root =  { a: "a", b: "b" },
+          align = { a: "a", b: "b" };
+      g.graph().edgesep = 20;
+      g.setNode("a", { rank: 0, order: 0, width: 100, dummy: true });
+      g.setNode("b", { rank: 0, order: 1, width: 200, dummy: true });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(100 / 2 + 20 + 200 / 2);
+    });
+
+    it("aligns the centers of nodes in the same block", function() {
+      var root =  { a: "a", b: "a" },
+          align = { a: "b", b: "a" };
+      g.setNode("a", { rank: 0, order: 0, width: 100 });
+      g.setNode("b", { rank: 1, order: 0, width: 200 });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(0);
+    });
+
+    it("separates blocks with the appropriate separation", function() {
+      var root =  { a: "a", b: "a", c: "c" },
+          align = { a: "b", b: "a", c: "c" };
+      g.graph().nodesep = 75;
+      g.setNode("a", { rank: 0, order: 0, width: 100 });
+      g.setNode("b", { rank: 1, order: 1, width: 200 });
+      g.setNode("c", { rank: 1, order: 0, width:  50 });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(50 / 2 + 75 + 200 / 2);
+      expect(xs.b).to.equal(50 / 2 + 75 + 200 / 2);
+      expect(xs.c).to.equal(0);
+    });
+
+    it("separates classes with the appropriate separation", function() {
+      var root =  { a: "a", b: "b", c: "c", d: "b" },
+          align = { a: "a", b: "d", c: "c", d: "b" };
+      g.graph().nodesep = 75;
+      g.setNode("a", { rank: 0, order: 0, width: 100 });
+      g.setNode("b", { rank: 0, order: 1, width: 200 });
+      g.setNode("c", { rank: 1, order: 0, width:  50 });
+      g.setNode("d", { rank: 1, order: 1, width:  80 });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(100 / 2 + 75 + 200 / 2);
+      expect(xs.c).to.equal(100 / 2 + 75 + 200 / 2 - 80 / 2 - 75 - 50 / 2);
+      expect(xs.d).to.equal(100 / 2 + 75 + 200 / 2);
+    });
+
+    it("shifts classes by max sep from the adjacent block #1", function() {
+      var root =  { a: "a", b: "b", c: "a", d: "b" },
+          align = { a: "c", b: "d", c: "a", d: "b" };
+      g.graph().nodesep = 75;
+      g.setNode("a", { rank: 0, order: 0, width:  50 });
+      g.setNode("b", { rank: 0, order: 1, width: 150 });
+      g.setNode("c", { rank: 1, order: 0, width:  60 });
+      g.setNode("d", { rank: 1, order: 1, width:  70 });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(50 / 2 + 75 + 150 / 2);
+      expect(xs.c).to.equal(0);
+      expect(xs.d).to.equal(50 / 2 + 75 + 150 / 2);
+    });
+
+    it("shifts classes by max sep from the adjacent block #2", function() {
+      var root =  { a: "a", b: "b", c: "a", d: "b" },
+          align = { a: "c", b: "d", c: "a", d: "b" };
+      g.graph().nodesep = 75;
+      g.setNode("a", { rank: 0, order: 0, width:  50 });
+      g.setNode("b", { rank: 0, order: 1, width:  70 });
+      g.setNode("c", { rank: 1, order: 0, width:  60 });
+      g.setNode("d", { rank: 1, order: 1, width: 150 });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(60 / 2 + 75 + 150 / 2);
+      expect(xs.c).to.equal(0);
+      expect(xs.d).to.equal(60 / 2 + 75 + 150 / 2);
+    });
+
+    it("cascades class shift", function() {
+      var root =  { a: "a", b: "b", c: "c", d: "d", e: "b", f: "f", g: "d" },
+          align = { a: "a", b: "e", c: "c", d: "g", e: "b", f: "f", g: "d" };
+      g.graph().nodesep = 75;
+      g.setNode("a", { rank: 0, order: 0, width: 50 });
+      g.setNode("b", { rank: 0, order: 1, width: 50 });
+      g.setNode("c", { rank: 1, order: 0, width: 50 });
+      g.setNode("d", { rank: 1, order: 1, width: 50 });
+      g.setNode("e", { rank: 1, order: 2, width: 50 });
+      g.setNode("f", { rank: 2, order: 0, width: 50 });
+      g.setNode("g", { rank: 2, order: 1, width: 50 });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+
+      // Use f as 0, everything is relative to it
+      expect(xs.a).to.equal(xs.b - 50 / 2 - 75 - 50 / 2);
+      expect(xs.b).to.equal(xs.e);
+      expect(xs.c).to.equal(xs.f);
+      expect(xs.d).to.equal(xs.c + 50 / 2 + 75 + 50 / 2);
+      expect(xs.e).to.equal(xs.d + 50 / 2 + 75 + 50 / 2);
+      expect(xs.g).to.equal(xs.f + 50 / 2 + 75 + 50 / 2);
+    });
+
+    it("handles labelpos = l", function() {
+      var root =  { a: "a", b: "b", c: "c" },
+          align = { a: "a", b: "b", c: "c" };
+      g.graph().edgesep = 50;
+      g.setNode("a", { rank: 0, order: 0, width:  100, dummy: "edge" });
+      g.setNode("b", {
+        rank: 0, order: 1, width: 200,
+        dummy: "edge-label", labelpos: "l"
+      });
+      g.setNode("c", { rank: 0, order: 2, width:  300, dummy: "edge" });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(xs.a + 100 / 2 + 50 + 200);
+      expect(xs.c).to.equal(xs.b + 0 + 50 + 300 / 2);
+    });
+
+    it("handles labelpos = c", function() {
+      var root =  { a: "a", b: "b", c: "c" },
+          align = { a: "a", b: "b", c: "c" };
+      g.graph().edgesep = 50;
+      g.setNode("a", { rank: 0, order: 0, width:  100, dummy: "edge" });
+      g.setNode("b", {
+        rank: 0, order: 1, width: 200,
+        dummy: "edge-label", labelpos: "c"
+      });
+      g.setNode("c", { rank: 0, order: 2, width:  300, dummy: "edge" });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(xs.a + 100 / 2 + 50 + 200 / 2);
+      expect(xs.c).to.equal(xs.b + 200 / 2 + 50 + 300 / 2);
+    });
+
+    it("handles labelpos = r", function() {
+      var root =  { a: "a", b: "b", c: "c" },
+          align = { a: "a", b: "b", c: "c" };
+      g.graph().edgesep = 50;
+      g.setNode("a", { rank: 0, order: 0, width:  100, dummy: "edge" });
+      g.setNode("b", {
+        rank: 0, order: 1, width: 200,
+        dummy: "edge-label", labelpos: "r"
+      });
+      g.setNode("c", { rank: 0, order: 2, width:  300, dummy: "edge" });
+
+      var xs = horizontalCompaction(g, buildLayerMatrix(g), root, align);
+      expect(xs.a).to.equal(0);
+      expect(xs.b).to.equal(xs.a + 100 / 2 + 50 + 0);
+      expect(xs.c).to.equal(xs.b + 200 + 50 + 300 / 2);
+    });
+  });
+
+  describe("alignCoordinates", function() {
+    it("aligns a single node", function() {
+      var xss = {
+        ul: { a:  50 },
+        ur: { a: 100 },
+        dl: { a:  50 },
+        dr: { a: 200 }
+      };
+
+      alignCoordinates(xss, xss.ul);
+
+      expect(xss.ul).to.eql({ a: 50 });
+      expect(xss.ur).to.eql({ a: 50 });
+      expect(xss.dl).to.eql({ a: 50 });
+      expect(xss.dr).to.eql({ a: 50 });
+    });
+
+    it("aligns multiple nodes", function() {
+      var xss = {
+        ul: { a:  50, b: 1000 },
+        ur: { a: 100, b:  900 },
+        dl: { a: 150, b:  800 },
+        dr: { a: 200, b:  700 }
+      };
+
+      alignCoordinates(xss, xss.ul);
+
+      expect(xss.ul).to.eql({ a:  50, b: 1000 });
+      expect(xss.ur).to.eql({ a: 200, b: 1000 });
+      expect(xss.dl).to.eql({ a:  50, b:  700 });
+      expect(xss.dr).to.eql({ a: 500, b: 1000 });
+    });
+  });
+
+  describe("findSmallestWidthAlignment", function() {
+    it("finds the alignment with the smallest width", function() {
+      g.setNode("a", { width: 50 });
+      g.setNode("b", { width: 50 });
+
+      var xss = {
+        ul: { a:  0, b: 1000 },
+        ur: { a: -5, b: 1000 },
+        dl: { a:  5, b: 2000 },
+        dr: { a:  0, b:  200 },
+      };
+
+      expect(findSmallestWidthAlignment(g, xss)).to.eql(xss.dr);
+    });
+
+    it("takes node width into account", function() {
+      g.setNode("a", { width:  50 });
+      g.setNode("b", { width:  50 });
+      g.setNode("c", { width: 200 });
+
+      var xss = {
+        ul: { a:  0, b: 100, c: 75 },
+        ur: { a:  0, b: 100, c: 80 },
+        dl: { a:  0, b: 100, c: 85 },
+        dr: { a:  0, b: 100, c: 90 },
+      };
+
+      expect(findSmallestWidthAlignment(g, xss)).to.eql(xss.ul);
+    });
+  });
+
+  describe("balance", function() {
+    it("aligns a single node to the shared median value", function() {
+      var xss = {
+        ul: { a:   0 },
+        ur: { a: 100 },
+        dl: { a: 100 },
+        dr: { a: 200 }
+      };
+
+      expect(balance(xss)).to.eql({ a: 100 });
+    });
+
+    it("aligns a single node to the average of different median values", function() {
+      var xss = {
+        ul: { a:   0 },
+        ur: { a:  75 },
+        dl: { a: 125 },
+        dr: { a: 200 }
+      };
+
+      expect(balance(xss)).to.eql({ a: 100 });
+    });
+
+    it("balances multiple nodes", function() {
+      var xss = {
+        ul: { a:   0, b: 50 },
+        ur: { a:  75, b:  0 },
+        dl: { a: 125, b: 60 },
+        dr: { a: 200, b: 75 }
+      };
+
+      expect(balance(xss)).to.eql({ a: 100, b: 55 });
+    });
+  });
+
+  describe("positionX", function() {
+    it("positions a single node at origin", function() {
+      g.setNode("a", { rank: 0, order: 0, width: 100 });
+      expect(positionX(g)).to.eql({ a: 0 });
+    });
+
+    it("positions a single node block at origin", function() {
+      g.setNode("a", { rank: 0, order: 0, width: 100 });
+      g.setNode("b", { rank: 1, order: 0, width: 100 });
+      g.setEdge("a", "b");
+      expect(positionX(g)).to.eql({ a: 0, b: 0 });
+    });
+
+    it("positions a single node block at origin even when their sizes differ", function() {
+      g.setNode("a", { rank: 0, order: 0, width:  40 });
+      g.setNode("b", { rank: 1, order: 0, width: 500 });
+      g.setNode("c", { rank: 2, order: 0, width:  20 });
+      g.setPath(["a", "b", "c"]);
+      expect(positionX(g)).to.eql({ a: 0, b: 0, c: 0 });
+    });
+
+    it("centers a node if it is a predecessor of two same sized nodes", function() {
+      g.graph().nodesep = 10;
+      g.setNode("a", { rank: 0, order: 0, width:  20 });
+      g.setNode("b", { rank: 1, order: 0, width:  50 });
+      g.setNode("c", { rank: 1, order: 1, width:  50 });
+      g.setEdge("a", "b");
+      g.setEdge("a", "c");
+
+      var pos = positionX(g),
+          a = pos.a;
+      expect(pos).to.eql({ a: a, b: a - (25 + 5), c: a + (25 + 5) });
+    });
+
+    it("shifts blocks on both sides of aligned block", function() {
+      g.graph().nodesep = 10;
+      g.setNode("a", { rank: 0, order: 0, width:  50 });
+      g.setNode("b", { rank: 0, order: 1, width:  60 });
+      g.setNode("c", { rank: 1, order: 0, width:  70 });
+      g.setNode("d", { rank: 1, order: 1, width:  80 });
+      g.setEdge("b", "c");
+
+      var pos = positionX(g),
+          b = pos.b,
+          c = b;
+      expect(pos).to.eql({
+        a: b - 60 / 2 - 10 - 50 / 2,
+        b: b,
+        c: c,
+        d: c + 70 / 2 + 10 + 80 / 2
+      });
+    });
+
+    it("aligns inner segments", function() {
+      g.graph().nodesep = 10;
+      g.setNode("a", { rank: 0, order: 0, width:  50, dummy: true });
+      g.setNode("b", { rank: 0, order: 1, width:  60 });
+      g.setNode("c", { rank: 1, order: 0, width:  70 });
+      g.setNode("d", { rank: 1, order: 1, width:  80, dummy: true });
+      g.setEdge("b", "c");
+      g.setEdge("a", "d");
+
+      var pos = positionX(g),
+          a = pos.a,
+          d = a;
+      expect(pos).to.eql({
+        a: a,
+        b: a + 50 / 2 + 10 + 60 / 2,
+        c: d - 70 / 2 - 10 - 80 / 2,
+        d: d
+      });
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/rank/feasible-tree-test.js b/debian/missing-source/dagre/test/rank/feasible-tree-test.js
new file mode 100644
index 0000000..13276a4
--- /dev/null
+++ b/debian/missing-source/dagre/test/rank/feasible-tree-test.js
@@ -0,0 +1,52 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    feasibleTree = require("../../lib/rank/feasible-tree");
+
+describe("feasibleTree", function() {
+  it("creates a tree for a trivial input graph", function() {
+    var g = new Graph()
+      .setNode("a", { rank: 0 })
+      .setNode("b", { rank: 1 })
+      .setEdge("a", "b", { minlen: 1 });
+
+    var tree = feasibleTree(g);
+    expect(g.node("b").rank).to.equal(g.node("a").rank + 1);
+    expect(tree.neighbors("a")).to.eql(["b"]);
+  });
+
+  it("correctly shortens slack by pulling a node up", function() {
+    var g = new Graph()
+      .setNode("a", { rank: 0 })
+      .setNode("b", { rank: 1 })
+      .setNode("c", { rank: 2 })
+      .setNode("d", { rank: 2 })
+      .setPath(["a", "b", "c"], { minlen: 1 })
+      .setEdge("a", "d", { minlen: 1 });
+
+    var tree = feasibleTree(g);
+    expect(g.node("b").rank).to.eql(g.node("a").rank + 1);
+    expect(g.node("c").rank).to.eql(g.node("b").rank + 1);
+    expect(g.node("d").rank).to.eql(g.node("a").rank + 1);
+    expect(_.sortBy(tree.neighbors("a"))).to.eql(["b", "d"]);
+    expect(_.sortBy(tree.neighbors("b"))).to.eql(["a", "c"]);
+    expect(tree.neighbors("c")).to.eql(["b"]);
+    expect(tree.neighbors("d")).to.eql(["a"]);
+  });
+
+  it("correctly shortens slack by pulling a node down", function() {
+    var g = new Graph()
+      .setNode("a", { rank: 2 })
+      .setNode("b", { rank: 0 })
+      .setNode("c", { rank: 2 })
+      .setEdge("b", "a", { minlen: 1 })
+      .setEdge("b", "c", { minlen: 1 });
+
+    var tree = feasibleTree(g);
+    expect(g.node("a").rank).to.eql(g.node("b").rank + 1);
+    expect(g.node("c").rank).to.eql(g.node("b").rank + 1);
+    expect(_.sortBy(tree.neighbors("a"))).to.eql(["b"]);
+    expect(_.sortBy(tree.neighbors("b"))).to.eql(["a", "c"]);
+    expect(_.sortBy(tree.neighbors("c"))).to.eql(["b"]);
+  });
+});
diff --git a/debian/missing-source/dagre/test/rank/network-simplex-test.js b/debian/missing-source/dagre/test/rank/network-simplex-test.js
new file mode 100644
index 0000000..f9ab5be
--- /dev/null
+++ b/debian/missing-source/dagre/test/rank/network-simplex-test.js
@@ -0,0 +1,499 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    Graph = require("graphlib").Graph,
+    networkSimplex = require("../../lib/rank/network-simplex"),
+    longestPath = require("../../lib/rank/util").longestPath,
+    initLowLimValues = networkSimplex.initLowLimValues,
+    initCutValues = networkSimplex.initCutValues,
+    calcCutValue = networkSimplex.calcCutValue,
+    leaveEdge = networkSimplex.leaveEdge,
+    enterEdge = networkSimplex.enterEdge,
+    exchangeEdges = networkSimplex.exchangeEdges,
+    normalizeRanks = require("../../lib/util").normalizeRanks;
+
+describe("network simplex", function() {
+  var g, t, gansnerGraph, gansnerTree;
+
+  beforeEach(function() {
+    g = new Graph({ multigraph: true })
+      .setDefaultNodeLabel(function() { return {}; })
+      .setDefaultEdgeLabel(function() { return { minlen: 1, weight: 1 }; });
+
+    t = new Graph({ directed: false })
+      .setDefaultNodeLabel(function() { return {}; })
+      .setDefaultEdgeLabel(function() { return {}; });
+
+    gansnerGraph = new Graph()
+      .setDefaultNodeLabel(function() { return {}; })
+      .setDefaultEdgeLabel(function() { return { minlen: 1, weight: 1 }; })
+      .setPath(["a", "b", "c", "d", "h"])
+      .setPath(["a", "e", "g", "h"])
+      .setPath(["a", "f", "g"]);
+
+    gansnerTree = new Graph({ directed: false })
+      .setDefaultNodeLabel(function() { return {}; })
+      .setDefaultEdgeLabel(function() { return {}; })
+      .setPath(["a", "b", "c", "d", "h", "g", "e"])
+      .setEdge("g", "f");
+  });
+
+  it("can assign a rank to a single node", function() {
+    g.setNode("a");
+    ns(g);
+    expect(g.node("a").rank).to.equal(0);
+  });
+
+  it("can assign a rank to a 2-node connected graph", function() {
+    g.setEdge("a", "b");
+    ns(g);
+    expect(g.node("a").rank).to.equal(0);
+    expect(g.node("b").rank).to.equal(1);
+  });
+
+  it("can assign ranks for a diamond", function() {
+    g.setPath(["a", "b", "d"]);
+    g.setPath(["a", "c", "d"]);
+    ns(g);
+    expect(g.node("a").rank).to.equal(0);
+    expect(g.node("b").rank).to.equal(1);
+    expect(g.node("c").rank).to.equal(1);
+    expect(g.node("d").rank).to.equal(2);
+  });
+
+  it("uses the minlen attribute on the edge", function() {
+    g.setPath(["a", "b", "d"]);
+    g.setEdge("a", "c");
+    g.setEdge("c", "d", { minlen: 2 });
+    ns(g);
+    expect(g.node("a").rank).to.equal(0);
+    // longest path biases towards the lowest rank it can assign. Since the
+    // graph has no optimization opportunities we can assume that the longest
+    // path ranking is used.
+    expect(g.node("b").rank).to.equal(2);
+    expect(g.node("c").rank).to.equal(1);
+    expect(g.node("d").rank).to.equal(3);
+  });
+
+  it("can rank the gansner graph", function() {
+    g = gansnerGraph;
+    ns(g);
+    expect(g.node("a").rank).to.equal(0);
+    expect(g.node("b").rank).to.equal(1);
+    expect(g.node("c").rank).to.equal(2);
+    expect(g.node("d").rank).to.equal(3);
+    expect(g.node("h").rank).to.equal(4);
+    expect(g.node("e").rank).to.equal(1);
+    expect(g.node("f").rank).to.equal(1);
+    expect(g.node("g").rank).to.equal(2);
+  });
+
+  it("can handle multi-edges", function() {
+    g.setPath(["a", "b", "c", "d"]);
+    g.setEdge("a", "e", { weight: 2, minlen: 1 });
+    g.setEdge("e", "d");
+    g.setEdge("b", "c", { weight: 1, minlen: 2 }, "multi");
+    ns(g);
+    expect(g.node("a").rank).to.equal(0);
+    expect(g.node("b").rank).to.equal(1);
+    // b -> c has minlen = 1 and minlen = 2, so it should be 2 ranks apart.
+    expect(g.node("c").rank).to.equal(3);
+    expect(g.node("d").rank).to.equal(4);
+    expect(g.node("e").rank).to.equal(1);
+  });
+
+  describe("leaveEdge", function() {
+    it("returns undefined if there is no edge with a negative cutvalue", function() {
+      var tree = new Graph({ directed: false });
+      tree.setEdge("a", "b", { cutvalue: 1 });
+      tree.setEdge("b", "c", { cutvalue: 1 });
+      expect(leaveEdge(tree)).to.be.undefined;
+    });
+
+    it("returns an edge if one is found with a negative cutvalue", function() {
+      var tree = new Graph({ directed: false });
+      tree.setEdge("a", "b", { cutvalue: 1 });
+      tree.setEdge("b", "c", { cutvalue: -1 });
+      expect(leaveEdge(tree)).to.eql({ v: "b", w: "c" });
+    });
+  });
+
+  describe("enterEdge", function() {
+    it("finds an edge from the head to tail component", function() {
+      g
+        .setNode("a", { rank: 0 })
+        .setNode("b", { rank: 2 })
+        .setNode("c", { rank: 3 })
+        .setPath(["a", "b", "c"])
+        .setEdge("a", "c");
+      t.setPath(["b", "c", "a"]);
+      initLowLimValues(t, "c");
+
+      var f = enterEdge(t, g, { v: "b", w: "c" });
+      expect(undirectedEdge(f)).to.eql(undirectedEdge({ v: "a", w: "b" }));
+    });
+
+    it("works when the root of the tree is in the tail component", function() {
+      g
+        .setNode("a", { rank: 0 })
+        .setNode("b", { rank: 2 })
+        .setNode("c", { rank: 3 })
+        .setPath(["a", "b", "c"])
+        .setEdge("a", "c");
+      t.setPath(["b", "c", "a"]);
+      initLowLimValues(t, "b");
+
+      var f = enterEdge(t, g, { v: "b", w: "c" });
+      expect(undirectedEdge(f)).to.eql(undirectedEdge({ v: "a", w: "b" }));
+    });
+
+    it("finds the edge with the least slack", function() {
+      g
+        .setNode("a", { rank: 0 })
+        .setNode("b", { rank: 1 })
+        .setNode("c", { rank: 3 })
+        .setNode("d", { rank: 4 })
+        .setEdge("a", "d")
+        .setPath(["a", "c", "d"])
+        .setEdge("b", "c");
+      t.setPath(["c", "d", "a", "b"]);
+      initLowLimValues(t, "a");
+
+      var f = enterEdge(t, g, { v: "c", w: "d" });
+      expect(undirectedEdge(f)).to.eql(undirectedEdge({ v: "b", w: "c" }));
+    });
+
+    it("finds an appropriate edge for gansner graph #1", function() {
+      g = gansnerGraph;
+      t = gansnerTree;
+      longestPath(g);
+      initLowLimValues(t, "a");
+
+      var f = enterEdge(t, g, { v: "g", w: "h" });
+      expect(undirectedEdge(f).v).to.equal("a");
+      expect(["e", "f"]).to.include(undirectedEdge(f).w);
+    });
+
+    it("finds an appropriate edge for gansner graph #2", function() {
+      g = gansnerGraph;
+      t = gansnerTree;
+      longestPath(g);
+      initLowLimValues(t, "e");
+
+      var f = enterEdge(t, g, { v: "g", w: "h" });
+      expect(undirectedEdge(f).v).to.equal("a");
+      expect(["e", "f"]).to.include(undirectedEdge(f).w);
+    });
+
+    it("finds an appropriate edge for gansner graph #3", function() {
+      g = gansnerGraph;
+      t = gansnerTree;
+      longestPath(g);
+      initLowLimValues(t, "a");
+
+      var f = enterEdge(t, g, { v: "h", w: "g" });
+      expect(undirectedEdge(f).v).to.equal("a");
+      expect(["e", "f"]).to.include(undirectedEdge(f).w);
+    });
+
+    it("finds an appropriate edge for gansner graph #4", function() {
+      g = gansnerGraph;
+      t = gansnerTree;
+      longestPath(g);
+      initLowLimValues(t, "e");
+
+      var f = enterEdge(t, g, { v: "h", w: "g" });
+      expect(undirectedEdge(f).v).to.equal("a");
+      expect(["e", "f"]).to.include(undirectedEdge(f).w);
+    });
+  });
+
+  describe("initLowLimValues", function() {
+    it("assigns low, lim, and parent for each node in a tree", function() {
+      var g = new Graph()
+        .setDefaultNodeLabel(function() { return {}; })
+        .setNodes(["a", "b", "c", "d", "e"])
+        .setPath(["a", "b", "a", "c", "d", "c", "e"]);
+
+      initLowLimValues(g, "a");
+
+      var a = g.node("a"),
+          b = g.node("b"),
+          c = g.node("c"),
+          d = g.node("d"),
+          e = g.node("e");
+
+      expect(_.sortBy(_.map(g.nodes(), function(v) { return g.node(v).lim; })))
+        .to.eql(_.range(1, 6));
+
+      expect(a).to.eql({ low: 1, lim: 5 });
+
+      expect(b.parent).to.equal("a");
+      expect(b.lim).to.be.lt(a.lim);
+
+      expect(c.parent).to.equal("a");
+      expect(c.lim).to.be.lt(a.lim);
+      expect(c.lim).to.not.equal(b.lim);
+
+      expect(d.parent).to.equal("c");
+      expect(d.lim).to.be.lt(c.lim);
+
+      expect(e.parent).to.equal("c");
+      expect(e.lim).to.be.lt(c.lim);
+      expect(e.lim).to.not.equal(d.lim);
+    });
+  });
+
+  describe("exchangeEdges", function() {
+    it("exchanges edges and updates cut values and low/lim numbers", function() {
+      g = gansnerGraph;
+      t = gansnerTree;
+      longestPath(g);
+      initLowLimValues(t);
+
+      exchangeEdges(t, g, { v: "g", w: "h" }, { v: "a", w: "e" });
+
+      // check new cut values
+      expect(t.edge("a", "b").cutvalue).to.equal(2);
+      expect(t.edge("b", "c").cutvalue).to.equal(2);
+      expect(t.edge("c", "d").cutvalue).to.equal(2);
+      expect(t.edge("d", "h").cutvalue).to.equal(2);
+      expect(t.edge("a", "e").cutvalue).to.equal(1);
+      expect(t.edge("e", "g").cutvalue).to.equal(1);
+      expect(t.edge("g", "f").cutvalue).to.equal(0);
+
+      // ensure lim numbers look right
+      var lims = _.sortBy(_.map(t.nodes(), function(v) { return t.node(v).lim; }));
+      expect(lims).to.eql(_.range(1, 9));
+    });
+
+    it("updates ranks", function() {
+      g = gansnerGraph;
+      t = gansnerTree;
+      longestPath(g);
+      initLowLimValues(t);
+
+      exchangeEdges(t, g, { v: "g", w: "h" }, { v: "a", w: "e" });
+      normalizeRanks(g);
+
+      // check new ranks
+      expect(g.node("a").rank).to.equal(0);
+      expect(g.node("b").rank).to.equal(1);
+      expect(g.node("c").rank).to.equal(2);
+      expect(g.node("d").rank).to.equal(3);
+      expect(g.node("e").rank).to.equal(1);
+      expect(g.node("f").rank).to.equal(1);
+      expect(g.node("g").rank).to.equal(2);
+      expect(g.node("h").rank).to.equal(4);
+    });
+  });
+
+  // Note: we use p for parent, c for child, gc_x for grandchild nodes, and o for
+  // other nodes in the tree for these tests.
+  describe("calcCutValue", function() {
+    it("works for a 2-node tree with c -> p", function() {
+      g.setPath(["c", "p"]);
+      t.setPath(["p", "c"]);
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(1);
+    });
+
+    it("works for a 2-node tree with c <- p", function() {
+      g.setPath(["p", "c"]);
+      t.setPath(["p", "c"]);
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(1);
+    });
+
+    it("works for 3-node tree with gc -> c -> p", function() {
+      g.setPath(["gc", "c", "p"]);
+      t
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("p", "c");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(3);
+    });
+
+    it("works for 3-node tree with gc -> c <- p", function() {
+      g
+        .setEdge("p", "c")
+        .setEdge("gc", "c");
+      t
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("p", "c");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(-1);
+    });
+
+    it("works for 3-node tree with gc <- c -> p", function() {
+      g
+        .setEdge("c", "p")
+        .setEdge("c", "gc");
+      t
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("p", "c");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(-1);
+    });
+
+    it("works for 3-node tree with gc <- c <- p", function() {
+      g.setPath(["p", "c", "gc"]);
+      t
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("p", "c");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(3);
+    });
+
+    it("works for 4-node tree with gc -> c -> p -> o, with o -> c", function() {
+      g
+        .setEdge("o", "c", { weight: 7 })
+        .setPath(["gc", "c", "p", "o"]);
+      t
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setPath(["c", "p", "o"]);
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(-4);
+    });
+
+    it("works for 4-node tree with gc -> c -> p -> o, with o <- c", function() {
+      g
+        .setEdge("c", "o", { weight: 7 })
+        .setPath(["gc", "c", "p", "o"]);
+      t
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setPath(["c", "p", "o"]);
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(10);
+    });
+
+    it("works for 4-node tree with o -> gc -> c -> p, with o -> c", function() {
+      g
+        .setEdge("o", "c", { weight: 7 })
+        .setPath(["o", "gc", "c", "p"]);
+      t
+        .setEdge("o", "gc")
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("c", "p");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(-4);
+    });
+
+    it("works for 4-node tree with o -> gc -> c -> p, with o <- c", function() {
+      g
+        .setEdge("c", "o", { weight: 7 })
+        .setPath(["o", "gc", "c", "p"]);
+      t
+        .setEdge("o", "gc")
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("c", "p");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(10);
+    });
+
+    it("works for 4-node tree with gc -> c <- p -> o, with o -> c", function() {
+      g
+        .setEdge("gc", "c")
+        .setEdge("p", "c")
+        .setEdge("p", "o")
+        .setEdge("o", "c", { weight: 7 });
+      t
+        .setEdge("o", "gc")
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("c", "p");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(6);
+    });
+
+    it("works for 4-node tree with gc -> c <- p -> o, with o <- c", function() {
+      g
+        .setEdge("gc", "c")
+        .setEdge("p", "c")
+        .setEdge("p", "o")
+        .setEdge("c", "o", { weight: 7 });
+      t
+        .setEdge("o", "gc")
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("c", "p");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(-8);
+    });
+
+    it("works for 4-node tree with o -> gc -> c <- p, with o -> c", function() {
+      g
+        .setEdge("o", "c", { weight: 7 })
+        .setPath(["o", "gc", "c"])
+        .setEdge("p", "c");
+      t
+        .setEdge("o", "gc")
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("c", "p");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(6);
+    });
+
+    it("works for 4-node tree with o -> gc -> c <- p, with o <- c", function() {
+      g
+        .setEdge("c", "o", { weight: 7 })
+        .setPath(["o", "gc", "c"])
+        .setEdge("p", "c");
+      t
+        .setEdge("o", "gc")
+        .setEdge("gc", "c", { cutvalue: 3 })
+        .setEdge("c", "p");
+      initLowLimValues(t, "p");
+
+      expect(calcCutValue(t, g, "c")).to.equal(-8);
+    });
+  });
+
+  describe("initCutValues", function() {
+    it("works for gansnerGraph", function() {
+      initLowLimValues(gansnerTree);
+      initCutValues(gansnerTree, gansnerGraph);
+      expect(gansnerTree.edge("a", "b").cutvalue).to.equal(3);
+      expect(gansnerTree.edge("b", "c").cutvalue).to.equal(3);
+      expect(gansnerTree.edge("c", "d").cutvalue).to.equal(3);
+      expect(gansnerTree.edge("d", "h").cutvalue).to.equal(3);
+      expect(gansnerTree.edge("g", "h").cutvalue).to.equal(-1);
+      expect(gansnerTree.edge("e", "g").cutvalue).to.equal(0);
+      expect(gansnerTree.edge("f", "g").cutvalue).to.equal(0);
+    });
+
+    it("works for updated gansnerGraph", function() {
+      gansnerTree.removeEdge("g", "h");
+      gansnerTree.setEdge("a", "e");
+      initLowLimValues(gansnerTree);
+      initCutValues(gansnerTree, gansnerGraph);
+      expect(gansnerTree.edge("a", "b").cutvalue).to.equal(2);
+      expect(gansnerTree.edge("b", "c").cutvalue).to.equal(2);
+      expect(gansnerTree.edge("c", "d").cutvalue).to.equal(2);
+      expect(gansnerTree.edge("d", "h").cutvalue).to.equal(2);
+      expect(gansnerTree.edge("a", "e").cutvalue).to.equal(1);
+      expect(gansnerTree.edge("e", "g").cutvalue).to.equal(1);
+      expect(gansnerTree.edge("f", "g").cutvalue).to.equal(0);
+    });
+  });
+});
+
+function ns(g) {
+  networkSimplex(g);
+  normalizeRanks(g);
+}
+
+function undirectedEdge(e) {
+  return e.v < e.w ? { v: e.v, w: e.w } : { v: e.w, w: e.v };
+}
diff --git a/debian/missing-source/dagre/test/rank/rank-test.js b/debian/missing-source/dagre/test/rank/rank-test.js
new file mode 100644
index 0000000..8511a62
--- /dev/null
+++ b/debian/missing-source/dagre/test/rank/rank-test.js
@@ -0,0 +1,42 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    rank = require("../../lib/rank"),
+    Graph = require("graphlib").Graph;
+
+describe("rank", function() {
+  var RANKERS = [
+        "longest-path", "tight-tree",
+        "network-simplex", "unknown-should-still-work"
+      ],
+      g;
+
+  beforeEach(function() {
+    g = new Graph()
+      .setGraph({})
+      .setDefaultNodeLabel(function() { return {}; })
+      .setDefaultEdgeLabel(function() { return { minlen: 1, weight: 1 }; })
+      .setPath(["a", "b", "c", "d", "h"])
+      .setPath(["a", "e", "g", "h"])
+      .setPath(["a", "f", "g"]);
+  });
+
+  _.each(RANKERS, function(ranker) {
+    describe(ranker, function() {
+      it("respects the minlen attribute", function() {
+        g.graph().ranker = ranker;
+        rank(g);
+        _.each(g.edges(), function(e) {
+          var vRank = g.node(e.v).rank,
+              wRank = g.node(e.w).rank;
+          expect(wRank - vRank).to.be.gte(g.edge(e).minlen);
+        });
+      });
+
+      it("can rank a single node graph", function() {
+        var g = new Graph().setGraph({}).setNode("a", {});
+        rank(g, ranker);
+        expect(g.node("a").rank).to.equal(0);
+      });
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/rank/util-test.js b/debian/missing-source/dagre/test/rank/util-test.js
new file mode 100644
index 0000000..68ee840
--- /dev/null
+++ b/debian/missing-source/dagre/test/rank/util-test.js
@@ -0,0 +1,65 @@
+var expect = require("../chai").expect,
+    Graph = require("graphlib").Graph,
+    normalizeRanks = require("../../lib/util").normalizeRanks,
+    rankUtil = require("../../lib/rank/util"),
+    longestPath = rankUtil.longestPath;
+
+describe("rank/util", function() {
+  describe("longestPath", function() {
+    var g;
+
+    beforeEach(function() {
+      g = new Graph()
+        .setDefaultNodeLabel(function() { return {}; })
+        .setDefaultEdgeLabel(function() { return { minlen: 1 }; });
+    });
+
+    it("can assign a rank to a single node graph", function() {
+      g.setNode("a");
+      longestPath(g);
+      normalizeRanks(g);
+      expect(g.node("a").rank).to.equal(0);
+    });
+
+    it("can assign ranks to unconnected nodes", function() {
+      g.setNode("a");
+      g.setNode("b");
+      longestPath(g);
+      normalizeRanks(g);
+      expect(g.node("a").rank).to.equal(0);
+      expect(g.node("b").rank).to.equal(0);
+    });
+
+    it("can assign ranks to connected nodes", function() {
+      g.setEdge("a", "b");
+      longestPath(g);
+      normalizeRanks(g);
+      expect(g.node("a").rank).to.equal(0);
+      expect(g.node("b").rank).to.equal(1);
+    });
+
+    it("can assign ranks for a diamond", function() {
+      g.setPath(["a", "b", "d"]);
+      g.setPath(["a", "c", "d"]);
+      longestPath(g);
+      normalizeRanks(g);
+      expect(g.node("a").rank).to.equal(0);
+      expect(g.node("b").rank).to.equal(1);
+      expect(g.node("c").rank).to.equal(1);
+      expect(g.node("d").rank).to.equal(2);
+    });
+
+    it("uses the minlen attribute on the edge", function() {
+      g.setPath(["a", "b", "d"]);
+      g.setEdge("a", "c");
+      g.setEdge("c", "d", { minlen: 2 });
+      longestPath(g);
+      normalizeRanks(g);
+      expect(g.node("a").rank).to.equal(0);
+      // longest path biases towards the lowest rank it can assign
+      expect(g.node("b").rank).to.equal(2);
+      expect(g.node("c").rank).to.equal(1);
+      expect(g.node("d").rank).to.equal(3);
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/util-test.js b/debian/missing-source/dagre/test/util-test.js
new file mode 100644
index 0000000..afc6da3
--- /dev/null
+++ b/debian/missing-source/dagre/test/util-test.js
@@ -0,0 +1,245 @@
+var _ = require("lodash"),
+    expect = require("./chai").expect,
+    Graph = require("graphlib").Graph,
+    util = require("../lib/util");
+
+describe("util", function() {
+  describe("simplify", function() {
+    var g;
+
+    beforeEach(function() {
+      g = new Graph({ multigraph: true });
+    });
+
+    it("copies without change a graph with no multi-edges", function() {
+      g.setEdge("a", "b", { weight: 1, minlen: 1 });
+      var g2 = util.simplify(g);
+      expect(g2.edge("a", "b")).eql({ weight: 1, minlen: 1 });
+      expect(g2.edgeCount()).equals(1);
+    });
+
+    it("collapses multi-edges", function() {
+      g.setEdge("a", "b", { weight: 1, minlen: 1 });
+      g.setEdge("a", "b", { weight: 2, minlen: 2 }, "multi");
+      var g2 = util.simplify(g);
+      expect(g2.isMultigraph()).to.be.false;
+      expect(g2.edge("a", "b")).eql({ weight: 3, minlen: 2 });
+      expect(g2.edgeCount()).equals(1);
+    });
+
+    it("copies the graph object", function() {
+      g.setGraph({ foo: "bar" });
+      var g2 = util.simplify(g);
+      expect(g2.graph()).eqls({ foo: "bar" });
+    });
+  });
+
+  describe("asNonCompoundGraph", function() {
+    var g;
+
+    beforeEach(function() {
+      g = new Graph({ compound: true, multigraph: true });
+    });
+
+    it("copies all nodes", function() {
+      g.setNode("a", { foo: "bar" });
+      g.setNode("b");
+      var g2 = util.asNonCompoundGraph(g);
+      expect(g2.node("a")).to.eql({ foo: "bar" });
+      expect(g2.hasNode("b")).to.be.true;
+    });
+
+    it("copies all edges", function() {
+      g.setEdge("a", "b", { foo: "bar" });
+      g.setEdge("a", "b", { foo: "baz" }, "multi");
+      var g2 = util.asNonCompoundGraph(g);
+      expect(g2.edge("a", "b")).eqls({ foo: "bar" });
+      expect(g2.edge("a", "b", "multi")).eqls({ foo: "baz" });
+    });
+
+    it("does not copy compound nodes", function() {
+      g.setParent("a", "sg1");
+      var g2 = util.asNonCompoundGraph(g);
+      expect(g2.parent(g)).to.be.undefined;
+      expect(g2.isCompound()).to.be.false;
+    });
+
+    it ("copies the graph object", function() {
+      g.setGraph({ foo: "bar" });
+      var g2 = util.asNonCompoundGraph(g);
+      expect(g2.graph()).eqls({ foo: "bar" });
+    });
+  });
+
+  describe("successorWeights", function() {
+    it("maps a node to its successors with associated weights", function() {
+       var g = new Graph({ multigraph: true });
+       g.setEdge("a", "b", { weight: 2 });
+       g.setEdge("b", "c", { weight: 1 });
+       g.setEdge("b", "c", { weight: 2 }, "multi");
+       g.setEdge("b", "d", { weight: 1 }, "multi");
+       expect(util.successorWeights(g).a).to.eql({ b: 2 });
+       expect(util.successorWeights(g).b).to.eql({ c: 3, d: 1 });
+       expect(util.successorWeights(g).c).to.eql({});
+       expect(util.successorWeights(g).d).to.eql({});
+    });
+  });
+
+  describe("predecessorWeights", function() {
+    it("maps a node to its predecessors with associated weights", function() {
+       var g = new Graph({ multigraph: true });
+       g.setEdge("a", "b", { weight: 2 });
+       g.setEdge("b", "c", { weight: 1 });
+       g.setEdge("b", "c", { weight: 2 }, "multi");
+       g.setEdge("b", "d", { weight: 1 }, "multi");
+       expect(util.predecessorWeights(g).a).to.eql({});
+       expect(util.predecessorWeights(g).b).to.eql({ a: 2 });
+       expect(util.predecessorWeights(g).c).to.eql({ b: 3 });
+       expect(util.predecessorWeights(g).d).to.eql({ b: 1 });
+    });
+  });
+
+  describe("intersectRect", function() {
+    function expectIntersects(rect, point) {
+      var cross = util.intersectRect(rect, point);
+      if (cross.x !== point.x) {
+        var m = (cross.y - point.y) / (cross.x - point.x);
+        expect(cross.y - rect.y).equals(m * (cross.x - rect.x));
+      }
+    }
+
+    function expectTouchesBorder(rect, point) {
+      var cross = util.intersectRect(rect, point);
+      if (Math.abs(rect.x - cross.x) !== rect.width / 2) {
+        expect(Math.abs(rect.y - cross.y)).equals(rect.height / 2);
+      }
+    }
+
+    it("creates a slope that will intersect the rectangle's center", function() {
+      var rect = { x: 0, y: 0, width: 1, height: 1 };
+      expectIntersects(rect, { x:  2, y:  6 });
+      expectIntersects(rect, { x:  2, y: -6 });
+      expectIntersects(rect, { x:  6, y:  2 });
+      expectIntersects(rect, { x: -6, y:  2 });
+      expectIntersects(rect, { x:  5, y:  0 });
+      expectIntersects(rect, { x:  0, y:  5 });
+    });
+
+    it("touches the border of the rectangle", function() {
+      var rect = { x: 0, y: 0, width: 1, height: 1 };
+      expectTouchesBorder(rect, { x:  2, y:  6 });
+      expectTouchesBorder(rect, { x:  2, y: -6 });
+      expectTouchesBorder(rect, { x:  6, y:  2 });
+      expectTouchesBorder(rect, { x: -6, y:  2 });
+      expectTouchesBorder(rect, { x:  5, y:  0 });
+      expectTouchesBorder(rect, { x:  0, y:  5 });
+    });
+
+    it("throws an error if the point is at the center of the rectangle", function() {
+      var rect = { x: 0, y: 0, width: 1, height: 1 };
+      expect(function() { util.intersectRect(rect, { x: 0, y: 0 }); }).to.throw();
+    });
+  });
+
+  describe("buildLayerMatrix", function() {
+    it("creates a matrix based on rank and order of nodes in the graph", function() {
+      var g = new Graph();
+      g.setNode("a", { rank: 0, order: 0 });
+      g.setNode("b", { rank: 0, order: 1 });
+      g.setNode("c", { rank: 1, order: 0 });
+      g.setNode("d", { rank: 1, order: 1 });
+      g.setNode("e", { rank: 2, order: 0 });
+
+      expect(util.buildLayerMatrix(g)).to.eql([
+        ["a", "b"],
+        ["c", "d"],
+        ["e"]
+      ]);
+    });
+  });
+
+  describe("time", function() {
+    var consoleLog;
+
+    beforeEach(function() {
+      consoleLog = console.log;
+    });
+
+    afterEach(function() {
+      console.log = consoleLog;
+    });
+
+    it("logs timing information", function() {
+      var capture = [];
+      console.log = function() { capture.push(_.toArray(arguments)[0]); };
+      util.time("foo", function() {});
+      expect(capture.length).to.equal(1);
+      expect(capture[0]).to.match(/^foo time: .*ms/);
+    });
+
+    it("returns the value from the evaluated function", function() {
+      console.log = function() {};
+      expect(util.time("foo", _.constant("bar"))).to.equal("bar");
+    });
+  });
+
+  describe("normalizeRanks", function() {
+    it("adjust ranks such that all are >= 0, and at least one is 0", function() {
+      var g = new Graph()
+        .setNode("a", { rank: 3 })
+        .setNode("b", { rank: 2 })
+        .setNode("c", { rank: 4 });
+
+      util.normalizeRanks(g);
+
+      expect(g.node("a").rank).to.equal(1);
+      expect(g.node("b").rank).to.equal(0);
+      expect(g.node("c").rank).to.equal(2);
+    });
+
+    it("works for negative ranks", function() {
+      var g = new Graph()
+        .setNode("a", { rank: -3 })
+        .setNode("b", { rank: -2 });
+
+      util.normalizeRanks(g);
+
+      expect(g.node("a").rank).to.equal(0);
+      expect(g.node("b").rank).to.equal(1);
+    });
+
+    it("does not assign a rank to subgraphs", function() {
+      var g = new Graph({ compound: true })
+        .setNode("a", { rank: 0 })
+        .setNode("sg", {})
+        .setParent("a", "sg");
+
+      util.normalizeRanks(g);
+
+      expect(g.node("sg")).to.not.have.property("rank");
+      expect(g.node("a").rank).to.equal(0);
+    });
+  });
+
+  describe("removeEmptyRanks", function() {
+    it("Removes border ranks without any nodes", function() {
+      var g = new Graph()
+        .setGraph({ nodeRankFactor: 4 })
+        .setNode("a", { rank: 0 })
+        .setNode("b", { rank: 4 });
+      util.removeEmptyRanks(g);
+      expect(g.node("a").rank).equals(0);
+      expect(g.node("b").rank).equals(1);
+    });
+
+    it("Does not remove non-border ranks", function() {
+      var g = new Graph()
+        .setGraph({ nodeRankFactor: 4 })
+        .setNode("a", { rank: 0 })
+        .setNode("b", { rank: 8 });
+      util.removeEmptyRanks(g);
+      expect(g.node("a").rank).equals(0);
+      expect(g.node("b").rank).equals(2);
+    });
+  });
+});
diff --git a/debian/missing-source/dagre/test/version-test.js b/debian/missing-source/dagre/test/version-test.js
new file mode 100644
index 0000000..a3915e2
--- /dev/null
+++ b/debian/missing-source/dagre/test/version-test.js
@@ -0,0 +1,8 @@
+var expect = require("./chai").expect;
+
+describe("version", function() {
+  it("should match the version from package.json", function() {
+    var packageVersion = require("../package").version;
+    expect(require("../").version).to.equal(packageVersion);
+  });
+});
diff --git a/debian/missing-source/graphlib-dot.js b/debian/missing-source/graphlib-dot.js
deleted file mode 100644
index 5332115..0000000
--- a/debian/missing-source/graphlib-dot.js
+++ /dev/null
@@ -1,10701 +0,0 @@
-(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-(function (global){
-/*
- * Copyright (c) 2012-2013 Chris Pettitt
- *
- * 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.
- */
-global.graphlibDot = require("./index");
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./index":2}],2:[function(require,module,exports){
-var read = require("./lib/read-one"),
-    readMany = require("./lib/read-many"),
-    write = require("./lib/write-one"),
-    version = require("./lib/version");
-
-module.exports = {
-  graphlib: require("./lib/graphlib"),
-
-  // Parsing
-  read: read,
-  readMany: readMany,
-
-  // Writing
-  write: write,
-
-  // Version
-  version: version,
-
-  // For levelup encoding
-  type: "dot",
-  buffer: false
-};
-
-},{"./lib/graphlib":5,"./lib/read-many":7,"./lib/read-one":8,"./lib/version":9,"./lib/write-one":10}],3:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash"),
-    Graph = require("./graphlib").Graph;
-
-module.exports = buildGraph;
-
-function buildGraph(parseTree) {
-  var isDirected = parseTree.type !== "graph",
-      isMultigraph = !parseTree.strict,
-      defaultStack = [{ node: {}, edge: {} }],
-      id = parseTree.id,
-      g = new Graph({ directed: isDirected, multigraph: isMultigraph, compound: true });
-      g.setGraph(id === null ? {} : {id: id});
-  _.each(parseTree.stmts, function(stmt) { handleStmt(g, stmt, defaultStack); });
-  return g;
-}
-
-function handleStmt(g, stmt, defaultStack, sg) {
-  switch(stmt.type) {
-    case "node": handleNodeStmt(g, stmt, defaultStack, sg); break;
-    case "edge": handleEdgeStmt(g, stmt, defaultStack, sg); break;
-    case "subgraph": handleSubgraphStmt(g, stmt, defaultStack, sg); break;
-    case "attr": handleAttrStmt(g, stmt, defaultStack); break;
-    case "inlineAttr": handleInlineAttrsStmt(g, stmt, defaultStack, sg); break;
-  }
-}
-
-function handleNodeStmt(g, stmt, defaultStack, sg) {
-  var v = stmt.id,
-      attrs = stmt.attrs;
-  maybeCreateNode(g, v, defaultStack, sg);
-  _.merge(g.node(v), attrs);
-}
-
-function handleEdgeStmt(g, stmt, defaultStack, sg) {
-  var attrs = stmt.attrs,
-      prev, curr;
-  _.each(stmt.elems, function(elem) {
-    handleStmt(g, elem, defaultStack, sg);
-
-    switch(elem.type) {
-      case "node": curr = [elem.id]; break;
-      case "subgraph": curr = collectNodeIds(elem); break;
-    }
-
-    _.each(prev, function(v) {
-      _.each(curr, function(w) {
-        var name;
-        if (g.hasEdge(v, w) && g.isMultigraph()) {
-          name = _.uniqueId("edge");
-        }
-        if (!g.hasEdge(v, w, name)) {
-          g.setEdge(v, w, _.clone(_.last(defaultStack).edge), name);
-        }
-        _.merge(g.edge(v, w, name), attrs);
-      });
-    });
-
-    prev = curr;
-  });
-}
-
-function handleSubgraphStmt(g, stmt, defaultStack, sg) {
-  var id = stmt.id;
-  if (id === undefined) {
-    id = generateSubgraphId(g);
-  }
-
-  defaultStack.push(_.clone(_.last(defaultStack)));
-
-  maybeCreateNode(g, id, defaultStack, sg);
-
-  _.each(stmt.stmts, function(s) {
-    handleStmt(g, s, defaultStack, id);
-  });
-
-  // If there are no statements remove the subgraph
-  if (!g.children(id).length) {
-    g.removeNode(id);
-  }
-
-  defaultStack.pop();
-}
-
-function handleAttrStmt(g, stmt, defaultStack) {
-  _.merge(_.last(defaultStack)[stmt.attrType], stmt.attrs);
-}
-
-function handleInlineAttrsStmt(g, stmt, defaultStack, sg) {
-  _.merge(sg ? g.node(sg) : g.graph(), stmt.attrs);
-}
-
-function generateSubgraphId(g) {
-  var id;
-  do {
-    id = _.uniqueId("sg");
-  } while (g.hasNode(id));
-  return id;
-}
-
-function maybeCreateNode(g, v, defaultStack, sg) {
-  if (!g.hasNode(v)) {
-    g.setNode(v, _.clone(_.last(defaultStack).node));
-    g.setParent(v, sg);
-  }
-}
-
-// Collect all nodes involved in a subgraph statement
-function collectNodeIds(stmt) {
-  var ids = {},
-      stack = [],
-      curr;
-
-  var push = stack.push.bind(stack);
-
-  push(stmt);
-  while(stack.length) {
-    curr = stack.pop();
-    switch(curr.type) {
-      case "node": ids[curr.id] = true; break;
-      case "edge": _.each(curr.elems, push); break;
-      case "subgraph": _.each(curr.stmts, push); break;
-    }
-  }
-
-  return _.keys(ids);
-}
-
-
-},{"./graphlib":5,"./lodash":6}],4:[function(require,module,exports){
-module.exports = (function() {
-  /*
-   * Generated by PEG.js 0.8.0.
-   *
-   * http://pegjs.majda.cz/
-   */
-
-  function peg$subclass(child, parent) {
-    function ctor() { this.constructor = child; }
-    ctor.prototype = parent.prototype;
-    child.prototype = new ctor();
-  }
-
-  function SyntaxError(message, expected, found, offset, line, column) {
-    this.message  = message;
-    this.expected = expected;
-    this.found    = found;
-    this.offset   = offset;
-    this.line     = line;
-    this.column   = column;
-
-    this.name     = "SyntaxError";
-  }
-
-  peg$subclass(SyntaxError, Error);
-
-  function parse(input) {
-    var options = arguments.length > 1 ? arguments[1] : {},
-
-        peg$FAILED = {},
-
-        peg$startRuleFunctions = { start: peg$parsestart, graphStmt: peg$parsegraphStmt },
-        peg$startRuleFunction  = peg$parsestart,
-
-        peg$c0 = [],
-        peg$c1 = peg$FAILED,
-        peg$c2 = null,
-        peg$c3 = "{",
-        peg$c4 = { type: "literal", value: "{", description: "\"{\"" },
-        peg$c5 = "}",
-        peg$c6 = { type: "literal", value: "}", description: "\"}\"" },
-        peg$c7 = function(strict, type, id, stmts) {
-              return {type: type, id: id, strict: strict !== null, stmts: stmts};
-            },
-        peg$c8 = ";",
-        peg$c9 = { type: "literal", value: ";", description: "\";\"" },
-        peg$c10 = function(first, rest) {
-              var result = [first];
-              for (var i = 0; i < rest.length; ++i) {
-                result.push(rest[i][1]);
-              }
-              return result;
-            },
-        peg$c11 = function(type, attrs) {
-              return { type: "attr", attrType: type, attrs: attrs || {}};
-            },
-        peg$c12 = "=",
-        peg$c13 = { type: "literal", value: "=", description: "\"=\"" },
-        peg$c14 = function(k, v) {
-              var attrs = {};
-              attrs[k] = v;
-              return { type: "inlineAttr", attrs: attrs };
-            },
-        peg$c15 = function(id, attrs) { return {type: "node", id: id, attrs: attrs || {}}; },
-        peg$c16 = function(lhs, rhs, attrs) {
-              var elems = [lhs];
-              for (var i = 0; i < rhs.length; ++i) {
-                elems.push(rhs[i]);
-              }
-              return { type: "edge", elems: elems, attrs: attrs || {} };
-            },
-        peg$c17 = function(id, stmts) {
-              id = (id && id[2]) || [];
-              return { type: "subgraph", id: id[0], stmts: stmts };
-            },
-        peg$c18 = function(first, rest) {
-              var result = first;
-              for (var i = 0; i < rest.length; ++i) {
-                _.merge(result, rest[i][1]);
-              }
-              return result;
-            },
-        peg$c19 = "[",
-        peg$c20 = { type: "literal", value: "[", description: "\"[\"" },
-        peg$c21 = "]",
-        peg$c22 = { type: "literal", value: "]", description: "\"]\"" },
-        peg$c23 = function(aList) { return aList; },
-        peg$c24 = ",",
-        peg$c25 = { type: "literal", value: ",", description: "\",\"" },
-        peg$c26 = function(first, rest) {
-              var result = first;
-              for (var i = 0; i < rest.length; ++i) {
-                _.merge(result, rest[i][3]);
-              }
-              return result;
-            },
-        peg$c27 = "--",
-        peg$c28 = { type: "literal", value: "--", description: "\"--\"" },
-        peg$c29 = function() { return directed; },
-        peg$c30 = void 0,
-        peg$c31 = "->",
-        peg$c32 = { type: "literal", value: "->", description: "\"->\"" },
-        peg$c33 = function(rhs, rest) {
-              var result = [rhs];
-              if (rest) {
-                for (var i = 0; i < rest.length; ++i) {
-                  result.push(rest[i]);
-                }
-              }
-              return result;
-            },
-        peg$c34 = function(k, v) {
-              var result = {};
-              result[k] = v[3];
-              return result;
-            },
-        peg$c35 = function(id) { return { type: "node", id: id, attrs: {} }; },
-        peg$c36 = function(id) { return id; },
-        peg$c37 = ":",
-        peg$c38 = { type: "literal", value: ":", description: "\":\"" },
-        peg$c39 = "ne",
-        peg$c40 = { type: "literal", value: "ne", description: "\"ne\"" },
-        peg$c41 = "se",
-        peg$c42 = { type: "literal", value: "se", description: "\"se\"" },
-        peg$c43 = "sw",
-        peg$c44 = { type: "literal", value: "sw", description: "\"sw\"" },
-        peg$c45 = "nw",
-        peg$c46 = { type: "literal", value: "nw", description: "\"nw\"" },
-        peg$c47 = "n",
-        peg$c48 = { type: "literal", value: "n", description: "\"n\"" },
-        peg$c49 = "e",
-        peg$c50 = { type: "literal", value: "e", description: "\"e\"" },
-        peg$c51 = "s",
-        peg$c52 = { type: "literal", value: "s", description: "\"s\"" },
-        peg$c53 = "w",
-        peg$c54 = { type: "literal", value: "w", description: "\"w\"" },
-        peg$c55 = "c",
-        peg$c56 = { type: "literal", value: "c", description: "\"c\"" },
-        peg$c57 = "_",
-        peg$c58 = { type: "literal", value: "_", description: "\"_\"" },
-        peg$c59 = { type: "other", description: "identifier" },
-        peg$c60 = /^[a-zA-Z\u0200-\u0377_]/,
-        peg$c61 = { type: "class", value: "[a-zA-Z\\u0200-\\u0377_]", description: "[a-zA-Z\\u0200-\\u0377_]" },
-        peg$c62 = /^[a-zA-Z\u0200-\u0377_0-9]/,
-        peg$c63 = { type: "class", value: "[a-zA-Z\\u0200-\\u0377_0-9]", description: "[a-zA-Z\\u0200-\\u0377_0-9]" },
-        peg$c64 = function(fst, rest) { return fst + rest.join(""); },
-        peg$c65 = "-",
-        peg$c66 = { type: "literal", value: "-", description: "\"-\"" },
-        peg$c67 = ".",
-        peg$c68 = { type: "literal", value: ".", description: "\".\"" },
-        peg$c69 = /^[0-9]/,
-        peg$c70 = { type: "class", value: "[0-9]", description: "[0-9]" },
-        peg$c71 = function(sign, dot, after) {
-              return (sign || "") + dot + after.join("");
-            },
-        peg$c72 = function(sign, before, after) {
-              return (sign || "") + before.join("") + (after ? after[0] : "") + (after ? after[1].join("") : "");
-            },
-        peg$c73 = "\"",
-        peg$c74 = { type: "literal", value: "\"", description: "\"\\\"\"" },
-        peg$c75 = "\\\"",
-        peg$c76 = { type: "literal", value: "\\\"", description: "\"\\\\\\\"\"" },
-        peg$c77 = function() { return '"'; },
-        peg$c78 = "\\",
-        peg$c79 = { type: "literal", value: "\\", description: "\"\\\\\"" },
-        peg$c80 = /^[^"]/,
-        peg$c81 = { type: "class", value: "[^\"]", description: "[^\"]" },
-        peg$c82 = function(ch) { return "\\" + ch; },
-        peg$c83 = function(id) {
-              return id.join("");
-            },
-        peg$c84 = "node",
-        peg$c85 = { type: "literal", value: "node", description: "\"node\"" },
-        peg$c86 = function(k) { return k.toLowerCase(); },
-        peg$c87 = "edge",
-        peg$c88 = { type: "literal", value: "edge", description: "\"edge\"" },
-        peg$c89 = "graph",
-        peg$c90 = { type: "literal", value: "graph", description: "\"graph\"" },
-        peg$c91 = "digraph",
-        peg$c92 = { type: "literal", value: "digraph", description: "\"digraph\"" },
-        peg$c93 = "subgraph",
-        peg$c94 = { type: "literal", value: "subgraph", description: "\"subgraph\"" },
-        peg$c95 = "strict",
-        peg$c96 = { type: "literal", value: "strict", description: "\"strict\"" },
-        peg$c97 = function(graph) {
-              directed = graph === "digraph";
-              return graph;
-            },
-        peg$c98 = { type: "other", description: "whitespace" },
-        peg$c99 = /^[ \t\r\n]/,
-        peg$c100 = { type: "class", value: "[ \\t\\r\\n]", description: "[ \\t\\r\\n]" },
-        peg$c101 = { type: "other", description: "comment" },
-        peg$c102 = "//",
-        peg$c103 = { type: "literal", value: "//", description: "\"//\"" },
-        peg$c104 = /^[^\n]/,
-        peg$c105 = { type: "class", value: "[^\\n]", description: "[^\\n]" },
-        peg$c106 = "/*",
-        peg$c107 = { type: "literal", value: "/*", description: "\"/*\"" },
-        peg$c108 = "*/",
-        peg$c109 = { type: "literal", value: "*/", description: "\"*/\"" },
-        peg$c110 = { type: "any", description: "any character" },
-
-        peg$currPos          = 0,
-        peg$reportedPos      = 0,
-        peg$cachedPos        = 0,
-        peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
-        peg$maxFailPos       = 0,
-        peg$maxFailExpected  = [],
-        peg$silentFails      = 0,
-
-        peg$result;
-
-    if ("startRule" in options) {
-      if (!(options.startRule in peg$startRuleFunctions)) {
-        throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
-      }
-
-      peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
-    }
-
-    function text() {
-      return input.substring(peg$reportedPos, peg$currPos);
-    }
-
-    function offset() {
-      return peg$reportedPos;
-    }
-
-    function line() {
-      return peg$computePosDetails(peg$reportedPos).line;
-    }
-
-    function column() {
-      return peg$computePosDetails(peg$reportedPos).column;
-    }
-
-    function expected(description) {
-      throw peg$buildException(
-        null,
-        [{ type: "other", description: description }],
-        peg$reportedPos
-      );
-    }
-
-    function error(message) {
-      throw peg$buildException(message, null, peg$reportedPos);
-    }
-
-    function peg$computePosDetails(pos) {
-      function advance(details, startPos, endPos) {
-        var p, ch;
-
-        for (p = startPos; p < endPos; p++) {
-          ch = input.charAt(p);
-          if (ch === "\n") {
-            if (!details.seenCR) { details.line++; }
-            details.column = 1;
-            details.seenCR = false;
-          } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
-            details.line++;
-            details.column = 1;
-            details.seenCR = true;
-          } else {
-            details.column++;
-            details.seenCR = false;
-          }
-        }
-      }
-
-      if (peg$cachedPos !== pos) {
-        if (peg$cachedPos > pos) {
-          peg$cachedPos = 0;
-          peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
-        }
-        advance(peg$cachedPosDetails, peg$cachedPos, pos);
-        peg$cachedPos = pos;
-      }
-
-      return peg$cachedPosDetails;
-    }
-
-    function peg$fail(expected) {
-      if (peg$currPos < peg$maxFailPos) { return; }
-
-      if (peg$currPos > peg$maxFailPos) {
-        peg$maxFailPos = peg$currPos;
-        peg$maxFailExpected = [];
-      }
-
-      peg$maxFailExpected.push(expected);
-    }
-
-    function peg$buildException(message, expected, pos) {
-      function cleanupExpected(expected) {
-        var i = 1;
-
-        expected.sort(function(a, b) {
-          if (a.description < b.description) {
-            return -1;
-          } else if (a.description > b.description) {
-            return 1;
-          } else {
-            return 0;
-          }
-        });
-
-        while (i < expected.length) {
-          if (expected[i - 1] === expected[i]) {
-            expected.splice(i, 1);
-          } else {
-            i++;
-          }
-        }
-      }
-
-      function buildMessage(expected, found) {
-        function stringEscape(s) {
-          function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
-
-          return s
-            .replace(/\\/g,   '\\\\')
-            .replace(/"/g,    '\\"')
-            .replace(/\x08/g, '\\b')
-            .replace(/\t/g,   '\\t')
-            .replace(/\n/g,   '\\n')
-            .replace(/\f/g,   '\\f')
-            .replace(/\r/g,   '\\r')
-            .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
-            .replace(/[\x10-\x1F\x80-\xFF]/g,    function(ch) { return '\\x'  + hex(ch); })
-            .replace(/[\u0180-\u0FFF]/g,         function(ch) { return '\\u0' + hex(ch); })
-            .replace(/[\u1080-\uFFFF]/g,         function(ch) { return '\\u'  + hex(ch); });
-        }
-
-        var expectedDescs = new Array(expected.length),
-            expectedDesc, foundDesc, i;
-
-        for (i = 0; i < expected.length; i++) {
-          expectedDescs[i] = expected[i].description;
-        }
-
-        expectedDesc = expected.length > 1
-          ? expectedDescs.slice(0, -1).join(", ")
-              + " or "
-              + expectedDescs[expected.length - 1]
-          : expectedDescs[0];
-
-        foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
-
-        return "Expected " + expectedDesc + " but " + foundDesc + " found.";
-      }
-
-      var posDetails = peg$computePosDetails(pos),
-          found      = pos < input.length ? input.charAt(pos) : null;
-
-      if (expected !== null) {
-        cleanupExpected(expected);
-      }
-
-      return new SyntaxError(
-        message !== null ? message : buildMessage(expected, found),
-        expected,
-        found,
-        pos,
-        posDetails.line,
-        posDetails.column
-      );
-    }
-
-    function peg$parsestart() {
-      var s0, s1;
-
-      s0 = [];
-      s1 = peg$parsegraphStmt();
-      if (s1 !== peg$FAILED) {
-        while (s1 !== peg$FAILED) {
-          s0.push(s1);
-          s1 = peg$parsegraphStmt();
-        }
-      } else {
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsegraphStmt() {
-      var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13;
-
-      s0 = peg$currPos;
-      s1 = [];
-      s2 = peg$parse_();
-      while (s2 !== peg$FAILED) {
-        s1.push(s2);
-        s2 = peg$parse_();
-      }
-      if (s1 !== peg$FAILED) {
-        s2 = peg$currPos;
-        s3 = peg$parsestrict();
-        if (s3 !== peg$FAILED) {
-          s4 = peg$parse_();
-          if (s4 !== peg$FAILED) {
-            s3 = [s3, s4];
-            s2 = s3;
-          } else {
-            peg$currPos = s2;
-            s2 = peg$c1;
-          }
-        } else {
-          peg$currPos = s2;
-          s2 = peg$c1;
-        }
-        if (s2 === peg$FAILED) {
-          s2 = peg$c2;
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = peg$parsegraphType();
-          if (s3 !== peg$FAILED) {
-            s4 = [];
-            s5 = peg$parse_();
-            while (s5 !== peg$FAILED) {
-              s4.push(s5);
-              s5 = peg$parse_();
-            }
-            if (s4 !== peg$FAILED) {
-              s5 = peg$parseid();
-              if (s5 === peg$FAILED) {
-                s5 = peg$c2;
-              }
-              if (s5 !== peg$FAILED) {
-                s6 = [];
-                s7 = peg$parse_();
-                while (s7 !== peg$FAILED) {
-                  s6.push(s7);
-                  s7 = peg$parse_();
-                }
-                if (s6 !== peg$FAILED) {
-                  if (input.charCodeAt(peg$currPos) === 123) {
-                    s7 = peg$c3;
-                    peg$currPos++;
-                  } else {
-                    s7 = peg$FAILED;
-                    if (peg$silentFails === 0) { peg$fail(peg$c4); }
-                  }
-                  if (s7 !== peg$FAILED) {
-                    s8 = [];
-                    s9 = peg$parse_();
-                    while (s9 !== peg$FAILED) {
-                      s8.push(s9);
-                      s9 = peg$parse_();
-                    }
-                    if (s8 !== peg$FAILED) {
-                      s9 = peg$parsestmtList();
-                      if (s9 === peg$FAILED) {
-                        s9 = peg$c2;
-                      }
-                      if (s9 !== peg$FAILED) {
-                        s10 = [];
-                        s11 = peg$parse_();
-                        while (s11 !== peg$FAILED) {
-                          s10.push(s11);
-                          s11 = peg$parse_();
-                        }
-                        if (s10 !== peg$FAILED) {
-                          if (input.charCodeAt(peg$currPos) === 125) {
-                            s11 = peg$c5;
-                            peg$currPos++;
-                          } else {
-                            s11 = peg$FAILED;
-                            if (peg$silentFails === 0) { peg$fail(peg$c6); }
-                          }
-                          if (s11 !== peg$FAILED) {
-                            s12 = [];
-                            s13 = peg$parse_();
-                            while (s13 !== peg$FAILED) {
-                              s12.push(s13);
-                              s13 = peg$parse_();
-                            }
-                            if (s12 !== peg$FAILED) {
-                              peg$reportedPos = s0;
-                              s1 = peg$c7(s2, s3, s5, s9);
-                              s0 = s1;
-                            } else {
-                              peg$currPos = s0;
-                              s0 = peg$c1;
-                            }
-                          } else {
-                            peg$currPos = s0;
-                            s0 = peg$c1;
-                          }
-                        } else {
-                          peg$currPos = s0;
-                          s0 = peg$c1;
-                        }
-                      } else {
-                        peg$currPos = s0;
-                        s0 = peg$c1;
-                      }
-                    } else {
-                      peg$currPos = s0;
-                      s0 = peg$c1;
-                    }
-                  } else {
-                    peg$currPos = s0;
-                    s0 = peg$c1;
-                  }
-                } else {
-                  peg$currPos = s0;
-                  s0 = peg$c1;
-                }
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsestmtList() {
-      var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
-
-      s0 = peg$currPos;
-      s1 = peg$parsestmt();
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          if (input.charCodeAt(peg$currPos) === 59) {
-            s3 = peg$c8;
-            peg$currPos++;
-          } else {
-            s3 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c9); }
-          }
-          if (s3 === peg$FAILED) {
-            s3 = peg$c2;
-          }
-          if (s3 !== peg$FAILED) {
-            s4 = [];
-            s5 = peg$currPos;
-            s6 = [];
-            s7 = peg$parse_();
-            while (s7 !== peg$FAILED) {
-              s6.push(s7);
-              s7 = peg$parse_();
-            }
-            if (s6 !== peg$FAILED) {
-              s7 = peg$parsestmt();
-              if (s7 !== peg$FAILED) {
-                s8 = [];
-                s9 = peg$parse_();
-                while (s9 !== peg$FAILED) {
-                  s8.push(s9);
-                  s9 = peg$parse_();
-                }
-                if (s8 !== peg$FAILED) {
-                  if (input.charCodeAt(peg$currPos) === 59) {
-                    s9 = peg$c8;
-                    peg$currPos++;
-                  } else {
-                    s9 = peg$FAILED;
-                    if (peg$silentFails === 0) { peg$fail(peg$c9); }
-                  }
-                  if (s9 === peg$FAILED) {
-                    s9 = peg$c2;
-                  }
-                  if (s9 !== peg$FAILED) {
-                    s6 = [s6, s7, s8, s9];
-                    s5 = s6;
-                  } else {
-                    peg$currPos = s5;
-                    s5 = peg$c1;
-                  }
-                } else {
-                  peg$currPos = s5;
-                  s5 = peg$c1;
-                }
-              } else {
-                peg$currPos = s5;
-                s5 = peg$c1;
-              }
-            } else {
-              peg$currPos = s5;
-              s5 = peg$c1;
-            }
-            while (s5 !== peg$FAILED) {
-              s4.push(s5);
-              s5 = peg$currPos;
-              s6 = [];
-              s7 = peg$parse_();
-              while (s7 !== peg$FAILED) {
-                s6.push(s7);
-                s7 = peg$parse_();
-              }
-              if (s6 !== peg$FAILED) {
-                s7 = peg$parsestmt();
-                if (s7 !== peg$FAILED) {
-                  s8 = [];
-                  s9 = peg$parse_();
-                  while (s9 !== peg$FAILED) {
-                    s8.push(s9);
-                    s9 = peg$parse_();
-                  }
-                  if (s8 !== peg$FAILED) {
-                    if (input.charCodeAt(peg$currPos) === 59) {
-                      s9 = peg$c8;
-                      peg$currPos++;
-                    } else {
-                      s9 = peg$FAILED;
-                      if (peg$silentFails === 0) { peg$fail(peg$c9); }
-                    }
-                    if (s9 === peg$FAILED) {
-                      s9 = peg$c2;
-                    }
-                    if (s9 !== peg$FAILED) {
-                      s6 = [s6, s7, s8, s9];
-                      s5 = s6;
-                    } else {
-                      peg$currPos = s5;
-                      s5 = peg$c1;
-                    }
-                  } else {
-                    peg$currPos = s5;
-                    s5 = peg$c1;
-                  }
-                } else {
-                  peg$currPos = s5;
-                  s5 = peg$c1;
-                }
-              } else {
-                peg$currPos = s5;
-                s5 = peg$c1;
-              }
-            }
-            if (s4 !== peg$FAILED) {
-              peg$reportedPos = s0;
-              s1 = peg$c10(s1, s4);
-              s0 = s1;
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsestmt() {
-      var s0;
-
-      s0 = peg$parseattrStmt();
-      if (s0 === peg$FAILED) {
-        s0 = peg$parseedgeStmt();
-        if (s0 === peg$FAILED) {
-          s0 = peg$parsesubgraphStmt();
-          if (s0 === peg$FAILED) {
-            s0 = peg$parseinlineAttrStmt();
-            if (s0 === peg$FAILED) {
-              s0 = peg$parsenodeStmt();
-            }
-          }
-        }
-      }
-
-      return s0;
-    }
-
-    function peg$parseattrStmt() {
-      var s0, s1, s2, s3;
-
-      s0 = peg$currPos;
-      s1 = peg$parsegraph();
-      if (s1 === peg$FAILED) {
-        s1 = peg$parsenode();
-        if (s1 === peg$FAILED) {
-          s1 = peg$parseedge();
-        }
-      }
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = peg$parseattrList();
-          if (s3 !== peg$FAILED) {
-            peg$reportedPos = s0;
-            s1 = peg$c11(s1, s3);
-            s0 = s1;
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parseinlineAttrStmt() {
-      var s0, s1, s2, s3, s4, s5;
-
-      s0 = peg$currPos;
-      s1 = peg$parseid();
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          if (input.charCodeAt(peg$currPos) === 61) {
-            s3 = peg$c12;
-            peg$currPos++;
-          } else {
-            s3 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c13); }
-          }
-          if (s3 !== peg$FAILED) {
-            s4 = [];
-            s5 = peg$parse_();
-            while (s5 !== peg$FAILED) {
-              s4.push(s5);
-              s5 = peg$parse_();
-            }
-            if (s4 !== peg$FAILED) {
-              s5 = peg$parseid();
-              if (s5 !== peg$FAILED) {
-                peg$reportedPos = s0;
-                s1 = peg$c14(s1, s5);
-                s0 = s1;
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsenodeStmt() {
-      var s0, s1, s2, s3;
-
-      s0 = peg$currPos;
-      s1 = peg$parsenodeId();
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = peg$parseattrList();
-          if (s3 === peg$FAILED) {
-            s3 = peg$c2;
-          }
-          if (s3 !== peg$FAILED) {
-            peg$reportedPos = s0;
-            s1 = peg$c15(s1, s3);
-            s0 = s1;
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parseedgeStmt() {
-      var s0, s1, s2, s3, s4, s5;
-
-      s0 = peg$currPos;
-      s1 = peg$parsenodeIdOrSubgraph();
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = peg$parseedgeRHS();
-          if (s3 !== peg$FAILED) {
-            s4 = [];
-            s5 = peg$parse_();
-            while (s5 !== peg$FAILED) {
-              s4.push(s5);
-              s5 = peg$parse_();
-            }
-            if (s4 !== peg$FAILED) {
-              s5 = peg$parseattrList();
-              if (s5 === peg$FAILED) {
-                s5 = peg$c2;
-              }
-              if (s5 !== peg$FAILED) {
-                peg$reportedPos = s0;
-                s1 = peg$c16(s1, s3, s5);
-                s0 = s1;
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsesubgraphStmt() {
-      var s0, s1, s2, s3, s4, s5, s6, s7;
-
-      s0 = peg$currPos;
-      s1 = peg$currPos;
-      s2 = peg$parsesubgraph();
-      if (s2 !== peg$FAILED) {
-        s3 = [];
-        s4 = peg$parse_();
-        while (s4 !== peg$FAILED) {
-          s3.push(s4);
-          s4 = peg$parse_();
-        }
-        if (s3 !== peg$FAILED) {
-          s4 = peg$currPos;
-          s5 = peg$parseid();
-          if (s5 !== peg$FAILED) {
-            s6 = [];
-            s7 = peg$parse_();
-            while (s7 !== peg$FAILED) {
-              s6.push(s7);
-              s7 = peg$parse_();
-            }
-            if (s6 !== peg$FAILED) {
-              s5 = [s5, s6];
-              s4 = s5;
-            } else {
-              peg$currPos = s4;
-              s4 = peg$c1;
-            }
-          } else {
-            peg$currPos = s4;
-            s4 = peg$c1;
-          }
-          if (s4 === peg$FAILED) {
-            s4 = peg$c2;
-          }
-          if (s4 !== peg$FAILED) {
-            s2 = [s2, s3, s4];
-            s1 = s2;
-          } else {
-            peg$currPos = s1;
-            s1 = peg$c1;
-          }
-        } else {
-          peg$currPos = s1;
-          s1 = peg$c1;
-        }
-      } else {
-        peg$currPos = s1;
-        s1 = peg$c1;
-      }
-      if (s1 === peg$FAILED) {
-        s1 = peg$c2;
-      }
-      if (s1 !== peg$FAILED) {
-        if (input.charCodeAt(peg$currPos) === 123) {
-          s2 = peg$c3;
-          peg$currPos++;
-        } else {
-          s2 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$c4); }
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = [];
-          s4 = peg$parse_();
-          while (s4 !== peg$FAILED) {
-            s3.push(s4);
-            s4 = peg$parse_();
-          }
-          if (s3 !== peg$FAILED) {
-            s4 = peg$parsestmtList();
-            if (s4 === peg$FAILED) {
-              s4 = peg$c2;
-            }
-            if (s4 !== peg$FAILED) {
-              s5 = [];
-              s6 = peg$parse_();
-              while (s6 !== peg$FAILED) {
-                s5.push(s6);
-                s6 = peg$parse_();
-              }
-              if (s5 !== peg$FAILED) {
-                if (input.charCodeAt(peg$currPos) === 125) {
-                  s6 = peg$c5;
-                  peg$currPos++;
-                } else {
-                  s6 = peg$FAILED;
-                  if (peg$silentFails === 0) { peg$fail(peg$c6); }
-                }
-                if (s6 !== peg$FAILED) {
-                  peg$reportedPos = s0;
-                  s1 = peg$c17(s1, s4);
-                  s0 = s1;
-                } else {
-                  peg$currPos = s0;
-                  s0 = peg$c1;
-                }
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parseattrList() {
-      var s0, s1, s2, s3, s4, s5;
-
-      s0 = peg$currPos;
-      s1 = peg$parseattrListBlock();
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$currPos;
-        s4 = [];
-        s5 = peg$parse_();
-        while (s5 !== peg$FAILED) {
-          s4.push(s5);
-          s5 = peg$parse_();
-        }
-        if (s4 !== peg$FAILED) {
-          s5 = peg$parseattrListBlock();
-          if (s5 !== peg$FAILED) {
-            s4 = [s4, s5];
-            s3 = s4;
-          } else {
-            peg$currPos = s3;
-            s3 = peg$c1;
-          }
-        } else {
-          peg$currPos = s3;
-          s3 = peg$c1;
-        }
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$currPos;
-          s4 = [];
-          s5 = peg$parse_();
-          while (s5 !== peg$FAILED) {
-            s4.push(s5);
-            s5 = peg$parse_();
-          }
-          if (s4 !== peg$FAILED) {
-            s5 = peg$parseattrListBlock();
-            if (s5 !== peg$FAILED) {
-              s4 = [s4, s5];
-              s3 = s4;
-            } else {
-              peg$currPos = s3;
-              s3 = peg$c1;
-            }
-          } else {
-            peg$currPos = s3;
-            s3 = peg$c1;
-          }
-        }
-        if (s2 !== peg$FAILED) {
-          peg$reportedPos = s0;
-          s1 = peg$c18(s1, s2);
-          s0 = s1;
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parseattrListBlock() {
-      var s0, s1, s2, s3, s4, s5;
-
-      s0 = peg$currPos;
-      if (input.charCodeAt(peg$currPos) === 91) {
-        s1 = peg$c19;
-        peg$currPos++;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c20); }
-      }
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = peg$parseaList();
-          if (s3 === peg$FAILED) {
-            s3 = peg$c2;
-          }
-          if (s3 !== peg$FAILED) {
-            s4 = [];
-            s5 = peg$parse_();
-            while (s5 !== peg$FAILED) {
-              s4.push(s5);
-              s5 = peg$parse_();
-            }
-            if (s4 !== peg$FAILED) {
-              if (input.charCodeAt(peg$currPos) === 93) {
-                s5 = peg$c21;
-                peg$currPos++;
-              } else {
-                s5 = peg$FAILED;
-                if (peg$silentFails === 0) { peg$fail(peg$c22); }
-              }
-              if (s5 !== peg$FAILED) {
-                peg$reportedPos = s0;
-                s1 = peg$c23(s3);
-                s0 = s1;
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parseaList() {
-      var s0, s1, s2, s3, s4, s5, s6, s7;
-
-      s0 = peg$currPos;
-      s1 = peg$parseidDef();
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$currPos;
-        s4 = [];
-        s5 = peg$parse_();
-        while (s5 !== peg$FAILED) {
-          s4.push(s5);
-          s5 = peg$parse_();
-        }
-        if (s4 !== peg$FAILED) {
-          if (input.charCodeAt(peg$currPos) === 44) {
-            s5 = peg$c24;
-            peg$currPos++;
-          } else {
-            s5 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c25); }
-          }
-          if (s5 === peg$FAILED) {
-            s5 = peg$c2;
-          }
-          if (s5 !== peg$FAILED) {
-            s6 = [];
-            s7 = peg$parse_();
-            while (s7 !== peg$FAILED) {
-              s6.push(s7);
-              s7 = peg$parse_();
-            }
-            if (s6 !== peg$FAILED) {
-              s7 = peg$parseidDef();
-              if (s7 !== peg$FAILED) {
-                s4 = [s4, s5, s6, s7];
-                s3 = s4;
-              } else {
-                peg$currPos = s3;
-                s3 = peg$c1;
-              }
-            } else {
-              peg$currPos = s3;
-              s3 = peg$c1;
-            }
-          } else {
-            peg$currPos = s3;
-            s3 = peg$c1;
-          }
-        } else {
-          peg$currPos = s3;
-          s3 = peg$c1;
-        }
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$currPos;
-          s4 = [];
-          s5 = peg$parse_();
-          while (s5 !== peg$FAILED) {
-            s4.push(s5);
-            s5 = peg$parse_();
-          }
-          if (s4 !== peg$FAILED) {
-            if (input.charCodeAt(peg$currPos) === 44) {
-              s5 = peg$c24;
-              peg$currPos++;
-            } else {
-              s5 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$c25); }
-            }
-            if (s5 === peg$FAILED) {
-              s5 = peg$c2;
-            }
-            if (s5 !== peg$FAILED) {
-              s6 = [];
-              s7 = peg$parse_();
-              while (s7 !== peg$FAILED) {
-                s6.push(s7);
-                s7 = peg$parse_();
-              }
-              if (s6 !== peg$FAILED) {
-                s7 = peg$parseidDef();
-                if (s7 !== peg$FAILED) {
-                  s4 = [s4, s5, s6, s7];
-                  s3 = s4;
-                } else {
-                  peg$currPos = s3;
-                  s3 = peg$c1;
-                }
-              } else {
-                peg$currPos = s3;
-                s3 = peg$c1;
-              }
-            } else {
-              peg$currPos = s3;
-              s3 = peg$c1;
-            }
-          } else {
-            peg$currPos = s3;
-            s3 = peg$c1;
-          }
-        }
-        if (s2 !== peg$FAILED) {
-          peg$reportedPos = s0;
-          s1 = peg$c26(s1, s2);
-          s0 = s1;
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parseedgeRHS() {
-      var s0, s1, s2, s3, s4, s5;
-
-      s0 = peg$currPos;
-      s1 = peg$currPos;
-      if (input.substr(peg$currPos, 2) === peg$c27) {
-        s2 = peg$c27;
-        peg$currPos += 2;
-      } else {
-        s2 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c28); }
-      }
-      if (s2 !== peg$FAILED) {
-        peg$reportedPos = peg$currPos;
-        s3 = peg$c29();
-        if (s3) {
-          s3 = peg$c1;
-        } else {
-          s3 = peg$c30;
-        }
-        if (s3 !== peg$FAILED) {
-          s2 = [s2, s3];
-          s1 = s2;
-        } else {
-          peg$currPos = s1;
-          s1 = peg$c1;
-        }
-      } else {
-        peg$currPos = s1;
-        s1 = peg$c1;
-      }
-      if (s1 === peg$FAILED) {
-        s1 = peg$currPos;
-        if (input.substr(peg$currPos, 2) === peg$c31) {
-          s2 = peg$c31;
-          peg$currPos += 2;
-        } else {
-          s2 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$c32); }
-        }
-        if (s2 !== peg$FAILED) {
-          peg$reportedPos = peg$currPos;
-          s3 = peg$c29();
-          if (s3) {
-            s3 = peg$c30;
-          } else {
-            s3 = peg$c1;
-          }
-          if (s3 !== peg$FAILED) {
-            s2 = [s2, s3];
-            s1 = s2;
-          } else {
-            peg$currPos = s1;
-            s1 = peg$c1;
-          }
-        } else {
-          peg$currPos = s1;
-          s1 = peg$c1;
-        }
-      }
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = peg$parsenodeIdOrSubgraph();
-          if (s3 !== peg$FAILED) {
-            s4 = [];
-            s5 = peg$parse_();
-            while (s5 !== peg$FAILED) {
-              s4.push(s5);
-              s5 = peg$parse_();
-            }
-            if (s4 !== peg$FAILED) {
-              s5 = peg$parseedgeRHS();
-              if (s5 === peg$FAILED) {
-                s5 = peg$c2;
-              }
-              if (s5 !== peg$FAILED) {
-                peg$reportedPos = s0;
-                s1 = peg$c33(s3, s5);
-                s0 = s1;
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parseidDef() {
-      var s0, s1, s2, s3, s4, s5, s6;
-
-      s0 = peg$currPos;
-      s1 = peg$parseid();
-      if (s1 !== peg$FAILED) {
-        s2 = peg$currPos;
-        s3 = [];
-        s4 = peg$parse_();
-        while (s4 !== peg$FAILED) {
-          s3.push(s4);
-          s4 = peg$parse_();
-        }
-        if (s3 !== peg$FAILED) {
-          if (input.charCodeAt(peg$currPos) === 61) {
-            s4 = peg$c12;
-            peg$currPos++;
-          } else {
-            s4 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c13); }
-          }
-          if (s4 !== peg$FAILED) {
-            s5 = [];
-            s6 = peg$parse_();
-            while (s6 !== peg$FAILED) {
-              s5.push(s6);
-              s6 = peg$parse_();
-            }
-            if (s5 !== peg$FAILED) {
-              s6 = peg$parseid();
-              if (s6 !== peg$FAILED) {
-                s3 = [s3, s4, s5, s6];
-                s2 = s3;
-              } else {
-                peg$currPos = s2;
-                s2 = peg$c1;
-              }
-            } else {
-              peg$currPos = s2;
-              s2 = peg$c1;
-            }
-          } else {
-            peg$currPos = s2;
-            s2 = peg$c1;
-          }
-        } else {
-          peg$currPos = s2;
-          s2 = peg$c1;
-        }
-        if (s2 === peg$FAILED) {
-          s2 = peg$c2;
-        }
-        if (s2 !== peg$FAILED) {
-          peg$reportedPos = s0;
-          s1 = peg$c34(s1, s2);
-          s0 = s1;
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsenodeIdOrSubgraph() {
-      var s0, s1;
-
-      s0 = peg$parsesubgraphStmt();
-      if (s0 === peg$FAILED) {
-        s0 = peg$currPos;
-        s1 = peg$parsenodeId();
-        if (s1 !== peg$FAILED) {
-          peg$reportedPos = s0;
-          s1 = peg$c35(s1);
-        }
-        s0 = s1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsenodeId() {
-      var s0, s1, s2, s3;
-
-      s0 = peg$currPos;
-      s1 = peg$parseid();
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = peg$parseport();
-          if (s3 === peg$FAILED) {
-            s3 = peg$c2;
-          }
-          if (s3 !== peg$FAILED) {
-            peg$reportedPos = s0;
-            s1 = peg$c36(s1);
-            s0 = s1;
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parseport() {
-      var s0, s1, s2, s3, s4, s5, s6, s7, s8;
-
-      s0 = peg$currPos;
-      if (input.charCodeAt(peg$currPos) === 58) {
-        s1 = peg$c37;
-        peg$currPos++;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c38); }
-      }
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        s3 = peg$parse_();
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          s3 = peg$parse_();
-        }
-        if (s2 !== peg$FAILED) {
-          s3 = peg$parseid();
-          if (s3 !== peg$FAILED) {
-            s4 = [];
-            s5 = peg$parse_();
-            while (s5 !== peg$FAILED) {
-              s4.push(s5);
-              s5 = peg$parse_();
-            }
-            if (s4 !== peg$FAILED) {
-              s5 = peg$currPos;
-              if (input.charCodeAt(peg$currPos) === 58) {
-                s6 = peg$c37;
-                peg$currPos++;
-              } else {
-                s6 = peg$FAILED;
-                if (peg$silentFails === 0) { peg$fail(peg$c38); }
-              }
-              if (s6 !== peg$FAILED) {
-                s7 = [];
-                s8 = peg$parse_();
-                while (s8 !== peg$FAILED) {
-                  s7.push(s8);
-                  s8 = peg$parse_();
-                }
-                if (s7 !== peg$FAILED) {
-                  s8 = peg$parsecompassPt();
-                  if (s8 !== peg$FAILED) {
-                    s6 = [s6, s7, s8];
-                    s5 = s6;
-                  } else {
-                    peg$currPos = s5;
-                    s5 = peg$c1;
-                  }
-                } else {
-                  peg$currPos = s5;
-                  s5 = peg$c1;
-                }
-              } else {
-                peg$currPos = s5;
-                s5 = peg$c1;
-              }
-              if (s5 === peg$FAILED) {
-                s5 = peg$c2;
-              }
-              if (s5 !== peg$FAILED) {
-                s1 = [s1, s2, s3, s4, s5];
-                s0 = s1;
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsecompassPt() {
-      var s0;
-
-      if (input.substr(peg$currPos, 2) === peg$c39) {
-        s0 = peg$c39;
-        peg$currPos += 2;
-      } else {
-        s0 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c40); }
-      }
-      if (s0 === peg$FAILED) {
-        if (input.substr(peg$currPos, 2) === peg$c41) {
-          s0 = peg$c41;
-          peg$currPos += 2;
-        } else {
-          s0 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$c42); }
-        }
-        if (s0 === peg$FAILED) {
-          if (input.substr(peg$currPos, 2) === peg$c43) {
-            s0 = peg$c43;
-            peg$currPos += 2;
-          } else {
-            s0 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c44); }
-          }
-          if (s0 === peg$FAILED) {
-            if (input.substr(peg$currPos, 2) === peg$c45) {
-              s0 = peg$c45;
-              peg$currPos += 2;
-            } else {
-              s0 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$c46); }
-            }
-            if (s0 === peg$FAILED) {
-              if (input.charCodeAt(peg$currPos) === 110) {
-                s0 = peg$c47;
-                peg$currPos++;
-              } else {
-                s0 = peg$FAILED;
-                if (peg$silentFails === 0) { peg$fail(peg$c48); }
-              }
-              if (s0 === peg$FAILED) {
-                if (input.charCodeAt(peg$currPos) === 101) {
-                  s0 = peg$c49;
-                  peg$currPos++;
-                } else {
-                  s0 = peg$FAILED;
-                  if (peg$silentFails === 0) { peg$fail(peg$c50); }
-                }
-                if (s0 === peg$FAILED) {
-                  if (input.charCodeAt(peg$currPos) === 115) {
-                    s0 = peg$c51;
-                    peg$currPos++;
-                  } else {
-                    s0 = peg$FAILED;
-                    if (peg$silentFails === 0) { peg$fail(peg$c52); }
-                  }
-                  if (s0 === peg$FAILED) {
-                    if (input.charCodeAt(peg$currPos) === 119) {
-                      s0 = peg$c53;
-                      peg$currPos++;
-                    } else {
-                      s0 = peg$FAILED;
-                      if (peg$silentFails === 0) { peg$fail(peg$c54); }
-                    }
-                    if (s0 === peg$FAILED) {
-                      if (input.charCodeAt(peg$currPos) === 99) {
-                        s0 = peg$c55;
-                        peg$currPos++;
-                      } else {
-                        s0 = peg$FAILED;
-                        if (peg$silentFails === 0) { peg$fail(peg$c56); }
-                      }
-                      if (s0 === peg$FAILED) {
-                        if (input.charCodeAt(peg$currPos) === 95) {
-                          s0 = peg$c57;
-                          peg$currPos++;
-                        } else {
-                          s0 = peg$FAILED;
-                          if (peg$silentFails === 0) { peg$fail(peg$c58); }
-                        }
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-
-      return s0;
-    }
-
-    function peg$parseid() {
-      var s0, s1, s2, s3, s4, s5, s6;
-
-      peg$silentFails++;
-      s0 = peg$currPos;
-      if (peg$c60.test(input.charAt(peg$currPos))) {
-        s1 = input.charAt(peg$currPos);
-        peg$currPos++;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c61); }
-      }
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        if (peg$c62.test(input.charAt(peg$currPos))) {
-          s3 = input.charAt(peg$currPos);
-          peg$currPos++;
-        } else {
-          s3 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$c63); }
-        }
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          if (peg$c62.test(input.charAt(peg$currPos))) {
-            s3 = input.charAt(peg$currPos);
-            peg$currPos++;
-          } else {
-            s3 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c63); }
-          }
-        }
-        if (s2 !== peg$FAILED) {
-          peg$reportedPos = s0;
-          s1 = peg$c64(s1, s2);
-          s0 = s1;
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-      if (s0 === peg$FAILED) {
-        s0 = peg$currPos;
-        if (input.charCodeAt(peg$currPos) === 45) {
-          s1 = peg$c65;
-          peg$currPos++;
-        } else {
-          s1 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$c66); }
-        }
-        if (s1 === peg$FAILED) {
-          s1 = peg$c2;
-        }
-        if (s1 !== peg$FAILED) {
-          if (input.charCodeAt(peg$currPos) === 46) {
-            s2 = peg$c67;
-            peg$currPos++;
-          } else {
-            s2 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c68); }
-          }
-          if (s2 !== peg$FAILED) {
-            s3 = [];
-            if (peg$c69.test(input.charAt(peg$currPos))) {
-              s4 = input.charAt(peg$currPos);
-              peg$currPos++;
-            } else {
-              s4 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$c70); }
-            }
-            if (s4 !== peg$FAILED) {
-              while (s4 !== peg$FAILED) {
-                s3.push(s4);
-                if (peg$c69.test(input.charAt(peg$currPos))) {
-                  s4 = input.charAt(peg$currPos);
-                  peg$currPos++;
-                } else {
-                  s4 = peg$FAILED;
-                  if (peg$silentFails === 0) { peg$fail(peg$c70); }
-                }
-              }
-            } else {
-              s3 = peg$c1;
-            }
-            if (s3 !== peg$FAILED) {
-              peg$reportedPos = s0;
-              s1 = peg$c71(s1, s2, s3);
-              s0 = s1;
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-        if (s0 === peg$FAILED) {
-          s0 = peg$currPos;
-          if (input.charCodeAt(peg$currPos) === 45) {
-            s1 = peg$c65;
-            peg$currPos++;
-          } else {
-            s1 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c66); }
-          }
-          if (s1 === peg$FAILED) {
-            s1 = peg$c2;
-          }
-          if (s1 !== peg$FAILED) {
-            s2 = [];
-            if (peg$c69.test(input.charAt(peg$currPos))) {
-              s3 = input.charAt(peg$currPos);
-              peg$currPos++;
-            } else {
-              s3 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$c70); }
-            }
-            if (s3 !== peg$FAILED) {
-              while (s3 !== peg$FAILED) {
-                s2.push(s3);
-                if (peg$c69.test(input.charAt(peg$currPos))) {
-                  s3 = input.charAt(peg$currPos);
-                  peg$currPos++;
-                } else {
-                  s3 = peg$FAILED;
-                  if (peg$silentFails === 0) { peg$fail(peg$c70); }
-                }
-              }
-            } else {
-              s2 = peg$c1;
-            }
-            if (s2 !== peg$FAILED) {
-              s3 = peg$currPos;
-              if (input.charCodeAt(peg$currPos) === 46) {
-                s4 = peg$c67;
-                peg$currPos++;
-              } else {
-                s4 = peg$FAILED;
-                if (peg$silentFails === 0) { peg$fail(peg$c68); }
-              }
-              if (s4 !== peg$FAILED) {
-                s5 = [];
-                if (peg$c69.test(input.charAt(peg$currPos))) {
-                  s6 = input.charAt(peg$currPos);
-                  peg$currPos++;
-                } else {
-                  s6 = peg$FAILED;
-                  if (peg$silentFails === 0) { peg$fail(peg$c70); }
-                }
-                while (s6 !== peg$FAILED) {
-                  s5.push(s6);
-                  if (peg$c69.test(input.charAt(peg$currPos))) {
-                    s6 = input.charAt(peg$currPos);
-                    peg$currPos++;
-                  } else {
-                    s6 = peg$FAILED;
-                    if (peg$silentFails === 0) { peg$fail(peg$c70); }
-                  }
-                }
-                if (s5 !== peg$FAILED) {
-                  s4 = [s4, s5];
-                  s3 = s4;
-                } else {
-                  peg$currPos = s3;
-                  s3 = peg$c1;
-                }
-              } else {
-                peg$currPos = s3;
-                s3 = peg$c1;
-              }
-              if (s3 === peg$FAILED) {
-                s3 = peg$c2;
-              }
-              if (s3 !== peg$FAILED) {
-                peg$reportedPos = s0;
-                s1 = peg$c72(s1, s2, s3);
-                s0 = s1;
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-          if (s0 === peg$FAILED) {
-            s0 = peg$currPos;
-            if (input.charCodeAt(peg$currPos) === 34) {
-              s1 = peg$c73;
-              peg$currPos++;
-            } else {
-              s1 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$c74); }
-            }
-            if (s1 !== peg$FAILED) {
-              s2 = [];
-              s3 = peg$currPos;
-              if (input.substr(peg$currPos, 2) === peg$c75) {
-                s4 = peg$c75;
-                peg$currPos += 2;
-              } else {
-                s4 = peg$FAILED;
-                if (peg$silentFails === 0) { peg$fail(peg$c76); }
-              }
-              if (s4 !== peg$FAILED) {
-                peg$reportedPos = s3;
-                s4 = peg$c77();
-              }
-              s3 = s4;
-              if (s3 === peg$FAILED) {
-                s3 = peg$currPos;
-                if (input.charCodeAt(peg$currPos) === 92) {
-                  s4 = peg$c78;
-                  peg$currPos++;
-                } else {
-                  s4 = peg$FAILED;
-                  if (peg$silentFails === 0) { peg$fail(peg$c79); }
-                }
-                if (s4 !== peg$FAILED) {
-                  if (peg$c80.test(input.charAt(peg$currPos))) {
-                    s5 = input.charAt(peg$currPos);
-                    peg$currPos++;
-                  } else {
-                    s5 = peg$FAILED;
-                    if (peg$silentFails === 0) { peg$fail(peg$c81); }
-                  }
-                  if (s5 !== peg$FAILED) {
-                    peg$reportedPos = s3;
-                    s4 = peg$c82(s5);
-                    s3 = s4;
-                  } else {
-                    peg$currPos = s3;
-                    s3 = peg$c1;
-                  }
-                } else {
-                  peg$currPos = s3;
-                  s3 = peg$c1;
-                }
-                if (s3 === peg$FAILED) {
-                  if (peg$c80.test(input.charAt(peg$currPos))) {
-                    s3 = input.charAt(peg$currPos);
-                    peg$currPos++;
-                  } else {
-                    s3 = peg$FAILED;
-                    if (peg$silentFails === 0) { peg$fail(peg$c81); }
-                  }
-                }
-              }
-              while (s3 !== peg$FAILED) {
-                s2.push(s3);
-                s3 = peg$currPos;
-                if (input.substr(peg$currPos, 2) === peg$c75) {
-                  s4 = peg$c75;
-                  peg$currPos += 2;
-                } else {
-                  s4 = peg$FAILED;
-                  if (peg$silentFails === 0) { peg$fail(peg$c76); }
-                }
-                if (s4 !== peg$FAILED) {
-                  peg$reportedPos = s3;
-                  s4 = peg$c77();
-                }
-                s3 = s4;
-                if (s3 === peg$FAILED) {
-                  s3 = peg$currPos;
-                  if (input.charCodeAt(peg$currPos) === 92) {
-                    s4 = peg$c78;
-                    peg$currPos++;
-                  } else {
-                    s4 = peg$FAILED;
-                    if (peg$silentFails === 0) { peg$fail(peg$c79); }
-                  }
-                  if (s4 !== peg$FAILED) {
-                    if (peg$c80.test(input.charAt(peg$currPos))) {
-                      s5 = input.charAt(peg$currPos);
-                      peg$currPos++;
-                    } else {
-                      s5 = peg$FAILED;
-                      if (peg$silentFails === 0) { peg$fail(peg$c81); }
-                    }
-                    if (s5 !== peg$FAILED) {
-                      peg$reportedPos = s3;
-                      s4 = peg$c82(s5);
-                      s3 = s4;
-                    } else {
-                      peg$currPos = s3;
-                      s3 = peg$c1;
-                    }
-                  } else {
-                    peg$currPos = s3;
-                    s3 = peg$c1;
-                  }
-                  if (s3 === peg$FAILED) {
-                    if (peg$c80.test(input.charAt(peg$currPos))) {
-                      s3 = input.charAt(peg$currPos);
-                      peg$currPos++;
-                    } else {
-                      s3 = peg$FAILED;
-                      if (peg$silentFails === 0) { peg$fail(peg$c81); }
-                    }
-                  }
-                }
-              }
-              if (s2 !== peg$FAILED) {
-                if (input.charCodeAt(peg$currPos) === 34) {
-                  s3 = peg$c73;
-                  peg$currPos++;
-                } else {
-                  s3 = peg$FAILED;
-                  if (peg$silentFails === 0) { peg$fail(peg$c74); }
-                }
-                if (s3 !== peg$FAILED) {
-                  peg$reportedPos = s0;
-                  s1 = peg$c83(s2);
-                  s0 = s1;
-                } else {
-                  peg$currPos = s0;
-                  s0 = peg$c1;
-                }
-              } else {
-                peg$currPos = s0;
-                s0 = peg$c1;
-              }
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          }
-        }
-      }
-      peg$silentFails--;
-      if (s0 === peg$FAILED) {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c59); }
-      }
-
-      return s0;
-    }
-
-    function peg$parsenode() {
-      var s0, s1;
-
-      s0 = peg$currPos;
-      if (input.substr(peg$currPos, 4).toLowerCase() === peg$c84) {
-        s1 = input.substr(peg$currPos, 4);
-        peg$currPos += 4;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c85); }
-      }
-      if (s1 !== peg$FAILED) {
-        peg$reportedPos = s0;
-        s1 = peg$c86(s1);
-      }
-      s0 = s1;
-
-      return s0;
-    }
-
-    function peg$parseedge() {
-      var s0, s1;
-
-      s0 = peg$currPos;
-      if (input.substr(peg$currPos, 4).toLowerCase() === peg$c87) {
-        s1 = input.substr(peg$currPos, 4);
-        peg$currPos += 4;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c88); }
-      }
-      if (s1 !== peg$FAILED) {
-        peg$reportedPos = s0;
-        s1 = peg$c86(s1);
-      }
-      s0 = s1;
-
-      return s0;
-    }
-
-    function peg$parsegraph() {
-      var s0, s1;
-
-      s0 = peg$currPos;
-      if (input.substr(peg$currPos, 5).toLowerCase() === peg$c89) {
-        s1 = input.substr(peg$currPos, 5);
-        peg$currPos += 5;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c90); }
-      }
-      if (s1 !== peg$FAILED) {
-        peg$reportedPos = s0;
-        s1 = peg$c86(s1);
-      }
-      s0 = s1;
-
-      return s0;
-    }
-
-    function peg$parsedigraph() {
-      var s0, s1;
-
-      s0 = peg$currPos;
-      if (input.substr(peg$currPos, 7).toLowerCase() === peg$c91) {
-        s1 = input.substr(peg$currPos, 7);
-        peg$currPos += 7;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c92); }
-      }
-      if (s1 !== peg$FAILED) {
-        peg$reportedPos = s0;
-        s1 = peg$c86(s1);
-      }
-      s0 = s1;
-
-      return s0;
-    }
-
-    function peg$parsesubgraph() {
-      var s0, s1;
-
-      s0 = peg$currPos;
-      if (input.substr(peg$currPos, 8).toLowerCase() === peg$c93) {
-        s1 = input.substr(peg$currPos, 8);
-        peg$currPos += 8;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c94); }
-      }
-      if (s1 !== peg$FAILED) {
-        peg$reportedPos = s0;
-        s1 = peg$c86(s1);
-      }
-      s0 = s1;
-
-      return s0;
-    }
-
-    function peg$parsestrict() {
-      var s0, s1;
-
-      s0 = peg$currPos;
-      if (input.substr(peg$currPos, 6).toLowerCase() === peg$c95) {
-        s1 = input.substr(peg$currPos, 6);
-        peg$currPos += 6;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c96); }
-      }
-      if (s1 !== peg$FAILED) {
-        peg$reportedPos = s0;
-        s1 = peg$c86(s1);
-      }
-      s0 = s1;
-
-      return s0;
-    }
-
-    function peg$parsegraphType() {
-      var s0, s1;
-
-      s0 = peg$parsegraph();
-      if (s0 === peg$FAILED) {
-        s0 = peg$currPos;
-        s1 = peg$parsedigraph();
-        if (s1 !== peg$FAILED) {
-          peg$reportedPos = s0;
-          s1 = peg$c97(s1);
-        }
-        s0 = s1;
-      }
-
-      return s0;
-    }
-
-    function peg$parsewhitespace() {
-      var s0, s1;
-
-      peg$silentFails++;
-      s0 = [];
-      if (peg$c99.test(input.charAt(peg$currPos))) {
-        s1 = input.charAt(peg$currPos);
-        peg$currPos++;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c100); }
-      }
-      if (s1 !== peg$FAILED) {
-        while (s1 !== peg$FAILED) {
-          s0.push(s1);
-          if (peg$c99.test(input.charAt(peg$currPos))) {
-            s1 = input.charAt(peg$currPos);
-            peg$currPos++;
-          } else {
-            s1 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c100); }
-          }
-        }
-      } else {
-        s0 = peg$c1;
-      }
-      peg$silentFails--;
-      if (s0 === peg$FAILED) {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c98); }
-      }
-
-      return s0;
-    }
-
-    function peg$parsecomment() {
-      var s0, s1, s2, s3, s4, s5;
-
-      peg$silentFails++;
-      s0 = peg$currPos;
-      if (input.substr(peg$currPos, 2) === peg$c102) {
-        s1 = peg$c102;
-        peg$currPos += 2;
-      } else {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c103); }
-      }
-      if (s1 !== peg$FAILED) {
-        s2 = [];
-        if (peg$c104.test(input.charAt(peg$currPos))) {
-          s3 = input.charAt(peg$currPos);
-          peg$currPos++;
-        } else {
-          s3 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$c105); }
-        }
-        while (s3 !== peg$FAILED) {
-          s2.push(s3);
-          if (peg$c104.test(input.charAt(peg$currPos))) {
-            s3 = input.charAt(peg$currPos);
-            peg$currPos++;
-          } else {
-            s3 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c105); }
-          }
-        }
-        if (s2 !== peg$FAILED) {
-          s1 = [s1, s2];
-          s0 = s1;
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      } else {
-        peg$currPos = s0;
-        s0 = peg$c1;
-      }
-      if (s0 === peg$FAILED) {
-        s0 = peg$currPos;
-        if (input.substr(peg$currPos, 2) === peg$c106) {
-          s1 = peg$c106;
-          peg$currPos += 2;
-        } else {
-          s1 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$c107); }
-        }
-        if (s1 !== peg$FAILED) {
-          s2 = [];
-          s3 = peg$currPos;
-          s4 = peg$currPos;
-          peg$silentFails++;
-          if (input.substr(peg$currPos, 2) === peg$c108) {
-            s5 = peg$c108;
-            peg$currPos += 2;
-          } else {
-            s5 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$c109); }
-          }
-          peg$silentFails--;
-          if (s5 === peg$FAILED) {
-            s4 = peg$c30;
-          } else {
-            peg$currPos = s4;
-            s4 = peg$c1;
-          }
-          if (s4 !== peg$FAILED) {
-            if (input.length > peg$currPos) {
-              s5 = input.charAt(peg$currPos);
-              peg$currPos++;
-            } else {
-              s5 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$c110); }
-            }
-            if (s5 !== peg$FAILED) {
-              s4 = [s4, s5];
-              s3 = s4;
-            } else {
-              peg$currPos = s3;
-              s3 = peg$c1;
-            }
-          } else {
-            peg$currPos = s3;
-            s3 = peg$c1;
-          }
-          while (s3 !== peg$FAILED) {
-            s2.push(s3);
-            s3 = peg$currPos;
-            s4 = peg$currPos;
-            peg$silentFails++;
-            if (input.substr(peg$currPos, 2) === peg$c108) {
-              s5 = peg$c108;
-              peg$currPos += 2;
-            } else {
-              s5 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$c109); }
-            }
-            peg$silentFails--;
-            if (s5 === peg$FAILED) {
-              s4 = peg$c30;
-            } else {
-              peg$currPos = s4;
-              s4 = peg$c1;
-            }
-            if (s4 !== peg$FAILED) {
-              if (input.length > peg$currPos) {
-                s5 = input.charAt(peg$currPos);
-                peg$currPos++;
-              } else {
-                s5 = peg$FAILED;
-                if (peg$silentFails === 0) { peg$fail(peg$c110); }
-              }
-              if (s5 !== peg$FAILED) {
-                s4 = [s4, s5];
-                s3 = s4;
-              } else {
-                peg$currPos = s3;
-                s3 = peg$c1;
-              }
-            } else {
-              peg$currPos = s3;
-              s3 = peg$c1;
-            }
-          }
-          if (s2 !== peg$FAILED) {
-            if (input.substr(peg$currPos, 2) === peg$c108) {
-              s3 = peg$c108;
-              peg$currPos += 2;
-            } else {
-              s3 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$c109); }
-            }
-            if (s3 !== peg$FAILED) {
-              s1 = [s1, s2, s3];
-              s0 = s1;
-            } else {
-              peg$currPos = s0;
-              s0 = peg$c1;
-            }
-          } else {
-            peg$currPos = s0;
-            s0 = peg$c1;
-          }
-        } else {
-          peg$currPos = s0;
-          s0 = peg$c1;
-        }
-      }
-      peg$silentFails--;
-      if (s0 === peg$FAILED) {
-        s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$c101); }
-      }
-
-      return s0;
-    }
-
-    function peg$parse_() {
-      var s0;
-
-      s0 = peg$parsewhitespace();
-      if (s0 === peg$FAILED) {
-        s0 = peg$parsecomment();
-      }
-
-      return s0;
-    }
-
-
-      var _ = require("./lodash");
-      var directed;
-
-
-    peg$result = peg$startRuleFunction();
-
-    if (peg$result !== peg$FAILED && peg$currPos === input.length) {
-      return peg$result;
-    } else {
-      if (peg$result !== peg$FAILED && peg$currPos < input.length) {
-        peg$fail({ type: "end", description: "end of input" });
-      }
-
-      throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
-    }
-  }
-
-  return {
-    SyntaxError: SyntaxError,
-    parse:       parse
-  };
-})();
-
-},{"./lodash":6}],5:[function(require,module,exports){
-/* global window */
-
-var graphlib;
-
-if (require) {
-  try {
-    graphlib = require("graphlib");
-  } catch (e) {}
-}
-
-if (!graphlib) {
-  graphlib = window.graphlib;
-}
-
-module.exports = graphlib;
-
-},{"graphlib":11}],6:[function(require,module,exports){
-/* global window */
-
-var lodash;
-
-if (require) {
-  try {
-    lodash = require("lodash");
-  } catch (e) {}
-}
-
-if (!lodash) {
-  lodash = window._;
-}
-
-module.exports = lodash;
-
-},{"lodash":31}],7:[function(require,module,exports){
-var _ = require("./lodash"),
-    grammar = require("./dot-grammar"),
-    buildGraph = require("./build-graph");
-
-module.exports = function readMany(str) {
-  var parseTree = grammar.parse(str);
-  return _.map(parseTree, buildGraph);
-};
-
-},{"./build-graph":3,"./dot-grammar":4,"./lodash":6}],8:[function(require,module,exports){
-var grammar = require("./dot-grammar"),
-    buildGraph = require("./build-graph");
-
-module.exports = function readOne(str) {
-  var parseTree = grammar.parse(str, { startRule: "graphStmt" });
-  return buildGraph(parseTree);
-};
-
-
-},{"./build-graph":3,"./dot-grammar":4}],9:[function(require,module,exports){
-module.exports = '0.6.2';
-
-},{}],10:[function(require,module,exports){
-var _ = require("./lodash");
-
-module.exports = writeOne;
-
-var UNESCAPED_ID_PATTERN = /^[a-zA-Z\200-\377_][a-zA-Z\200-\377_0-9]*$/;
-
-function writeOne(g) {
-  var ec = g.isDirected() ? "->" : "--",
-      writer = new Writer();
-
-  if (!g.isMultigraph()) {
-    writer.write("strict ");
-  }
-
-  writer.writeLine((g.isDirected() ? "digraph" : "graph") + " {");
-  writer.indent();
-
-  var graphAttrs = g.graph();
-  if (_.isObject(graphAttrs)) {
-    _.each(graphAttrs, function(v, k) {
-      writer.writeLine(id(k) + "=" + id(v) + ";");
-    });
-  }
-
-  writeSubgraph(g, undefined, writer);
-
-  g.edges().forEach(function(edge) {
-    writeEdge(g, edge, ec, writer);
-  });
-
-  writer.unindent();
-  writer.writeLine("}");
-
-  return writer.toString();
-}
-
-function writeSubgraph(g, v, writer) {
-  var children = g.isCompound() ? g.children(v) : g.nodes();
-  _.each(children, function(w) {
-    if (!g.isCompound() || !g.children(w).length) {
-      writeNode(g, w, writer);
-    } else {
-      writer.writeLine("subgraph " + id(w) + " {");
-      writer.indent();
-
-      if (_.isObject(g.node(w))) {
-        _.map(g.node(w), function(val, key) {
-          writer.writeLine(id(key) + "=" + id(val) + ";");
-        });
-      }
-
-      writeSubgraph(g, w, writer);
-      writer.unindent();
-      writer.writeLine("}");
-    }
-  });
-}
-
-function writeNode(g, v, writer) {
-  writer.write(id(v));
-  writeAttrs(g.node(v), writer);
-  writer.writeLine();
-}
-
-function writeEdge(g, edge, ec, writer) {
-  var v = edge.v,
-      w = edge.w,
-      attrs = g.edge(edge);
-
-  writer.write(id(v) + " " + ec + " " + id(w));
-  writeAttrs(attrs, writer);
-  writer.writeLine();
-}
-
-function writeAttrs(attrs, writer) {
-  if (_.isObject(attrs)) {
-    var attrStrs = _.map(attrs, function(val, key) {
-      return id(key) + "=" + id(val);
-    });
-    if (attrStrs.length) {
-      writer.write(" [" + attrStrs.join(",") + "]");
-    }
-  }
-}
-
-function id(obj) {
-  if (typeof obj === "number" || obj.toString().match(UNESCAPED_ID_PATTERN)) {
-    return obj;
-  }
-
-  return "\"" + obj.toString().replace(/"/g, "\\\"") + "\"";
-}
-
-// Helper object for making a pretty printer
-function Writer() {
-  this._indent = "";
-  this._content = "";
-  this._shouldIndent = true;
-}
-
-Writer.prototype.INDENT = "  ";
-
-Writer.prototype.indent = function() {
-  this._indent += this.INDENT;
-};
-
-Writer.prototype.unindent = function() {
-  this._indent = this._indent.slice(this.INDENT.length);
-};
-
-Writer.prototype.writeLine = function(line) {
-  this.write((line || "") + "\n");
-  this._shouldIndent = true;
-};
-
-Writer.prototype.write = function(str) {
-  if (this._shouldIndent) {
-    this._shouldIndent = false;
-    this._content += this._indent;
-  }
-  this._content += str;
-};
-
-Writer.prototype.toString = function() {
-  return this._content;
-};
-
-
-},{"./lodash":6}],11:[function(require,module,exports){
-/**
- * Copyright (c) 2014, Chris Pettitt
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors
- * may be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-var lib = require("./lib");
-
-module.exports = {
-  Graph: lib.Graph,
-  json: require("./lib/json"),
-  alg: require("./lib/alg"),
-  version: lib.version
-};
-
-},{"./lib":27,"./lib/alg":18,"./lib/json":28}],12:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = components;
-
-function components(g) {
-  var visited = {},
-      cmpts = [],
-      cmpt;
-
-  function dfs(v) {
-    if (_.has(visited, v)) return;
-    visited[v] = true;
-    cmpt.push(v);
-    _.each(g.successors(v), dfs);
-    _.each(g.predecessors(v), dfs);
-  }
-
-  _.each(g.nodes(), function(v) {
-    cmpt = [];
-    dfs(v);
-    if (cmpt.length) {
-      cmpts.push(cmpt);
-    }
-  });
-
-  return cmpts;
-}
-
-},{"../lodash":29}],13:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = dfs;
-
-/*
- * A helper that preforms a pre- or post-order traversal on the input graph
- * and returns the nodes in the order they were visited. This algorithm treats
- * the input as undirected.
- *
- * Order must be one of "pre" or "post".
- */
-function dfs(g, vs, order) {
-  if (!_.isArray(vs)) {
-    vs = [vs];
-  }
-
-  var acc = [],
-      visited = {};
-  _.each(vs, function(v) {
-    if (!g.hasNode(v)) {
-      throw new Error("Graph does not have node: " + v);
-    }
-
-    doDfs(g, v, order === "post", visited, acc);
-  });
-  return acc;
-}
-
-function doDfs(g, v, postorder, visited, acc) {
-  if (!_.has(visited, v)) {
-    visited[v] = true;
-
-    if (!postorder) { acc.push(v); }
-    _.each(g.neighbors(v), function(w) {
-      doDfs(g, w, postorder, visited, acc);
-    });
-    if (postorder) { acc.push(v); }
-  }
-}
-
-},{"../lodash":29}],14:[function(require,module,exports){
-var dijkstra = require("./dijkstra"),
-    _ = require("../lodash");
-
-module.exports = dijkstraAll;
-
-function dijkstraAll(g, weightFunc, edgeFunc) {
-  return _.transform(g.nodes(), function(acc, v) {
-    acc[v] = dijkstra(g, v, weightFunc, edgeFunc);
-  }, {});
-}
-
-},{"../lodash":29,"./dijkstra":15}],15:[function(require,module,exports){
-var _ = require("../lodash"),
-    PriorityQueue = require("../data/priority-queue");
-
-module.exports = dijkstra;
-
-var DEFAULT_WEIGHT_FUNC = _.constant(1);
-
-function dijkstra(g, source, weightFn, edgeFn) {
-  return runDijkstra(g, String(source),
-                     weightFn || DEFAULT_WEIGHT_FUNC,
-                     edgeFn || function(v) { return g.outEdges(v); });
-}
-
-function runDijkstra(g, source, weightFn, edgeFn) {
-  var results = {},
-      pq = new PriorityQueue(),
-      v, vEntry;
-
-  var updateNeighbors = function(edge) {
-    var w = edge.v !== v ? edge.v : edge.w,
-        wEntry = results[w],
-        weight = weightFn(edge),
-        distance = vEntry.distance + weight;
-
-    if (weight < 0) {
-      throw new Error("dijkstra does not allow negative edge weights. " +
-                      "Bad edge: " + edge + " Weight: " + weight);
-    }
-
-    if (distance < wEntry.distance) {
-      wEntry.distance = distance;
-      wEntry.predecessor = v;
-      pq.decrease(w, distance);
-    }
-  };
-
-  g.nodes().forEach(function(v) {
-    var distance = v === source ? 0 : Number.POSITIVE_INFINITY;
-    results[v] = { distance: distance };
-    pq.add(v, distance);
-  });
-
-  while (pq.size() > 0) {
-    v = pq.removeMin();
-    vEntry = results[v];
-    if (vEntry.distance === Number.POSITIVE_INFINITY) {
-      break;
-    }
-
-    edgeFn(v).forEach(updateNeighbors);
-  }
-
-  return results;
-}
-
-},{"../data/priority-queue":25,"../lodash":29}],16:[function(require,module,exports){
-var _ = require("../lodash"),
-    tarjan = require("./tarjan");
-
-module.exports = findCycles;
-
-function findCycles(g) {
-  return _.filter(tarjan(g), function(cmpt) {
-    return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0]));
-  });
-}
-
-},{"../lodash":29,"./tarjan":23}],17:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = floydWarshall;
-
-var DEFAULT_WEIGHT_FUNC = _.constant(1);
-
-function floydWarshall(g, weightFn, edgeFn) {
-  return runFloydWarshall(g,
-                          weightFn || DEFAULT_WEIGHT_FUNC,
-                          edgeFn || function(v) { return g.outEdges(v); });
-}
-
-function runFloydWarshall(g, weightFn, edgeFn) {
-  var results = {},
-      nodes = g.nodes();
-
-  nodes.forEach(function(v) {
-    results[v] = {};
-    results[v][v] = { distance: 0 };
-    nodes.forEach(function(w) {
-      if (v !== w) {
-        results[v][w] = { distance: Number.POSITIVE_INFINITY };
-      }
-    });
-    edgeFn(v).forEach(function(edge) {
-      var w = edge.v === v ? edge.w : edge.v,
-          d = weightFn(edge);
-      results[v][w] = { distance: d, predecessor: v };
-    });
-  });
-
-  nodes.forEach(function(k) {
-    var rowK = results[k];
-    nodes.forEach(function(i) {
-      var rowI = results[i];
-      nodes.forEach(function(j) {
-        var ik = rowI[k];
-        var kj = rowK[j];
-        var ij = rowI[j];
-        var altDistance = ik.distance + kj.distance;
-        if (altDistance < ij.distance) {
-          ij.distance = altDistance;
-          ij.predecessor = kj.predecessor;
-        }
-      });
-    });
-  });
-
-  return results;
-}
-
-},{"../lodash":29}],18:[function(require,module,exports){
-module.exports = {
-  components: require("./components"),
-  dijkstra: require("./dijkstra"),
-  dijkstraAll: require("./dijkstra-all"),
-  findCycles: require("./find-cycles"),
-  floydWarshall: require("./floyd-warshall"),
-  isAcyclic: require("./is-acyclic"),
-  postorder: require("./postorder"),
-  preorder: require("./preorder"),
-  prim: require("./prim"),
-  tarjan: require("./tarjan"),
-  topsort: require("./topsort")
-};
-
-},{"./components":12,"./dijkstra":15,"./dijkstra-all":14,"./find-cycles":16,"./floyd-warshall":17,"./is-acyclic":19,"./postorder":20,"./preorder":21,"./prim":22,"./tarjan":23,"./topsort":24}],19:[function(require,module,exports){
-var topsort = require("./topsort");
-
-module.exports = isAcyclic;
-
-function isAcyclic(g) {
-  try {
-    topsort(g);
-  } catch (e) {
-    if (e instanceof topsort.CycleException) {
-      return false;
-    }
-    throw e;
-  }
-  return true;
-}
-
-},{"./topsort":24}],20:[function(require,module,exports){
-var dfs = require("./dfs");
-
-module.exports = postorder;
-
-function postorder(g, vs) {
-  return dfs(g, vs, "post");
-}
-
-},{"./dfs":13}],21:[function(require,module,exports){
-var dfs = require("./dfs");
-
-module.exports = preorder;
-
-function preorder(g, vs) {
-  return dfs(g, vs, "pre");
-}
-
-},{"./dfs":13}],22:[function(require,module,exports){
-var _ = require("../lodash"),
-    Graph = require("../graph"),
-    PriorityQueue = require("../data/priority-queue");
-
-module.exports = prim;
-
-function prim(g, weightFunc) {
-  var result = new Graph(),
-      parents = {},
-      pq = new PriorityQueue(),
-      v;
-
-  function updateNeighbors(edge) {
-    var w = edge.v === v ? edge.w : edge.v,
-        pri = pq.priority(w);
-    if (pri !== undefined) {
-      var edgeWeight = weightFunc(edge);
-      if (edgeWeight < pri) {
-        parents[w] = v;
-        pq.decrease(w, edgeWeight);
-      }
-    }
-  }
-
-  if (g.nodeCount() === 0) {
-    return result;
-  }
-
-  _.each(g.nodes(), function(v) {
-    pq.add(v, Number.POSITIVE_INFINITY);
-    result.setNode(v);
-  });
-
-  // Start from an arbitrary node
-  pq.decrease(g.nodes()[0], 0);
-
-  var init = false;
-  while (pq.size() > 0) {
-    v = pq.removeMin();
-    if (_.has(parents, v)) {
-      result.setEdge(v, parents[v]);
-    } else if (init) {
-      throw new Error("Input graph is not connected: " + g);
-    } else {
-      init = true;
-    }
-
-    g.nodeEdges(v).forEach(updateNeighbors);
-  }
-
-  return result;
-}
-
-},{"../data/priority-queue":25,"../graph":26,"../lodash":29}],23:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = tarjan;
-
-function tarjan(g) {
-  var index = 0,
-      stack = [],
-      visited = {}, // node id -> { onStack, lowlink, index }
-      results = [];
-
-  function dfs(v) {
-    var entry = visited[v] = {
-      onStack: true,
-      lowlink: index,
-      index: index++
-    };
-    stack.push(v);
-
-    g.successors(v).forEach(function(w) {
-      if (!_.has(visited, w)) {
-        dfs(w);
-        entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
-      } else if (visited[w].onStack) {
-        entry.lowlink = Math.min(entry.lowlink, visited[w].index);
-      }
-    });
-
-    if (entry.lowlink === entry.index) {
-      var cmpt = [],
-          w;
-      do {
-        w = stack.pop();
-        visited[w].onStack = false;
-        cmpt.push(w);
-      } while (v !== w);
-      results.push(cmpt);
-    }
-  }
-
-  g.nodes().forEach(function(v) {
-    if (!_.has(visited, v)) {
-      dfs(v);
-    }
-  });
-
-  return results;
-}
-
-},{"../lodash":29}],24:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = topsort;
-topsort.CycleException = CycleException;
-
-function topsort(g) {
-  var visited = {},
-      stack = {},
-      results = [];
-
-  function visit(node) {
-    if (_.has(stack, node)) {
-      throw new CycleException();
-    }
-
-    if (!_.has(visited, node)) {
-      stack[node] = true;
-      visited[node] = true;
-      _.each(g.predecessors(node), visit);
-      delete stack[node];
-      results.push(node);
-    }
-  }
-
-  _.each(g.sinks(), visit);
-
-  if (_.size(visited) !== g.nodeCount()) {
-    throw new CycleException();
-  }
-
-  return results;
-}
-
-function CycleException() {}
-
-},{"../lodash":29}],25:[function(require,module,exports){
-var _ = require("../lodash");
-
-module.exports = PriorityQueue;
-
-/**
- * A min-priority queue data structure. This algorithm is derived from Cormen,
- * et al., "Introduction to Algorithms". The basic idea of a min-priority
- * queue is that you can efficiently (in O(1) time) get the smallest key in
- * the queue. Adding and removing elements takes O(log n) time. A key can
- * have its priority decreased in O(log n) time.
- */
-function PriorityQueue() {
-  this._arr = [];
-  this._keyIndices = {};
-}
-
-/**
- * Returns the number of elements in the queue. Takes `O(1)` time.
- */
-PriorityQueue.prototype.size = function() {
-  return this._arr.length;
-};
-
-/**
- * Returns the keys that are in the queue. Takes `O(n)` time.
- */
-PriorityQueue.prototype.keys = function() {
-  return this._arr.map(function(x) { return x.key; });
-};
-
-/**
- * Returns `true` if **key** is in the queue and `false` if not.
- */
-PriorityQueue.prototype.has = function(key) {
-  return _.has(this._keyIndices, key);
-};
-
-/**
- * Returns the priority for **key**. If **key** is not present in the queue
- * then this function returns `undefined`. Takes `O(1)` time.
- *
- * @param {Object} key
- */
-PriorityQueue.prototype.priority = function(key) {
-  var index = this._keyIndices[key];
-  if (index !== undefined) {
-    return this._arr[index].priority;
-  }
-};
-
-/**
- * Returns the key for the minimum element in this queue. If the queue is
- * empty this function throws an Error. Takes `O(1)` time.
- */
-PriorityQueue.prototype.min = function() {
-  if (this.size() === 0) {
-    throw new Error("Queue underflow");
-  }
-  return this._arr[0].key;
-};
-
-/**
- * Inserts a new key into the priority queue. If the key already exists in
- * the queue this function returns `false`; otherwise it will return `true`.
- * Takes `O(n)` time.
- *
- * @param {Object} key the key to add
- * @param {Number} priority the initial priority for the key
- */
-PriorityQueue.prototype.add = function(key, priority) {
-  var keyIndices = this._keyIndices;
-  key = String(key);
-  if (!_.has(keyIndices, key)) {
-    var arr = this._arr;
-    var index = arr.length;
-    keyIndices[key] = index;
-    arr.push({key: key, priority: priority});
-    this._decrease(index);
-    return true;
-  }
-  return false;
-};
-
-/**
- * Removes and returns the smallest key in the queue. Takes `O(log n)` time.
- */
-PriorityQueue.prototype.removeMin = function() {
-  this._swap(0, this._arr.length - 1);
-  var min = this._arr.pop();
-  delete this._keyIndices[min.key];
-  this._heapify(0);
-  return min.key;
-};
-
-/**
- * Decreases the priority for **key** to **priority**. If the new priority is
- * greater than the previous priority, this function will throw an Error.
- *
- * @param {Object} key the key for which to raise priority
- * @param {Number} priority the new priority for the key
- */
-PriorityQueue.prototype.decrease = function(key, priority) {
-  var index = this._keyIndices[key];
-  if (priority > this._arr[index].priority) {
-    throw new Error("New priority is greater than current priority. " +
-        "Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority);
-  }
-  this._arr[index].priority = priority;
-  this._decrease(index);
-};
-
-PriorityQueue.prototype._heapify = function(i) {
-  var arr = this._arr;
-  var l = 2 * i,
-      r = l + 1,
-      largest = i;
-  if (l < arr.length) {
-    largest = arr[l].priority < arr[largest].priority ? l : largest;
-    if (r < arr.length) {
-      largest = arr[r].priority < arr[largest].priority ? r : largest;
-    }
-    if (largest !== i) {
-      this._swap(i, largest);
-      this._heapify(largest);
-    }
-  }
-};
-
-PriorityQueue.prototype._decrease = function(index) {
-  var arr = this._arr;
-  var priority = arr[index].priority;
-  var parent;
-  while (index !== 0) {
-    parent = index >> 1;
-    if (arr[parent].priority < priority) {
-      break;
-    }
-    this._swap(index, parent);
-    index = parent;
-  }
-};
-
-PriorityQueue.prototype._swap = function(i, j) {
-  var arr = this._arr;
-  var keyIndices = this._keyIndices;
-  var origArrI = arr[i];
-  var origArrJ = arr[j];
-  arr[i] = origArrJ;
-  arr[j] = origArrI;
-  keyIndices[origArrJ.key] = i;
-  keyIndices[origArrI.key] = j;
-};
-
-},{"../lodash":29}],26:[function(require,module,exports){
-"use strict";
-
-var _ = require("./lodash");
-
-module.exports = Graph;
-
-var DEFAULT_EDGE_NAME = "\x00",
-    GRAPH_NODE = "\x00",
-    EDGE_KEY_DELIM = "\x01";
-
-// Implementation notes:
-//
-//  * Node id query functions should return string ids for the nodes
-//  * Edge id query functions should return an "edgeObj", edge object, that is
-//    composed of enough information to uniquely identify an edge: {v, w, name}.
-//  * Internally we use an "edgeId", a stringified form of the edgeObj, to
-//    reference edges. This is because we need a performant way to look these
-//    edges up and, object properties, which have string keys, are the closest
-//    we're going to get to a performant hashtable in JavaScript.
-
-function Graph(opts) {
-  this._isDirected = _.has(opts, "directed") ? opts.directed : true;
-  this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false;
-  this._isCompound = _.has(opts, "compound") ? opts.compound : false;
-
-  // Label for the graph itself
-  this._label = undefined;
-
-  // Defaults to be set when creating a new node
-  this._defaultNodeLabelFn = _.constant(undefined);
-
-  // Defaults to be set when creating a new edge
-  this._defaultEdgeLabelFn = _.constant(undefined);
-
-  // v -> label
-  this._nodes = {};
-
-  if (this._isCompound) {
-    // v -> parent
-    this._parent = {};
-
-    // v -> children
-    this._children = {};
-    this._children[GRAPH_NODE] = {};
-  }
-
-  // v -> edgeObj
-  this._in = {};
-
-  // u -> v -> Number
-  this._preds = {};
-
-  // v -> edgeObj
-  this._out = {};
-
-  // v -> w -> Number
-  this._sucs = {};
-
-  // e -> edgeObj
-  this._edgeObjs = {};
-
-  // e -> label
-  this._edgeLabels = {};
-}
-
-/* Number of nodes in the graph. Should only be changed by the implementation. */
-Graph.prototype._nodeCount = 0;
-
-/* Number of edges in the graph. Should only be changed by the implementation. */
-Graph.prototype._edgeCount = 0;
-
-
-/* === Graph functions ========= */
-
-Graph.prototype.isDirected = function() {
-  return this._isDirected;
-};
-
-Graph.prototype.isMultigraph = function() {
-  return this._isMultigraph;
-};
-
-Graph.prototype.isCompound = function() {
-  return this._isCompound;
-};
-
-Graph.prototype.setGraph = function(label) {
-  this._label = label;
-  return this;
-};
-
-Graph.prototype.graph = function() {
-  return this._label;
-};
-
-
-/* === Node functions ========== */
-
-Graph.prototype.setDefaultNodeLabel = function(newDefault) {
-  if (!_.isFunction(newDefault)) {
-    newDefault = _.constant(newDefault);
-  }
-  this._defaultNodeLabelFn = newDefault;
-  return this;
-};
-
-Graph.prototype.nodeCount = function() {
-  return this._nodeCount;
-};
-
-Graph.prototype.nodes = function() {
-  return _.keys(this._nodes);
-};
-
-Graph.prototype.sources = function() {
-  return _.filter(this.nodes(), function(v) {
-    return _.isEmpty(this._in[v]);
-  }, this);
-};
-
-Graph.prototype.sinks = function() {
-  return _.filter(this.nodes(), function(v) {
-    return _.isEmpty(this._out[v]);
-  }, this);
-};
-
-Graph.prototype.setNodes = function(vs, value) {
-  var args = arguments;
-  _.each(vs, function(v) {
-    if (args.length > 1) {
-      this.setNode(v, value);
-    } else {
-      this.setNode(v);
-    }
-  }, this);
-  return this;
-};
-
-Graph.prototype.setNode = function(v, value) {
-  if (_.has(this._nodes, v)) {
-    if (arguments.length > 1) {
-      this._nodes[v] = value;
-    }
-    return this;
-  }
-
-  this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
-  if (this._isCompound) {
-    this._parent[v] = GRAPH_NODE;
-    this._children[v] = {};
-    this._children[GRAPH_NODE][v] = true;
-  }
-  this._in[v] = {};
-  this._preds[v] = {};
-  this._out[v] = {};
-  this._sucs[v] = {};
-  ++this._nodeCount;
-  return this;
-};
-
-Graph.prototype.node = function(v) {
-  return this._nodes[v];
-};
-
-Graph.prototype.hasNode = function(v) {
-  return _.has(this._nodes, v);
-};
-
-Graph.prototype.removeNode =  function(v) {
-  var self = this;
-  if (_.has(this._nodes, v)) {
-    var removeEdge = function(e) { self.removeEdge(self._edgeObjs[e]); };
-    delete this._nodes[v];
-    if (this._isCompound) {
-      this._removeFromParentsChildList(v);
-      delete this._parent[v];
-      _.each(this.children(v), function(child) {
-        this.setParent(child);
-      }, this);
-      delete this._children[v];
-    }
-    _.each(_.keys(this._in[v]), removeEdge);
-    delete this._in[v];
-    delete this._preds[v];
-    _.each(_.keys(this._out[v]), removeEdge);
-    delete this._out[v];
-    delete this._sucs[v];
-    --this._nodeCount;
-  }
-  return this;
-};
-
-Graph.prototype.setParent = function(v, parent) {
-  if (!this._isCompound) {
-    throw new Error("Cannot set parent in a non-compound graph");
-  }
-
-  if (_.isUndefined(parent)) {
-    parent = GRAPH_NODE;
-  } else {
-    // Coerce parent to string
-    parent += "";
-    for (var ancestor = parent;
-         !_.isUndefined(ancestor);
-         ancestor = this.parent(ancestor)) {
-      if (ancestor === v) {
-        throw new Error("Setting " + parent+ " as parent of " + v +
-                        " would create create a cycle");
-      }
-    }
-
-    this.setNode(parent);
-  }
-
-  this.setNode(v);
-  this._removeFromParentsChildList(v);
-  this._parent[v] = parent;
-  this._children[parent][v] = true;
-  return this;
-};
-
-Graph.prototype._removeFromParentsChildList = function(v) {
-  delete this._children[this._parent[v]][v];
-};
-
-Graph.prototype.parent = function(v) {
-  if (this._isCompound) {
-    var parent = this._parent[v];
-    if (parent !== GRAPH_NODE) {
-      return parent;
-    }
-  }
-};
-
-Graph.prototype.children = function(v) {
-  if (_.isUndefined(v)) {
-    v = GRAPH_NODE;
-  }
-
-  if (this._isCompound) {
-    var children = this._children[v];
-    if (children) {
-      return _.keys(children);
-    }
-  } else if (v === GRAPH_NODE) {
-    return this.nodes();
-  } else if (this.hasNode(v)) {
-    return [];
-  }
-};
-
-Graph.prototype.predecessors = function(v) {
-  var predsV = this._preds[v];
-  if (predsV) {
-    return _.keys(predsV);
-  }
-};
-
-Graph.prototype.successors = function(v) {
-  var sucsV = this._sucs[v];
-  if (sucsV) {
-    return _.keys(sucsV);
-  }
-};
-
-Graph.prototype.neighbors = function(v) {
-  var preds = this.predecessors(v);
-  if (preds) {
-    return _.union(preds, this.successors(v));
-  }
-};
-
-/* === Edge functions ========== */
-
-Graph.prototype.setDefaultEdgeLabel = function(newDefault) {
-  if (!_.isFunction(newDefault)) {
-    newDefault = _.constant(newDefault);
-  }
-  this._defaultEdgeLabelFn = newDefault;
-  return this;
-};
-
-Graph.prototype.edgeCount = function() {
-  return this._edgeCount;
-};
-
-Graph.prototype.edges = function() {
-  return _.values(this._edgeObjs);
-};
-
-Graph.prototype.setPath = function(vs, value) {
-  var self = this,
-      args = arguments;
-  _.reduce(vs, function(v, w) {
-    if (args.length > 1) {
-      self.setEdge(v, w, value);
-    } else {
-      self.setEdge(v, w);
-    }
-    return w;
-  });
-  return this;
-};
-
-/*
- * setEdge(v, w, [value, [name]])
- * setEdge({ v, w, [name] }, [value])
- */
-Graph.prototype.setEdge = function() {
-  var v, w, name, value,
-      valueSpecified = false;
-
-  if (_.isPlainObject(arguments[0])) {
-    v = arguments[0].v;
-    w = arguments[0].w;
-    name = arguments[0].name;
-    if (arguments.length === 2) {
-      value = arguments[1];
-      valueSpecified = true;
-    }
-  } else {
-    v = arguments[0];
-    w = arguments[1];
-    name = arguments[3];
-    if (arguments.length > 2) {
-      value = arguments[2];
-      valueSpecified = true;
-    }
-  }
-
-  v = "" + v;
-  w = "" + w;
-  if (!_.isUndefined(name)) {
-    name = "" + name;
-  }
-
-  var e = edgeArgsToId(this._isDirected, v, w, name);
-  if (_.has(this._edgeLabels, e)) {
-    if (valueSpecified) {
-      this._edgeLabels[e] = value;
-    }
-    return this;
-  }
-
-  if (!_.isUndefined(name) && !this._isMultigraph) {
-    throw new Error("Cannot set a named edge when isMultigraph = false");
-  }
-
-  // It didn't exist, so we need to create it.
-  // First ensure the nodes exist.
-  this.setNode(v);
-  this.setNode(w);
-
-  this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name);
-
-  var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
-  // Ensure we add undirected edges in a consistent way.
-  v = edgeObj.v;
-  w = edgeObj.w;
-
-  Object.freeze(edgeObj);
-  this._edgeObjs[e] = edgeObj;
-  incrementOrInitEntry(this._preds[w], v);
-  incrementOrInitEntry(this._sucs[v], w);
-  this._in[w][e] = edgeObj;
-  this._out[v][e] = edgeObj;
-  this._edgeCount++;
-  return this;
-};
-
-Graph.prototype.edge = function(v, w, name) {
-  var e = (arguments.length === 1
-            ? edgeObjToId(this._isDirected, arguments[0])
-            : edgeArgsToId(this._isDirected, v, w, name));
-  return this._edgeLabels[e];
-};
-
-Graph.prototype.hasEdge = function(v, w, name) {
-  var e = (arguments.length === 1
-            ? edgeObjToId(this._isDirected, arguments[0])
-            : edgeArgsToId(this._isDirected, v, w, name));
-  return _.has(this._edgeLabels, e);
-};
-
-Graph.prototype.removeEdge = function(v, w, name) {
-  var e = (arguments.length === 1
-            ? edgeObjToId(this._isDirected, arguments[0])
-            : edgeArgsToId(this._isDirected, v, w, name)),
-      edge = this._edgeObjs[e];
-  if (edge) {
-    v = edge.v;
-    w = edge.w;
-    delete this._edgeLabels[e];
-    delete this._edgeObjs[e];
-    decrementOrRemoveEntry(this._preds[w], v);
-    decrementOrRemoveEntry(this._sucs[v], w);
-    delete this._in[w][e];
-    delete this._out[v][e];
-    this._edgeCount--;
-  }
-  return this;
-};
-
-Graph.prototype.inEdges = function(v, u) {
-  var inV = this._in[v];
-  if (inV) {
-    var edges = _.values(inV);
-    if (!u) {
-      return edges;
-    }
-    return _.filter(edges, function(edge) { return edge.v === u; });
-  }
-};
-
-Graph.prototype.outEdges = function(v, w) {
-  var outV = this._out[v];
-  if (outV) {
-    var edges = _.values(outV);
-    if (!w) {
-      return edges;
-    }
-    return _.filter(edges, function(edge) { return edge.w === w; });
-  }
-};
-
-Graph.prototype.nodeEdges = function(v, w) {
-  var inEdges = this.inEdges(v, w);
-  if (inEdges) {
-    return inEdges.concat(this.outEdges(v, w));
-  }
-};
-
-function incrementOrInitEntry(map, k) {
-  if (_.has(map, k)) {
-    map[k]++;
-  } else {
-    map[k] = 1;
-  }
-}
-
-function decrementOrRemoveEntry(map, k) {
-  if (!--map[k]) { delete map[k]; }
-}
-
-function edgeArgsToId(isDirected, v, w, name) {
-  if (!isDirected && v > w) {
-    var tmp = v;
-    v = w;
-    w = tmp;
-  }
-  return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM +
-             (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name);
-}
-
-function edgeArgsToObj(isDirected, v, w, name) {
-  if (!isDirected && v > w) {
-    var tmp = v;
-    v = w;
-    w = tmp;
-  }
-  var edgeObj =  { v: v, w: w };
-  if (name) {
-    edgeObj.name = name;
-  }
-  return edgeObj;
-}
-
-function edgeObjToId(isDirected, edgeObj) {
-  return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
-}
-
-},{"./lodash":29}],27:[function(require,module,exports){
-// Includes only the "core" of graphlib
-module.exports = {
-  Graph: require("./graph"),
-  version: require("./version")
-};
-
-},{"./graph":26,"./version":30}],28:[function(require,module,exports){
-var _ = require("./lodash"),
-    Graph = require("./graph");
-
-module.exports = {
-  write: write,
-  read: read
-};
-
-function write(g) {
-  var json = {
-    options: {
-      directed: g.isDirected(),
-      multigraph: g.isMultigraph(),
-      compound: g.isCompound()
-    },
-    nodes: writeNodes(g),
-    edges: writeEdges(g)
-  };
-  if (!_.isUndefined(g.graph())) {
-    json.value = _.clone(g.graph());
-  }
-  return json;
-}
-
-function writeNodes(g) {
-  return _.map(g.nodes(), function(v) {
-    var nodeValue = g.node(v),
-        parent = g.parent(v),
-        node = { v: v };
-    if (!_.isUndefined(nodeValue)) {
-      node.value = nodeValue;
-    }
-    if (!_.isUndefined(parent)) {
-      node.parent = parent;
-    }
-    return node;
-  });
-}
-
-function writeEdges(g) {
-  return _.map(g.edges(), function(e) {
-    var edgeValue = g.edge(e),
-        edge = { v: e.v, w: e.w };
-    if (!_.isUndefined(e.name)) {
-      edge.name = e.name;
-    }
-    if (!_.isUndefined(edgeValue)) {
-      edge.value = edgeValue;
-    }
-    return edge;
-  });
-}
-
-function read(json) {
-  var g = new Graph(json.options).setGraph(json.value);
-  _.each(json.nodes, function(entry) {
-    g.setNode(entry.v, entry.value);
-    if (entry.parent) {
-      g.setParent(entry.v, entry.parent);
-    }
-  });
-  _.each(json.edges, function(entry) {
-    g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value);
-  });
-  return g;
-}
-
-},{"./graph":26,"./lodash":29}],29:[function(require,module,exports){
-/* global window */
-
-var lodash;
-
-if (typeof require === "function") {
-  try {
-    lodash = require("lodash");
-  } catch (e) {}
-}
-
-if (!lodash) {
-  lodash = window._;
-}
-
-module.exports = lodash;
-
-},{"lodash":31}],30:[function(require,module,exports){
-module.exports = '1.0.5';
-
-},{}],31:[function(require,module,exports){
-(function (global){
-/**
- * @license
- * Lo-Dash 2.4.2 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern -o ./dist/lodash.js`
- * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-;(function() {
-
-  /** Used as a safe reference for `undefined` in pre ES5 environments */
-  var undefined;
-
-  /** Used to pool arrays and objects used internally */
-  var arrayPool = [],
-      objectPool = [];
-
-  /** Used to generate unique IDs */
-  var idCounter = 0;
-
-  /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
-  var keyPrefix = +new Date + '';
-
-  /** Used as the size when optimizations are enabled for large arrays */
-  var largeArraySize = 75;
-
-  /** Used as the max size of the `arrayPool` and `objectPool` */
-  var maxPoolSize = 40;
-
-  /** Used to detect and test whitespace */
-  var whitespace = (
-    // whitespace
-    ' \t\x0B\f\xA0\ufeff' +
-
-    // line terminators
-    '\n\r\u2028\u2029' +
-
-    // unicode category "Zs" space separators
-    '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
-  );
-
-  /** Used to match empty string literals in compiled template source */
-  var reEmptyStringLeading = /\b__p \+= '';/g,
-      reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
-      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
-
-  /**
-   * Used to match ES6 template delimiters
-   * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
-   */
-  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
-
-  /** Used to match regexp flags from their coerced string values */
-  var reFlags = /\w*$/;
-
-  /** Used to detected named functions */
-  var reFuncName = /^\s*function[ \n\r\t]+\w/;
-
-  /** Used to match "interpolate" template delimiters */
-  var reInterpolate = /<%=([\s\S]+?)%>/g;
-
-  /** Used to match leading whitespace and zeros to be removed */
-  var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
-
-  /** Used to ensure capturing order of template delimiters */
-  var reNoMatch = /($^)/;
-
-  /** Used to detect functions containing a `this` reference */
-  var reThis = /\bthis\b/;
-
-  /** Used to match unescaped characters in compiled string literals */
-  var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
-
-  /** Used to assign default `context` object properties */
-  var contextProps = [
-    'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
-    'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
-    'parseInt', 'setTimeout'
-  ];
-
-  /** Used to make template sourceURLs easier to identify */
-  var templateCounter = 0;
-
-  /** `Object#toString` result shortcuts */
-  var argsClass = '[object Arguments]',
-      arrayClass = '[object Array]',
-      boolClass = '[object Boolean]',
-      dateClass = '[object Date]',
-      funcClass = '[object Function]',
-      numberClass = '[object Number]',
-      objectClass = '[object Object]',
-      regexpClass = '[object RegExp]',
-      stringClass = '[object String]';
-
-  /** Used to identify object classifications that `_.clone` supports */
-  var cloneableClasses = {};
-  cloneableClasses[funcClass] = false;
-  cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
-  cloneableClasses[boolClass] = cloneableClasses[dateClass] =
-  cloneableClasses[numberClass] = cloneableClasses[objectClass] =
-  cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
-
-  /** Used as an internal `_.debounce` options object */
-  var debounceOptions = {
-    'leading': false,
-    'maxWait': 0,
-    'trailing': false
-  };
-
-  /** Used as the property descriptor for `__bindData__` */
-  var descriptor = {
-    'configurable': false,
-    'enumerable': false,
-    'value': null,
-    'writable': false
-  };
-
-  /** Used to determine if values are of the language type Object */
-  var objectTypes = {
-    'boolean': false,
-    'function': true,
-    'object': true,
-    'number': false,
-    'string': false,
-    'undefined': false
-  };
-
-  /** Used to escape characters for inclusion in compiled string literals */
-  var stringEscapes = {
-    '\\': '\\',
-    "'": "'",
-    '\n': 'n',
-    '\r': 'r',
-    '\t': 't',
-    '\u2028': 'u2028',
-    '\u2029': 'u2029'
-  };
-
-  /** Used as a reference to the global object */
-  var root = (objectTypes[typeof window] && window) || this;
-
-  /** Detect free variable `exports` */
-  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
-
-  /** Detect free variable `module` */
-  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
-
-  /** Detect the popular CommonJS extension `module.exports` */
-  var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
-
-  /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
-  var freeGlobal = objectTypes[typeof global] && global;
-  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
-    root = freeGlobal;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * The base implementation of `_.indexOf` without support for binary searches
-   * or `fromIndex` constraints.
-   *
-   * @private
-   * @param {Array} array The array to search.
-   * @param {*} value The value to search for.
-   * @param {number} [fromIndex=0] The index to search from.
-   * @returns {number} Returns the index of the matched value or `-1`.
-   */
-  function baseIndexOf(array, value, fromIndex) {
-    var index = (fromIndex || 0) - 1,
-        length = array ? array.length : 0;
-
-    while (++index < length) {
-      if (array[index] === value) {
-        return index;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * An implementation of `_.contains` for cache objects that mimics the return
-   * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
-   *
-   * @private
-   * @param {Object} cache The cache object to inspect.
-   * @param {*} value The value to search for.
-   * @returns {number} Returns `0` if `value` is found, else `-1`.
-   */
-  function cacheIndexOf(cache, value) {
-    var type = typeof value;
-    cache = cache.cache;
-
-    if (type == 'boolean' || value == null) {
-      return cache[value] ? 0 : -1;
-    }
-    if (type != 'number' && type != 'string') {
-      type = 'object';
-    }
-    var key = type == 'number' ? value : keyPrefix + value;
-    cache = (cache = cache[type]) && cache[key];
-
-    return type == 'object'
-      ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
-      : (cache ? 0 : -1);
-  }
-
-  /**
-   * Adds a given value to the corresponding cache object.
-   *
-   * @private
-   * @param {*} value The value to add to the cache.
-   */
-  function cachePush(value) {
-    var cache = this.cache,
-        type = typeof value;
-
-    if (type == 'boolean' || value == null) {
-      cache[value] = true;
-    } else {
-      if (type != 'number' && type != 'string') {
-        type = 'object';
-      }
-      var key = type == 'number' ? value : keyPrefix + value,
-          typeCache = cache[type] || (cache[type] = {});
-
-      if (type == 'object') {
-        (typeCache[key] || (typeCache[key] = [])).push(value);
-      } else {
-        typeCache[key] = true;
-      }
-    }
-  }
-
-  /**
-   * Used by `_.max` and `_.min` as the default callback when a given
-   * collection is a string value.
-   *
-   * @private
-   * @param {string} value The character to inspect.
-   * @returns {number} Returns the code unit of given character.
-   */
-  function charAtCallback(value) {
-    return value.charCodeAt(0);
-  }
-
-  /**
-   * Used by `sortBy` to compare transformed `collection` elements, stable sorting
-   * them in ascending order.
-   *
-   * @private
-   * @param {Object} a The object to compare to `b`.
-   * @param {Object} b The object to compare to `a`.
-   * @returns {number} Returns the sort order indicator of `1` or `-1`.
-   */
-  function compareAscending(a, b) {
-    var ac = a.criteria,
-        bc = b.criteria,
-        index = -1,
-        length = ac.length;
-
-    while (++index < length) {
-      var value = ac[index],
-          other = bc[index];
-
-      if (value !== other) {
-        if (value > other || typeof value == 'undefined') {
-          return 1;
-        }
-        if (value < other || typeof other == 'undefined') {
-          return -1;
-        }
-      }
-    }
-    // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
-    // that causes it, under certain circumstances, to return the same value for
-    // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
-    //
-    // This also ensures a stable sort in V8 and other engines.
-    // See http://code.google.com/p/v8/issues/detail?id=90
-    return a.index - b.index;
-  }
-
-  /**
-   * Creates a cache object to optimize linear searches of large arrays.
-   *
-   * @private
-   * @param {Array} [array=[]] The array to search.
-   * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
-   */
-  function createCache(array) {
-    var index = -1,
-        length = array.length,
-        first = array[0],
-        mid = array[(length / 2) | 0],
-        last = array[length - 1];
-
-    if (first && typeof first == 'object' &&
-        mid && typeof mid == 'object' && last && typeof last == 'object') {
-      return false;
-    }
-    var cache = getObject();
-    cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
-
-    var result = getObject();
-    result.array = array;
-    result.cache = cache;
-    result.push = cachePush;
-
-    while (++index < length) {
-      result.push(array[index]);
-    }
-    return result;
-  }
-
-  /**
-   * Used by `template` to escape characters for inclusion in compiled
-   * string literals.
-   *
-   * @private
-   * @param {string} match The matched character to escape.
-   * @returns {string} Returns the escaped character.
-   */
-  function escapeStringChar(match) {
-    return '\\' + stringEscapes[match];
-  }
-
-  /**
-   * Gets an array from the array pool or creates a new one if the pool is empty.
-   *
-   * @private
-   * @returns {Array} The array from the pool.
-   */
-  function getArray() {
-    return arrayPool.pop() || [];
-  }
-
-  /**
-   * Gets an object from the object pool or creates a new one if the pool is empty.
-   *
-   * @private
-   * @returns {Object} The object from the pool.
-   */
-  function getObject() {
-    return objectPool.pop() || {
-      'array': null,
-      'cache': null,
-      'criteria': null,
-      'false': false,
-      'index': 0,
-      'null': false,
-      'number': null,
-      'object': null,
-      'push': null,
-      'string': null,
-      'true': false,
-      'undefined': false,
-      'value': null
-    };
-  }
-
-  /**
-   * Releases the given array back to the array pool.
-   *
-   * @private
-   * @param {Array} [array] The array to release.
-   */
-  function releaseArray(array) {
-    array.length = 0;
-    if (arrayPool.length < maxPoolSize) {
-      arrayPool.push(array);
-    }
-  }
-
-  /**
-   * Releases the given object back to the object pool.
-   *
-   * @private
-   * @param {Object} [object] The object to release.
-   */
-  function releaseObject(object) {
-    var cache = object.cache;
-    if (cache) {
-      releaseObject(cache);
-    }
-    object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
-    if (objectPool.length < maxPoolSize) {
-      objectPool.push(object);
-    }
-  }
-
-  /**
-   * Slices the `collection` from the `start` index up to, but not including,
-   * the `end` index.
-   *
-   * Note: This function is used instead of `Array#slice` to support node lists
-   * in IE < 9 and to ensure dense arrays are returned.
-   *
-   * @private
-   * @param {Array|Object|string} collection The collection to slice.
-   * @param {number} start The start index.
-   * @param {number} end The end index.
-   * @returns {Array} Returns the new array.
-   */
-  function slice(array, start, end) {
-    start || (start = 0);
-    if (typeof end == 'undefined') {
-      end = array ? array.length : 0;
-    }
-    var index = -1,
-        length = end - start || 0,
-        result = Array(length < 0 ? 0 : length);
-
-    while (++index < length) {
-      result[index] = array[start + index];
-    }
-    return result;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * Create a new `lodash` function using the given context object.
-   *
-   * @static
-   * @memberOf _
-   * @category Utilities
-   * @param {Object} [context=root] The context object.
-   * @returns {Function} Returns the `lodash` function.
-   */
-  function runInContext(context) {
-    // Avoid issues with some ES3 environments that attempt to use values, named
-    // after built-in constructors like `Object`, for the creation of literals.
-    // ES5 clears this up by stating that literals must use built-in constructors.
-    // See http://es5.github.io/#x11.1.5.
-    context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
-
-    /** Native constructor references */
-    var Array = context.Array,
-        Boolean = context.Boolean,
-        Date = context.Date,
-        Function = context.Function,
-        Math = context.Math,
-        Number = context.Number,
-        Object = context.Object,
-        RegExp = context.RegExp,
-        String = context.String,
-        TypeError = context.TypeError;
-
-    /**
-     * Used for `Array` method references.
-     *
-     * Normally `Array.prototype` would suffice, however, using an array literal
-     * avoids issues in Narwhal.
-     */
-    var arrayRef = [];
-
-    /** Used for native method references */
-    var objectProto = Object.prototype;
-
-    /** Used to restore the original `_` reference in `noConflict` */
-    var oldDash = context._;
-
-    /** Used to resolve the internal [[Class]] of values */
-    var toString = objectProto.toString;
-
-    /** Used to detect if a method is native */
-    var reNative = RegExp('^' +
-      String(toString)
-        .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
-        .replace(/toString| for [^\]]+/g, '.*?') + '$'
-    );
-
-    /** Native method shortcuts */
-    var ceil = Math.ceil,
-        clearTimeout = context.clearTimeout,
-        floor = Math.floor,
-        fnToString = Function.prototype.toString,
-        getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
-        hasOwnProperty = objectProto.hasOwnProperty,
-        push = arrayRef.push,
-        setTimeout = context.setTimeout,
-        splice = arrayRef.splice,
-        unshift = arrayRef.unshift;
-
-    /** Used to set meta data on functions */
-    var defineProperty = (function() {
-      // IE 8 only accepts DOM elements
-      try {
-        var o = {},
-            func = isNative(func = Object.defineProperty) && func,
-            result = func(o, o, o) && func;
-      } catch(e) { }
-      return result;
-    }());
-
-    /* Native method shortcuts for methods with the same name as other `lodash` methods */
-    var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
-        nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
-        nativeIsFinite = context.isFinite,
-        nativeIsNaN = context.isNaN,
-        nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
-        nativeMax = Math.max,
-        nativeMin = Math.min,
-        nativeParseInt = context.parseInt,
-        nativeRandom = Math.random;
-
-    /** Used to lookup a built-in constructor by [[Class]] */
-    var ctorByClass = {};
-    ctorByClass[arrayClass] = Array;
-    ctorByClass[boolClass] = Boolean;
-    ctorByClass[dateClass] = Date;
-    ctorByClass[funcClass] = Function;
-    ctorByClass[objectClass] = Object;
-    ctorByClass[numberClass] = Number;
-    ctorByClass[regexpClass] = RegExp;
-    ctorByClass[stringClass] = String;
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a `lodash` object which wraps the given value to enable intuitive
-     * method chaining.
-     *
-     * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
-     * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
-     * and `unshift`
-     *
-     * Chaining is supported in custom builds as long as the `value` method is
-     * implicitly or explicitly included in the build.
-     *
-     * The chainable wrapper functions are:
-     * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
-     * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
-     * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
-     * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
-     * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
-     * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
-     * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
-     * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
-     * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
-     * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
-     * and `zip`
-     *
-     * The non-chainable wrapper functions are:
-     * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
-     * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
-     * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
-     * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
-     * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
-     * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
-     * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
-     * `template`, `unescape`, `uniqueId`, and `value`
-     *
-     * The wrapper functions `first` and `last` return wrapped values when `n` is
-     * provided, otherwise they return unwrapped values.
-     *
-     * Explicit chaining can be enabled by using the `_.chain` method.
-     *
-     * @name _
-     * @constructor
-     * @category Chaining
-     * @param {*} value The value to wrap in a `lodash` instance.
-     * @returns {Object} Returns a `lodash` instance.
-     * @example
-     *
-     * var wrapped = _([1, 2, 3]);
-     *
-     * // returns an unwrapped value
-     * wrapped.reduce(function(sum, num) {
-     *   return sum + num;
-     * });
-     * // => 6
-     *
-     * // returns a wrapped value
-     * var squares = wrapped.map(function(num) {
-     *   return num * num;
-     * });
-     *
-     * _.isArray(squares);
-     * // => false
-     *
-     * _.isArray(squares.value());
-     * // => true
-     */
-    function lodash(value) {
-      // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
-      return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
-       ? value
-       : new lodashWrapper(value);
-    }
-
-    /**
-     * A fast path for creating `lodash` wrapper objects.
-     *
-     * @private
-     * @param {*} value The value to wrap in a `lodash` instance.
-     * @param {boolean} chainAll A flag to enable chaining for all methods
-     * @returns {Object} Returns a `lodash` instance.
-     */
-    function lodashWrapper(value, chainAll) {
-      this.__chain__ = !!chainAll;
-      this.__wrapped__ = value;
-    }
-    // ensure `new lodashWrapper` is an instance of `lodash`
-    lodashWrapper.prototype = lodash.prototype;
-
-    /**
-     * An object used to flag environments features.
-     *
-     * @static
-     * @memberOf _
-     * @type Object
-     */
-    var support = lodash.support = {};
-
-    /**
-     * Detect if functions can be decompiled by `Function#toString`
-     * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
-     *
-     * @memberOf _.support
-     * @type boolean
-     */
-    support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
-
-    /**
-     * Detect if `Function#name` is supported (all but IE).
-     *
-     * @memberOf _.support
-     * @type boolean
-     */
-    support.funcNames = typeof Function.name == 'string';
-
-    /**
-     * By default, the template delimiters used by Lo-Dash are similar to those in
-     * embedded Ruby (ERB). Change the following template settings to use alternative
-     * delimiters.
-     *
-     * @static
-     * @memberOf _
-     * @type Object
-     */
-    lodash.templateSettings = {
-
-      /**
-       * Used to detect `data` property values to be HTML-escaped.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'escape': /<%-([\s\S]+?)%>/g,
-
-      /**
-       * Used to detect code to be evaluated.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'evaluate': /<%([\s\S]+?)%>/g,
-
-      /**
-       * Used to detect `data` property values to inject.
-       *
-       * @memberOf _.templateSettings
-       * @type RegExp
-       */
-      'interpolate': reInterpolate,
-
-      /**
-       * Used to reference the data object in the template text.
-       *
-       * @memberOf _.templateSettings
-       * @type string
-       */
-      'variable': '',
-
-      /**
-       * Used to import variables into the compiled template.
-       *
-       * @memberOf _.templateSettings
-       * @type Object
-       */
-      'imports': {
-
-        /**
-         * A reference to the `lodash` function.
-         *
-         * @memberOf _.templateSettings.imports
-         * @type Function
-         */
-        '_': lodash
-      }
-    };
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * The base implementation of `_.bind` that creates the bound function and
-     * sets its meta data.
-     *
-     * @private
-     * @param {Array} bindData The bind data array.
-     * @returns {Function} Returns the new bound function.
-     */
-    function baseBind(bindData) {
-      var func = bindData[0],
-          partialArgs = bindData[2],
-          thisArg = bindData[4];
-
-      function bound() {
-        // `Function#bind` spec
-        // http://es5.github.io/#x15.3.4.5
-        if (partialArgs) {
-          // avoid `arguments` object deoptimizations by using `slice` instead
-          // of `Array.prototype.slice.call` and not assigning `arguments` to a
-          // variable as a ternary expression
-          var args = slice(partialArgs);
-          push.apply(args, arguments);
-        }
-        // mimic the constructor's `return` behavior
-        // http://es5.github.io/#x13.2.2
-        if (this instanceof bound) {
-          // ensure `new bound` is an instance of `func`
-          var thisBinding = baseCreate(func.prototype),
-              result = func.apply(thisBinding, args || arguments);
-          return isObject(result) ? result : thisBinding;
-        }
-        return func.apply(thisArg, args || arguments);
-      }
-      setBindData(bound, bindData);
-      return bound;
-    }
-
-    /**
-     * The base implementation of `_.clone` without argument juggling or support
-     * for `thisArg` binding.
-     *
-     * @private
-     * @param {*} value The value to clone.
-     * @param {boolean} [isDeep=false] Specify a deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {Array} [stackA=[]] Tracks traversed source objects.
-     * @param {Array} [stackB=[]] Associates clones with source counterparts.
-     * @returns {*} Returns the cloned value.
-     */
-    function baseClone(value, isDeep, callback, stackA, stackB) {
-      if (callback) {
-        var result = callback(value);
-        if (typeof result != 'undefined') {
-          return result;
-        }
-      }
-      // inspect [[Class]]
-      var isObj = isObject(value);
-      if (isObj) {
-        var className = toString.call(value);
-        if (!cloneableClasses[className]) {
-          return value;
-        }
-        var ctor = ctorByClass[className];
-        switch (className) {
-          case boolClass:
-          case dateClass:
-            return new ctor(+value);
-
-          case numberClass:
-          case stringClass:
-            return new ctor(value);
-
-          case regexpClass:
-            result = ctor(value.source, reFlags.exec(value));
-            result.lastIndex = value.lastIndex;
-            return result;
-        }
-      } else {
-        return value;
-      }
-      var isArr = isArray(value);
-      if (isDeep) {
-        // check for circular references and return corresponding clone
-        var initedStack = !stackA;
-        stackA || (stackA = getArray());
-        stackB || (stackB = getArray());
-
-        var length = stackA.length;
-        while (length--) {
-          if (stackA[length] == value) {
-            return stackB[length];
-          }
-        }
-        result = isArr ? ctor(value.length) : {};
-      }
-      else {
-        result = isArr ? slice(value) : assign({}, value);
-      }
-      // add array properties assigned by `RegExp#exec`
-      if (isArr) {
-        if (hasOwnProperty.call(value, 'index')) {
-          result.index = value.index;
-        }
-        if (hasOwnProperty.call(value, 'input')) {
-          result.input = value.input;
-        }
-      }
-      // exit for shallow clone
-      if (!isDeep) {
-        return result;
-      }
-      // add the source value to the stack of traversed objects
-      // and associate it with its clone
-      stackA.push(value);
-      stackB.push(result);
-
-      // recursively populate clone (susceptible to call stack limits)
-      (isArr ? forEach : forOwn)(value, function(objValue, key) {
-        result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
-      });
-
-      if (initedStack) {
-        releaseArray(stackA);
-        releaseArray(stackB);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.create` without support for assigning
-     * properties to the created object.
-     *
-     * @private
-     * @param {Object} prototype The object to inherit from.
-     * @returns {Object} Returns the new object.
-     */
-    function baseCreate(prototype, properties) {
-      return isObject(prototype) ? nativeCreate(prototype) : {};
-    }
-    // fallback for browsers without `Object.create`
-    if (!nativeCreate) {
-      baseCreate = (function() {
-        function Object() {}
-        return function(prototype) {
-          if (isObject(prototype)) {
-            Object.prototype = prototype;
-            var result = new Object;
-            Object.prototype = null;
-          }
-          return result || context.Object();
-        };
-      }());
-    }
-
-    /**
-     * The base implementation of `_.createCallback` without support for creating
-     * "_.pluck" or "_.where" style callbacks.
-     *
-     * @private
-     * @param {*} [func=identity] The value to convert to a callback.
-     * @param {*} [thisArg] The `this` binding of the created callback.
-     * @param {number} [argCount] The number of arguments the callback accepts.
-     * @returns {Function} Returns a callback function.
-     */
-    function baseCreateCallback(func, thisArg, argCount) {
-      if (typeof func != 'function') {
-        return identity;
-      }
-      // exit early for no `thisArg` or already bound by `Function#bind`
-      if (typeof thisArg == 'undefined' || !('prototype' in func)) {
-        return func;
-      }
-      var bindData = func.__bindData__;
-      if (typeof bindData == 'undefined') {
-        if (support.funcNames) {
-          bindData = !func.name;
-        }
-        bindData = bindData || !support.funcDecomp;
-        if (!bindData) {
-          var source = fnToString.call(func);
-          if (!support.funcNames) {
-            bindData = !reFuncName.test(source);
-          }
-          if (!bindData) {
-            // checks if `func` references the `this` keyword and stores the result
-            bindData = reThis.test(source);
-            setBindData(func, bindData);
-          }
-        }
-      }
-      // exit early if there are no `this` references or `func` is bound
-      if (bindData === false || (bindData !== true && bindData[1] & 1)) {
-        return func;
-      }
-      switch (argCount) {
-        case 1: return function(value) {
-          return func.call(thisArg, value);
-        };
-        case 2: return function(a, b) {
-          return func.call(thisArg, a, b);
-        };
-        case 3: return function(value, index, collection) {
-          return func.call(thisArg, value, index, collection);
-        };
-        case 4: return function(accumulator, value, index, collection) {
-          return func.call(thisArg, accumulator, value, index, collection);
-        };
-      }
-      return bind(func, thisArg);
-    }
-
-    /**
-     * The base implementation of `createWrapper` that creates the wrapper and
-     * sets its meta data.
-     *
-     * @private
-     * @param {Array} bindData The bind data array.
-     * @returns {Function} Returns the new function.
-     */
-    function baseCreateWrapper(bindData) {
-      var func = bindData[0],
-          bitmask = bindData[1],
-          partialArgs = bindData[2],
-          partialRightArgs = bindData[3],
-          thisArg = bindData[4],
-          arity = bindData[5];
-
-      var isBind = bitmask & 1,
-          isBindKey = bitmask & 2,
-          isCurry = bitmask & 4,
-          isCurryBound = bitmask & 8,
-          key = func;
-
-      function bound() {
-        var thisBinding = isBind ? thisArg : this;
-        if (partialArgs) {
-          var args = slice(partialArgs);
-          push.apply(args, arguments);
-        }
-        if (partialRightArgs || isCurry) {
-          args || (args = slice(arguments));
-          if (partialRightArgs) {
-            push.apply(args, partialRightArgs);
-          }
-          if (isCurry && args.length < arity) {
-            bitmask |= 16 & ~32;
-            return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
-          }
-        }
-        args || (args = arguments);
-        if (isBindKey) {
-          func = thisBinding[key];
-        }
-        if (this instanceof bound) {
-          thisBinding = baseCreate(func.prototype);
-          var result = func.apply(thisBinding, args);
-          return isObject(result) ? result : thisBinding;
-        }
-        return func.apply(thisBinding, args);
-      }
-      setBindData(bound, bindData);
-      return bound;
-    }
-
-    /**
-     * The base implementation of `_.difference` that accepts a single array
-     * of values to exclude.
-     *
-     * @private
-     * @param {Array} array The array to process.
-     * @param {Array} [values] The array of values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     */
-    function baseDifference(array, values) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = array ? array.length : 0,
-          isLarge = length >= largeArraySize && indexOf === baseIndexOf,
-          result = [];
-
-      if (isLarge) {
-        var cache = createCache(values);
-        if (cache) {
-          indexOf = cacheIndexOf;
-          values = cache;
-        } else {
-          isLarge = false;
-        }
-      }
-      while (++index < length) {
-        var value = array[index];
-        if (indexOf(values, value) < 0) {
-          result.push(value);
-        }
-      }
-      if (isLarge) {
-        releaseObject(values);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.flatten` without support for callback
-     * shorthands or `thisArg` binding.
-     *
-     * @private
-     * @param {Array} array The array to flatten.
-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
-     * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
-     * @param {number} [fromIndex=0] The index to start from.
-     * @returns {Array} Returns a new flattened array.
-     */
-    function baseFlatten(array, isShallow, isStrict, fromIndex) {
-      var index = (fromIndex || 0) - 1,
-          length = array ? array.length : 0,
-          result = [];
-
-      while (++index < length) {
-        var value = array[index];
-
-        if (value && typeof value == 'object' && typeof value.length == 'number'
-            && (isArray(value) || isArguments(value))) {
-          // recursively flatten arrays (susceptible to call stack limits)
-          if (!isShallow) {
-            value = baseFlatten(value, isShallow, isStrict);
-          }
-          var valIndex = -1,
-              valLength = value.length,
-              resIndex = result.length;
-
-          result.length += valLength;
-          while (++valIndex < valLength) {
-            result[resIndex++] = value[valIndex];
-          }
-        } else if (!isStrict) {
-          result.push(value);
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.isEqual`, without support for `thisArg` binding,
-     * that allows partial "_.where" style comparisons.
-     *
-     * @private
-     * @param {*} a The value to compare.
-     * @param {*} b The other value to compare.
-     * @param {Function} [callback] The function to customize comparing values.
-     * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
-     * @param {Array} [stackA=[]] Tracks traversed `a` objects.
-     * @param {Array} [stackB=[]] Tracks traversed `b` objects.
-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-     */
-    function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
-      // used to indicate that when comparing objects, `a` has at least the properties of `b`
-      if (callback) {
-        var result = callback(a, b);
-        if (typeof result != 'undefined') {
-          return !!result;
-        }
-      }
-      // exit early for identical values
-      if (a === b) {
-        // treat `+0` vs. `-0` as not equal
-        return a !== 0 || (1 / a == 1 / b);
-      }
-      var type = typeof a,
-          otherType = typeof b;
-
-      // exit early for unlike primitive values
-      if (a === a &&
-          !(a && objectTypes[type]) &&
-          !(b && objectTypes[otherType])) {
-        return false;
-      }
-      // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
-      // http://es5.github.io/#x15.3.4.4
-      if (a == null || b == null) {
-        return a === b;
-      }
-      // compare [[Class]] names
-      var className = toString.call(a),
-          otherClass = toString.call(b);
-
-      if (className == argsClass) {
-        className = objectClass;
-      }
-      if (otherClass == argsClass) {
-        otherClass = objectClass;
-      }
-      if (className != otherClass) {
-        return false;
-      }
-      switch (className) {
-        case boolClass:
-        case dateClass:
-          // coerce dates and booleans to numbers, dates to milliseconds and booleans
-          // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
-          return +a == +b;
-
-        case numberClass:
-          // treat `NaN` vs. `NaN` as equal
-          return (a != +a)
-            ? b != +b
-            // but treat `+0` vs. `-0` as not equal
-            : (a == 0 ? (1 / a == 1 / b) : a == +b);
-
-        case regexpClass:
-        case stringClass:
-          // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
-          // treat string primitives and their corresponding object instances as equal
-          return a == String(b);
-      }
-      var isArr = className == arrayClass;
-      if (!isArr) {
-        // unwrap any `lodash` wrapped values
-        var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
-            bWrapped = hasOwnProperty.call(b, '__wrapped__');
-
-        if (aWrapped || bWrapped) {
-          return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
-        }
-        // exit for functions and DOM nodes
-        if (className != objectClass) {
-          return false;
-        }
-        // in older versions of Opera, `arguments` objects have `Array` constructors
-        var ctorA = a.constructor,
-            ctorB = b.constructor;
-
-        // non `Object` object instances with different constructors are not equal
-        if (ctorA != ctorB &&
-              !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
-              ('constructor' in a && 'constructor' in b)
-            ) {
-          return false;
-        }
-      }
-      // assume cyclic structures are equal
-      // the algorithm for detecting cyclic structures is adapted from ES 5.1
-      // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
-      var initedStack = !stackA;
-      stackA || (stackA = getArray());
-      stackB || (stackB = getArray());
-
-      var length = stackA.length;
-      while (length--) {
-        if (stackA[length] == a) {
-          return stackB[length] == b;
-        }
-      }
-      var size = 0;
-      result = true;
-
-      // add `a` and `b` to the stack of traversed objects
-      stackA.push(a);
-      stackB.push(b);
-
-      // recursively compare objects and arrays (susceptible to call stack limits)
-      if (isArr) {
-        // compare lengths to determine if a deep comparison is necessary
-        length = a.length;
-        size = b.length;
-        result = size == length;
-
-        if (result || isWhere) {
-          // deep compare the contents, ignoring non-numeric properties
-          while (size--) {
-            var index = length,
-                value = b[size];
-
-            if (isWhere) {
-              while (index--) {
-                if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
-                  break;
-                }
-              }
-            } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
-              break;
-            }
-          }
-        }
-      }
-      else {
-        // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
-        // which, in this case, is more costly
-        forIn(b, function(value, key, b) {
-          if (hasOwnProperty.call(b, key)) {
-            // count the number of properties.
-            size++;
-            // deep compare each property value.
-            return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
-          }
-        });
-
-        if (result && !isWhere) {
-          // ensure both objects have the same number of properties
-          forIn(a, function(value, key, a) {
-            if (hasOwnProperty.call(a, key)) {
-              // `size` will be `-1` if `a` has more properties than `b`
-              return (result = --size > -1);
-            }
-          });
-        }
-      }
-      stackA.pop();
-      stackB.pop();
-
-      if (initedStack) {
-        releaseArray(stackA);
-        releaseArray(stackB);
-      }
-      return result;
-    }
-
-    /**
-     * The base implementation of `_.merge` without argument juggling or support
-     * for `thisArg` binding.
-     *
-     * @private
-     * @param {Object} object The destination object.
-     * @param {Object} source The source object.
-     * @param {Function} [callback] The function to customize merging properties.
-     * @param {Array} [stackA=[]] Tracks traversed source objects.
-     * @param {Array} [stackB=[]] Associates values with source counterparts.
-     */
-    function baseMerge(object, source, callback, stackA, stackB) {
-      (isArray(source) ? forEach : forOwn)(source, function(source, key) {
-        var found,
-            isArr,
-            result = source,
-            value = object[key];
-
-        if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
-          // avoid merging previously merged cyclic sources
-          var stackLength = stackA.length;
-          while (stackLength--) {
-            if ((found = stackA[stackLength] == source)) {
-              value = stackB[stackLength];
-              break;
-            }
-          }
-          if (!found) {
-            var isShallow;
-            if (callback) {
-              result = callback(value, source);
-              if ((isShallow = typeof result != 'undefined')) {
-                value = result;
-              }
-            }
-            if (!isShallow) {
-              value = isArr
-                ? (isArray(value) ? value : [])
-                : (isPlainObject(value) ? value : {});
-            }
-            // add `source` and associated `value` to the stack of traversed objects
-            stackA.push(source);
-            stackB.push(value);
-
-            // recursively merge objects and arrays (susceptible to call stack limits)
-            if (!isShallow) {
-              baseMerge(value, source, callback, stackA, stackB);
-            }
-          }
-        }
-        else {
-          if (callback) {
-            result = callback(value, source);
-            if (typeof result == 'undefined') {
-              result = source;
-            }
-          }
-          if (typeof result != 'undefined') {
-            value = result;
-          }
-        }
-        object[key] = value;
-      });
-    }
-
-    /**
-     * The base implementation of `_.random` without argument juggling or support
-     * for returning floating-point numbers.
-     *
-     * @private
-     * @param {number} min The minimum possible value.
-     * @param {number} max The maximum possible value.
-     * @returns {number} Returns a random number.
-     */
-    function baseRandom(min, max) {
-      return min + floor(nativeRandom() * (max - min + 1));
-    }
-
-    /**
-     * The base implementation of `_.uniq` without support for callback shorthands
-     * or `thisArg` binding.
-     *
-     * @private
-     * @param {Array} array The array to process.
-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
-     * @param {Function} [callback] The function called per iteration.
-     * @returns {Array} Returns a duplicate-value-free array.
-     */
-    function baseUniq(array, isSorted, callback) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = array ? array.length : 0,
-          result = [];
-
-      var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
-          seen = (callback || isLarge) ? getArray() : result;
-
-      if (isLarge) {
-        var cache = createCache(seen);
-        indexOf = cacheIndexOf;
-        seen = cache;
-      }
-      while (++index < length) {
-        var value = array[index],
-            computed = callback ? callback(value, index, array) : value;
-
-        if (isSorted
-              ? !index || seen[seen.length - 1] !== computed
-              : indexOf(seen, computed) < 0
-            ) {
-          if (callback || isLarge) {
-            seen.push(computed);
-          }
-          result.push(value);
-        }
-      }
-      if (isLarge) {
-        releaseArray(seen.array);
-        releaseObject(seen);
-      } else if (callback) {
-        releaseArray(seen);
-      }
-      return result;
-    }
-
-    /**
-     * Creates a function that aggregates a collection, creating an object composed
-     * of keys generated from the results of running each element of the collection
-     * through a callback. The given `setter` function sets the keys and values
-     * of the composed object.
-     *
-     * @private
-     * @param {Function} setter The setter function.
-     * @returns {Function} Returns the new aggregator function.
-     */
-    function createAggregator(setter) {
-      return function(collection, callback, thisArg) {
-        var result = {};
-        callback = lodash.createCallback(callback, thisArg, 3);
-
-        var index = -1,
-            length = collection ? collection.length : 0;
-
-        if (typeof length == 'number') {
-          while (++index < length) {
-            var value = collection[index];
-            setter(result, value, callback(value, index, collection), collection);
-          }
-        } else {
-          forOwn(collection, function(value, key, collection) {
-            setter(result, value, callback(value, key, collection), collection);
-          });
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Creates a function that, when called, either curries or invokes `func`
-     * with an optional `this` binding and partially applied arguments.
-     *
-     * @private
-     * @param {Function|string} func The function or method name to reference.
-     * @param {number} bitmask The bitmask of method flags to compose.
-     *  The bitmask may be composed of the following flags:
-     *  1 - `_.bind`
-     *  2 - `_.bindKey`
-     *  4 - `_.curry`
-     *  8 - `_.curry` (bound)
-     *  16 - `_.partial`
-     *  32 - `_.partialRight`
-     * @param {Array} [partialArgs] An array of arguments to prepend to those
-     *  provided to the new function.
-     * @param {Array} [partialRightArgs] An array of arguments to append to those
-     *  provided to the new function.
-     * @param {*} [thisArg] The `this` binding of `func`.
-     * @param {number} [arity] The arity of `func`.
-     * @returns {Function} Returns the new function.
-     */
-    function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
-      var isBind = bitmask & 1,
-          isBindKey = bitmask & 2,
-          isCurry = bitmask & 4,
-          isCurryBound = bitmask & 8,
-          isPartial = bitmask & 16,
-          isPartialRight = bitmask & 32;
-
-      if (!isBindKey && !isFunction(func)) {
-        throw new TypeError;
-      }
-      if (isPartial && !partialArgs.length) {
-        bitmask &= ~16;
-        isPartial = partialArgs = false;
-      }
-      if (isPartialRight && !partialRightArgs.length) {
-        bitmask &= ~32;
-        isPartialRight = partialRightArgs = false;
-      }
-      var bindData = func && func.__bindData__;
-      if (bindData && bindData !== true) {
-        // clone `bindData`
-        bindData = slice(bindData);
-        if (bindData[2]) {
-          bindData[2] = slice(bindData[2]);
-        }
-        if (bindData[3]) {
-          bindData[3] = slice(bindData[3]);
-        }
-        // set `thisBinding` is not previously bound
-        if (isBind && !(bindData[1] & 1)) {
-          bindData[4] = thisArg;
-        }
-        // set if previously bound but not currently (subsequent curried functions)
-        if (!isBind && bindData[1] & 1) {
-          bitmask |= 8;
-        }
-        // set curried arity if not yet set
-        if (isCurry && !(bindData[1] & 4)) {
-          bindData[5] = arity;
-        }
-        // append partial left arguments
-        if (isPartial) {
-          push.apply(bindData[2] || (bindData[2] = []), partialArgs);
-        }
-        // append partial right arguments
-        if (isPartialRight) {
-          unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
-        }
-        // merge flags
-        bindData[1] |= bitmask;
-        return createWrapper.apply(null, bindData);
-      }
-      // fast path for `_.bind`
-      var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
-      return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
-    }
-
-    /**
-     * Used by `escape` to convert characters to HTML entities.
-     *
-     * @private
-     * @param {string} match The matched character to escape.
-     * @returns {string} Returns the escaped character.
-     */
-    function escapeHtmlChar(match) {
-      return htmlEscapes[match];
-    }
-
-    /**
-     * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
-     * customized, this method returns the custom method, otherwise it returns
-     * the `baseIndexOf` function.
-     *
-     * @private
-     * @returns {Function} Returns the "indexOf" function.
-     */
-    function getIndexOf() {
-      var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
-      return result;
-    }
-
-    /**
-     * Checks if `value` is a native function.
-     *
-     * @private
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
-     */
-    function isNative(value) {
-      return typeof value == 'function' && reNative.test(value);
-    }
-
-    /**
-     * Sets `this` binding data on a given function.
-     *
-     * @private
-     * @param {Function} func The function to set data on.
-     * @param {Array} value The data array to set.
-     */
-    var setBindData = !defineProperty ? noop : function(func, value) {
-      descriptor.value = value;
-      defineProperty(func, '__bindData__', descriptor);
-      descriptor.value = null;
-    };
-
-    /**
-     * A fallback implementation of `isPlainObject` which checks if a given value
-     * is an object created by the `Object` constructor, assuming objects created
-     * by the `Object` constructor have no inherited enumerable properties and that
-     * there are no `Object.prototype` extensions.
-     *
-     * @private
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-     */
-    function shimIsPlainObject(value) {
-      var ctor,
-          result;
-
-      // avoid non Object objects, `arguments` objects, and DOM elements
-      if (!(value && toString.call(value) == objectClass) ||
-          (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
-        return false;
-      }
-      // In most environments an object's own properties are iterated before
-      // its inherited properties. If the last iterated property is an object's
-      // own property then there are no inherited enumerable properties.
-      forIn(value, function(value, key) {
-        result = key;
-      });
-      return typeof result == 'undefined' || hasOwnProperty.call(value, result);
-    }
-
-    /**
-     * Used by `unescape` to convert HTML entities to characters.
-     *
-     * @private
-     * @param {string} match The matched character to unescape.
-     * @returns {string} Returns the unescaped character.
-     */
-    function unescapeHtmlChar(match) {
-      return htmlUnescapes[match];
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Checks if `value` is an `arguments` object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
-     * @example
-     *
-     * (function() { return _.isArguments(arguments); })(1, 2, 3);
-     * // => true
-     *
-     * _.isArguments([1, 2, 3]);
-     * // => false
-     */
-    function isArguments(value) {
-      return value && typeof value == 'object' && typeof value.length == 'number' &&
-        toString.call(value) == argsClass || false;
-    }
-
-    /**
-     * Checks if `value` is an array.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
-     * @example
-     *
-     * (function() { return _.isArray(arguments); })();
-     * // => false
-     *
-     * _.isArray([1, 2, 3]);
-     * // => true
-     */
-    var isArray = nativeIsArray || function(value) {
-      return value && typeof value == 'object' && typeof value.length == 'number' &&
-        toString.call(value) == arrayClass || false;
-    };
-
-    /**
-     * A fallback implementation of `Object.keys` which produces an array of the
-     * given object's own enumerable property names.
-     *
-     * @private
-     * @type Function
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names.
-     */
-    var shimKeys = function(object) {
-      var index, iterable = object, result = [];
-      if (!iterable) return result;
-      if (!(objectTypes[typeof object])) return result;
-        for (index in iterable) {
-          if (hasOwnProperty.call(iterable, index)) {
-            result.push(index);
-          }
-        }
-      return result
-    };
-
-    /**
-     * Creates an array composed of the own enumerable property names of an object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names.
-     * @example
-     *
-     * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
-     */
-    var keys = !nativeKeys ? shimKeys : function(object) {
-      if (!isObject(object)) {
-        return [];
-      }
-      return nativeKeys(object);
-    };
-
-    /**
-     * Used to convert characters to HTML entities:
-     *
-     * Though the `>` character is escaped for symmetry, characters like `>` and `/`
-     * don't require escaping in HTML and have no special meaning unless they're part
-     * of a tag or an unquoted attribute value.
-     * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
-     */
-    var htmlEscapes = {
-      '&': '&',
-      '<': '<',
-      '>': '>',
-      '"': '"',
-      "'": '''
-    };
-
-    /** Used to convert HTML entities to characters */
-    var htmlUnescapes = invert(htmlEscapes);
-
-    /** Used to match HTML entities and HTML characters */
-    var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
-        reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Assigns own enumerable properties of source object(s) to the destination
-     * object. Subsequent sources will overwrite property assignments of previous
-     * sources. If a callback is provided it will be executed to produce the
-     * assigned values. The callback is bound to `thisArg` and invoked with two
-     * arguments; (objectValue, sourceValue).
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @alias extend
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param {Function} [callback] The function to customize assigning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
-     * // => { 'name': 'fred', 'employer': 'slate' }
-     *
-     * var defaults = _.partialRight(_.assign, function(a, b) {
-     *   return typeof a == 'undefined' ? b : a;
-     * });
-     *
-     * var object = { 'name': 'barney' };
-     * defaults(object, { 'name': 'fred', 'employer': 'slate' });
-     * // => { 'name': 'barney', 'employer': 'slate' }
-     */
-    var assign = function(object, source, guard) {
-      var index, iterable = object, result = iterable;
-      if (!iterable) return result;
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = typeof guard == 'number' ? 2 : args.length;
-      if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
-        var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
-      } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
-        callback = args[--argsLength];
-      }
-      while (++argsIndex < argsLength) {
-        iterable = args[argsIndex];
-        if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
-        }
-        }
-      }
-      return result
-    };
-
-    /**
-     * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
-     * be cloned, otherwise they will be assigned by reference. If a callback
-     * is provided it will be executed to produce the cloned values. If the
-     * callback returns `undefined` cloning will be handled by the method instead.
-     * The callback is bound to `thisArg` and invoked with one argument; (value).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to clone.
-     * @param {boolean} [isDeep=false] Specify a deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the cloned value.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * var shallow = _.clone(characters);
-     * shallow[0] === characters[0];
-     * // => true
-     *
-     * var deep = _.clone(characters, true);
-     * deep[0] === characters[0];
-     * // => false
-     *
-     * _.mixin({
-     *   'clone': _.partialRight(_.clone, function(value) {
-     *     return _.isElement(value) ? value.cloneNode(false) : undefined;
-     *   })
-     * });
-     *
-     * var clone = _.clone(document.body);
-     * clone.childNodes.length;
-     * // => 0
-     */
-    function clone(value, isDeep, callback, thisArg) {
-      // allows working with "Collections" methods without using their `index`
-      // and `collection` arguments for `isDeep` and `callback`
-      if (typeof isDeep != 'boolean' && isDeep != null) {
-        thisArg = callback;
-        callback = isDeep;
-        isDeep = false;
-      }
-      return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
-    }
-
-    /**
-     * Creates a deep clone of `value`. If a callback is provided it will be
-     * executed to produce the cloned values. If the callback returns `undefined`
-     * cloning will be handled by the method instead. The callback is bound to
-     * `thisArg` and invoked with one argument; (value).
-     *
-     * Note: This method is loosely based on the structured clone algorithm. Functions
-     * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
-     * objects created by constructors other than `Object` are cloned to plain `Object` objects.
-     * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to deep clone.
-     * @param {Function} [callback] The function to customize cloning values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the deep cloned value.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * var deep = _.cloneDeep(characters);
-     * deep[0] === characters[0];
-     * // => false
-     *
-     * var view = {
-     *   'label': 'docs',
-     *   'node': element
-     * };
-     *
-     * var clone = _.cloneDeep(view, function(value) {
-     *   return _.isElement(value) ? value.cloneNode(true) : undefined;
-     * });
-     *
-     * clone.node == view.node;
-     * // => false
-     */
-    function cloneDeep(value, callback, thisArg) {
-      return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
-    }
-
-    /**
-     * Creates an object that inherits from the given `prototype` object. If a
-     * `properties` object is provided its own enumerable properties are assigned
-     * to the created object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} prototype The object to inherit from.
-     * @param {Object} [properties] The properties to assign to the object.
-     * @returns {Object} Returns the new object.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * function Circle() {
-     *   Shape.call(this);
-     * }
-     *
-     * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
-     *
-     * var circle = new Circle;
-     * circle instanceof Circle;
-     * // => true
-     *
-     * circle instanceof Shape;
-     * // => true
-     */
-    function create(prototype, properties) {
-      var result = baseCreate(prototype);
-      return properties ? assign(result, properties) : result;
-    }
-
-    /**
-     * Assigns own enumerable properties of source object(s) to the destination
-     * object for all destination properties that resolve to `undefined`. Once a
-     * property is set, additional defaults of the same property will be ignored.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param- {Object} [guard] Allows working with `_.reduce` without using its
-     *  `key` and `object` arguments as sources.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * var object = { 'name': 'barney' };
-     * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
-     * // => { 'name': 'barney', 'employer': 'slate' }
-     */
-    var defaults = function(object, source, guard) {
-      var index, iterable = object, result = iterable;
-      if (!iterable) return result;
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = typeof guard == 'number' ? 2 : args.length;
-      while (++argsIndex < argsLength) {
-        iterable = args[argsIndex];
-        if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (typeof result[index] == 'undefined') result[index] = iterable[index];
-        }
-        }
-      }
-      return result
-    };
-
-    /**
-     * This method is like `_.findIndex` except that it returns the key of the
-     * first element that passes the callback check, instead of the element itself.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to search.
-     * @param {Function|Object|string} [callback=identity] The function called per
-     *  iteration. If a property name or object is provided it will be used to
-     *  create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
-     * @example
-     *
-     * var characters = {
-     *   'barney': {  'age': 36, 'blocked': false },
-     *   'fred': {    'age': 40, 'blocked': true },
-     *   'pebbles': { 'age': 1,  'blocked': false }
-     * };
-     *
-     * _.findKey(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => 'barney' (property order is not guaranteed across environments)
-     *
-     * // using "_.where" callback shorthand
-     * _.findKey(characters, { 'age': 1 });
-     * // => 'pebbles'
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findKey(characters, 'blocked');
-     * // => 'fred'
-     */
-    function findKey(object, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forOwn(object, function(value, key, object) {
-        if (callback(value, key, object)) {
-          result = key;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * This method is like `_.findKey` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to search.
-     * @param {Function|Object|string} [callback=identity] The function called per
-     *  iteration. If a property name or object is provided it will be used to
-     *  create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {string|undefined} Returns the key of the found element, else `undefined`.
-     * @example
-     *
-     * var characters = {
-     *   'barney': {  'age': 36, 'blocked': true },
-     *   'fred': {    'age': 40, 'blocked': false },
-     *   'pebbles': { 'age': 1,  'blocked': true }
-     * };
-     *
-     * _.findLastKey(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => returns `pebbles`, assuming `_.findKey` returns `barney`
-     *
-     * // using "_.where" callback shorthand
-     * _.findLastKey(characters, { 'age': 40 });
-     * // => 'fred'
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findLastKey(characters, 'blocked');
-     * // => 'pebbles'
-     */
-    function findLastKey(object, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forOwnRight(object, function(value, key, object) {
-        if (callback(value, key, object)) {
-          result = key;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * Iterates over own and inherited enumerable properties of an object,
-     * executing the callback for each property. The callback is bound to `thisArg`
-     * and invoked with three arguments; (value, key, object). Callbacks may exit
-     * iteration early by explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * Shape.prototype.move = function(x, y) {
-     *   this.x += x;
-     *   this.y += y;
-     * };
-     *
-     * _.forIn(new Shape, function(value, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
-     */
-    var forIn = function(collection, callback, thisArg) {
-      var index, iterable = collection, result = iterable;
-      if (!iterable) return result;
-      if (!objectTypes[typeof iterable]) return result;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-        for (index in iterable) {
-          if (callback(iterable[index], index, collection) === false) return result;
-        }
-      return result
-    };
-
-    /**
-     * This method is like `_.forIn` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * Shape.prototype.move = function(x, y) {
-     *   this.x += x;
-     *   this.y += y;
-     * };
-     *
-     * _.forInRight(new Shape, function(value, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
-     */
-    function forInRight(object, callback, thisArg) {
-      var pairs = [];
-
-      forIn(object, function(value, key) {
-        pairs.push(key, value);
-      });
-
-      var length = pairs.length;
-      callback = baseCreateCallback(callback, thisArg, 3);
-      while (length--) {
-        if (callback(pairs[length--], pairs[length], object) === false) {
-          break;
-        }
-      }
-      return object;
-    }
-
-    /**
-     * Iterates over own enumerable properties of an object, executing the callback
-     * for each property. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, key, object). Callbacks may exit iteration early by
-     * explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
-     *   console.log(key);
-     * });
-     * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
-     */
-    var forOwn = function(collection, callback, thisArg) {
-      var index, iterable = collection, result = iterable;
-      if (!iterable) return result;
-      if (!objectTypes[typeof iterable]) return result;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (callback(iterable[index], index, collection) === false) return result;
-        }
-      return result
-    };
-
-    /**
-     * This method is like `_.forOwn` except that it iterates over elements
-     * of a `collection` in the opposite order.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
-     *   console.log(key);
-     * });
-     * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
-     */
-    function forOwnRight(object, callback, thisArg) {
-      var props = keys(object),
-          length = props.length;
-
-      callback = baseCreateCallback(callback, thisArg, 3);
-      while (length--) {
-        var key = props[length];
-        if (callback(object[key], key, object) === false) {
-          break;
-        }
-      }
-      return object;
-    }
-
-    /**
-     * Creates a sorted array of property names of all enumerable properties,
-     * own and inherited, of `object` that have function values.
-     *
-     * @static
-     * @memberOf _
-     * @alias methods
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property names that have function values.
-     * @example
-     *
-     * _.functions(_);
-     * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
-     */
-    function functions(object) {
-      var result = [];
-      forIn(object, function(value, key) {
-        if (isFunction(value)) {
-          result.push(key);
-        }
-      });
-      return result.sort();
-    }
-
-    /**
-     * Checks if the specified property name exists as a direct property of `object`,
-     * instead of an inherited property.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @param {string} key The name of the property to check.
-     * @returns {boolean} Returns `true` if key is a direct property, else `false`.
-     * @example
-     *
-     * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
-     * // => true
-     */
-    function has(object, key) {
-      return object ? hasOwnProperty.call(object, key) : false;
-    }
-
-    /**
-     * Creates an object composed of the inverted keys and values of the given object.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to invert.
-     * @returns {Object} Returns the created inverted object.
-     * @example
-     *
-     * _.invert({ 'first': 'fred', 'second': 'barney' });
-     * // => { 'fred': 'first', 'barney': 'second' }
-     */
-    function invert(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = {};
-
-      while (++index < length) {
-        var key = props[index];
-        result[object[key]] = key;
-      }
-      return result;
-    }
-
-    /**
-     * Checks if `value` is a boolean value.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
-     * @example
-     *
-     * _.isBoolean(null);
-     * // => false
-     */
-    function isBoolean(value) {
-      return value === true || value === false ||
-        value && typeof value == 'object' && toString.call(value) == boolClass || false;
-    }
-
-    /**
-     * Checks if `value` is a date.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
-     * @example
-     *
-     * _.isDate(new Date);
-     * // => true
-     */
-    function isDate(value) {
-      return value && typeof value == 'object' && toString.call(value) == dateClass || false;
-    }
-
-    /**
-     * Checks if `value` is a DOM element.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
-     * @example
-     *
-     * _.isElement(document.body);
-     * // => true
-     */
-    function isElement(value) {
-      return value && value.nodeType === 1 || false;
-    }
-
-    /**
-     * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
-     * length of `0` and objects with no own enumerable properties are considered
-     * "empty".
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Array|Object|string} value The value to inspect.
-     * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
-     * @example
-     *
-     * _.isEmpty([1, 2, 3]);
-     * // => false
-     *
-     * _.isEmpty({});
-     * // => true
-     *
-     * _.isEmpty('');
-     * // => true
-     */
-    function isEmpty(value) {
-      var result = true;
-      if (!value) {
-        return result;
-      }
-      var className = toString.call(value),
-          length = value.length;
-
-      if ((className == arrayClass || className == stringClass || className == argsClass ) ||
-          (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
-        return !length;
-      }
-      forOwn(value, function() {
-        return (result = false);
-      });
-      return result;
-    }
-
-    /**
-     * Performs a deep comparison between two values to determine if they are
-     * equivalent to each other. If a callback is provided it will be executed
-     * to compare values. If the callback returns `undefined` comparisons will
-     * be handled by the method instead. The callback is bound to `thisArg` and
-     * invoked with two arguments; (a, b).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} a The value to compare.
-     * @param {*} b The other value to compare.
-     * @param {Function} [callback] The function to customize comparing values.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * var copy = { 'name': 'fred' };
-     *
-     * object == copy;
-     * // => false
-     *
-     * _.isEqual(object, copy);
-     * // => true
-     *
-     * var words = ['hello', 'goodbye'];
-     * var otherWords = ['hi', 'goodbye'];
-     *
-     * _.isEqual(words, otherWords, function(a, b) {
-     *   var reGreet = /^(?:hello|hi)$/i,
-     *       aGreet = _.isString(a) && reGreet.test(a),
-     *       bGreet = _.isString(b) && reGreet.test(b);
-     *
-     *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
-     * });
-     * // => true
-     */
-    function isEqual(a, b, callback, thisArg) {
-      return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
-    }
-
-    /**
-     * Checks if `value` is, or can be coerced to, a finite number.
-     *
-     * Note: This is not the same as native `isFinite` which will return true for
-     * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
-     * @example
-     *
-     * _.isFinite(-101);
-     * // => true
-     *
-     * _.isFinite('10');
-     * // => true
-     *
-     * _.isFinite(true);
-     * // => false
-     *
-     * _.isFinite('');
-     * // => false
-     *
-     * _.isFinite(Infinity);
-     * // => false
-     */
-    function isFinite(value) {
-      return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
-    }
-
-    /**
-     * Checks if `value` is a function.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
-     * @example
-     *
-     * _.isFunction(_);
-     * // => true
-     */
-    function isFunction(value) {
-      return typeof value == 'function';
-    }
-
-    /**
-     * Checks if `value` is the language type of Object.
-     * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
-     * @example
-     *
-     * _.isObject({});
-     * // => true
-     *
-     * _.isObject([1, 2, 3]);
-     * // => true
-     *
-     * _.isObject(1);
-     * // => false
-     */
-    function isObject(value) {
-      // check if the value is the ECMAScript language type of Object
-      // http://es5.github.io/#x8
-      // and avoid a V8 bug
-      // http://code.google.com/p/v8/issues/detail?id=2291
-      return !!(value && objectTypes[typeof value]);
-    }
-
-    /**
-     * Checks if `value` is `NaN`.
-     *
-     * Note: This is not the same as native `isNaN` which will return `true` for
-     * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
-     * @example
-     *
-     * _.isNaN(NaN);
-     * // => true
-     *
-     * _.isNaN(new Number(NaN));
-     * // => true
-     *
-     * isNaN(undefined);
-     * // => true
-     *
-     * _.isNaN(undefined);
-     * // => false
-     */
-    function isNaN(value) {
-      // `NaN` as a primitive is the only value that is not equal to itself
-      // (perform the [[Class]] check first to avoid errors with some host objects in IE)
-      return isNumber(value) && value != +value;
-    }
-
-    /**
-     * Checks if `value` is `null`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
-     * @example
-     *
-     * _.isNull(null);
-     * // => true
-     *
-     * _.isNull(undefined);
-     * // => false
-     */
-    function isNull(value) {
-      return value === null;
-    }
-
-    /**
-     * Checks if `value` is a number.
-     *
-     * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
-     * @example
-     *
-     * _.isNumber(8.4 * 5);
-     * // => true
-     */
-    function isNumber(value) {
-      return typeof value == 'number' ||
-        value && typeof value == 'object' && toString.call(value) == numberClass || false;
-    }
-
-    /**
-     * Checks if `value` is an object created by the `Object` constructor.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-     * @example
-     *
-     * function Shape() {
-     *   this.x = 0;
-     *   this.y = 0;
-     * }
-     *
-     * _.isPlainObject(new Shape);
-     * // => false
-     *
-     * _.isPlainObject([1, 2, 3]);
-     * // => false
-     *
-     * _.isPlainObject({ 'x': 0, 'y': 0 });
-     * // => true
-     */
-    var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
-      if (!(value && toString.call(value) == objectClass)) {
-        return false;
-      }
-      var valueOf = value.valueOf,
-          objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
-
-      return objProto
-        ? (value == objProto || getPrototypeOf(value) == objProto)
-        : shimIsPlainObject(value);
-    };
-
-    /**
-     * Checks if `value` is a regular expression.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
-     * @example
-     *
-     * _.isRegExp(/fred/);
-     * // => true
-     */
-    function isRegExp(value) {
-      return value && typeof value == 'object' && toString.call(value) == regexpClass || false;
-    }
-
-    /**
-     * Checks if `value` is a string.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
-     * @example
-     *
-     * _.isString('fred');
-     * // => true
-     */
-    function isString(value) {
-      return typeof value == 'string' ||
-        value && typeof value == 'object' && toString.call(value) == stringClass || false;
-    }
-
-    /**
-     * Checks if `value` is `undefined`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {*} value The value to check.
-     * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
-     * @example
-     *
-     * _.isUndefined(void 0);
-     * // => true
-     */
-    function isUndefined(value) {
-      return typeof value == 'undefined';
-    }
-
-    /**
-     * Creates an object with the same keys as `object` and values generated by
-     * running each own enumerable property of `object` through the callback.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new object with values of the results of each `callback` execution.
-     * @example
-     *
-     * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     *
-     * var characters = {
-     *   'fred': { 'name': 'fred', 'age': 40 },
-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
-     * };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.mapValues(characters, 'age');
-     * // => { 'fred': 40, 'pebbles': 1 }
-     */
-    function mapValues(object, callback, thisArg) {
-      var result = {};
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      forOwn(object, function(value, key, object) {
-        result[key] = callback(value, key, object);
-      });
-      return result;
-    }
-
-    /**
-     * Recursively merges own enumerable properties of the source object(s), that
-     * don't resolve to `undefined` into the destination object. Subsequent sources
-     * will overwrite property assignments of previous sources. If a callback is
-     * provided it will be executed to produce the merged values of the destination
-     * and source properties. If the callback returns `undefined` merging will
-     * be handled by the method instead. The callback is bound to `thisArg` and
-     * invoked with two arguments; (objectValue, sourceValue).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The destination object.
-     * @param {...Object} [source] The source objects.
-     * @param {Function} [callback] The function to customize merging properties.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the destination object.
-     * @example
-     *
-     * var names = {
-     *   'characters': [
-     *     { 'name': 'barney' },
-     *     { 'name': 'fred' }
-     *   ]
-     * };
-     *
-     * var ages = {
-     *   'characters': [
-     *     { 'age': 36 },
-     *     { 'age': 40 }
-     *   ]
-     * };
-     *
-     * _.merge(names, ages);
-     * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
-     *
-     * var food = {
-     *   'fruits': ['apple'],
-     *   'vegetables': ['beet']
-     * };
-     *
-     * var otherFood = {
-     *   'fruits': ['banana'],
-     *   'vegetables': ['carrot']
-     * };
-     *
-     * _.merge(food, otherFood, function(a, b) {
-     *   return _.isArray(a) ? a.concat(b) : undefined;
-     * });
-     * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
-     */
-    function merge(object) {
-      var args = arguments,
-          length = 2;
-
-      if (!isObject(object)) {
-        return object;
-      }
-      // allows working with `_.reduce` and `_.reduceRight` without using
-      // their `index` and `collection` arguments
-      if (typeof args[2] != 'number') {
-        length = args.length;
-      }
-      if (length > 3 && typeof args[length - 2] == 'function') {
-        var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
-      } else if (length > 2 && typeof args[length - 1] == 'function') {
-        callback = args[--length];
-      }
-      var sources = slice(arguments, 1, length),
-          index = -1,
-          stackA = getArray(),
-          stackB = getArray();
-
-      while (++index < length) {
-        baseMerge(object, sources[index], callback, stackA, stackB);
-      }
-      releaseArray(stackA);
-      releaseArray(stackB);
-      return object;
-    }
-
-    /**
-     * Creates a shallow clone of `object` excluding the specified properties.
-     * Property names may be specified as individual arguments or as arrays of
-     * property names. If a callback is provided it will be executed for each
-     * property of `object` omitting the properties the callback returns truey
-     * for. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The source object.
-     * @param {Function|...string|string[]} [callback] The properties to omit or the
-     *  function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns an object without the omitted properties.
-     * @example
-     *
-     * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
-     * // => { 'name': 'fred' }
-     *
-     * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
-     *   return typeof value == 'number';
-     * });
-     * // => { 'name': 'fred' }
-     */
-    function omit(object, callback, thisArg) {
-      var result = {};
-      if (typeof callback != 'function') {
-        var props = [];
-        forIn(object, function(value, key) {
-          props.push(key);
-        });
-        props = baseDifference(props, baseFlatten(arguments, true, false, 1));
-
-        var index = -1,
-            length = props.length;
-
-        while (++index < length) {
-          var key = props[index];
-          result[key] = object[key];
-        }
-      } else {
-        callback = lodash.createCallback(callback, thisArg, 3);
-        forIn(object, function(value, key, object) {
-          if (!callback(value, key, object)) {
-            result[key] = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Creates a two dimensional array of an object's key-value pairs,
-     * i.e. `[[key1, value1], [key2, value2]]`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns new array of key-value pairs.
-     * @example
-     *
-     * _.pairs({ 'barney': 36, 'fred': 40 });
-     * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
-     */
-    function pairs(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = Array(length);
-
-      while (++index < length) {
-        var key = props[index];
-        result[index] = [key, object[key]];
-      }
-      return result;
-    }
-
-    /**
-     * Creates a shallow clone of `object` composed of the specified properties.
-     * Property names may be specified as individual arguments or as arrays of
-     * property names. If a callback is provided it will be executed for each
-     * property of `object` picking the properties the callback returns truey
-     * for. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, key, object).
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The source object.
-     * @param {Function|...string|string[]} [callback] The function called per
-     *  iteration or property names to pick, specified as individual property
-     *  names or arrays of property names.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns an object composed of the picked properties.
-     * @example
-     *
-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
-     * // => { 'name': 'fred' }
-     *
-     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
-     *   return key.charAt(0) != '_';
-     * });
-     * // => { 'name': 'fred' }
-     */
-    function pick(object, callback, thisArg) {
-      var result = {};
-      if (typeof callback != 'function') {
-        var index = -1,
-            props = baseFlatten(arguments, true, false, 1),
-            length = isObject(object) ? props.length : 0;
-
-        while (++index < length) {
-          var key = props[index];
-          if (key in object) {
-            result[key] = object[key];
-          }
-        }
-      } else {
-        callback = lodash.createCallback(callback, thisArg, 3);
-        forIn(object, function(value, key, object) {
-          if (callback(value, key, object)) {
-            result[key] = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * An alternative to `_.reduce` this method transforms `object` to a new
-     * `accumulator` object which is the result of running each of its own
-     * enumerable properties through a callback, with each callback execution
-     * potentially mutating the `accumulator` object. The callback is bound to
-     * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
-     * Callbacks may exit iteration early by explicitly returning `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Array|Object} object The object to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] The custom accumulator value.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
-     *   num *= num;
-     *   if (num % 2) {
-     *     return result.push(num) < 3;
-     *   }
-     * });
-     * // => [1, 9, 25]
-     *
-     * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
-     *   result[key] = num * 3;
-     * });
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     */
-    function transform(object, callback, accumulator, thisArg) {
-      var isArr = isArray(object);
-      if (accumulator == null) {
-        if (isArr) {
-          accumulator = [];
-        } else {
-          var ctor = object && object.constructor,
-              proto = ctor && ctor.prototype;
-
-          accumulator = baseCreate(proto);
-        }
-      }
-      if (callback) {
-        callback = lodash.createCallback(callback, thisArg, 4);
-        (isArr ? forEach : forOwn)(object, function(value, index, object) {
-          return callback(accumulator, value, index, object);
-        });
-      }
-      return accumulator;
-    }
-
-    /**
-     * Creates an array composed of the own enumerable property values of `object`.
-     *
-     * @static
-     * @memberOf _
-     * @category Objects
-     * @param {Object} object The object to inspect.
-     * @returns {Array} Returns an array of property values.
-     * @example
-     *
-     * _.values({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => [1, 2, 3] (property order is not guaranteed across environments)
-     */
-    function values(object) {
-      var index = -1,
-          props = keys(object),
-          length = props.length,
-          result = Array(length);
-
-      while (++index < length) {
-        result[index] = object[props[index]];
-      }
-      return result;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates an array of elements from the specified indexes, or keys, of the
-     * `collection`. Indexes may be specified as individual arguments or as arrays
-     * of indexes.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
-     *   to retrieve, specified as individual indexes or arrays of indexes.
-     * @returns {Array} Returns a new array of elements corresponding to the
-     *  provided indexes.
-     * @example
-     *
-     * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
-     * // => ['a', 'c', 'e']
-     *
-     * _.at(['fred', 'barney', 'pebbles'], 0, 2);
-     * // => ['fred', 'pebbles']
-     */
-    function at(collection) {
-      var args = arguments,
-          index = -1,
-          props = baseFlatten(args, true, false, 1),
-          length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
-          result = Array(length);
-
-      while(++index < length) {
-        result[index] = collection[props[index]];
-      }
-      return result;
-    }
-
-    /**
-     * Checks if a given value is present in a collection using strict equality
-     * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
-     * offset from the end of the collection.
-     *
-     * @static
-     * @memberOf _
-     * @alias include
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {*} target The value to check for.
-     * @param {number} [fromIndex=0] The index to search from.
-     * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
-     * @example
-     *
-     * _.contains([1, 2, 3], 1);
-     * // => true
-     *
-     * _.contains([1, 2, 3], 1, 2);
-     * // => false
-     *
-     * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
-     * // => true
-     *
-     * _.contains('pebbles', 'eb');
-     * // => true
-     */
-    function contains(collection, target, fromIndex) {
-      var index = -1,
-          indexOf = getIndexOf(),
-          length = collection ? collection.length : 0,
-          result = false;
-
-      fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
-      if (isArray(collection)) {
-        result = indexOf(collection, target, fromIndex) > -1;
-      } else if (typeof length == 'number') {
-        result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
-      } else {
-        forOwn(collection, function(value) {
-          if (++index >= fromIndex) {
-            return !(result = value === target);
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of `collection` through the callback. The corresponding value
-     * of each key is the number of times the key was returned by the callback.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
-     * // => { '4': 1, '6': 2 }
-     *
-     * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-     * // => { '4': 1, '6': 2 }
-     *
-     * _.countBy(['one', 'two', 'three'], 'length');
-     * // => { '3': 2, '5': 1 }
-     */
-    var countBy = createAggregator(function(result, value, key) {
-      (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
-    });
-
-    /**
-     * Checks if the given callback returns truey value for **all** elements of
-     * a collection. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias all
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if all elements passed the callback check,
-     *  else `false`.
-     * @example
-     *
-     * _.every([true, 1, null, 'yes']);
-     * // => false
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.every(characters, 'age');
-     * // => true
-     *
-     * // using "_.where" callback shorthand
-     * _.every(characters, { 'age': 36 });
-     * // => false
-     */
-    function every(collection, callback, thisArg) {
-      var result = true;
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if (!(result = !!callback(collection[index], index, collection))) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          return (result = !!callback(value, index, collection));
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, returning an array of all elements
-     * the callback returns truey for. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias select
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of elements that passed the callback check.
-     * @example
-     *
-     * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-     * // => [2, 4, 6]
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.filter(characters, 'blocked');
-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
-     *
-     * // using "_.where" callback shorthand
-     * _.filter(characters, { 'age': 36 });
-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-     */
-    function filter(collection, callback, thisArg) {
-      var result = [];
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          var value = collection[index];
-          if (callback(value, index, collection)) {
-            result.push(value);
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          if (callback(value, index, collection)) {
-            result.push(value);
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, returning the first element that
-     * the callback returns truey for. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias detect, findWhere
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the found element, else `undefined`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
-     * ];
-     *
-     * _.find(characters, function(chr) {
-     *   return chr.age < 40;
-     * });
-     * // => { 'name': 'barney', 'age': 36, 'blocked': false }
-     *
-     * // using "_.where" callback shorthand
-     * _.find(characters, { 'age': 1 });
-     * // =>  { 'name': 'pebbles', 'age': 1, 'blocked': false }
-     *
-     * // using "_.pluck" callback shorthand
-     * _.find(characters, 'blocked');
-     * // => { 'name': 'fred', 'age': 40, 'blocked': true }
-     */
-    function find(collection, callback, thisArg) {
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          var value = collection[index];
-          if (callback(value, index, collection)) {
-            return value;
-          }
-        }
-      } else {
-        var result;
-        forOwn(collection, function(value, index, collection) {
-          if (callback(value, index, collection)) {
-            result = value;
-            return false;
-          }
-        });
-        return result;
-      }
-    }
-
-    /**
-     * This method is like `_.find` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the found element, else `undefined`.
-     * @example
-     *
-     * _.findLast([1, 2, 3, 4], function(num) {
-     *   return num % 2 == 1;
-     * });
-     * // => 3
-     */
-    function findLast(collection, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      forEachRight(collection, function(value, index, collection) {
-        if (callback(value, index, collection)) {
-          result = value;
-          return false;
-        }
-      });
-      return result;
-    }
-
-    /**
-     * Iterates over elements of a collection, executing the callback for each
-     * element. The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection). Callbacks may exit iteration early by
-     * explicitly returning `false`.
-     *
-     * Note: As with other "Collections" methods, objects with a `length` property
-     * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
-     * may be used for object iteration.
-     *
-     * @static
-     * @memberOf _
-     * @alias each
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array|Object|string} Returns `collection`.
-     * @example
-     *
-     * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
-     * // => logs each number and returns '1,2,3'
-     *
-     * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
-     * // => logs each number and returns the object (property order is not guaranteed across environments)
-     */
-    function forEach(collection, callback, thisArg) {
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if (callback(collection[index], index, collection) === false) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, callback);
-      }
-      return collection;
-    }
-
-    /**
-     * This method is like `_.forEach` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @alias eachRight
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array|Object|string} Returns `collection`.
-     * @example
-     *
-     * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
-     * // => logs each number from right to left and returns '3,2,1'
-     */
-    function forEachRight(collection, callback, thisArg) {
-      var length = collection ? collection.length : 0;
-      callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        while (length--) {
-          if (callback(collection[length], length, collection) === false) {
-            break;
-          }
-        }
-      } else {
-        var props = keys(collection);
-        length = props.length;
-        forOwn(collection, function(value, key, collection) {
-          key = props ? props[--length] : --length;
-          return callback(collection[key], key, collection);
-        });
-      }
-      return collection;
-    }
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of a collection through the callback. The corresponding value
-     * of each key is an array of the elements responsible for generating the key.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
-     * // => { '4': [4.2], '6': [6.1, 6.4] }
-     *
-     * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-     * // => { '4': [4.2], '6': [6.1, 6.4] }
-     *
-     * // using "_.pluck" callback shorthand
-     * _.groupBy(['one', 'two', 'three'], 'length');
-     * // => { '3': ['one', 'two'], '5': ['three'] }
-     */
-    var groupBy = createAggregator(function(result, value, key) {
-      (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
-    });
-
-    /**
-     * Creates an object composed of keys generated from the results of running
-     * each element of the collection through the given callback. The corresponding
-     * value of each key is the last element responsible for generating the key.
-     * The callback is bound to `thisArg` and invoked with three arguments;
-     * (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Object} Returns the composed aggregate object.
-     * @example
-     *
-     * var keys = [
-     *   { 'dir': 'left', 'code': 97 },
-     *   { 'dir': 'right', 'code': 100 }
-     * ];
-     *
-     * _.indexBy(keys, 'dir');
-     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
-     *
-     * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
-     *
-     * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
-     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
-     */
-    var indexBy = createAggregator(function(result, value, key) {
-      result[key] = value;
-    });
-
-    /**
-     * Invokes the method named by `methodName` on each element in the `collection`
-     * returning an array of the results of each invoked method. Additional arguments
-     * will be provided to each invoked method. If `methodName` is a function it
-     * will be invoked for, and `this` bound to, each element in the `collection`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|string} methodName The name of the method to invoke or
-     *  the function invoked per iteration.
-     * @param {...*} [arg] Arguments to invoke the method with.
-     * @returns {Array} Returns a new array of the results of each invoked method.
-     * @example
-     *
-     * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
-     * // => [[1, 5, 7], [1, 2, 3]]
-     *
-     * _.invoke([123, 456], String.prototype.split, '');
-     * // => [['1', '2', '3'], ['4', '5', '6']]
-     */
-    function invoke(collection, methodName) {
-      var args = slice(arguments, 2),
-          index = -1,
-          isFunc = typeof methodName == 'function',
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      forEach(collection, function(value) {
-        result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
-      });
-      return result;
-    }
-
-    /**
-     * Creates an array of values by running each element in the collection
-     * through the callback. The callback is bound to `thisArg` and invoked with
-     * three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias collect
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of the results of each `callback` execution.
-     * @example
-     *
-     * _.map([1, 2, 3], function(num) { return num * 3; });
-     * // => [3, 6, 9]
-     *
-     * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
-     * // => [3, 6, 9] (property order is not guaranteed across environments)
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.map(characters, 'name');
-     * // => ['barney', 'fred']
-     */
-    function map(collection, callback, thisArg) {
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      if (typeof length == 'number') {
-        var result = Array(length);
-        while (++index < length) {
-          result[index] = callback(collection[index], index, collection);
-        }
-      } else {
-        result = [];
-        forOwn(collection, function(value, key, collection) {
-          result[++index] = callback(value, key, collection);
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the maximum value of a collection. If the collection is empty or
-     * falsey `-Infinity` is returned. If a callback is provided it will be executed
-     * for each value in the collection to generate the criterion by which the value
-     * is ranked. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the maximum value.
-     * @example
-     *
-     * _.max([4, 2, 8, 6]);
-     * // => 8
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.max(characters, function(chr) { return chr.age; });
-     * // => { 'name': 'fred', 'age': 40 };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.max(characters, 'age');
-     * // => { 'name': 'fred', 'age': 40 };
-     */
-    function max(collection, callback, thisArg) {
-      var computed = -Infinity,
-          result = computed;
-
-      // allows working with functions like `_.map` without using
-      // their `index` argument as a callback
-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
-        callback = null;
-      }
-      if (callback == null && isArray(collection)) {
-        var index = -1,
-            length = collection.length;
-
-        while (++index < length) {
-          var value = collection[index];
-          if (value > result) {
-            result = value;
-          }
-        }
-      } else {
-        callback = (callback == null && isString(collection))
-          ? charAtCallback
-          : lodash.createCallback(callback, thisArg, 3);
-
-        forEach(collection, function(value, index, collection) {
-          var current = callback(value, index, collection);
-          if (current > computed) {
-            computed = current;
-            result = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the minimum value of a collection. If the collection is empty or
-     * falsey `Infinity` is returned. If a callback is provided it will be executed
-     * for each value in the collection to generate the criterion by which the value
-     * is ranked. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the minimum value.
-     * @example
-     *
-     * _.min([4, 2, 8, 6]);
-     * // => 2
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.min(characters, function(chr) { return chr.age; });
-     * // => { 'name': 'barney', 'age': 36 };
-     *
-     * // using "_.pluck" callback shorthand
-     * _.min(characters, 'age');
-     * // => { 'name': 'barney', 'age': 36 };
-     */
-    function min(collection, callback, thisArg) {
-      var computed = Infinity,
-          result = computed;
-
-      // allows working with functions like `_.map` without using
-      // their `index` argument as a callback
-      if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
-        callback = null;
-      }
-      if (callback == null && isArray(collection)) {
-        var index = -1,
-            length = collection.length;
-
-        while (++index < length) {
-          var value = collection[index];
-          if (value < result) {
-            result = value;
-          }
-        }
-      } else {
-        callback = (callback == null && isString(collection))
-          ? charAtCallback
-          : lodash.createCallback(callback, thisArg, 3);
-
-        forEach(collection, function(value, index, collection) {
-          var current = callback(value, index, collection);
-          if (current < computed) {
-            computed = current;
-            result = value;
-          }
-        });
-      }
-      return result;
-    }
-
-    /**
-     * Retrieves the value of a specified property from all elements in the collection.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {string} property The name of the property to pluck.
-     * @returns {Array} Returns a new array of property values.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * _.pluck(characters, 'name');
-     * // => ['barney', 'fred']
-     */
-    var pluck = map;
-
-    /**
-     * Reduces a collection to a value which is the accumulated result of running
-     * each element in the collection through the callback, where each successive
-     * callback execution consumes the return value of the previous execution. If
-     * `accumulator` is not provided the first element of the collection will be
-     * used as the initial `accumulator` value. The callback is bound to `thisArg`
-     * and invoked with four arguments; (accumulator, value, index|key, collection).
-     *
-     * @static
-     * @memberOf _
-     * @alias foldl, inject
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] Initial value of the accumulator.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var sum = _.reduce([1, 2, 3], function(sum, num) {
-     *   return sum + num;
-     * });
-     * // => 6
-     *
-     * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
-     *   result[key] = num * 3;
-     *   return result;
-     * }, {});
-     * // => { 'a': 3, 'b': 6, 'c': 9 }
-     */
-    function reduce(collection, callback, accumulator, thisArg) {
-      if (!collection) return accumulator;
-      var noaccum = arguments.length < 3;
-      callback = lodash.createCallback(callback, thisArg, 4);
-
-      var index = -1,
-          length = collection.length;
-
-      if (typeof length == 'number') {
-        if (noaccum) {
-          accumulator = collection[++index];
-        }
-        while (++index < length) {
-          accumulator = callback(accumulator, collection[index], index, collection);
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          accumulator = noaccum
-            ? (noaccum = false, value)
-            : callback(accumulator, value, index, collection)
-        });
-      }
-      return accumulator;
-    }
-
-    /**
-     * This method is like `_.reduce` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * @static
-     * @memberOf _
-     * @alias foldr
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function} [callback=identity] The function called per iteration.
-     * @param {*} [accumulator] Initial value of the accumulator.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the accumulated value.
-     * @example
-     *
-     * var list = [[0, 1], [2, 3], [4, 5]];
-     * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
-     * // => [4, 5, 2, 3, 0, 1]
-     */
-    function reduceRight(collection, callback, accumulator, thisArg) {
-      var noaccum = arguments.length < 3;
-      callback = lodash.createCallback(callback, thisArg, 4);
-      forEachRight(collection, function(value, index, collection) {
-        accumulator = noaccum
-          ? (noaccum = false, value)
-          : callback(accumulator, value, index, collection);
-      });
-      return accumulator;
-    }
-
-    /**
-     * The opposite of `_.filter` this method returns the elements of a
-     * collection that the callback does **not** return truey for.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of elements that failed the callback check.
-     * @example
-     *
-     * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-     * // => [1, 3, 5]
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.reject(characters, 'blocked');
-     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-     *
-     * // using "_.where" callback shorthand
-     * _.reject(characters, { 'age': 36 });
-     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
-     */
-    function reject(collection, callback, thisArg) {
-      callback = lodash.createCallback(callback, thisArg, 3);
-      return filter(collection, function(value, index, collection) {
-        return !callback(value, index, collection);
-      });
-    }
-
-    /**
-     * Retrieves a random element or `n` random elements from a collection.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to sample.
-     * @param {number} [n] The number of elements to sample.
-     * @param- {Object} [guard] Allows working with functions like `_.map`
-     *  without using their `index` arguments as `n`.
-     * @returns {Array} Returns the random sample(s) of `collection`.
-     * @example
-     *
-     * _.sample([1, 2, 3, 4]);
-     * // => 2
-     *
-     * _.sample([1, 2, 3, 4], 2);
-     * // => [3, 1]
-     */
-    function sample(collection, n, guard) {
-      if (collection && typeof collection.length != 'number') {
-        collection = values(collection);
-      }
-      if (n == null || guard) {
-        return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
-      }
-      var result = shuffle(collection);
-      result.length = nativeMin(nativeMax(0, n), result.length);
-      return result;
-    }
-
-    /**
-     * Creates an array of shuffled values, using a version of the Fisher-Yates
-     * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to shuffle.
-     * @returns {Array} Returns a new shuffled collection.
-     * @example
-     *
-     * _.shuffle([1, 2, 3, 4, 5, 6]);
-     * // => [4, 1, 6, 3, 5, 2]
-     */
-    function shuffle(collection) {
-      var index = -1,
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      forEach(collection, function(value) {
-        var rand = baseRandom(0, ++index);
-        result[index] = result[rand];
-        result[rand] = value;
-      });
-      return result;
-    }
-
-    /**
-     * Gets the size of the `collection` by returning `collection.length` for arrays
-     * and array-like objects or the number of own enumerable properties for objects.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to inspect.
-     * @returns {number} Returns `collection.length` or number of own enumerable properties.
-     * @example
-     *
-     * _.size([1, 2]);
-     * // => 2
-     *
-     * _.size({ 'one': 1, 'two': 2, 'three': 3 });
-     * // => 3
-     *
-     * _.size('pebbles');
-     * // => 7
-     */
-    function size(collection) {
-      var length = collection ? collection.length : 0;
-      return typeof length == 'number' ? length : keys(collection).length;
-    }
-
-    /**
-     * Checks if the callback returns a truey value for **any** element of a
-     * collection. The function returns as soon as it finds a passing value and
-     * does not iterate over the entire collection. The callback is bound to
-     * `thisArg` and invoked with three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias any
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {boolean} Returns `true` if any element passed the callback check,
-     *  else `false`.
-     * @example
-     *
-     * _.some([null, 0, 'yes', false], Boolean);
-     * // => true
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'blocked': false },
-     *   { 'name': 'fred',   'age': 40, 'blocked': true }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.some(characters, 'blocked');
-     * // => true
-     *
-     * // using "_.where" callback shorthand
-     * _.some(characters, { 'age': 1 });
-     * // => false
-     */
-    function some(collection, callback, thisArg) {
-      var result;
-      callback = lodash.createCallback(callback, thisArg, 3);
-
-      var index = -1,
-          length = collection ? collection.length : 0;
-
-      if (typeof length == 'number') {
-        while (++index < length) {
-          if ((result = callback(collection[index], index, collection))) {
-            break;
-          }
-        }
-      } else {
-        forOwn(collection, function(value, index, collection) {
-          return !(result = callback(value, index, collection));
-        });
-      }
-      return !!result;
-    }
-
-    /**
-     * Creates an array of elements, sorted in ascending order by the results of
-     * running each element in a collection through the callback. This method
-     * performs a stable sort, that is, it will preserve the original sort order
-     * of equal elements. The callback is bound to `thisArg` and invoked with
-     * three arguments; (value, index|key, collection).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an array of property names is provided for `callback` the collection
-     * will be sorted by each property value.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Array|Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of sorted elements.
-     * @example
-     *
-     * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
-     * // => [3, 1, 2]
-     *
-     * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
-     * // => [3, 1, 2]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36 },
-     *   { 'name': 'fred',    'age': 40 },
-     *   { 'name': 'barney',  'age': 26 },
-     *   { 'name': 'fred',    'age': 30 }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.map(_.sortBy(characters, 'age'), _.values);
-     * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
-     *
-     * // sorting by multiple properties
-     * _.map(_.sortBy(characters, ['name', 'age']), _.values);
-     * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
-     */
-    function sortBy(collection, callback, thisArg) {
-      var index = -1,
-          isArr = isArray(callback),
-          length = collection ? collection.length : 0,
-          result = Array(typeof length == 'number' ? length : 0);
-
-      if (!isArr) {
-        callback = lodash.createCallback(callback, thisArg, 3);
-      }
-      forEach(collection, function(value, key, collection) {
-        var object = result[++index] = getObject();
-        if (isArr) {
-          object.criteria = map(callback, function(key) { return value[key]; });
-        } else {
-          (object.criteria = getArray())[0] = callback(value, key, collection);
-        }
-        object.index = index;
-        object.value = value;
-      });
-
-      length = result.length;
-      result.sort(compareAscending);
-      while (length--) {
-        var object = result[length];
-        result[length] = object.value;
-        if (!isArr) {
-          releaseArray(object.criteria);
-        }
-        releaseObject(object);
-      }
-      return result;
-    }
-
-    /**
-     * Converts the `collection` to an array.
-     *
-     * @static
-     * @memberOf _
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to convert.
-     * @returns {Array} Returns the new converted array.
-     * @example
-     *
-     * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
-     * // => [2, 3, 4]
-     */
-    function toArray(collection) {
-      if (collection && typeof collection.length == 'number') {
-        return slice(collection);
-      }
-      return values(collection);
-    }
-
-    /**
-     * Performs a deep comparison of each element in a `collection` to the given
-     * `properties` object, returning an array of all elements that have equivalent
-     * property values.
-     *
-     * @static
-     * @memberOf _
-     * @type Function
-     * @category Collections
-     * @param {Array|Object|string} collection The collection to iterate over.
-     * @param {Object} props The object of property values to filter by.
-     * @returns {Array} Returns a new array of elements that have the given properties.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
-     * ];
-     *
-     * _.where(characters, { 'age': 36 });
-     * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
-     *
-     * _.where(characters, { 'pets': ['dino'] });
-     * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
-     */
-    var where = filter;
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates an array with all falsey values removed. The values `false`, `null`,
-     * `0`, `""`, `undefined`, and `NaN` are all falsey.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to compact.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.compact([0, 1, false, 2, '', 3]);
-     * // => [1, 2, 3]
-     */
-    function compact(array) {
-      var index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      while (++index < length) {
-        var value = array[index];
-        if (value) {
-          result.push(value);
-        }
-      }
-      return result;
-    }
-
-    /**
-     * Creates an array excluding all values of the provided arrays using strict
-     * equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to process.
-     * @param {...Array} [values] The arrays of values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
-     * // => [1, 3, 4]
-     */
-    function difference(array) {
-      return baseDifference(array, baseFlatten(arguments, true, true, 1));
-    }
-
-    /**
-     * This method is like `_.find` except that it returns the index of the first
-     * element that passes the callback check, instead of the element itself.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index of the found element, else `-1`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': false },
-     *   { 'name': 'fred',    'age': 40, 'blocked': true },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
-     * ];
-     *
-     * _.findIndex(characters, function(chr) {
-     *   return chr.age < 20;
-     * });
-     * // => 2
-     *
-     * // using "_.where" callback shorthand
-     * _.findIndex(characters, { 'age': 36 });
-     * // => 0
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findIndex(characters, 'blocked');
-     * // => 1
-     */
-    function findIndex(array, callback, thisArg) {
-      var index = -1,
-          length = array ? array.length : 0;
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (++index < length) {
-        if (callback(array[index], index, array)) {
-          return index;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * This method is like `_.findIndex` except that it iterates over elements
-     * of a `collection` from right to left.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index of the found element, else `-1`.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36, 'blocked': true },
-     *   { 'name': 'fred',    'age': 40, 'blocked': false },
-     *   { 'name': 'pebbles', 'age': 1,  'blocked': true }
-     * ];
-     *
-     * _.findLastIndex(characters, function(chr) {
-     *   return chr.age > 30;
-     * });
-     * // => 1
-     *
-     * // using "_.where" callback shorthand
-     * _.findLastIndex(characters, { 'age': 36 });
-     * // => 0
-     *
-     * // using "_.pluck" callback shorthand
-     * _.findLastIndex(characters, 'blocked');
-     * // => 2
-     */
-    function findLastIndex(array, callback, thisArg) {
-      var length = array ? array.length : 0;
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (length--) {
-        if (callback(array[length], length, array)) {
-          return length;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * Gets the first element or first `n` elements of an array. If a callback
-     * is provided elements at the beginning of the array are returned as long
-     * as the callback returns truey. The callback is bound to `thisArg` and
-     * invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias head, take
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback] The function called
-     *  per element or the number of elements to return. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the first element(s) of `array`.
-     * @example
-     *
-     * _.first([1, 2, 3]);
-     * // => 1
-     *
-     * _.first([1, 2, 3], 2);
-     * // => [1, 2]
-     *
-     * _.first([1, 2, 3], function(num) {
-     *   return num < 3;
-     * });
-     * // => [1, 2]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.first(characters, 'blocked');
-     * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
-     *
-     * // using "_.where" callback shorthand
-     * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
-     * // => ['barney', 'fred']
-     */
-    function first(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = -1;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (++index < length && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = callback;
-        if (n == null || thisArg) {
-          return array ? array[0] : undefined;
-        }
-      }
-      return slice(array, 0, nativeMin(nativeMax(0, n), length));
-    }
-
-    /**
-     * Flattens a nested array (the nesting can be to any depth). If `isShallow`
-     * is truey, the array will only be flattened a single level. If a callback
-     * is provided each element of the array is passed through the callback before
-     * flattening. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to flatten.
-     * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new flattened array.
-     * @example
-     *
-     * _.flatten([1, [2], [3, [[4]]]]);
-     * // => [1, 2, 3, 4];
-     *
-     * _.flatten([1, [2], [3, [[4]]]], true);
-     * // => [1, 2, 3, [[4]]];
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
-     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.flatten(characters, 'pets');
-     * // => ['hoppy', 'baby puss', 'dino']
-     */
-    function flatten(array, isShallow, callback, thisArg) {
-      // juggle arguments
-      if (typeof isShallow != 'boolean' && isShallow != null) {
-        thisArg = callback;
-        callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
-        isShallow = false;
-      }
-      if (callback != null) {
-        array = map(array, callback, thisArg);
-      }
-      return baseFlatten(array, isShallow);
-    }
-
-    /**
-     * Gets the index at which the first occurrence of `value` is found using
-     * strict equality for comparisons, i.e. `===`. If the array is already sorted
-     * providing `true` for `fromIndex` will run a faster binary search.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {*} value The value to search for.
-     * @param {boolean|number} [fromIndex=0] The index to search from or `true`
-     *  to perform a binary search on a sorted array.
-     * @returns {number} Returns the index of the matched value or `-1`.
-     * @example
-     *
-     * _.indexOf([1, 2, 3, 1, 2, 3], 2);
-     * // => 1
-     *
-     * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
-     * // => 4
-     *
-     * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
-     * // => 2
-     */
-    function indexOf(array, value, fromIndex) {
-      if (typeof fromIndex == 'number') {
-        var length = array ? array.length : 0;
-        fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
-      } else if (fromIndex) {
-        var index = sortedIndex(array, value);
-        return array[index] === value ? index : -1;
-      }
-      return baseIndexOf(array, value, fromIndex);
-    }
-
-    /**
-     * Gets all but the last element or last `n` elements of an array. If a
-     * callback is provided elements at the end of the array are excluded from
-     * the result as long as the callback returns truey. The callback is bound
-     * to `thisArg` and invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback=1] The function called
-     *  per element or the number of elements to exclude. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a slice of `array`.
-     * @example
-     *
-     * _.initial([1, 2, 3]);
-     * // => [1, 2]
-     *
-     * _.initial([1, 2, 3], 2);
-     * // => [1]
-     *
-     * _.initial([1, 2, 3], function(num) {
-     *   return num > 1;
-     * });
-     * // => [1]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.initial(characters, 'blocked');
-     * // => [{ 'name': 'barney',  'blocked': false, 'employer': 'slate' }]
-     *
-     * // using "_.where" callback shorthand
-     * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
-     * // => ['barney', 'fred']
-     */
-    function initial(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = length;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (index-- && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = (callback == null || thisArg) ? 1 : callback || n;
-      }
-      return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
-    }
-
-    /**
-     * Creates an array of unique values present in all provided arrays using
-     * strict equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of shared values.
-     * @example
-     *
-     * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-     * // => [1, 2]
-     */
-    function intersection() {
-      var args = [],
-          argsIndex = -1,
-          argsLength = arguments.length,
-          caches = getArray(),
-          indexOf = getIndexOf(),
-          trustIndexOf = indexOf === baseIndexOf,
-          seen = getArray();
-
-      while (++argsIndex < argsLength) {
-        var value = arguments[argsIndex];
-        if (isArray(value) || isArguments(value)) {
-          args.push(value);
-          caches.push(trustIndexOf && value.length >= largeArraySize &&
-            createCache(argsIndex ? args[argsIndex] : seen));
-        }
-      }
-      var array = args[0],
-          index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      outer:
-      while (++index < length) {
-        var cache = caches[0];
-        value = array[index];
-
-        if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
-          argsIndex = argsLength;
-          (cache || seen).push(value);
-          while (--argsIndex) {
-            cache = caches[argsIndex];
-            if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
-              continue outer;
-            }
-          }
-          result.push(value);
-        }
-      }
-      while (argsLength--) {
-        cache = caches[argsLength];
-        if (cache) {
-          releaseObject(cache);
-        }
-      }
-      releaseArray(caches);
-      releaseArray(seen);
-      return result;
-    }
-
-    /**
-     * Gets the last element or last `n` elements of an array. If a callback is
-     * provided elements at the end of the array are returned as long as the
-     * callback returns truey. The callback is bound to `thisArg` and invoked
-     * with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback] The function called
-     *  per element or the number of elements to return. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {*} Returns the last element(s) of `array`.
-     * @example
-     *
-     * _.last([1, 2, 3]);
-     * // => 3
-     *
-     * _.last([1, 2, 3], 2);
-     * // => [2, 3]
-     *
-     * _.last([1, 2, 3], function(num) {
-     *   return num > 1;
-     * });
-     * // => [2, 3]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.pluck(_.last(characters, 'blocked'), 'name');
-     * // => ['fred', 'pebbles']
-     *
-     * // using "_.where" callback shorthand
-     * _.last(characters, { 'employer': 'na' });
-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-     */
-    function last(array, callback, thisArg) {
-      var n = 0,
-          length = array ? array.length : 0;
-
-      if (typeof callback != 'number' && callback != null) {
-        var index = length;
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (index-- && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = callback;
-        if (n == null || thisArg) {
-          return array ? array[length - 1] : undefined;
-        }
-      }
-      return slice(array, nativeMax(0, length - n));
-    }
-
-    /**
-     * Gets the index at which the last occurrence of `value` is found using strict
-     * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
-     * as the offset from the end of the collection.
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to search.
-     * @param {*} value The value to search for.
-     * @param {number} [fromIndex=array.length-1] The index to search from.
-     * @returns {number} Returns the index of the matched value or `-1`.
-     * @example
-     *
-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
-     * // => 4
-     *
-     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
-     * // => 1
-     */
-    function lastIndexOf(array, value, fromIndex) {
-      var index = array ? array.length : 0;
-      if (typeof fromIndex == 'number') {
-        index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
-      }
-      while (index--) {
-        if (array[index] === value) {
-          return index;
-        }
-      }
-      return -1;
-    }
-
-    /**
-     * Removes all provided values from the given array using strict equality for
-     * comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to modify.
-     * @param {...*} [value] The values to remove.
-     * @returns {Array} Returns `array`.
-     * @example
-     *
-     * var array = [1, 2, 3, 1, 2, 3];
-     * _.pull(array, 2, 3);
-     * console.log(array);
-     * // => [1, 1]
-     */
-    function pull(array) {
-      var args = arguments,
-          argsIndex = 0,
-          argsLength = args.length,
-          length = array ? array.length : 0;
-
-      while (++argsIndex < argsLength) {
-        var index = -1,
-            value = args[argsIndex];
-        while (++index < length) {
-          if (array[index] === value) {
-            splice.call(array, index--, 1);
-            length--;
-          }
-        }
-      }
-      return array;
-    }
-
-    /**
-     * Creates an array of numbers (positive and/or negative) progressing from
-     * `start` up to but not including `end`. If `start` is less than `stop` a
-     * zero-length range is created unless a negative `step` is specified.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {number} [start=0] The start of the range.
-     * @param {number} end The end of the range.
-     * @param {number} [step=1] The value to increment or decrement by.
-     * @returns {Array} Returns a new range array.
-     * @example
-     *
-     * _.range(4);
-     * // => [0, 1, 2, 3]
-     *
-     * _.range(1, 5);
-     * // => [1, 2, 3, 4]
-     *
-     * _.range(0, 20, 5);
-     * // => [0, 5, 10, 15]
-     *
-     * _.range(0, -4, -1);
-     * // => [0, -1, -2, -3]
-     *
-     * _.range(1, 4, 0);
-     * // => [1, 1, 1]
-     *
-     * _.range(0);
-     * // => []
-     */
-    function range(start, end, step) {
-      start = +start || 0;
-      step = typeof step == 'number' ? step : (+step || 1);
-
-      if (end == null) {
-        end = start;
-        start = 0;
-      }
-      // use `Array(length)` so engines like Chakra and V8 avoid slower modes
-      // http://youtu.be/XAqIpGU8ZZk#t=17m25s
-      var index = -1,
-          length = nativeMax(0, ceil((end - start) / (step || 1))),
-          result = Array(length);
-
-      while (++index < length) {
-        result[index] = start;
-        start += step;
-      }
-      return result;
-    }
-
-    /**
-     * Removes all elements from an array that the callback returns truey for
-     * and returns an array of removed elements. The callback is bound to `thisArg`
-     * and invoked with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to modify.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a new array of removed elements.
-     * @example
-     *
-     * var array = [1, 2, 3, 4, 5, 6];
-     * var evens = _.remove(array, function(num) { return num % 2 == 0; });
-     *
-     * console.log(array);
-     * // => [1, 3, 5]
-     *
-     * console.log(evens);
-     * // => [2, 4, 6]
-     */
-    function remove(array, callback, thisArg) {
-      var index = -1,
-          length = array ? array.length : 0,
-          result = [];
-
-      callback = lodash.createCallback(callback, thisArg, 3);
-      while (++index < length) {
-        var value = array[index];
-        if (callback(value, index, array)) {
-          result.push(value);
-          splice.call(array, index--, 1);
-          length--;
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The opposite of `_.initial` this method gets all but the first element or
-     * first `n` elements of an array. If a callback function is provided elements
-     * at the beginning of the array are excluded from the result as long as the
-     * callback returns truey. The callback is bound to `thisArg` and invoked
-     * with three arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias drop, tail
-     * @category Arrays
-     * @param {Array} array The array to query.
-     * @param {Function|Object|number|string} [callback=1] The function called
-     *  per element or the number of elements to exclude. If a property name or
-     *  object is provided it will be used to create a "_.pluck" or "_.where"
-     *  style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a slice of `array`.
-     * @example
-     *
-     * _.rest([1, 2, 3]);
-     * // => [2, 3]
-     *
-     * _.rest([1, 2, 3], 2);
-     * // => [3]
-     *
-     * _.rest([1, 2, 3], function(num) {
-     *   return num < 3;
-     * });
-     * // => [3]
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
-     *   { 'name': 'fred',    'blocked': false,  'employer': 'slate' },
-     *   { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
-     * ];
-     *
-     * // using "_.pluck" callback shorthand
-     * _.pluck(_.rest(characters, 'blocked'), 'name');
-     * // => ['fred', 'pebbles']
-     *
-     * // using "_.where" callback shorthand
-     * _.rest(characters, { 'employer': 'slate' });
-     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-     */
-    function rest(array, callback, thisArg) {
-      if (typeof callback != 'number' && callback != null) {
-        var n = 0,
-            index = -1,
-            length = array ? array.length : 0;
-
-        callback = lodash.createCallback(callback, thisArg, 3);
-        while (++index < length && callback(array[index], index, array)) {
-          n++;
-        }
-      } else {
-        n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
-      }
-      return slice(array, n);
-    }
-
-    /**
-     * Uses a binary search to determine the smallest index at which a value
-     * should be inserted into a given sorted array in order to maintain the sort
-     * order of the array. If a callback is provided it will be executed for
-     * `value` and each element of `array` to compute their sort ranking. The
-     * callback is bound to `thisArg` and invoked with one argument; (value).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to inspect.
-     * @param {*} value The value to evaluate.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {number} Returns the index at which `value` should be inserted
-     *  into `array`.
-     * @example
-     *
-     * _.sortedIndex([20, 30, 50], 40);
-     * // => 2
-     *
-     * // using "_.pluck" callback shorthand
-     * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
-     * // => 2
-     *
-     * var dict = {
-     *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
-     * };
-     *
-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
-     *   return dict.wordToNumber[word];
-     * });
-     * // => 2
-     *
-     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
-     *   return this.wordToNumber[word];
-     * }, dict);
-     * // => 2
-     */
-    function sortedIndex(array, value, callback, thisArg) {
-      var low = 0,
-          high = array ? array.length : low;
-
-      // explicitly reference `identity` for better inlining in Firefox
-      callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
-      value = callback(value);
-
-      while (low < high) {
-        var mid = (low + high) >>> 1;
-        (callback(array[mid]) < value)
-          ? low = mid + 1
-          : high = mid;
-      }
-      return low;
-    }
-
-    /**
-     * Creates an array of unique values, in order, of the provided arrays using
-     * strict equality for comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of combined values.
-     * @example
-     *
-     * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-     * // => [1, 2, 3, 5, 4]
-     */
-    function union() {
-      return baseUniq(baseFlatten(arguments, true, true));
-    }
-
-    /**
-     * Creates a duplicate-value-free version of an array using strict equality
-     * for comparisons, i.e. `===`. If the array is sorted, providing
-     * `true` for `isSorted` will use a faster algorithm. If a callback is provided
-     * each element of `array` is passed through the callback before uniqueness
-     * is computed. The callback is bound to `thisArg` and invoked with three
-     * arguments; (value, index, array).
-     *
-     * If a property name is provided for `callback` the created "_.pluck" style
-     * callback will return the property value of the given element.
-     *
-     * If an object is provided for `callback` the created "_.where" style callback
-     * will return `true` for elements that have the properties of the given object,
-     * else `false`.
-     *
-     * @static
-     * @memberOf _
-     * @alias unique
-     * @category Arrays
-     * @param {Array} array The array to process.
-     * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
-     * @param {Function|Object|string} [callback=identity] The function called
-     *  per iteration. If a property name or object is provided it will be used
-     *  to create a "_.pluck" or "_.where" style callback, respectively.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns a duplicate-value-free array.
-     * @example
-     *
-     * _.uniq([1, 2, 1, 3, 1]);
-     * // => [1, 2, 3]
-     *
-     * _.uniq([1, 1, 2, 2, 3], true);
-     * // => [1, 2, 3]
-     *
-     * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
-     * // => ['A', 'b', 'C']
-     *
-     * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
-     * // => [1, 2.5, 3]
-     *
-     * // using "_.pluck" callback shorthand
-     * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
-     * // => [{ 'x': 1 }, { 'x': 2 }]
-     */
-    function uniq(array, isSorted, callback, thisArg) {
-      // juggle arguments
-      if (typeof isSorted != 'boolean' && isSorted != null) {
-        thisArg = callback;
-        callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
-        isSorted = false;
-      }
-      if (callback != null) {
-        callback = lodash.createCallback(callback, thisArg, 3);
-      }
-      return baseUniq(array, isSorted, callback);
-    }
-
-    /**
-     * Creates an array excluding all provided values using strict equality for
-     * comparisons, i.e. `===`.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {Array} array The array to filter.
-     * @param {...*} [value] The values to exclude.
-     * @returns {Array} Returns a new array of filtered values.
-     * @example
-     *
-     * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
-     * // => [2, 3, 4]
-     */
-    function without(array) {
-      return baseDifference(array, slice(arguments, 1));
-    }
-
-    /**
-     * Creates an array that is the symmetric difference of the provided arrays.
-     * See http://en.wikipedia.org/wiki/Symmetric_difference.
-     *
-     * @static
-     * @memberOf _
-     * @category Arrays
-     * @param {...Array} [array] The arrays to inspect.
-     * @returns {Array} Returns an array of values.
-     * @example
-     *
-     * _.xor([1, 2, 3], [5, 2, 1, 4]);
-     * // => [3, 5, 4]
-     *
-     * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
-     * // => [1, 4, 5]
-     */
-    function xor() {
-      var index = -1,
-          length = arguments.length;
-
-      while (++index < length) {
-        var array = arguments[index];
-        if (isArray(array) || isArguments(array)) {
-          var result = result
-            ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
-            : array;
-        }
-      }
-      return result || [];
-    }
-
-    /**
-     * Creates an array of grouped elements, the first of which contains the first
-     * elements of the given arrays, the second of which contains the second
-     * elements of the given arrays, and so on.
-     *
-     * @static
-     * @memberOf _
-     * @alias unzip
-     * @category Arrays
-     * @param {...Array} [array] Arrays to process.
-     * @returns {Array} Returns a new array of grouped elements.
-     * @example
-     *
-     * _.zip(['fred', 'barney'], [30, 40], [true, false]);
-     * // => [['fred', 30, true], ['barney', 40, false]]
-     */
-    function zip() {
-      var array = arguments.length > 1 ? arguments : arguments[0],
-          index = -1,
-          length = array ? max(pluck(array, 'length')) : 0,
-          result = Array(length < 0 ? 0 : length);
-
-      while (++index < length) {
-        result[index] = pluck(array, index);
-      }
-      return result;
-    }
-
-    /**
-     * Creates an object composed from arrays of `keys` and `values`. Provide
-     * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
-     * or two arrays, one of `keys` and one of corresponding `values`.
-     *
-     * @static
-     * @memberOf _
-     * @alias object
-     * @category Arrays
-     * @param {Array} keys The array of keys.
-     * @param {Array} [values=[]] The array of values.
-     * @returns {Object} Returns an object composed of the given keys and
-     *  corresponding values.
-     * @example
-     *
-     * _.zipObject(['fred', 'barney'], [30, 40]);
-     * // => { 'fred': 30, 'barney': 40 }
-     */
-    function zipObject(keys, values) {
-      var index = -1,
-          length = keys ? keys.length : 0,
-          result = {};
-
-      if (!values && length && !isArray(keys[0])) {
-        values = [];
-      }
-      while (++index < length) {
-        var key = keys[index];
-        if (values) {
-          result[key] = values[index];
-        } else if (key) {
-          result[key[0]] = key[1];
-        }
-      }
-      return result;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a function that executes `func`, with  the `this` binding and
-     * arguments of the created function, only after being called `n` times.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {number} n The number of times the function must be called before
-     *  `func` is executed.
-     * @param {Function} func The function to restrict.
-     * @returns {Function} Returns the new restricted function.
-     * @example
-     *
-     * var saves = ['profile', 'settings'];
-     *
-     * var done = _.after(saves.length, function() {
-     *   console.log('Done saving!');
-     * });
-     *
-     * _.forEach(saves, function(type) {
-     *   asyncSave({ 'type': type, 'complete': done });
-     * });
-     * // => logs 'Done saving!', after all saves have completed
-     */
-    function after(n, func) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      return function() {
-        if (--n < 1) {
-          return func.apply(this, arguments);
-        }
-      };
-    }
-
-    /**
-     * Creates a function that, when called, invokes `func` with the `this`
-     * binding of `thisArg` and prepends any additional `bind` arguments to those
-     * provided to the bound function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to bind.
-     * @param {*} [thisArg] The `this` binding of `func`.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new bound function.
-     * @example
-     *
-     * var func = function(greeting) {
-     *   return greeting + ' ' + this.name;
-     * };
-     *
-     * func = _.bind(func, { 'name': 'fred' }, 'hi');
-     * func();
-     * // => 'hi fred'
-     */
-    function bind(func, thisArg) {
-      return arguments.length > 2
-        ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
-        : createWrapper(func, 1, null, null, thisArg);
-    }
-
-    /**
-     * Binds methods of an object to the object itself, overwriting the existing
-     * method. Method names may be specified as individual arguments or as arrays
-     * of method names. If no method names are provided all the function properties
-     * of `object` will be bound.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Object} object The object to bind and assign the bound methods to.
-     * @param {...string} [methodName] The object method names to
-     *  bind, specified as individual method names or arrays of method names.
-     * @returns {Object} Returns `object`.
-     * @example
-     *
-     * var view = {
-     *   'label': 'docs',
-     *   'onClick': function() { console.log('clicked ' + this.label); }
-     * };
-     *
-     * _.bindAll(view);
-     * jQuery('#docs').on('click', view.onClick);
-     * // => logs 'clicked docs', when the button is clicked
-     */
-    function bindAll(object) {
-      var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
-          index = -1,
-          length = funcs.length;
-
-      while (++index < length) {
-        var key = funcs[index];
-        object[key] = createWrapper(object[key], 1, null, null, object);
-      }
-      return object;
-    }
-
-    /**
-     * Creates a function that, when called, invokes the method at `object[key]`
-     * and prepends any additional `bindKey` arguments to those provided to the bound
-     * function. This method differs from `_.bind` by allowing bound functions to
-     * reference methods that will be redefined or don't yet exist.
-     * See http://michaux.ca/articles/lazy-function-definition-pattern.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Object} object The object the method belongs to.
-     * @param {string} key The key of the method.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new bound function.
-     * @example
-     *
-     * var object = {
-     *   'name': 'fred',
-     *   'greet': function(greeting) {
-     *     return greeting + ' ' + this.name;
-     *   }
-     * };
-     *
-     * var func = _.bindKey(object, 'greet', 'hi');
-     * func();
-     * // => 'hi fred'
-     *
-     * object.greet = function(greeting) {
-     *   return greeting + 'ya ' + this.name + '!';
-     * };
-     *
-     * func();
-     * // => 'hiya fred!'
-     */
-    function bindKey(object, key) {
-      return arguments.length > 2
-        ? createWrapper(key, 19, slice(arguments, 2), null, object)
-        : createWrapper(key, 3, null, null, object);
-    }
-
-    /**
-     * Creates a function that is the composition of the provided functions,
-     * where each function consumes the return value of the function that follows.
-     * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
-     * Each function is executed with the `this` binding of the composed function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {...Function} [func] Functions to compose.
-     * @returns {Function} Returns the new composed function.
-     * @example
-     *
-     * var realNameMap = {
-     *   'pebbles': 'penelope'
-     * };
-     *
-     * var format = function(name) {
-     *   name = realNameMap[name.toLowerCase()] || name;
-     *   return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
-     * };
-     *
-     * var greet = function(formatted) {
-     *   return 'Hiya ' + formatted + '!';
-     * };
-     *
-     * var welcome = _.compose(greet, format);
-     * welcome('pebbles');
-     * // => 'Hiya Penelope!'
-     */
-    function compose() {
-      var funcs = arguments,
-          length = funcs.length;
-
-      while (length--) {
-        if (!isFunction(funcs[length])) {
-          throw new TypeError;
-        }
-      }
-      return function() {
-        var args = arguments,
-            length = funcs.length;
-
-        while (length--) {
-          args = [funcs[length].apply(this, args)];
-        }
-        return args[0];
-      };
-    }
-
-    /**
-     * Creates a function which accepts one or more arguments of `func` that when
-     * invoked either executes `func` returning its result, if all `func` arguments
-     * have been provided, or returns a function that accepts one or more of the
-     * remaining `func` arguments, and so on. The arity of `func` can be specified
-     * if `func.length` is not sufficient.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to curry.
-     * @param {number} [arity=func.length] The arity of `func`.
-     * @returns {Function} Returns the new curried function.
-     * @example
-     *
-     * var curried = _.curry(function(a, b, c) {
-     *   console.log(a + b + c);
-     * });
-     *
-     * curried(1)(2)(3);
-     * // => 6
-     *
-     * curried(1, 2)(3);
-     * // => 6
-     *
-     * curried(1, 2, 3);
-     * // => 6
-     */
-    function curry(func, arity) {
-      arity = typeof arity == 'number' ? arity : (+arity || func.length);
-      return createWrapper(func, 4, null, null, null, arity);
-    }
-
-    /**
-     * Creates a function that will delay the execution of `func` until after
-     * `wait` milliseconds have elapsed since the last time it was invoked.
-     * Provide an options object to indicate that `func` should be invoked on
-     * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
-     * to the debounced function will return the result of the last `func` call.
-     *
-     * Note: If `leading` and `trailing` options are `true` `func` will be called
-     * on the trailing edge of the timeout only if the the debounced function is
-     * invoked more than once during the `wait` timeout.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to debounce.
-     * @param {number} wait The number of milliseconds to delay.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
-     * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
-     * @returns {Function} Returns the new debounced function.
-     * @example
-     *
-     * // avoid costly calculations while the window size is in flux
-     * var lazyLayout = _.debounce(calculateLayout, 150);
-     * jQuery(window).on('resize', lazyLayout);
-     *
-     * // execute `sendMail` when the click event is fired, debouncing subsequent calls
-     * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
-     *   'leading': true,
-     *   'trailing': false
-     * });
-     *
-     * // ensure `batchLog` is executed once after 1 second of debounced calls
-     * var source = new EventSource('/stream');
-     * source.addEventListener('message', _.debounce(batchLog, 250, {
-     *   'maxWait': 1000
-     * }, false);
-     */
-    function debounce(func, wait, options) {
-      var args,
-          maxTimeoutId,
-          result,
-          stamp,
-          thisArg,
-          timeoutId,
-          trailingCall,
-          lastCalled = 0,
-          maxWait = false,
-          trailing = true;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      wait = nativeMax(0, wait) || 0;
-      if (options === true) {
-        var leading = true;
-        trailing = false;
-      } else if (isObject(options)) {
-        leading = options.leading;
-        maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
-        trailing = 'trailing' in options ? options.trailing : trailing;
-      }
-      var delayed = function() {
-        var remaining = wait - (now() - stamp);
-        if (remaining <= 0) {
-          if (maxTimeoutId) {
-            clearTimeout(maxTimeoutId);
-          }
-          var isCalled = trailingCall;
-          maxTimeoutId = timeoutId = trailingCall = undefined;
-          if (isCalled) {
-            lastCalled = now();
-            result = func.apply(thisArg, args);
-            if (!timeoutId && !maxTimeoutId) {
-              args = thisArg = null;
-            }
-          }
-        } else {
-          timeoutId = setTimeout(delayed, remaining);
-        }
-      };
-
-      var maxDelayed = function() {
-        if (timeoutId) {
-          clearTimeout(timeoutId);
-        }
-        maxTimeoutId = timeoutId = trailingCall = undefined;
-        if (trailing || (maxWait !== wait)) {
-          lastCalled = now();
-          result = func.apply(thisArg, args);
-          if (!timeoutId && !maxTimeoutId) {
-            args = thisArg = null;
-          }
-        }
-      };
-
-      return function() {
-        args = arguments;
-        stamp = now();
-        thisArg = this;
-        trailingCall = trailing && (timeoutId || !leading);
-
-        if (maxWait === false) {
-          var leadingCall = leading && !timeoutId;
-        } else {
-          if (!maxTimeoutId && !leading) {
-            lastCalled = stamp;
-          }
-          var remaining = maxWait - (stamp - lastCalled),
-              isCalled = remaining <= 0;
-
-          if (isCalled) {
-            if (maxTimeoutId) {
-              maxTimeoutId = clearTimeout(maxTimeoutId);
-            }
-            lastCalled = stamp;
-            result = func.apply(thisArg, args);
-          }
-          else if (!maxTimeoutId) {
-            maxTimeoutId = setTimeout(maxDelayed, remaining);
-          }
-        }
-        if (isCalled && timeoutId) {
-          timeoutId = clearTimeout(timeoutId);
-        }
-        else if (!timeoutId && wait !== maxWait) {
-          timeoutId = setTimeout(delayed, wait);
-        }
-        if (leadingCall) {
-          isCalled = true;
-          result = func.apply(thisArg, args);
-        }
-        if (isCalled && !timeoutId && !maxTimeoutId) {
-          args = thisArg = null;
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Defers executing the `func` function until the current call stack has cleared.
-     * Additional arguments will be provided to `func` when it is invoked.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to defer.
-     * @param {...*} [arg] Arguments to invoke the function with.
-     * @returns {number} Returns the timer id.
-     * @example
-     *
-     * _.defer(function(text) { console.log(text); }, 'deferred');
-     * // logs 'deferred' after one or more milliseconds
-     */
-    function defer(func) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var args = slice(arguments, 1);
-      return setTimeout(function() { func.apply(undefined, args); }, 1);
-    }
-
-    /**
-     * Executes the `func` function after `wait` milliseconds. Additional arguments
-     * will be provided to `func` when it is invoked.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to delay.
-     * @param {number} wait The number of milliseconds to delay execution.
-     * @param {...*} [arg] Arguments to invoke the function with.
-     * @returns {number} Returns the timer id.
-     * @example
-     *
-     * _.delay(function(text) { console.log(text); }, 1000, 'later');
-     * // => logs 'later' after one second
-     */
-    function delay(func, wait) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var args = slice(arguments, 2);
-      return setTimeout(function() { func.apply(undefined, args); }, wait);
-    }
-
-    /**
-     * Creates a function that memoizes the result of `func`. If `resolver` is
-     * provided it will be used to determine the cache key for storing the result
-     * based on the arguments provided to the memoized function. By default, the
-     * first argument provided to the memoized function is used as the cache key.
-     * The `func` is executed with the `this` binding of the memoized function.
-     * The result cache is exposed as the `cache` property on the memoized function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to have its output memoized.
-     * @param {Function} [resolver] A function used to resolve the cache key.
-     * @returns {Function} Returns the new memoizing function.
-     * @example
-     *
-     * var fibonacci = _.memoize(function(n) {
-     *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
-     * });
-     *
-     * fibonacci(9)
-     * // => 34
-     *
-     * var data = {
-     *   'fred': { 'name': 'fred', 'age': 40 },
-     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
-     * };
-     *
-     * // modifying the result cache
-     * var get = _.memoize(function(name) { return data[name]; }, _.identity);
-     * get('pebbles');
-     * // => { 'name': 'pebbles', 'age': 1 }
-     *
-     * get.cache.pebbles.name = 'penelope';
-     * get('pebbles');
-     * // => { 'name': 'penelope', 'age': 1 }
-     */
-    function memoize(func, resolver) {
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      var memoized = function() {
-        var cache = memoized.cache,
-            key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
-
-        return hasOwnProperty.call(cache, key)
-          ? cache[key]
-          : (cache[key] = func.apply(this, arguments));
-      }
-      memoized.cache = {};
-      return memoized;
-    }
-
-    /**
-     * Creates a function that is restricted to execute `func` once. Repeat calls to
-     * the function will return the value of the first call. The `func` is executed
-     * with the `this` binding of the created function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to restrict.
-     * @returns {Function} Returns the new restricted function.
-     * @example
-     *
-     * var initialize = _.once(createApplication);
-     * initialize();
-     * initialize();
-     * // `initialize` executes `createApplication` once
-     */
-    function once(func) {
-      var ran,
-          result;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      return function() {
-        if (ran) {
-          return result;
-        }
-        ran = true;
-        result = func.apply(this, arguments);
-
-        // clear the `func` variable so the function may be garbage collected
-        func = null;
-        return result;
-      };
-    }
-
-    /**
-     * Creates a function that, when called, invokes `func` with any additional
-     * `partial` arguments prepended to those provided to the new function. This
-     * method is similar to `_.bind` except it does **not** alter the `this` binding.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to partially apply arguments to.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new partially applied function.
-     * @example
-     *
-     * var greet = function(greeting, name) { return greeting + ' ' + name; };
-     * var hi = _.partial(greet, 'hi');
-     * hi('fred');
-     * // => 'hi fred'
-     */
-    function partial(func) {
-      return createWrapper(func, 16, slice(arguments, 1));
-    }
-
-    /**
-     * This method is like `_.partial` except that `partial` arguments are
-     * appended to those provided to the new function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to partially apply arguments to.
-     * @param {...*} [arg] Arguments to be partially applied.
-     * @returns {Function} Returns the new partially applied function.
-     * @example
-     *
-     * var defaultsDeep = _.partialRight(_.merge, _.defaults);
-     *
-     * var options = {
-     *   'variable': 'data',
-     *   'imports': { 'jq': $ }
-     * };
-     *
-     * defaultsDeep(options, _.templateSettings);
-     *
-     * options.variable
-     * // => 'data'
-     *
-     * options.imports
-     * // => { '_': _, 'jq': $ }
-     */
-    function partialRight(func) {
-      return createWrapper(func, 32, null, slice(arguments, 1));
-    }
-
-    /**
-     * Creates a function that, when executed, will only call the `func` function
-     * at most once per every `wait` milliseconds. Provide an options object to
-     * indicate that `func` should be invoked on the leading and/or trailing edge
-     * of the `wait` timeout. Subsequent calls to the throttled function will
-     * return the result of the last `func` call.
-     *
-     * Note: If `leading` and `trailing` options are `true` `func` will be called
-     * on the trailing edge of the timeout only if the the throttled function is
-     * invoked more than once during the `wait` timeout.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {Function} func The function to throttle.
-     * @param {number} wait The number of milliseconds to throttle executions to.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
-     * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
-     * @returns {Function} Returns the new throttled function.
-     * @example
-     *
-     * // avoid excessively updating the position while scrolling
-     * var throttled = _.throttle(updatePosition, 100);
-     * jQuery(window).on('scroll', throttled);
-     *
-     * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
-     * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
-     *   'trailing': false
-     * }));
-     */
-    function throttle(func, wait, options) {
-      var leading = true,
-          trailing = true;
-
-      if (!isFunction(func)) {
-        throw new TypeError;
-      }
-      if (options === false) {
-        leading = false;
-      } else if (isObject(options)) {
-        leading = 'leading' in options ? options.leading : leading;
-        trailing = 'trailing' in options ? options.trailing : trailing;
-      }
-      debounceOptions.leading = leading;
-      debounceOptions.maxWait = wait;
-      debounceOptions.trailing = trailing;
-
-      return debounce(func, wait, debounceOptions);
-    }
-
-    /**
-     * Creates a function that provides `value` to the wrapper function as its
-     * first argument. Additional arguments provided to the function are appended
-     * to those provided to the wrapper function. The wrapper is executed with
-     * the `this` binding of the created function.
-     *
-     * @static
-     * @memberOf _
-     * @category Functions
-     * @param {*} value The value to wrap.
-     * @param {Function} wrapper The wrapper function.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var p = _.wrap(_.escape, function(func, text) {
-     *   return '<p>' + func(text) + '</p>';
-     * });
-     *
-     * p('Fred, Wilma, & Pebbles');
-     * // => '<p>Fred, Wilma, & Pebbles</p>'
-     */
-    function wrap(value, wrapper) {
-      return createWrapper(wrapper, 16, [value]);
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a function that returns `value`.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} value The value to return from the new function.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * var getter = _.constant(object);
-     * getter() === object;
-     * // => true
-     */
-    function constant(value) {
-      return function() {
-        return value;
-      };
-    }
-
-    /**
-     * Produces a callback bound to an optional `thisArg`. If `func` is a property
-     * name the created callback will return the property value for a given element.
-     * If `func` is an object the created callback will return `true` for elements
-     * that contain the equivalent object properties, otherwise it will return `false`.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} [func=identity] The value to convert to a callback.
-     * @param {*} [thisArg] The `this` binding of the created callback.
-     * @param {number} [argCount] The number of arguments the callback accepts.
-     * @returns {Function} Returns a callback function.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // wrap to create custom callback shorthands
-     * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
-     *   var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
-     *   return !match ? func(callback, thisArg) : function(object) {
-     *     return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
-     *   };
-     * });
-     *
-     * _.filter(characters, 'age__gt38');
-     * // => [{ 'name': 'fred', 'age': 40 }]
-     */
-    function createCallback(func, thisArg, argCount) {
-      var type = typeof func;
-      if (func == null || type == 'function') {
-        return baseCreateCallback(func, thisArg, argCount);
-      }
-      // handle "_.pluck" style callback shorthands
-      if (type != 'object') {
-        return property(func);
-      }
-      var props = keys(func),
-          key = props[0],
-          a = func[key];
-
-      // handle "_.where" style callback shorthands
-      if (props.length == 1 && a === a && !isObject(a)) {
-        // fast path the common case of providing an object with a single
-        // property containing a primitive value
-        return function(object) {
-          var b = object[key];
-          return a === b && (a !== 0 || (1 / a == 1 / b));
-        };
-      }
-      return function(object) {
-        var length = props.length,
-            result = false;
-
-        while (length--) {
-          if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
-            break;
-          }
-        }
-        return result;
-      };
-    }
-
-    /**
-     * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
-     * corresponding HTML entities.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} string The string to escape.
-     * @returns {string} Returns the escaped string.
-     * @example
-     *
-     * _.escape('Fred, Wilma, & Pebbles');
-     * // => 'Fred, Wilma, & Pebbles'
-     */
-    function escape(string) {
-      return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
-    }
-
-    /**
-     * This method returns the first argument provided to it.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {*} value Any value.
-     * @returns {*} Returns `value`.
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * _.identity(object) === object;
-     * // => true
-     */
-    function identity(value) {
-      return value;
-    }
-
-    /**
-     * Adds function properties of a source object to the destination object.
-     * If `object` is a function methods will be added to its prototype as well.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {Function|Object} [object=lodash] object The destination object.
-     * @param {Object} source The object of functions to add.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
-     * @example
-     *
-     * function capitalize(string) {
-     *   return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
-     * }
-     *
-     * _.mixin({ 'capitalize': capitalize });
-     * _.capitalize('fred');
-     * // => 'Fred'
-     *
-     * _('fred').capitalize().value();
-     * // => 'Fred'
-     *
-     * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
-     * _('fred').capitalize();
-     * // => 'Fred'
-     */
-    function mixin(object, source, options) {
-      var chain = true,
-          methodNames = source && functions(source);
-
-      if (!source || (!options && !methodNames.length)) {
-        if (options == null) {
-          options = source;
-        }
-        ctor = lodashWrapper;
-        source = object;
-        object = lodash;
-        methodNames = functions(source);
-      }
-      if (options === false) {
-        chain = false;
-      } else if (isObject(options) && 'chain' in options) {
-        chain = options.chain;
-      }
-      var ctor = object,
-          isFunc = isFunction(ctor);
-
-      forEach(methodNames, function(methodName) {
-        var func = object[methodName] = source[methodName];
-        if (isFunc) {
-          ctor.prototype[methodName] = function() {
-            var chainAll = this.__chain__,
-                value = this.__wrapped__,
-                args = [value];
-
-            push.apply(args, arguments);
-            var result = func.apply(object, args);
-            if (chain || chainAll) {
-              if (value === result && isObject(result)) {
-                return this;
-              }
-              result = new ctor(result);
-              result.__chain__ = chainAll;
-            }
-            return result;
-          };
-        }
-      });
-    }
-
-    /**
-     * Reverts the '_' variable to its previous value and returns a reference to
-     * the `lodash` function.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @returns {Function} Returns the `lodash` function.
-     * @example
-     *
-     * var lodash = _.noConflict();
-     */
-    function noConflict() {
-      context._ = oldDash;
-      return this;
-    }
-
-    /**
-     * A no-operation function.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @example
-     *
-     * var object = { 'name': 'fred' };
-     * _.noop(object) === undefined;
-     * // => true
-     */
-    function noop() {
-      // no operation performed
-    }
-
-    /**
-     * Gets the number of milliseconds that have elapsed since the Unix epoch
-     * (1 January 1970 00:00:00 UTC).
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @example
-     *
-     * var stamp = _.now();
-     * _.defer(function() { console.log(_.now() - stamp); });
-     * // => logs the number of milliseconds it took for the deferred function to be called
-     */
-    var now = isNative(now = Date.now) && now || function() {
-      return new Date().getTime();
-    };
-
-    /**
-     * Converts the given value into an integer of the specified radix.
-     * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
-     * `value` is a hexadecimal, in which case a `radix` of `16` is used.
-     *
-     * Note: This method avoids differences in native ES3 and ES5 `parseInt`
-     * implementations. See http://es5.github.io/#E.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} value The value to parse.
-     * @param {number} [radix] The radix used to interpret the value to parse.
-     * @returns {number} Returns the new integer value.
-     * @example
-     *
-     * _.parseInt('08');
-     * // => 8
-     */
-    var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
-      // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
-      return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
-    };
-
-    /**
-     * Creates a "_.pluck" style function, which returns the `key` value of a
-     * given object.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} key The name of the property to retrieve.
-     * @returns {Function} Returns the new function.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'fred',   'age': 40 },
-     *   { 'name': 'barney', 'age': 36 }
-     * ];
-     *
-     * var getName = _.property('name');
-     *
-     * _.map(characters, getName);
-     * // => ['barney', 'fred']
-     *
-     * _.sortBy(characters, getName);
-     * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred',   'age': 40 }]
-     */
-    function property(key) {
-      return function(object) {
-        return object[key];
-      };
-    }
-
-    /**
-     * Produces a random number between `min` and `max` (inclusive). If only one
-     * argument is provided a number between `0` and the given number will be
-     * returned. If `floating` is truey or either `min` or `max` are floats a
-     * floating-point number will be returned instead of an integer.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {number} [min=0] The minimum possible value.
-     * @param {number} [max=1] The maximum possible value.
-     * @param {boolean} [floating=false] Specify returning a floating-point number.
-     * @returns {number} Returns a random number.
-     * @example
-     *
-     * _.random(0, 5);
-     * // => an integer between 0 and 5
-     *
-     * _.random(5);
-     * // => also an integer between 0 and 5
-     *
-     * _.random(5, true);
-     * // => a floating-point number between 0 and 5
-     *
-     * _.random(1.2, 5.2);
-     * // => a floating-point number between 1.2 and 5.2
-     */
-    function random(min, max, floating) {
-      var noMin = min == null,
-          noMax = max == null;
-
-      if (floating == null) {
-        if (typeof min == 'boolean' && noMax) {
-          floating = min;
-          min = 1;
-        }
-        else if (!noMax && typeof max == 'boolean') {
-          floating = max;
-          noMax = true;
-        }
-      }
-      if (noMin && noMax) {
-        max = 1;
-      }
-      min = +min || 0;
-      if (noMax) {
-        max = min;
-        min = 0;
-      } else {
-        max = +max || 0;
-      }
-      if (floating || min % 1 || max % 1) {
-        var rand = nativeRandom();
-        return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
-      }
-      return baseRandom(min, max);
-    }
-
-    /**
-     * Resolves the value of property `key` on `object`. If `key` is a function
-     * it will be invoked with the `this` binding of `object` and its result returned,
-     * else the property value is returned. If `object` is falsey then `undefined`
-     * is returned.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {Object} object The object to inspect.
-     * @param {string} key The name of the property to resolve.
-     * @returns {*} Returns the resolved value.
-     * @example
-     *
-     * var object = {
-     *   'cheese': 'crumpets',
-     *   'stuff': function() {
-     *     return 'nonsense';
-     *   }
-     * };
-     *
-     * _.result(object, 'cheese');
-     * // => 'crumpets'
-     *
-     * _.result(object, 'stuff');
-     * // => 'nonsense'
-     */
-    function result(object, key) {
-      if (object) {
-        var value = object[key];
-        return isFunction(value) ? object[key]() : value;
-      }
-    }
-
-    /**
-     * A micro-templating method that handles arbitrary delimiters, preserves
-     * whitespace, and correctly escapes quotes within interpolated code.
-     *
-     * Note: In the development build, `_.template` utilizes sourceURLs for easier
-     * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-     *
-     * For more information on precompiling templates see:
-     * https://lodash.com/custom-builds
-     *
-     * For more information on Chrome extension sandboxes see:
-     * http://developer.chrome.com/stable/extensions/sandboxingEval.html
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} text The template text.
-     * @param {Object} data The data object used to populate the text.
-     * @param {Object} [options] The options object.
-     * @param {RegExp} [options.escape] The "escape" delimiter.
-     * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
-     * @param {Object} [options.imports] An object to import into the template as local variables.
-     * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
-     * @param {string} [sourceURL] The sourceURL of the template's compiled source.
-     * @param {string} [variable] The data object variable name.
-     * @returns {Function|string} Returns a compiled function when no `data` object
-     *  is given, else it returns the interpolated text.
-     * @example
-     *
-     * // using the "interpolate" delimiter to create a compiled template
-     * var compiled = _.template('hello <%= name %>');
-     * compiled({ 'name': 'fred' });
-     * // => 'hello fred'
-     *
-     * // using the "escape" delimiter to escape HTML in data property values
-     * _.template('<b><%- value %></b>', { 'value': '<script>' });
-     * // => '<b><script></b>'
-     *
-     * // using the "evaluate" delimiter to generate HTML
-     * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
-     * _.template(list, { 'people': ['fred', 'barney'] });
-     * // => '<li>fred</li><li>barney</li>'
-     *
-     * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
-     * _.template('hello ${ name }', { 'name': 'pebbles' });
-     * // => 'hello pebbles'
-     *
-     * // using the internal `print` function in "evaluate" delimiters
-     * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
-     * // => 'hello barney!'
-     *
-     * // using a custom template delimiters
-     * _.templateSettings = {
-     *   'interpolate': /{{([\s\S]+?)}}/g
-     * };
-     *
-     * _.template('hello {{ name }}!', { 'name': 'mustache' });
-     * // => 'hello mustache!'
-     *
-     * // using the `imports` option to import jQuery
-     * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
-     * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
-     * // => '<li>fred</li><li>barney</li>'
-     *
-     * // using the `sourceURL` option to specify a custom sourceURL for the template
-     * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
-     * compiled(data);
-     * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
-     *
-     * // using the `variable` option to ensure a with-statement isn't used in the compiled template
-     * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
-     * compiled.source;
-     * // => function(data) {
-     *   var __t, __p = '', __e = _.escape;
-     *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
-     *   return __p;
-     * }
-     *
-     * // using the `source` property to inline compiled templates for meaningful
-     * // line numbers in error messages and a stack trace
-     * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
-     *   var JST = {\
-     *     "main": ' + _.template(mainText).source + '\
-     *   };\
-     * ');
-     */
-    function template(text, data, options) {
-      // based on John Resig's `tmpl` implementation
-      // http://ejohn.org/blog/javascript-micro-templating/
-      // and Laura Doktorova's doT.js
-      // https://github.com/olado/doT
-      var settings = lodash.templateSettings;
-      text = String(text || '');
-
-      // avoid missing dependencies when `iteratorTemplate` is not defined
-      options = defaults({}, options, settings);
-
-      var imports = defaults({}, options.imports, settings.imports),
-          importsKeys = keys(imports),
-          importsValues = values(imports);
-
-      var isEvaluating,
-          index = 0,
-          interpolate = options.interpolate || reNoMatch,
-          source = "__p += '";
-
-      // compile the regexp to match each delimiter
-      var reDelimiters = RegExp(
-        (options.escape || reNoMatch).source + '|' +
-        interpolate.source + '|' +
-        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
-        (options.evaluate || reNoMatch).source + '|$'
-      , 'g');
-
-      text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
-        interpolateValue || (interpolateValue = esTemplateValue);
-
-        // escape characters that cannot be included in string literals
-        source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
-
-        // replace delimiters with snippets
-        if (escapeValue) {
-          source += "' +\n__e(" + escapeValue + ") +\n'";
-        }
-        if (evaluateValue) {
-          isEvaluating = true;
-          source += "';\n" + evaluateValue + ";\n__p += '";
-        }
-        if (interpolateValue) {
-          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
-        }
-        index = offset + match.length;
-
-        // the JS engine embedded in Adobe products requires returning the `match`
-        // string in order to produce the correct `offset` value
-        return match;
-      });
-
-      source += "';\n";
-
-      // if `variable` is not specified, wrap a with-statement around the generated
-      // code to add the data object to the top of the scope chain
-      var variable = options.variable,
-          hasVariable = variable;
-
-      if (!hasVariable) {
-        variable = 'obj';
-        source = 'with (' + variable + ') {\n' + source + '\n}\n';
-      }
-      // cleanup code by stripping empty strings
-      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
-        .replace(reEmptyStringMiddle, '$1')
-        .replace(reEmptyStringTrailing, '$1;');
-
-      // frame code as the function body
-      source = 'function(' + variable + ') {\n' +
-        (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
-        "var __t, __p = '', __e = _.escape" +
-        (isEvaluating
-          ? ', __j = Array.prototype.join;\n' +
-            "function print() { __p += __j.call(arguments, '') }\n"
-          : ';\n'
-        ) +
-        source +
-        'return __p\n}';
-
-      // Use a sourceURL for easier debugging.
-      // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-      var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
-
-      try {
-        var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
-      } catch(e) {
-        e.source = source;
-        throw e;
-      }
-      if (data) {
-        return result(data);
-      }
-      // provide the compiled function's source by its `toString` method, in
-      // supported environments, or the `source` property as a convenience for
-      // inlining compiled templates during the build process
-      result.source = source;
-      return result;
-    }
-
-    /**
-     * Executes the callback `n` times, returning an array of the results
-     * of each callback execution. The callback is bound to `thisArg` and invoked
-     * with one argument; (index).
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {number} n The number of times to execute the callback.
-     * @param {Function} callback The function called per iteration.
-     * @param {*} [thisArg] The `this` binding of `callback`.
-     * @returns {Array} Returns an array of the results of each `callback` execution.
-     * @example
-     *
-     * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
-     * // => [3, 6, 4]
-     *
-     * _.times(3, function(n) { mage.castSpell(n); });
-     * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
-     *
-     * _.times(3, function(n) { this.cast(n); }, mage);
-     * // => also calls `mage.castSpell(n)` three times
-     */
-    function times(n, callback, thisArg) {
-      n = (n = +n) > -1 ? n : 0;
-      var index = -1,
-          result = Array(n);
-
-      callback = baseCreateCallback(callback, thisArg, 1);
-      while (++index < n) {
-        result[index] = callback(index);
-      }
-      return result;
-    }
-
-    /**
-     * The inverse of `_.escape` this method converts the HTML entities
-     * `&`, `<`, `>`, `"`, and `'` in `string` to their
-     * corresponding characters.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} string The string to unescape.
-     * @returns {string} Returns the unescaped string.
-     * @example
-     *
-     * _.unescape('Fred, Barney & Pebbles');
-     * // => 'Fred, Barney & Pebbles'
-     */
-    function unescape(string) {
-      return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
-    }
-
-    /**
-     * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
-     *
-     * @static
-     * @memberOf _
-     * @category Utilities
-     * @param {string} [prefix] The value to prefix the ID with.
-     * @returns {string} Returns the unique ID.
-     * @example
-     *
-     * _.uniqueId('contact_');
-     * // => 'contact_104'
-     *
-     * _.uniqueId();
-     * // => '105'
-     */
-    function uniqueId(prefix) {
-      var id = ++idCounter;
-      return String(prefix == null ? '' : prefix) + id;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * Creates a `lodash` object that wraps the given value with explicit
-     * method chaining enabled.
-     *
-     * @static
-     * @memberOf _
-     * @category Chaining
-     * @param {*} value The value to wrap.
-     * @returns {Object} Returns the wrapper object.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney',  'age': 36 },
-     *   { 'name': 'fred',    'age': 40 },
-     *   { 'name': 'pebbles', 'age': 1 }
-     * ];
-     *
-     * var youngest = _.chain(characters)
-     *     .sortBy('age')
-     *     .map(function(chr) { return chr.name + ' is ' + chr.age; })
-     *     .first()
-     *     .value();
-     * // => 'pebbles is 1'
-     */
-    function chain(value) {
-      value = new lodashWrapper(value);
-      value.__chain__ = true;
-      return value;
-    }
-
-    /**
-     * Invokes `interceptor` with the `value` as the first argument and then
-     * returns `value`. The purpose of this method is to "tap into" a method
-     * chain in order to perform operations on intermediate results within
-     * the chain.
-     *
-     * @static
-     * @memberOf _
-     * @category Chaining
-     * @param {*} value The value to provide to `interceptor`.
-     * @param {Function} interceptor The function to invoke.
-     * @returns {*} Returns `value`.
-     * @example
-     *
-     * _([1, 2, 3, 4])
-     *  .tap(function(array) { array.pop(); })
-     *  .reverse()
-     *  .value();
-     * // => [3, 2, 1]
-     */
-    function tap(value, interceptor) {
-      interceptor(value);
-      return value;
-    }
-
-    /**
-     * Enables explicit method chaining on the wrapper object.
-     *
-     * @name chain
-     * @memberOf _
-     * @category Chaining
-     * @returns {*} Returns the wrapper object.
-     * @example
-     *
-     * var characters = [
-     *   { 'name': 'barney', 'age': 36 },
-     *   { 'name': 'fred',   'age': 40 }
-     * ];
-     *
-     * // without explicit chaining
-     * _(characters).first();
-     * // => { 'name': 'barney', 'age': 36 }
-     *
-     * // with explicit chaining
-     * _(characters).chain()
-     *   .first()
-     *   .pick('age')
-     *   .value();
-     * // => { 'age': 36 }
-     */
-    function wrapperChain() {
-      this.__chain__ = true;
-      return this;
-    }
-
-    /**
-     * Produces the `toString` result of the wrapped value.
-     *
-     * @name toString
-     * @memberOf _
-     * @category Chaining
-     * @returns {string} Returns the string result.
-     * @example
-     *
-     * _([1, 2, 3]).toString();
-     * // => '1,2,3'
-     */
-    function wrapperToString() {
-      return String(this.__wrapped__);
-    }
-
-    /**
-     * Extracts the wrapped value.
-     *
-     * @name valueOf
-     * @memberOf _
-     * @alias value
-     * @category Chaining
-     * @returns {*} Returns the wrapped value.
-     * @example
-     *
-     * _([1, 2, 3]).valueOf();
-     * // => [1, 2, 3]
-     */
-    function wrapperValueOf() {
-      return this.__wrapped__;
-    }
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions that return wrapped values when chaining
-    lodash.after = after;
-    lodash.assign = assign;
-    lodash.at = at;
-    lodash.bind = bind;
-    lodash.bindAll = bindAll;
-    lodash.bindKey = bindKey;
-    lodash.chain = chain;
-    lodash.compact = compact;
-    lodash.compose = compose;
-    lodash.constant = constant;
-    lodash.countBy = countBy;
-    lodash.create = create;
-    lodash.createCallback = createCallback;
-    lodash.curry = curry;
-    lodash.debounce = debounce;
-    lodash.defaults = defaults;
-    lodash.defer = defer;
-    lodash.delay = delay;
-    lodash.difference = difference;
-    lodash.filter = filter;
-    lodash.flatten = flatten;
-    lodash.forEach = forEach;
-    lodash.forEachRight = forEachRight;
-    lodash.forIn = forIn;
-    lodash.forInRight = forInRight;
-    lodash.forOwn = forOwn;
-    lodash.forOwnRight = forOwnRight;
-    lodash.functions = functions;
-    lodash.groupBy = groupBy;
-    lodash.indexBy = indexBy;
-    lodash.initial = initial;
-    lodash.intersection = intersection;
-    lodash.invert = invert;
-    lodash.invoke = invoke;
-    lodash.keys = keys;
-    lodash.map = map;
-    lodash.mapValues = mapValues;
-    lodash.max = max;
-    lodash.memoize = memoize;
-    lodash.merge = merge;
-    lodash.min = min;
-    lodash.omit = omit;
-    lodash.once = once;
-    lodash.pairs = pairs;
-    lodash.partial = partial;
-    lodash.partialRight = partialRight;
-    lodash.pick = pick;
-    lodash.pluck = pluck;
-    lodash.property = property;
-    lodash.pull = pull;
-    lodash.range = range;
-    lodash.reject = reject;
-    lodash.remove = remove;
-    lodash.rest = rest;
-    lodash.shuffle = shuffle;
-    lodash.sortBy = sortBy;
-    lodash.tap = tap;
-    lodash.throttle = throttle;
-    lodash.times = times;
-    lodash.toArray = toArray;
-    lodash.transform = transform;
-    lodash.union = union;
-    lodash.uniq = uniq;
-    lodash.values = values;
-    lodash.where = where;
-    lodash.without = without;
-    lodash.wrap = wrap;
-    lodash.xor = xor;
-    lodash.zip = zip;
-    lodash.zipObject = zipObject;
-
-    // add aliases
-    lodash.collect = map;
-    lodash.drop = rest;
-    lodash.each = forEach;
-    lodash.eachRight = forEachRight;
-    lodash.extend = assign;
-    lodash.methods = functions;
-    lodash.object = zipObject;
-    lodash.select = filter;
-    lodash.tail = rest;
-    lodash.unique = uniq;
-    lodash.unzip = zip;
-
-    // add functions to `lodash.prototype`
-    mixin(lodash);
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions that return unwrapped values when chaining
-    lodash.clone = clone;
-    lodash.cloneDeep = cloneDeep;
-    lodash.contains = contains;
-    lodash.escape = escape;
-    lodash.every = every;
-    lodash.find = find;
-    lodash.findIndex = findIndex;
-    lodash.findKey = findKey;
-    lodash.findLast = findLast;
-    lodash.findLastIndex = findLastIndex;
-    lodash.findLastKey = findLastKey;
-    lodash.has = has;
-    lodash.identity = identity;
-    lodash.indexOf = indexOf;
-    lodash.isArguments = isArguments;
-    lodash.isArray = isArray;
-    lodash.isBoolean = isBoolean;
-    lodash.isDate = isDate;
-    lodash.isElement = isElement;
-    lodash.isEmpty = isEmpty;
-    lodash.isEqual = isEqual;
-    lodash.isFinite = isFinite;
-    lodash.isFunction = isFunction;
-    lodash.isNaN = isNaN;
-    lodash.isNull = isNull;
-    lodash.isNumber = isNumber;
-    lodash.isObject = isObject;
-    lodash.isPlainObject = isPlainObject;
-    lodash.isRegExp = isRegExp;
-    lodash.isString = isString;
-    lodash.isUndefined = isUndefined;
-    lodash.lastIndexOf = lastIndexOf;
-    lodash.mixin = mixin;
-    lodash.noConflict = noConflict;
-    lodash.noop = noop;
-    lodash.now = now;
-    lodash.parseInt = parseInt;
-    lodash.random = random;
-    lodash.reduce = reduce;
-    lodash.reduceRight = reduceRight;
-    lodash.result = result;
-    lodash.runInContext = runInContext;
-    lodash.size = size;
-    lodash.some = some;
-    lodash.sortedIndex = sortedIndex;
-    lodash.template = template;
-    lodash.unescape = unescape;
-    lodash.uniqueId = uniqueId;
-
-    // add aliases
-    lodash.all = every;
-    lodash.any = some;
-    lodash.detect = find;
-    lodash.findWhere = find;
-    lodash.foldl = reduce;
-    lodash.foldr = reduceRight;
-    lodash.include = contains;
-    lodash.inject = reduce;
-
-    mixin(function() {
-      var source = {}
-      forOwn(lodash, function(func, methodName) {
-        if (!lodash.prototype[methodName]) {
-          source[methodName] = func;
-        }
-      });
-      return source;
-    }(), false);
-
-    /*--------------------------------------------------------------------------*/
-
-    // add functions capable of returning wrapped and unwrapped values when chaining
-    lodash.first = first;
-    lodash.last = last;
-    lodash.sample = sample;
-
-    // add aliases
-    lodash.take = first;
-    lodash.head = first;
-
-    forOwn(lodash, function(func, methodName) {
-      var callbackable = methodName !== 'sample';
-      if (!lodash.prototype[methodName]) {
-        lodash.prototype[methodName]= function(n, guard) {
-          var chainAll = this.__chain__,
-              result = func(this.__wrapped__, n, guard);
-
-          return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
-            ? result
-            : new lodashWrapper(result, chainAll);
-        };
-      }
-    });
-
-    /*--------------------------------------------------------------------------*/
-
-    /**
-     * The semantic version number.
-     *
-     * @static
-     * @memberOf _
-     * @type string
-     */
-    lodash.VERSION = '2.4.2';
-
-    // add "Chaining" functions to the wrapper
-    lodash.prototype.chain = wrapperChain;
-    lodash.prototype.toString = wrapperToString;
-    lodash.prototype.value = wrapperValueOf;
-    lodash.prototype.valueOf = wrapperValueOf;
-
-    // add `Array` functions that return unwrapped values
-    forEach(['join', 'pop', 'shift'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        var chainAll = this.__chain__,
-            result = func.apply(this.__wrapped__, arguments);
-
-        return chainAll
-          ? new lodashWrapper(result, chainAll)
-          : result;
-      };
-    });
-
-    // add `Array` functions that return the existing wrapped value
-    forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        func.apply(this.__wrapped__, arguments);
-        return this;
-      };
-    });
-
-    // add `Array` functions that return new wrapped values
-    forEach(['concat', 'slice', 'splice'], function(methodName) {
-      var func = arrayRef[methodName];
-      lodash.prototype[methodName] = function() {
-        return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
-      };
-    });
-
-    return lodash;
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  // expose Lo-Dash
-  var _ = runInContext();
-
-  // some AMD build optimizers like r.js check for condition patterns like the following:
-  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
-    // Expose Lo-Dash to the global object even when an AMD loader is present in
-    // case Lo-Dash is loaded with a RequireJS shim config.
-    // See http://requirejs.org/docs/api.html#config-shim
-    root._ = _;
-
-    // define as an anonymous module so, through path mapping, it can be
-    // referenced as the "underscore" module
-    define(function() {
-      return _;
-    });
-  }
-  // check for `exports` after `define` in case a build optimizer adds an `exports` object
-  else if (freeExports && freeModule) {
-    // in Node.js or RingoJS
-    if (moduleExports) {
-      (freeModule.exports = _)._ = _;
-    }
-    // in Narwhal or Rhino -require
-    else {
-      freeExports._ = _;
-    }
-  }
-  else {
-    // in a browser or Rhino
-    root._ = _;
-  }
-}.call(this));
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}]},{},[1]);
diff --git a/debian/missing-source/graphlib-dot/.gitignore b/debian/missing-source/graphlib-dot/.gitignore
new file mode 100644
index 0000000..7d5b7a9
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/.gitignore
@@ -0,0 +1,2 @@
+/build
+/node_modules
diff --git a/debian/missing-source/graphlib-dot/.jscsrc b/debian/missing-source/graphlib-dot/.jscsrc
new file mode 100644
index 0000000..a48833f
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/.jscsrc
@@ -0,0 +1,6 @@
+{
+  "disallowSpaceAfterPrefixUnaryOperators": true,
+  "disallowTrailingWhitespace": true,
+  "maximumLineLength": 100,
+  "validateQuoteMarks": true
+}
diff --git a/debian/missing-source/graphlib-dot/.jshintrc b/debian/missing-source/graphlib-dot/.jshintrc
new file mode 100644
index 0000000..1f6cd62
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/.jshintrc
@@ -0,0 +1,25 @@
+{
+  "camelcase": true,
+  "eqeqeq": true,
+  "expr": true,
+  "freeze": true,
+  "immed": true,
+  "newcap": true,
+  "noarg": true,
+  "quotmark": true,
+  "trailing": true,
+  "undef": true,
+  "unused": true,
+
+  "laxbreak": true,
+
+  "node": true,
+
+  "globals": {
+      "beforeEach": false,
+      "describe": false,
+      "it": false,
+      "Map": true,
+      "Set": true
+  }
+}
diff --git a/debian/missing-source/graphlib-dot/.npmignore b/debian/missing-source/graphlib-dot/.npmignore
new file mode 100644
index 0000000..d36e788
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/.npmignore
@@ -0,0 +1,7 @@
+/browser.js
+/build
+/doc
+/Makefile
+/node_modules
+/src
+/test
diff --git a/debian/missing-source/graphlib-dot/.travis.yml b/debian/missing-source/graphlib-dot/.travis.yml
new file mode 100644
index 0000000..c7900cd
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - "0.10"
+script: KARMA_OPTS="--browsers Firefox,PhantomJS" make -e test
+before_script:
+  - export DISPLAY=:99.0
+  - sh -e /etc/init.d/xvfb start
diff --git a/debian/missing-source/graphlib-dot/LICENSE b/debian/missing-source/graphlib-dot/LICENSE
new file mode 100644
index 0000000..77264b5
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012-2013 Chris Pettitt
+
+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/debian/missing-source/graphlib-dot/Makefile b/debian/missing-source/graphlib-dot/Makefile
new file mode 100644
index 0000000..4c85e29
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/Makefile
@@ -0,0 +1,83 @@
+MOD = graphlib-dot
+
+NPM = npm
+BROWSERIFY = browserify-lite
+ISTANBUL = ./node_modules/istanbul/lib/cli.js
+JSHINT = ./node_modules/jshint/bin/jshint
+JSCS = ./node_modules/jscs/bin/jscs
+KARMA = ./node_modules/karma/bin/karma
+MOCHA = ./node_modules/mocha/bin/_mocha
+PEGJS = pegjs
+UGLIFY = uglifyjs
+
+ISTANBUL_OPTS = --dir $(COVERAGE_DIR) --report html
+JSHINT_OPTS = --reporter node_modules/jshint-stylish/stylish.js
+MOCHA_OPTS = -R dot
+
+BUILD_DIR = build
+COVERAGE_DIR = $(BUILD_DIR)/cov
+DIST_DIR = dist
+
+SRC_FILES = index.js lib/dot-grammar.js lib/version.js $(shell find lib -type f -name '*.js')
+TEST_FILES = $(shell find test -type f -name '*.js' | grep -v 'bundle-test.js')
+BUILD_FILES = $(addprefix $(BUILD_DIR)/, \
+						$(MOD).js $(MOD).min.js)
+
+DIRS = $(BUILD_DIR)
+
+.PHONY: all clean browser-test unit-test test dist
+
+all: unit-test
+
+lib/dot-grammar.js: src/dot-grammar.pegjs
+	$(PEGJS) -e 'module.exports' $< $@
+
+lib/version.js: package.json
+	@src/release/make-version.js > $@
+
+$(DIRS):
+	@mkdir -p $@
+
+test: unit-test browser-test
+
+unit-test: $(SRC_FILES) $(TEST_FILES) node_modules | $(BUILD_DIR)
+	@$(ISTANBUL) cover $(ISTANBUL_OPTS) $(MOCHA) --dir $(COVERAGE_DIR) -- $(MOCHA_OPTS) $(TEST_FILES) || $(MOCHA) $(MOCHA_OPTS) $(TEST_FILES)
+	@$(JSHINT) $(JSHINT_OPTS) $(filter-out node_modules lib/dot-grammar.js, $?)
+	@$(JSCS) $(filter-out node_modules lib/dot-grammar.js, $?)
+
+browser-test: $(BUILD_DIR)/$(MOD).js $(BUILD_DIR)/$(MOD).core.js
+	$(KARMA) start --single-run $(KARMA_OPTS)
+	$(KARMA) start karma.core.conf.js --single-run $(KARMA_OPTS)
+
+bower.json: package.json src/release/make-bower.json.js
+	@src/release/make-bower.json.js > $@
+
+$(BUILD_DIR)/$(MOD).js: browser.js $(SRC_FILES) | $(BUILD_DIR)
+	@$(BROWSERIFY) ./$< --outfile $@
+
+$(BUILD_DIR)/$(MOD).min.js: $(BUILD_DIR)/$(MOD).js
+	@$(UGLIFY) $< --comments '@license' > $@
+
+$(BUILD_DIR)/$(MOD).core.js: browser.js | $(BUILD_DIR)
+	@$(BROWSERIFY) $< > $@ --no-bundle-external
+
+$(BUILD_DIR)/$(MOD).core.min.js: $(BUILD_DIR)/$(MOD).core.js
+	@$(UGLIFY) $< --comments '@license' > $@
+
+dist: $(BUILD_FILES) | bower.json
+	@rm -rf $@
+	@mkdir -p $@
+	cp $^ $@
+
+release: dist
+	@echo
+	@echo Starting release...
+	@echo
+	@src/release/release.sh $(MOD) dist
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+node_modules: package.json
+	@$(NPM) install
+	@touch $@
diff --git a/debian/missing-source/graphlib-dot/README.md b/debian/missing-source/graphlib-dot/README.md
new file mode 100644
index 0000000..4097ea5
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/README.md
@@ -0,0 +1,14 @@
+# graphlib-dot
+
+A [DOT language](http://www.graphviz.org/content/dot-language) parser / writer for [graphlib](https://github.com/cpettitt/graphlib).
+
+[![Build Status](https://secure.travis-ci.org/cpettitt/graphlib-dot.png)](http://travis-ci.org/cpettitt/graphlib-dot)
+
+To learn more about graphlib-dot [see our Wiki](https://github.com/cpettitt/graphlib-dot/wiki).
+
+# License
+
+graphlib-dot is licensed under the terms of the MIT License. See the LICENSE file
+for details.
+
+[npm package manager]: http://npmjs.org/
diff --git a/debian/missing-source/graphlib-dot/browser.js b/debian/missing-source/graphlib-dot/browser.js
new file mode 100644
index 0000000..99d1337
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/browser.js
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012-2013 Chris Pettitt
+ *
+ * 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.
+ */
+global.graphlibDot = require("./index");
diff --git a/debian/missing-source/graphlib-dot/index.js b/debian/missing-source/graphlib-dot/index.js
new file mode 100644
index 0000000..4a23245
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/index.js
@@ -0,0 +1,22 @@
+var read = require("./lib/read-one"),
+    readMany = require("./lib/read-many"),
+    write = require("./lib/write-one"),
+    version = require("./lib/version");
+
+module.exports = {
+  graphlib: require("./lib/graphlib"),
+
+  // Parsing
+  read: read,
+  readMany: readMany,
+
+  // Writing
+  write: write,
+
+  // Version
+  version: version,
+
+  // For levelup encoding
+  type: "dot",
+  buffer: false
+};
diff --git a/debian/missing-source/graphlib-dot/karma.conf.js b/debian/missing-source/graphlib-dot/karma.conf.js
new file mode 100644
index 0000000..1425214
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/karma.conf.js
@@ -0,0 +1,68 @@
+// Karma configuration
+// Generated on Sat Oct 18 2014 17:38:05 GMT-0700 (PDT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['mocha'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      'build/graphlib-dot.js',
+
+      'node_modules/chai/chai.js',
+      'test/bundle-test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome', 'Firefox', 'PhantomJS', 'Safari'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/debian/missing-source/graphlib-dot/karma.core.conf.js b/debian/missing-source/graphlib-dot/karma.core.conf.js
new file mode 100644
index 0000000..b9d6192
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/karma.core.conf.js
@@ -0,0 +1,70 @@
+// Karma configuration
+// Generated on Sat Oct 18 2014 17:38:05 GMT-0700 (PDT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['mocha'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      'node_modules/lodash/lodash.js',
+      'node_modules/graphlib/dist/graphlib.core.js',
+      'build/graphlib-dot.core.js',
+
+      'node_modules/chai/chai.js',
+      'test/bundle-test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome', 'Firefox', 'PhantomJS', 'Safari'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/debian/missing-source/graphlib-dot/lib/build-graph.js b/debian/missing-source/graphlib-dot/lib/build-graph.js
new file mode 100644
index 0000000..e57fcf8
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/lib/build-graph.js
@@ -0,0 +1,129 @@
+"use strict";
+
+var _ = require("./lodash"),
+    Graph = require("./graphlib").Graph;
+
+module.exports = buildGraph;
+
+function buildGraph(parseTree) {
+  var isDirected = parseTree.type !== "graph",
+      isMultigraph = !parseTree.strict,
+      defaultStack = [{ node: {}, edge: {} }],
+      id = parseTree.id,
+      g = new Graph({ directed: isDirected, multigraph: isMultigraph, compound: true });
+      g.setGraph(id === null ? {} : {id: id});
+  _.each(parseTree.stmts, function(stmt) { handleStmt(g, stmt, defaultStack); });
+  return g;
+}
+
+function handleStmt(g, stmt, defaultStack, sg) {
+  switch(stmt.type) {
+    case "node": handleNodeStmt(g, stmt, defaultStack, sg); break;
+    case "edge": handleEdgeStmt(g, stmt, defaultStack, sg); break;
+    case "subgraph": handleSubgraphStmt(g, stmt, defaultStack, sg); break;
+    case "attr": handleAttrStmt(g, stmt, defaultStack); break;
+    case "inlineAttr": handleInlineAttrsStmt(g, stmt, defaultStack, sg); break;
+  }
+}
+
+function handleNodeStmt(g, stmt, defaultStack, sg) {
+  var v = stmt.id,
+      attrs = stmt.attrs;
+  maybeCreateNode(g, v, defaultStack, sg);
+  _.merge(g.node(v), attrs);
+}
+
+function handleEdgeStmt(g, stmt, defaultStack, sg) {
+  var attrs = stmt.attrs,
+      prev, curr;
+  _.each(stmt.elems, function(elem) {
+    handleStmt(g, elem, defaultStack, sg);
+
+    switch(elem.type) {
+      case "node": curr = [elem.id]; break;
+      case "subgraph": curr = collectNodeIds(elem); break;
+    }
+
+    _.each(prev, function(v) {
+      _.each(curr, function(w) {
+        var name;
+        if (g.hasEdge(v, w) && g.isMultigraph()) {
+          name = _.uniqueId("edge");
+        }
+        if (!g.hasEdge(v, w, name)) {
+          g.setEdge(v, w, _.clone(_.last(defaultStack).edge), name);
+        }
+        _.merge(g.edge(v, w, name), attrs);
+      });
+    });
+
+    prev = curr;
+  });
+}
+
+function handleSubgraphStmt(g, stmt, defaultStack, sg) {
+  var id = stmt.id;
+  if (id === undefined) {
+    id = generateSubgraphId(g);
+  }
+
+  defaultStack.push(_.clone(_.last(defaultStack)));
+
+  maybeCreateNode(g, id, defaultStack, sg);
+
+  _.each(stmt.stmts, function(s) {
+    handleStmt(g, s, defaultStack, id);
+  });
+
+  // If there are no statements remove the subgraph
+  if (!g.children(id).length) {
+    g.removeNode(id);
+  }
+
+  defaultStack.pop();
+}
+
+function handleAttrStmt(g, stmt, defaultStack) {
+  _.merge(_.last(defaultStack)[stmt.attrType], stmt.attrs);
+}
+
+function handleInlineAttrsStmt(g, stmt, defaultStack, sg) {
+  _.merge(sg ? g.node(sg) : g.graph(), stmt.attrs);
+}
+
+function generateSubgraphId(g) {
+  var id;
+  do {
+    id = _.uniqueId("sg");
+  } while (g.hasNode(id));
+  return id;
+}
+
+function maybeCreateNode(g, v, defaultStack, sg) {
+  if (!g.hasNode(v)) {
+    g.setNode(v, _.clone(_.last(defaultStack).node));
+    g.setParent(v, sg);
+  }
+}
+
+// Collect all nodes involved in a subgraph statement
+function collectNodeIds(stmt) {
+  var ids = {},
+      stack = [],
+      curr;
+
+  var push = stack.push.bind(stack);
+
+  push(stmt);
+  while(stack.length) {
+    curr = stack.pop();
+    switch(curr.type) {
+      case "node": ids[curr.id] = true; break;
+      case "edge": _.each(curr.elems, push); break;
+      case "subgraph": _.each(curr.stmts, push); break;
+    }
+  }
+
+  return _.keys(ids);
+}
+
diff --git a/debian/missing-source/graphlib-dot/lib/graphlib.js b/debian/missing-source/graphlib-dot/lib/graphlib.js
new file mode 100644
index 0000000..df2a45a
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/lib/graphlib.js
@@ -0,0 +1,15 @@
+/* global window */
+
+var graphlib;
+
+if (require) {
+  try {
+    graphlib = require("graphlib");
+  } catch (e) {}
+}
+
+if (!graphlib) {
+  graphlib = window.graphlib;
+}
+
+module.exports = graphlib;
diff --git a/debian/missing-source/graphlib-dot/lib/index.js b/debian/missing-source/graphlib-dot/lib/index.js
new file mode 100644
index 0000000..88821b5
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/lib/index.js
@@ -0,0 +1,9 @@
+var read = require("./read-one"),
+    readMany = require("./read-many"),
+    write = require("./write-one");
+
+module.exports = {
+  read: read,
+  readMany: readMany,
+  write: write
+};
diff --git a/debian/missing-source/graphlib-dot/lib/lodash.js b/debian/missing-source/graphlib-dot/lib/lodash.js
new file mode 100644
index 0000000..915596b
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/lib/lodash.js
@@ -0,0 +1,15 @@
+/* global window */
+
+var lodash;
+
+if (require) {
+  try {
+    lodash = require("lodash");
+  } catch (e) {}
+}
+
+if (!lodash) {
+  lodash = window._;
+}
+
+module.exports = lodash;
diff --git a/debian/missing-source/graphlib-dot/lib/read-many.js b/debian/missing-source/graphlib-dot/lib/read-many.js
new file mode 100644
index 0000000..6608d1d
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/lib/read-many.js
@@ -0,0 +1,8 @@
+var _ = require("./lodash"),
+    grammar = require("./dot-grammar"),
+    buildGraph = require("./build-graph");
+
+module.exports = function readMany(str) {
+  var parseTree = grammar.parse(str);
+  return _.map(parseTree, buildGraph);
+};
diff --git a/debian/missing-source/graphlib-dot/lib/read-one.js b/debian/missing-source/graphlib-dot/lib/read-one.js
new file mode 100644
index 0000000..1776239
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/lib/read-one.js
@@ -0,0 +1,8 @@
+var grammar = require("./dot-grammar"),
+    buildGraph = require("./build-graph");
+
+module.exports = function readOne(str) {
+  var parseTree = grammar.parse(str, "graphStmt");
+  return buildGraph(parseTree);
+};
+
diff --git a/debian/missing-source/graphlib-dot/lib/write-one.js b/debian/missing-source/graphlib-dot/lib/write-one.js
new file mode 100644
index 0000000..8a39b1e
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/lib/write-one.js
@@ -0,0 +1,127 @@
+var _ = require("./lodash");
+
+module.exports = writeOne;
+
+var UNESCAPED_ID_PATTERN = /^[a-zA-Z\200-\377_][a-zA-Z\200-\377_0-9]*$/;
+
+function writeOne(g) {
+  var ec = g.isDirected() ? "->" : "--",
+      writer = new Writer();
+
+  if (!g.isMultigraph()) {
+    writer.write("strict ");
+  }
+
+  writer.writeLine((g.isDirected() ? "digraph" : "graph") + " {");
+  writer.indent();
+
+  var graphAttrs = g.graph();
+  if (_.isObject(graphAttrs)) {
+    _.each(graphAttrs, function(v, k) {
+      writer.writeLine(id(k) + "=" + id(v) + ";");
+    });
+  }
+
+  writeSubgraph(g, undefined, writer);
+
+  g.edges().forEach(function(edge) {
+    writeEdge(g, edge, ec, writer);
+  });
+
+  writer.unindent();
+  writer.writeLine("}");
+
+  return writer.toString();
+}
+
+function writeSubgraph(g, v, writer) {
+  var children = g.isCompound() ? g.children(v) : g.nodes();
+  _.each(children, function(w) {
+    if (!g.isCompound() || !g.children(w).length) {
+      writeNode(g, w, writer);
+    } else {
+      writer.writeLine("subgraph " + id(w) + " {");
+      writer.indent();
+
+      if (_.isObject(g.node(w))) {
+        _.map(g.node(w), function(val, key) {
+          writer.writeLine(id(key) + "=" + id(val) + ";");
+        });
+      }
+
+      writeSubgraph(g, w, writer);
+      writer.unindent();
+      writer.writeLine("}");
+    }
+  });
+}
+
+function writeNode(g, v, writer) {
+  writer.write(id(v));
+  writeAttrs(g.node(v), writer);
+  writer.writeLine();
+}
+
+function writeEdge(g, edge, ec, writer) {
+  var v = edge.v,
+      w = edge.w,
+      attrs = g.edge(edge);
+
+  writer.write(id(v) + " " + ec + " " + id(w));
+  writeAttrs(attrs, writer);
+  writer.writeLine();
+}
+
+function writeAttrs(attrs, writer) {
+  if (_.isObject(attrs)) {
+    var attrStrs = _.map(attrs, function(val, key) {
+      return id(key) + "=" + id(val);
+    });
+    if (attrStrs.length) {
+      writer.write(" [" + attrStrs.join(",") + "]");
+    }
+  }
+}
+
+function id(obj) {
+  if (typeof obj === "number" || obj.toString().match(UNESCAPED_ID_PATTERN)) {
+    return obj;
+  }
+
+  return "\"" + obj.toString().replace(/"/g, "\\\"") + "\"";
+}
+
+// Helper object for making a pretty printer
+function Writer() {
+  this._indent = "";
+  this._content = "";
+  this._shouldIndent = true;
+}
+
+Writer.prototype.INDENT = "  ";
+
+Writer.prototype.indent = function() {
+  this._indent += this.INDENT;
+};
+
+Writer.prototype.unindent = function() {
+  this._indent = this._indent.slice(this.INDENT.length);
+};
+
+Writer.prototype.writeLine = function(line) {
+  this.write((line || "") + "\n");
+  this._shouldIndent = true;
+};
+
+Writer.prototype.write = function(str) {
+  if (this._shouldIndent) {
+    this._shouldIndent = false;
+    this._content += this._indent;
+  }
+  this._content += str;
+};
+
+Writer.prototype.toString = function() {
+  return this._content;
+};
+
diff --git a/debian/missing-source/graphlib-dot/package.json b/debian/missing-source/graphlib-dot/package.json
new file mode 100644
index 0000000..7d4bc96
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/package.json
@@ -0,0 +1,43 @@
+{
+  "name": "graphlib-dot",
+  "version": "0.6.2",
+  "description": "A DOT language parser / writer for graphlib",
+  "author": "Chris Pettitt <cpettitt at gmail.com>",
+  "main": "index.js",
+  "keywords": [
+    "graph",
+    "dot",
+    "parse"
+  ],
+  "dependencies": {
+    "graphlib": "^1.0.1",
+    "lodash": "^2.4.1"
+  },
+  "devDependencies": {
+    "browserify": "^6.1.0",
+    "chai": "^1.9.2",
+    "istanbul": "^0.3.2",
+    "jscs": "^1.7.3",
+    "jshint": "^2.5.6",
+    "jshint-stylish": "^1.0.0",
+    "karma": "^0.12.24",
+    "karma-chrome-launcher": "^0.1.5",
+    "karma-firefox-launcher": "^0.1.3",
+    "karma-mocha": "^0.1.9",
+    "karma-phantomjs-launcher": "^0.1.4",
+    "karma-safari-launcher": "^0.1.1",
+    "mocha": "^1.21.5",
+    "pegjs": "^0.8.0",
+    "semver": "^4.1.0",
+    "sprintf": "^0.1.4",
+    "uglify-js": "^2.4.15"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/cpettitt/graphlib-dot.git"
+  },
+  "contributors": [
+    "Dominic Tarr <dominic.tarr at gmail.com> (http://bit.ly/dominictarr)"
+  ],
+  "license": "MIT"
+}
diff --git a/debian/missing-source/graphlib-dot/src/dot-grammar.pegjs b/debian/missing-source/graphlib-dot/src/dot-grammar.pegjs
new file mode 100644
index 0000000..cbd311e
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/src/dot-grammar.pegjs
@@ -0,0 +1,153 @@
+// Simplified DOT grammar
+//
+// Not supported (yet):
+//
+//  * HTML IDs
+
+{
+  var _ = require("./lodash");
+  var directed;
+}
+
+start
+  = graphStmt+
+
+graphStmt
+  = _* strict:(strict _)? type:graphType _* id:(id)? _* '{' _* stmts:stmtList? _* '}' _* {
+      return {type: type, id: id, strict: strict !== null, stmts: stmts};
+    }
+
+stmtList
+  = first:stmt _* ';'? rest:(_* inner:stmt _* ';'?)* {
+      var result = [first];
+      for (var i = 0; i < rest.length; ++i) {
+        result.push(rest[i][1]);
+      }
+      return result;
+    }
+
+stmt
+  = attrStmt
+  / edgeStmt
+  / subgraphStmt
+  / inlineAttrStmt
+  / nodeStmt
+
+attrStmt
+  = type:(graph / node /edge) _* attrs:attrList {
+      return { type: "attr", attrType: type, attrs: attrs || {}};
+    }
+
+inlineAttrStmt
+  = k:id _* '=' _* v:id {
+      var attrs = {};
+      attrs[k] = v;
+      return { type: "inlineAttr", attrs: attrs };
+    } 
+
+nodeStmt
+  = id:nodeId _* attrs:attrList? { return {type: "node", id: id, attrs: attrs || {}}; }
+
+edgeStmt
+  = lhs:(nodeIdOrSubgraph) _* rhs:edgeRHS _* attrs:attrList? {
+      var elems = [lhs];
+      for (var i = 0; i < rhs.length; ++i) {
+        elems.push(rhs[i]);
+      }
+      return { type: "edge", elems: elems, attrs: attrs || {} };
+    }
+
+subgraphStmt
+  = id:(subgraph _* (id _*)?)? '{' _* stmts:stmtList? _* '}' {
+      id = (id && id[2]) || [];
+      return { type: "subgraph", id: id[0], stmts: stmts };
+    }
+
+attrList
+  = first:attrListBlock rest:(_* attrListBlock)* {
+      var result = first;
+      for (var i = 0; i < rest.length; ++i) {
+        _.merge(result, rest[i][1]);
+      }
+      return result;
+    }
+
+attrListBlock
+  = '[' _* aList:aList? _* ']' { return aList; }
+
+aList
+  = first:idDef rest:(_* ','? _* idDef)* {
+      var result = first;
+      for (var i = 0; i < rest.length; ++i) {
+        _.merge(result, rest[i][3]);
+      }
+      return result;
+    }
+
+edgeRHS
+  = ("--" !{ return directed; } / "->" &{ return directed; }) _* rhs:(nodeIdOrSubgraph) _* rest:edgeRHS? {
+      var result = [rhs];
+      if (rest) {
+        for (var i = 0; i < rest.length; ++i) {
+          result.push(rest[i]);
+        }
+      }
+      return result;
+    }
+
+idDef
+  = k:id v:(_* '=' _* id)? {
+      var result = {};
+      result[k] = v[3];
+      return result;
+    }
+
+nodeIdOrSubgraph
+  = subgraphStmt
+  / id:nodeId { return { type: "node", id: id, attrs: {} }; }
+
+nodeId
+  = id:id _* port? { return id; }
+
+port
+  = ':' _* id _* (':' _* compassPt)?
+
+compassPt
+  = "ne" / "se" / "sw" / "nw" / "n" / "e" / "s" / "w" / "c" / "_"
+
+id "identifier"
+  = fst:[a-zA-Z\u0200-\u0377_] rest:[a-zA-Z\u0200-\u0377_0-9]* { return fst + rest.join(""); }
+  / sign:'-'? dot:'.' after:[0-9]+ {
+      return (sign || "") + dot + after.join("");
+    }
+  / sign:'-'? before:[0-9]+ after:('.' [0-9]*)? {
+      return (sign || "") + before.join("") + (after ? after[0] : "") + (after ? after[1].join("") : "");
+    }
+  / '"' id:("\\\"" { return '"'; } / "\\" ch:[^"] { return "\\" + ch; }  / [^"])* '"' {
+      return id.join("");
+    }
+
+node = k:"node"i { return k.toLowerCase(); }
+edge = k:"edge"i { return k.toLowerCase(); }
+graph = k:"graph"i { return k.toLowerCase(); }
+digraph = k:"digraph"i { return k.toLowerCase(); }
+subgraph = k:"subgraph"i { return k.toLowerCase(); }
+strict = k:"strict"i { return k.toLowerCase(); }
+
+graphType
+  = graph:graph / graph:digraph {
+      directed = graph === "digraph";
+      return graph;
+    }
+
+whitespace "whitespace"
+  = [ \t\r\n]+
+
+comment "comment"
+  = "//" ([^\n])*
+  / "/*" (!"*/" .)* "*/"
+
+_
+  = whitespace
+  / comment
+
diff --git a/debian/missing-source/graphlib-dot/src/release/bump-version.js b/debian/missing-source/graphlib-dot/src/release/bump-version.js
new file mode 100755
index 0000000..80f7b3d
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/src/release/bump-version.js
@@ -0,0 +1,26 @@
+#!/usr/bin/env node
+
+/*
+ * Bumps the minor version and sets the prelease tag.
+ */
+
+var fs = require("fs"),
+    semver = require("semver");
+
+var packageFile = fs.readFileSync("package.json");
+var packageJson = JSON.parse(packageFile);
+
+if (!("version" in packageJson)) {
+  bail("ERROR: Could not find version in package.json");
+}
+
+var ver = semver.parse(packageJson.version);
+packageJson.version = ver.inc("patch").toString() + "-pre";
+
+fs.writeFileSync("package.json", JSON.stringify(packageJson, undefined, 2));
+
+// Write an error message to stderr and then exit immediately with an error.
+function bail(msg) {
+  stderr.write(msg + "\n");
+  process.exit(1);
+}
diff --git a/debian/missing-source/graphlib-dot/src/release/check-version.js b/debian/missing-source/graphlib-dot/src/release/check-version.js
new file mode 100755
index 0000000..1890158
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/src/release/check-version.js
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+
+/*
+ * Prints the current version from the specified package-file to stdout or
+ * fails with an error if either the version cannot be determined or it is
+ * a pre-release.
+ */
+
+var fs = require("fs"),
+    semver = require("semver");
+
+var packageFile = fs.readFileSync("package.json");
+var packageJson = JSON.parse(packageFile);
+
+if (!("version" in packageJson)) {
+  bail("ERROR: Could not find version in package.json");
+}
+
+var ver = semver.parse(packageJson.version),
+    preRelease = process.env.PRE_RELEASE;
+
+if (ver.prerelease.length > 0 && !preRelease) {
+  bail("ERROR: version is a pre-release: " + ver);
+}
+
+console.log(ver.toString());
+
+// Write an error message to stderr and then exit immediately with an error.
+function bail(msg) {
+  process.stderr.write(msg + "\n");
+  process.exit(1);
+}
diff --git a/debian/missing-source/graphlib-dot/src/release/make-bower.json.js b/debian/missing-source/graphlib-dot/src/release/make-bower.json.js
new file mode 100755
index 0000000..a3b7944
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/src/release/make-bower.json.js
@@ -0,0 +1,29 @@
+#!/usr/bin/env node
+
+// Renders the bower.json template and prints it to stdout
+
+var packageJson = require("../../package.json");
+
+var template = {
+  name: packageJson.name,
+  version: packageJson.version,
+  main: ["dist/" + packageJson.name + ".core.js", "dist/" + packageJson.name + ".core.min.js"],
+  ignore: [
+    ".*",
+    "README.md",
+    "CHANGELOG.md",
+    "Makefile",
+    "browser.js",
+    "dist/" + packageJson.name + ".js",
+    "dist/" + packageJson.name + ".min.js",
+    "index.js",
+    "karma*",
+    "lib/**",
+    "package.json",
+    "src/**",
+    "test/**"
+  ],
+  dependencies: packageJson.dependencies
+};
+
+console.log(JSON.stringify(template, null, 2));
diff --git a/debian/missing-source/graphlib-dot/src/release/make-version.js b/debian/missing-source/graphlib-dot/src/release/make-version.js
new file mode 100755
index 0000000..39f2642
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/src/release/make-version.js
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+var package = require('../../package.json');
+console.log('module.exports = \'' + package.version + '\';');
diff --git a/debian/missing-source/graphlib-dot/src/release/release.sh b/debian/missing-source/graphlib-dot/src/release/release.sh
new file mode 100755
index 0000000..106a9a3
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/src/release/release.sh
@@ -0,0 +1,67 @@
+# Fail on error
+set -e
+[ -n "$DEBUG"] && set -x
+
+bail() {
+    echo $1 >&2
+    exit 1
+}
+
+# Initial config
+PROJECT=$1
+PROJECT_ROOT=`pwd`
+PAGES_DIR=/tmp/$PROJECT-pages
+DIST_DIR=$2
+
+# Check version. Is this a release? If not abort
+VERSION=$(./src/release/check-version.js)
+SHORT_VERSION=$(echo $VERSION | cut -f1 -d-)
+
+echo Attemping to publish version: $VERSION
+
+# Preflight checks
+[ -n "$PROJECT" ] || bail "No project name was specified."
+[ -n "$DIST_DIR" ] || bail "No dist dir was specified."
+[ -z "`git tag -l v$VERSION`" ] || bail "Version already published. Skipping publish."
+[ "`git rev-parse HEAD`" = "`git rev-parse master`" ] || [ -n "$PRE_RELEASE" ] || bail "ERROR: You must release from the master branch"
+[ -z "`git status --porcelain`" ] || bail "ERROR: Dirty index on working tree. Use git status to check"
+
+# Publish to pages
+rm -rf $PAGES_DIR
+git clone git at github.com:cpettitt/cpettitt.github.com.git $PAGES_DIR
+
+TMP_TARGET=$PAGES_DIR/project/$PROJECT/latest
+rm -rf $TMP_TARGET
+mkdir -p $TMP_TARGET
+cp -r $DIST_DIR/*.js $TMP_TARGET
+
+TMP_TARGET=$PAGES_DIR/project/$PROJECT/v$VERSION
+rm -rf $TMP_TARGET
+mkdir -p $TMP_TARGET
+cp -r $DIST_DIR/*.js $TMP_TARGET
+
+cd $PAGES_DIR/project/$PROJECT
+git add -A
+git commit -m "Publishing $PROJECT v$VERSION"
+git push -f origin master
+cd $PROJECT_ROOT
+echo "Published $PROJECT to pages"
+
+# Publish tag
+git tag v$VERSION
+git push origin
+git push origin v$VERSION
+echo Published $PROJECT v$VERSION
+
+# Publish to npm
+npm publish
+echo Published to npm
+
+# Update patch level version + commit
+./src/release/bump-version.js
+make lib/version.js
+git commit package.json lib/version.js -m "Bump version and set as pre-release"
+git push origin
+echo Updated patch version
+
+echo Release complete!
diff --git a/debian/missing-source/graphlib-dot/test/bundle-test.js b/debian/missing-source/graphlib-dot/test/bundle-test.js
new file mode 100644
index 0000000..d2b7c23
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/test/bundle-test.js
@@ -0,0 +1,32 @@
+/* global chai, graphlibDot */
+
+// These are smoke tests to make sure the bundles look like they are working
+// correctly.
+
+var expect = chai.expect,
+    graphlib = graphlibDot.graphlib;
+
+describe("bundle", function() {
+  it("exports graphlibDot", function() {
+    expect(graphlibDot).to.be.an("object");
+    ["read", "readMany", "write"].forEach(function(fn) {
+      expect(graphlibDot[fn]).to.be.a("function");
+    });
+    expect(graphlibDot.graphlib).to.be.an("object");
+    expect(graphlibDot.version).to.be.a("string");
+  });
+
+  it("can serialize to DOT and back", function() {
+    var g = new graphlib.Graph();
+    g.setNode("a", { label: "a" });
+    g.setNode("b", { label: "b" });
+    g.setEdge("a", "b", { label: "ab" });
+
+    var dot = graphlibDot.write(g),
+        g2 = graphlibDot.read(dot);
+
+    expect(g2.node("a")).eqls({ label: "a" });
+    expect(g2.node("b")).eqls({ label: "b" });
+    expect(g2.edge("a", "b")).eqls({ label: "ab" });
+  });
+});
diff --git a/debian/missing-source/graphlib-dot/test/chai.js b/debian/missing-source/graphlib-dot/test/chai.js
new file mode 100644
index 0000000..ba88ca6
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/test/chai.js
@@ -0,0 +1,5 @@
+var chai = require("chai");
+
+module.exports = chai;
+
+chai.config.includeStack = true;
diff --git a/debian/missing-source/graphlib-dot/test/read-many-test.js b/debian/missing-source/graphlib-dot/test/read-many-test.js
new file mode 100644
index 0000000..3792a65
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/test/read-many-test.js
@@ -0,0 +1,12 @@
+var expect = require("./chai").expect,
+    readMany = require("..").readMany;
+
+describe("readMany", function() {
+  it("can read multiple graphs", function() {
+    var gs = readMany("digraph {} graph {}");
+    expect(gs).to.have.length(2);
+    expect(gs[0].isDirected()).to.be.true;
+    expect(gs[1].isDirected()).to.be.false;
+  });
+});
+
diff --git a/debian/missing-source/graphlib-dot/test/read-one-test.js b/debian/missing-source/graphlib-dot/test/read-one-test.js
new file mode 100644
index 0000000..f5dee4d
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/test/read-one-test.js
@@ -0,0 +1,375 @@
+var _ = require("lodash"),
+    expect = require("./chai").expect,
+    read = require("..").read;
+
+describe("read", function() {
+  describe("graph", function() {
+    it("can read an empty digraph", function() {
+      var g = read("digraph {}");
+      expect(g.nodeCount()).to.equal(0);
+      expect(g.edgeCount()).to.equal(0);
+      expect(g.graph()).to.eql({});
+      expect(g.isDirected()).to.be.true;
+      expect(g.isMultigraph()).to.be.true;
+    });
+
+    it("can read an empty graph", function() {
+      var g = read("graph {}");
+      expect(g.nodeCount()).to.equal(0);
+      expect(g.edgeCount()).to.equal(0);
+      expect(g.graph()).to.eql({});
+      expect(g.isDirected()).to.be.false;
+      expect(g.isMultigraph()).to.be.true;
+    });
+
+    it("can read a strict graph", function() {
+      var g = read("strict digraph {}");
+      expect(g.isMultigraph()).to.be.false;
+    });
+
+    it("can handle leading and trailing whitespace", function() {
+      var g = read(" digraph {} ");
+      expect(g.nodeCount()).to.equal(0);
+      expect(g.edgeCount()).to.equal(0);
+      expect(g.graph()).to.eql({});
+      expect(g.isDirected()).to.be.true;
+    });
+
+    it("safely incorporates the id for the graph", function() {
+      var g = read("digraph foobar {}");
+      expect(g.nodeCount()).to.equal(0);
+      expect(g.edgeCount()).to.equal(0);
+      expect(g.graph()).to.eql({id: "foobar"});
+      expect(g.isDirected()).to.be.true;
+    });
+
+    it("can read graph attributes", function() {
+      var g = read("digraph { foo = bar; }");
+      expect(g.graph()).eql({ foo: "bar" });
+    });
+
+    it("can handle various forms of whitespace", function() {
+      var g = read("digraph {\tfoo\r=bar\n; }");
+      expect(g.graph()).to.eql({ foo: "bar" });
+    });
+  });
+
+  describe("comments", function() {
+    it("ignores single-line comments", function() {
+      var g = read("digraph { a //comment\n }");
+      expect(g.hasNode("a")).to.be.true;
+    });
+
+    it("ignores multi-line comments", function() {
+      var g = read("digraph { a /*comment*/\n }");
+      expect(g.hasNode("a")).to.be.true;
+    });
+  });
+
+  describe("nodes", function() {
+    it("can read a single node graph", function() {
+      var g = read("digraph { a }");
+      expect(g.nodeCount()).to.equal(1);
+      expect(g.hasNode("a")).to.be.true;
+      expect(g.edgeCount()).to.equal(0);
+    });
+
+    it("can read a node with an attribute", function() {
+      var g = read("digraph { a [label=foo]; }");
+      expect(g.node("a")).to.eql({ label: "foo" });
+    });
+
+    it("can read a node with a quoted attribute", function() {
+      var g = read("digraph { a [label=\"foo and bar\"]; }");
+      expect(g.node("a")).to.eql({ label: "foo and bar" });
+    });
+
+    it("can read a node with comma-separated attributes", function() {
+      var g = read("digraph { a [label=l, foo=f, bar=b]; }");
+      expect(g.node("a")).to.eql({ label: "l", foo: "f", bar: "b" });
+    });
+
+    it("can read a node with space-separated attributes", function() {
+      var g = read("digraph { a [label=l foo=f bar=b]; }");
+      expect(g.node("a")).to.eql({ label: "l", foo: "f", bar: "b" });
+    });
+
+    it("can read a node with multiple attr defs", function() {
+      var g = read("digraph { a [label=l] [foo=1] [foo=2]; }");
+      expect(g.node("a")).to.eql({ label: "l", foo: "2" });
+    });
+
+    it("can read nodes with numeric ids", function() {
+      var list = ["12", "-12", "12.34", "-12.34", ".34", "-.34", "12.", "-12."];
+      var g = read("digraph { " + list.join(";") + " }");
+      expect(_.sortBy(g.nodes())).to.eql(_.sortBy(list));
+    });
+
+    it("can read escaped quotes", function() {
+      expect(read("digraph { \"\\\"a\\\"\" }").nodes()).to.eql(["\"a\""]);
+    });
+
+    it("preserves non-quote escapes", function() {
+      expect(read("digraph { \"foo\\-bar\" }").nodes()).to.eql(["foo\\-bar"]);
+    });
+
+    it("can read quoted unicode", function() {
+      var g = read("digraph { \"♖♘♗♕♔♗♘♖\" }");
+      expect(g.nodes()).to.eql(["♖♘♗♕♔♗♘♖"]);
+    });
+
+    it("fails to read unquoted unicode", function() {
+      expect(function() { read("digraph { ♖♘♗♕♔♗♘♖ }"); }).to.throw();
+    });
+
+    it("treats a number id followed by a letter as two nodes", function() {
+      // Yes this is what the language specifies!
+      var g = read("digraph { 123a }");
+      expect(_.sortBy(g.nodes())).to.eql(["123", "a"]);
+    });
+
+    it("ignores node ports", function() {
+      var g = read("digraph { a:port }");
+      expect(g.node("a")).to.eql({});
+    });
+
+    var compass = ["n", "ne", "e", "se", "s", "sw", "w", "nw", "c", "_"];
+    it("ignores node compass", function() {
+      _.each(compass, function(c) {
+        expect(read("digraph { a:" + c + " }").node("a")).to.eql({});
+        expect(read("digraph { a : " + c + " }").node("a")).to.eql({});
+      });
+    });
+
+    it("ignores node port compass", function() {
+      _.each(compass, function(c) {
+        expect(read("digraph { a:port:" + c + " }").node("a")).to.eql({});
+        expect(read("digraph { a : port : " + c + " }").node("a")).to.eql({});
+      });
+    });
+  });
+
+  describe("edges", function() {
+    it("can read an unlabelled undirected edge", function() {
+      var g = read("strict graph { a -- b }");
+      expect(g.edgeCount()).to.equal(1);
+      expect(g.edge("a", "b")).to.eql({});
+    });
+
+    it("fails if reading an undirected edge in a directed graph", function() {
+      expect(function() { read("graph { a -> b }"); }).to.throw();
+    });
+
+    it("can read an unlabelled directed edge", function() {
+      var g = read("strict digraph { a -> b }");
+      expect(g.edgeCount()).to.equal(1);
+      expect(g.edge("a", "b")).to.eql({});
+    });
+
+    it("fails if reading a directed edge in an undirected graph", function() {
+      expect(function() { read("digraph { a -- b }"); }).to.throw();
+    });
+
+    it("can read an edge with attributes", function() {
+      var g = read("strict digraph { a -> b [label=foo]; }");
+      expect(g.edge("a", "b")).to.eql({ label: "foo" });
+    });
+
+    it("can assign attributes to a path of nodes", function() {
+      var g = read("strict digraph { a -> b -> c [label=foo]; }");
+      expect(g.edge("a", "b")).to.eql({ label: "foo" });
+      expect(g.edge("b", "c")).to.eql({ label: "foo" });
+      expect(g.edgeCount()).to.equal(2);
+    });
+
+    it("assigns multiple labels if an edge is defined multiple times", function() {
+      var g = read("digraph { a -> b [x=1 z=3]; a -> b [y=2 z=4] }");
+      var results = _.map(g.nodeEdges("a", "b"), function(edge) {
+        return g.edge(edge);
+      });
+      expect(_.sortBy(results, "z")).to.eql([
+        { x: "1", z: "3" },
+        { y: "2", z: "4" }
+      ]);
+      expect(g.edgeCount()).to.equal(2);
+    });
+
+    it("updates an edge if it is defined multiple times in strict mode", function() {
+      var g = read("strict digraph { a -> b [x=1 z=3]; a -> b [y=2 z=4] }");
+      expect(g.edge("a", "b")).to.eql({ x: "1", y: "2", z: "4" });
+      expect(g.edgeCount()).to.equal(1);
+    });
+  });
+
+  describe("subgraphs", function() {
+    it("ignores empty subgraphs", function() {
+      expect(read("digraph { subgraph X {} }").nodes()).to.be.empty;
+      expect(read("digraph { subgraph {} }").nodes()).to.be.empty;
+      expect(read("digraph { {} }").nodes()).to.be.empty;
+    });
+
+    it("reads nodes in a subgraph", function() {
+      var g = read("digraph { subgraph X { a; b }; c }");
+      expect(_.sortBy(g.nodes())).to.eql(["X", "a", "b", "c"]);
+      expect(_.sortBy(g.children())).to.eql(["X", "c"]);
+      expect(_.sortBy(g.children("X"))).to.eql(["a", "b"]);
+    });
+
+    it("assigns a node to the first subgraph in which it appears", function() {
+      var g = read("digraph { subgraph X { a }; subgraph Y { a; b } }");
+      expect(g.parent("a")).to.equal("X");
+      expect(g.parent("b")).to.equal("Y");
+    });
+
+    it("reads edges in a subgraph", function() {
+      var g = read("strict digraph { subgraph X { a; b; a -> b } }");
+      expect(_.sortBy(g.nodes())).to.eql(["X", "a", "b"]);
+      expect(_.sortBy(g.children("X"))).to.eql(["a", "b"]);
+      expect(g.edge("a", "b")).to.eql({});
+      expect(g.edgeCount()).to.equal(1);
+    });
+
+    it("assigns graph attributes to the subgraph in which they appear", function() {
+      var g = read("strict digraph { subgraph X { foo=bar; a } }");
+      expect(g.graph()).to.eql({});
+      expect(g.node("X")).to.eql({ foo: "bar" });
+    });
+
+    it("reads anonymous subgraphs #1", function() {
+      var g = read("digraph { subgraph { a } }");
+      expect(g.parent("a")).to.not.be.undefined;
+      expect(g.parent(g.parent("a"))).to.be.undefined;
+    });
+
+    it("reads anonymous subgraphs #2", function() {
+      var g = read("digraph { { a } }");
+      expect(g.parent("a")).to.not.be.undefined;
+      expect(g.parent(g.parent("a"))).to.be.undefined;
+    });
+
+    it("reads subgraphs as the LHS of an edge statement", function() {
+      var g = read("digraph { {a; b} -> c }");
+      expect(g.hasEdge("a", "c")).to.be.true;
+      expect(g.hasEdge("b", "c")).to.be.true;
+      expect(g.edgeCount()).to.equal(2);
+    });
+
+    it("reads subgraphs as the RHS of an edge statement", function() {
+      var g = read("digraph { a -> { b; c } }");
+      expect(g.hasEdge("a", "b")).to.be.true;
+      expect(g.hasEdge("a", "c")).to.be.true;
+      expect(g.edgeCount()).to.equal(2);
+    });
+
+    it("handles subgraphs with edges as an LHS of another edge statment", function() {
+      var g = read("digraph { {a -> b} -> c }");
+      expect(g.hasEdge("a", "b")).to.be.true;
+      expect(g.hasEdge("a", "c")).to.be.true;
+      expect(g.hasEdge("b", "c")).to.be.true;
+      expect(g.edgeCount()).to.equal(3);
+    });
+
+    it("reads subgraphs as both the LHS and RHS side of an edge statement", function() {
+      var g = read("digraph { { a; b } -> { c; d } }");
+      expect(g.hasEdge("a", "c")).to.be.true;
+      expect(g.hasEdge("a", "d")).to.be.true;
+      expect(g.hasEdge("b", "c")).to.be.true;
+      expect(g.hasEdge("b", "d")).to.be.true;
+      expect(g.edgeCount()).to.equal(4);
+    });
+
+    it("applies edges attributes when using subgraphs as LHS or RHS", function() {
+      var g = read("strict digraph { { a; b } -> { c; d } [foo=bar] }");
+      expect(g.edge("a", "c")).to.eql({ foo: "bar" });
+      expect(g.edge("a", "d")).to.eql({ foo: "bar" });
+      expect(g.edge("b", "c")).to.eql({ foo: "bar" });
+      expect(g.edge("b", "d")).to.eql({ foo: "bar" });
+      expect(g.edgeCount()).to.equal(4);
+    });
+  });
+
+  describe("defaults", function() {
+    it("adds default attributes to nodes", function() {
+      var g = read("digraph { node [color=black]; a [label=foo]; b [label=bar] }");
+      expect(g.node("a")).to.eql({ color: "black", label: "foo" });
+      expect(g.node("b")).to.eql({ color: "black", label: "bar" });
+    });
+
+    it("can apply multiple node defaults", function() {
+      var g = read("digraph { node[color=black]; node[shape=box]; a [label=foo] }");
+      expect(g.node("a")).to.eql({ color: "black", shape: "box", label: "foo" });
+    });
+
+    it("only applies defaults already visited", function() {
+      var g = read("digraph { node[color=black]; a; node[shape=box]; b; }");
+      expect(g.node("a")).to.eql({ color: "black" });
+      expect(g.node("b")).to.eql({ color: "black", shape: "box" });
+    });
+
+    it("only applies defaults to nodes created in the subgraph", function() {
+      var g = read("digraph { a; { node[color=black]; a; b; } }");
+      expect(g.node("a")).to.eql({});
+      expect(g.node("b")).to.eql({ color: "black" });
+    });
+
+    it("allows defaults to redefined", function() {
+      var g = read("digraph { node[color=black]; a; node[color=green]; b; }");
+      expect(g.node("a")).to.eql({ color: "black" });
+      expect(g.node("b")).to.eql({ color: "green" });
+    });
+
+    it("applies defaults to nodes created through an edge statement", function() {
+      var g = read("digraph { node[color=black]; a -> b; }");
+      expect(g.node("a")).to.eql({ color: "black" });
+      expect(g.node("b")).to.eql({ color: "black" });
+    });
+
+    it("applies defaults to subgraphs", function() {
+      var g = read("digraph { node[color=black]; { a; { b; c[color=green]; } } }");
+      expect(g.node("a")).to.eql({ color: "black" });
+      expect(g.node("b")).to.eql({ color: "black" });
+      expect(g.node("c")).to.eql({ color: "green" });
+    });
+
+    it("applies defaults to edges", function() {
+      var g = read("strict digraph { edge[color=black]; a -> b }");
+      expect(g.node("a")).to.eql({});
+      expect(g.node("b")).to.eql({});
+      expect(g.edge("a", "b")).to.eql({ color: "black" });
+    });
+  });
+
+  describe("failure cases", function() {
+    it("fails if the graph block is not closed", function() {
+      expect(function() { read("digraph {"); }).to.throw();
+    });
+
+    it("fails if an attribute block is not closed", function() {
+      expect(function() { read("digraph { a [k=v}"); }).to.throw();
+    });
+
+    it("fails if an attribute is missing a key", function() {
+      expect(function() { read("digraph { a [=v] }"); }).to.throw();
+    });
+
+    it("fails if an attribute is missing a value", function() {
+      expect(function() { read("digraph { a [k=] }"); }).to.throw();
+    });
+
+    it("fails if an edge is missing an LHS", function() {
+      expect(function() { read("digraph { -> b }"); }).to.throw();
+    });
+
+    it("fails if an edge is missing an RHS", function() {
+      expect(function() { read("digraph { a -> }"); }).to.throw();
+    });
+
+    it("fails if a subgraph is left unclosed", function() {
+      expect(function() { read("digraph { { a "); }).to.throw();
+    });
+
+    it("fails if a new subgraph is opened after a previous one", function() {
+      expect(function() { read("digraph {} digraph {}"); }).to.throw();
+    });
+  });
+});
diff --git a/debian/missing-source/graphlib-dot/test/version-test.js b/debian/missing-source/graphlib-dot/test/version-test.js
new file mode 100644
index 0000000..e151b2c
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/test/version-test.js
@@ -0,0 +1,8 @@
+var expect = require('./chai').expect;
+
+describe('version', function() {
+  it('should match the version from package.json', function() {
+    var packageVersion = require('../package').version;
+    expect(require('..').version).to.equal(packageVersion);
+  });
+});
diff --git a/debian/missing-source/graphlib-dot/test/write-test.js b/debian/missing-source/graphlib-dot/test/write-test.js
new file mode 100644
index 0000000..aa40067
--- /dev/null
+++ b/debian/missing-source/graphlib-dot/test/write-test.js
@@ -0,0 +1,137 @@
+var _ = require("lodash"),
+    expect = require("./chai").expect,
+    Graph = require("graphlib").Graph,
+    read = require("..").read,
+    write = require("..").write;
+
+describe("write", function() {
+  it("can write an empty digraph", function() {
+    var str = write(new Graph());
+    var g = read(str);
+    expect(g.nodeCount()).to.equal(0);
+    expect(g.edgeCount()).to.equal(0);
+    expect(g.graph()).to.eql({});
+    expect(g.isDirected()).to.be.true;
+  });
+
+  it("can write an empty undirected graph", function() {
+    var str = write(new Graph({ directed: false }));
+    var g = read(str);
+    expect(g.nodeCount()).to.equal(0);
+    expect(g.edgeCount()).to.equal(0);
+    expect(g.graph()).to.eql({});
+    expect(g.isDirected()).to.be.false;
+  });
+
+  it("can write a graph label with an object", function() {
+    var g = new Graph();
+    g.setGraph({ foo: "bar" });
+    var str = write(g);
+    var g2 = read(str);
+    expect(g2.graph()).to.eql({ foo: "bar" });
+  });
+
+  it("can write a node", function() {
+    var g = new Graph();
+    g.setNode("n1");
+    var str = write(g);
+    var g2 = read(str);
+    expect(g2.hasNode("n1")).to.be.true;
+    expect(g2.node("n1")).to.eql({});
+    expect(g2.nodeCount()).to.equal(1);
+    expect(g2.edgeCount()).to.equal(0);
+  });
+
+  it("can write a node with attributes", function() {
+    var g = new Graph();
+    g.setNode("n1", { foo: "bar" });
+    var str = write(g);
+    var g2 = read(str);
+    expect(g2.hasNode("n1"));
+    expect(g2.node("n1")).to.eql({ foo: "bar" });
+    expect(g2.nodeCount()).to.equal(1);
+    expect(g2.edgeCount()).to.equal(0);
+  });
+
+  it("can write an edge", function() {
+    var g = new Graph();
+    g.setEdge("n1", "n2");
+    var str = write(g, { strict: true });
+    var g2 = read(str);
+    expect(g2.edge("n1", "n2")).to.eql({});
+    expect(g2.nodeCount()).to.equal(2);
+    expect(g2.edgeCount()).to.equal(1);
+  });
+
+  it("can write an edge with attributes", function() {
+    var g = new Graph();
+    g.setEdge("n1", "n2", { foo: "bar" });
+    var str = write(g, { strict: true });
+    var g2 = read(str);
+    expect(g2.edge("n1", "n2")).to.eql({ foo: "bar" });
+    expect(g2.nodeCount()).to.equal(2);
+    expect(g2.edgeCount()).to.equal(1);
+  });
+
+  it("can write multi-edges", function() {
+    var g = new Graph({ multigraph: true });
+    g.setEdge("n1", "n2", { foo: "bar" });
+    g.setEdge("n1", "n2", { foo: "baz" }, "another");
+    var str = write(g);
+    var g2 = read(str);
+    expect(g2.nodeEdges("n1", "n2")).to.have.length(2);
+    var edgeAttrs = _.map(g2.nodeEdges("n1", "n2"), function(edge) {
+      return g2.edge(edge);
+    });
+    expect(_.sortBy(edgeAttrs)).to.eql([
+      { foo: "bar" },
+      { foo: "baz" }
+    ]);
+    expect(g2.nodeCount()).to.equal(2);
+    expect(g2.edgeCount()).to.equal(2);
+  });
+
+  it("preserves the strict (non-multigraph) state", function() {
+    var g = new Graph();
+    var str = write(g);
+    var g2 = read(str);
+    expect(g2.isMultigraph()).to.be.false;
+  });
+
+  it("can write ids that must be escaped", function() {
+    var g = new Graph();
+    g.setNode("\"n1\"");
+    var str = write(g);
+    var g2 = read(str);
+    expect(g2.hasNode("\"n1\"")).to.be.true;
+    expect(g2.node("\"n1\"")).to.eql({});
+    expect(g2.nodeCount()).to.equal(1);
+    expect(g2.edgeCount()).to.equal(0);
+  });
+
+  it("can write subgraphs", function() {
+    var g = new Graph({ compound: true });
+    g.setParent("n1", "root");
+    var str = write(g);
+    var g2 = read(str);
+    expect(g2.hasNode("n1")).to.be.true;
+    expect(g2.hasNode("root")).to.be.true;
+    expect(g2.parent("n1")).to.equal("root");
+    expect(g2.nodeCount()).to.equal(2);
+    expect(g2.edgeCount()).to.equal(0);
+  });
+
+  it("can write subgraphs with attributes", function() {
+    var g = new Graph({ compound: true });
+    g.setParent("n1", "root");
+    g.setNode("root", { foo: "bar" });
+    var str = write(g);
+    var g2 = read(str);
+    expect(g2.hasNode("n1")).to.be.true;
+    expect(g2.hasNode("root")).to.be.true;
+    expect(g2.node("root")).to.eql({ foo: "bar" });
+    expect(g2.parent("n1")).to.equal("root");
+    expect(g2.nodeCount()).to.equal(2);
+    expect(g2.edgeCount()).to.equal(0);
+  });
+});
diff --git a/debian/missing-source/graphlib/.gitignore b/debian/missing-source/graphlib/.gitignore
new file mode 100644
index 0000000..7d5b7a9
--- /dev/null
+++ b/debian/missing-source/graphlib/.gitignore
@@ -0,0 +1,2 @@
+/build
+/node_modules
diff --git a/debian/missing-source/graphlib/.jscsrc b/debian/missing-source/graphlib/.jscsrc
new file mode 100644
index 0000000..a48833f
--- /dev/null
+++ b/debian/missing-source/graphlib/.jscsrc
@@ -0,0 +1,6 @@
+{
+  "disallowSpaceAfterPrefixUnaryOperators": true,
+  "disallowTrailingWhitespace": true,
+  "maximumLineLength": 100,
+  "validateQuoteMarks": true
+}
diff --git a/debian/missing-source/graphlib/.jshintrc b/debian/missing-source/graphlib/.jshintrc
new file mode 100644
index 0000000..1f6cd62
--- /dev/null
+++ b/debian/missing-source/graphlib/.jshintrc
@@ -0,0 +1,25 @@
+{
+  "camelcase": true,
+  "eqeqeq": true,
+  "expr": true,
+  "freeze": true,
+  "immed": true,
+  "newcap": true,
+  "noarg": true,
+  "quotmark": true,
+  "trailing": true,
+  "undef": true,
+  "unused": true,
+
+  "laxbreak": true,
+
+  "node": true,
+
+  "globals": {
+      "beforeEach": false,
+      "describe": false,
+      "it": false,
+      "Map": true,
+      "Set": true
+  }
+}
diff --git a/debian/missing-source/graphlib/.npmignore b/debian/missing-source/graphlib/.npmignore
new file mode 100644
index 0000000..e4d4dce
--- /dev/null
+++ b/debian/missing-source/graphlib/.npmignore
@@ -0,0 +1,8 @@
+/browser.js
+/bench
+/build
+/doc
+/Makefile
+/node_modules
+/src
+/test
diff --git a/debian/missing-source/graphlib/.travis.yml b/debian/missing-source/graphlib/.travis.yml
new file mode 100644
index 0000000..0842667
--- /dev/null
+++ b/debian/missing-source/graphlib/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - "0.10"
+script: KARMA_OPTS="--browsers Firefox,PhantomJS" make -e test
+before_script:
+  - export DISPLAY=:99.0        
+  - sh -e /etc/init.d/xvfb start
diff --git a/debian/missing-source/graphlib/LICENSE b/debian/missing-source/graphlib/LICENSE
new file mode 100644
index 0000000..7d7dd94
--- /dev/null
+++ b/debian/missing-source/graphlib/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012-2014 Chris Pettitt
+
+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/debian/missing-source/graphlib/Makefile b/debian/missing-source/graphlib/Makefile
new file mode 100644
index 0000000..f05dd9f
--- /dev/null
+++ b/debian/missing-source/graphlib/Makefile
@@ -0,0 +1,83 @@
+MOD = graphlib
+
+NPM = npm
+BROWSERIFY = ./node_modules/browserify/bin/cmd.js
+ISTANBUL = ./node_modules/istanbul/lib/cli.js
+JSHINT = ./node_modules/jshint/bin/jshint
+JSCS = ./node_modules/jscs/bin/jscs
+KARMA = ./node_modules/karma/bin/karma
+MOCHA = ./node_modules/mocha/bin/_mocha
+UGLIFY = ./node_modules/uglify-js/bin/uglifyjs
+
+ISTANBUL_OPTS = --dir $(COVERAGE_DIR) --report html
+JSHINT_OPTS = --reporter node_modules/jshint-stylish/stylish.js
+MOCHA_OPTS = -R dot
+
+BUILD_DIR = build
+COVERAGE_DIR = $(BUILD_DIR)/cov
+DIST_DIR = dist
+
+SRC_FILES = index.js lib/version.js $(shell find lib -type f -name '*.js')
+TEST_FILES = $(shell find test -type f -name '*.js' | grep -v 'bundle-test.js')
+BUILD_FILES = $(addprefix $(BUILD_DIR)/, \
+						$(MOD).js $(MOD).min.js \
+						$(MOD).core.js $(MOD).core.min.js)
+
+DIRS = $(BUILD_DIR)
+
+.PHONY: all bench clean browser-test unit-test test dist
+
+all: unit-test
+
+bench: test
+	@src/bench.js
+
+lib/version.js: package.json
+	@src/release/make-version.js > $@
+
+$(DIRS):
+	@mkdir -p $@
+
+test: unit-test browser-test
+
+unit-test: $(SRC_FILES) $(TEST_FILES) node_modules | $(BUILD_DIR)
+	@$(ISTANBUL) cover $(ISTANBUL_OPTS) $(MOCHA) --dir $(COVERAGE_DIR) -- $(MOCHA_OPTS) $(TEST_FILES) || $(MOCHA) $(MOCHA_OPTS) $(TEST_FILES)
+	@$(JSHINT) $(JSHINT_OPTS) $(filter-out node_modules, $?)
+	@$(JSCS) $(filter-out node_modules, $?)
+
+browser-test: $(BUILD_DIR)/$(MOD).js $(BUILD_DIR)/$(MOD).core.js
+	$(KARMA) start --single-run $(KARMA_OPTS)
+	$(KARMA) start karma.core.conf.js --single-run $(KARMA_OPTS)
+
+bower.json: package.json src/release/make-bower.json.js
+	@src/release/make-bower.json.js > $@
+
+$(BUILD_DIR)/$(MOD).js: browser.js $(SRC_FILES) | unit-test
+	@$(BROWSERIFY) $< > $@
+
+$(BUILD_DIR)/$(MOD).min.js: $(BUILD_DIR)/$(MOD).js
+	@$(UGLIFY) $< --comments '@license' > $@
+
+$(BUILD_DIR)/$(MOD).core.js: browser.js $(SRC_FILES) | unit-test
+	@$(BROWSERIFY) $< > $@ --no-bundle-external
+
+$(BUILD_DIR)/$(MOD).core.min.js: $(BUILD_DIR)/$(MOD).core.js
+	@$(UGLIFY) $< --comments '@license' > $@
+
+dist: $(BUILD_FILES) | bower.json test
+	@rm -rf $@
+	@mkdir -p $@
+	@cp $^ dist
+
+release: dist
+	@echo
+	@echo Starting release...
+	@echo
+	@src/release/release.sh $(MOD) dist
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+node_modules: package.json
+	@$(NPM) install
+	@touch $@
diff --git a/debian/missing-source/graphlib/README.md b/debian/missing-source/graphlib/README.md
new file mode 100644
index 0000000..1e6f479
--- /dev/null
+++ b/debian/missing-source/graphlib/README.md
@@ -0,0 +1,16 @@
+# Graphlib
+
+Graphlib is a JavaScript library that provides data structures for undirected
+and directed multi-graphs along with algorithms that can be used with them.
+
+[![Build Status](https://secure.travis-ci.org/cpettitt/graphlib.png)](http://travis-ci.org/cpettitt/graphlib)
+
+To learn more [see our Wiki](https://github.com/cpettitt/graphlib/wiki).
+
+# License
+
+Graphlib is licensed under the terms of the MIT License. See the
+[LICENSE](LICENSE) file
+aor details.
+
+[npm package manager]: http://npmjs.org/
diff --git a/debian/missing-source/graphlib/bower.json b/debian/missing-source/graphlib/bower.json
new file mode 100644
index 0000000..edfabba
--- /dev/null
+++ b/debian/missing-source/graphlib/bower.json
@@ -0,0 +1,25 @@
+{
+  "name": "graphlib",
+  "version": "1.0.7",
+  "main": [
+    "dist/graphlib.core.js"
+  ],
+  "ignore": [
+    ".*",
+    "README.md",
+    "CHANGELOG.md",
+    "Makefile",
+    "browser.js",
+    "dist/graphlib.js",
+    "dist/graphlib.min.js",
+    "index.js",
+    "karma*",
+    "lib/**",
+    "package.json",
+    "src/**",
+    "test/**"
+  ],
+  "dependencies": {
+    "lodash": "^3.10.0"
+  }
+}
diff --git a/debian/missing-source/graphlib/browser.js b/debian/missing-source/graphlib/browser.js
new file mode 100644
index 0000000..eb671e9
--- /dev/null
+++ b/debian/missing-source/graphlib/browser.js
@@ -0,0 +1,31 @@
+/**
+ * @license
+ * Copyright (c) 2014, Chris Pettitt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+global.graphlib = require('./index');
diff --git a/debian/missing-source/graphlib/index.js b/debian/missing-source/graphlib/index.js
new file mode 100644
index 0000000..0b861f2
--- /dev/null
+++ b/debian/missing-source/graphlib/index.js
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2014, Chris Pettitt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var lib = require("./lib");
+
+module.exports = {
+  Graph: lib.Graph,
+  json: require("./lib/json"),
+  alg: require("./lib/alg"),
+  version: lib.version
+};
diff --git a/debian/missing-source/graphlib/karma.conf.js b/debian/missing-source/graphlib/karma.conf.js
new file mode 100644
index 0000000..2824ac5
--- /dev/null
+++ b/debian/missing-source/graphlib/karma.conf.js
@@ -0,0 +1,68 @@
+// Karma configuration
+// Generated on Sat Oct 18 2014 17:38:05 GMT-0700 (PDT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['mocha'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      'build/graphlib.js',
+
+      'node_modules/chai/chai.js',
+      'test/bundle-test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome', 'Firefox', 'PhantomJS', 'Safari'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/debian/missing-source/graphlib/karma.core.conf.js b/debian/missing-source/graphlib/karma.core.conf.js
new file mode 100644
index 0000000..7fae8b4
--- /dev/null
+++ b/debian/missing-source/graphlib/karma.core.conf.js
@@ -0,0 +1,69 @@
+// Karma configuration
+// Generated on Sat Oct 18 2014 17:38:05 GMT-0700 (PDT)
+
+module.exports = function(config) {
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['mocha'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      'node_modules/lodash/index.js',
+      'build/graphlib.core.js',
+
+      'node_modules/chai/chai.js',
+      'test/bundle-test.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+    },
+
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['progress'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['Chrome', 'Firefox', 'PhantomJS', 'Safari'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/debian/missing-source/graphlib/lib/alg/components.js b/debian/missing-source/graphlib/lib/alg/components.js
new file mode 100644
index 0000000..bc2fb31
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/components.js
@@ -0,0 +1,27 @@
+var _ = require("../lodash");
+
+module.exports = components;
+
+function components(g) {
+  var visited = {},
+      cmpts = [],
+      cmpt;
+
+  function dfs(v) {
+    if (_.has(visited, v)) return;
+    visited[v] = true;
+    cmpt.push(v);
+    _.each(g.successors(v), dfs);
+    _.each(g.predecessors(v), dfs);
+  }
+
+  _.each(g.nodes(), function(v) {
+    cmpt = [];
+    dfs(v);
+    if (cmpt.length) {
+      cmpts.push(cmpt);
+    }
+  });
+
+  return cmpts;
+}
diff --git a/debian/missing-source/graphlib/lib/alg/dfs.js b/debian/missing-source/graphlib/lib/alg/dfs.js
new file mode 100644
index 0000000..ddf8df8
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/dfs.js
@@ -0,0 +1,39 @@
+var _ = require("../lodash");
+
+module.exports = dfs;
+
+/*
+ * A helper that preforms a pre- or post-order traversal on the input graph
+ * and returns the nodes in the order they were visited. This algorithm treats
+ * the input as undirected.
+ *
+ * Order must be one of "pre" or "post".
+ */
+function dfs(g, vs, order) {
+  if (!_.isArray(vs)) {
+    vs = [vs];
+  }
+
+  var acc = [],
+      visited = {};
+  _.each(vs, function(v) {
+    if (!g.hasNode(v)) {
+      throw new Error("Graph does not have node: " + v);
+    }
+
+    doDfs(g, v, order === "post", visited, acc);
+  });
+  return acc;
+}
+
+function doDfs(g, v, postorder, visited, acc) {
+  if (!_.has(visited, v)) {
+    visited[v] = true;
+
+    if (!postorder) { acc.push(v); }
+    _.each(g.neighbors(v), function(w) {
+      doDfs(g, w, postorder, visited, acc);
+    });
+    if (postorder) { acc.push(v); }
+  }
+}
diff --git a/debian/missing-source/graphlib/lib/alg/dijkstra-all.js b/debian/missing-source/graphlib/lib/alg/dijkstra-all.js
new file mode 100644
index 0000000..3dfcc18
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/dijkstra-all.js
@@ -0,0 +1,10 @@
+var dijkstra = require("./dijkstra"),
+    _ = require("../lodash");
+
+module.exports = dijkstraAll;
+
+function dijkstraAll(g, weightFunc, edgeFunc) {
+  return _.transform(g.nodes(), function(acc, v) {
+    acc[v] = dijkstra(g, v, weightFunc, edgeFunc);
+  }, {});
+}
diff --git a/debian/missing-source/graphlib/lib/alg/dijkstra.js b/debian/missing-source/graphlib/lib/alg/dijkstra.js
new file mode 100644
index 0000000..4bd4eed
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/dijkstra.js
@@ -0,0 +1,54 @@
+var _ = require("../lodash"),
+    PriorityQueue = require("../data/priority-queue");
+
+module.exports = dijkstra;
+
+var DEFAULT_WEIGHT_FUNC = _.constant(1);
+
+function dijkstra(g, source, weightFn, edgeFn) {
+  return runDijkstra(g, String(source),
+                     weightFn || DEFAULT_WEIGHT_FUNC,
+                     edgeFn || function(v) { return g.outEdges(v); });
+}
+
+function runDijkstra(g, source, weightFn, edgeFn) {
+  var results = {},
+      pq = new PriorityQueue(),
+      v, vEntry;
+
+  var updateNeighbors = function(edge) {
+    var w = edge.v !== v ? edge.v : edge.w,
+        wEntry = results[w],
+        weight = weightFn(edge),
+        distance = vEntry.distance + weight;
+
+    if (weight < 0) {
+      throw new Error("dijkstra does not allow negative edge weights. " +
+                      "Bad edge: " + edge + " Weight: " + weight);
+    }
+
+    if (distance < wEntry.distance) {
+      wEntry.distance = distance;
+      wEntry.predecessor = v;
+      pq.decrease(w, distance);
+    }
+  };
+
+  g.nodes().forEach(function(v) {
+    var distance = v === source ? 0 : Number.POSITIVE_INFINITY;
+    results[v] = { distance: distance };
+    pq.add(v, distance);
+  });
+
+  while (pq.size() > 0) {
+    v = pq.removeMin();
+    vEntry = results[v];
+    if (vEntry.distance === Number.POSITIVE_INFINITY) {
+      break;
+    }
+
+    edgeFn(v).forEach(updateNeighbors);
+  }
+
+  return results;
+}
diff --git a/debian/missing-source/graphlib/lib/alg/find-cycles.js b/debian/missing-source/graphlib/lib/alg/find-cycles.js
new file mode 100644
index 0000000..8864f61
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/find-cycles.js
@@ -0,0 +1,10 @@
+var _ = require("../lodash"),
+    tarjan = require("./tarjan");
+
+module.exports = findCycles;
+
+function findCycles(g) {
+  return _.filter(tarjan(g), function(cmpt) {
+    return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0]));
+  });
+}
diff --git a/debian/missing-source/graphlib/lib/alg/floyd-warshall.js b/debian/missing-source/graphlib/lib/alg/floyd-warshall.js
new file mode 100644
index 0000000..e23b066
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/floyd-warshall.js
@@ -0,0 +1,50 @@
+var _ = require("../lodash");
+
+module.exports = floydWarshall;
+
+var DEFAULT_WEIGHT_FUNC = _.constant(1);
+
+function floydWarshall(g, weightFn, edgeFn) {
+  return runFloydWarshall(g,
+                          weightFn || DEFAULT_WEIGHT_FUNC,
+                          edgeFn || function(v) { return g.outEdges(v); });
+}
+
+function runFloydWarshall(g, weightFn, edgeFn) {
+  var results = {},
+      nodes = g.nodes();
+
+  nodes.forEach(function(v) {
+    results[v] = {};
+    results[v][v] = { distance: 0 };
+    nodes.forEach(function(w) {
+      if (v !== w) {
+        results[v][w] = { distance: Number.POSITIVE_INFINITY };
+      }
+    });
+    edgeFn(v).forEach(function(edge) {
+      var w = edge.v === v ? edge.w : edge.v,
+          d = weightFn(edge);
+      results[v][w] = { distance: d, predecessor: v };
+    });
+  });
+
+  nodes.forEach(function(k) {
+    var rowK = results[k];
+    nodes.forEach(function(i) {
+      var rowI = results[i];
+      nodes.forEach(function(j) {
+        var ik = rowI[k];
+        var kj = rowK[j];
+        var ij = rowI[j];
+        var altDistance = ik.distance + kj.distance;
+        if (altDistance < ij.distance) {
+          ij.distance = altDistance;
+          ij.predecessor = kj.predecessor;
+        }
+      });
+    });
+  });
+
+  return results;
+}
diff --git a/debian/missing-source/graphlib/lib/alg/index.js b/debian/missing-source/graphlib/lib/alg/index.js
new file mode 100644
index 0000000..2c3d76f
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/index.js
@@ -0,0 +1,13 @@
+module.exports = {
+  components: require("./components"),
+  dijkstra: require("./dijkstra"),
+  dijkstraAll: require("./dijkstra-all"),
+  findCycles: require("./find-cycles"),
+  floydWarshall: require("./floyd-warshall"),
+  isAcyclic: require("./is-acyclic"),
+  postorder: require("./postorder"),
+  preorder: require("./preorder"),
+  prim: require("./prim"),
+  tarjan: require("./tarjan"),
+  topsort: require("./topsort")
+};
diff --git a/debian/missing-source/graphlib/lib/alg/is-acyclic.js b/debian/missing-source/graphlib/lib/alg/is-acyclic.js
new file mode 100644
index 0000000..eff4ef0
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/is-acyclic.js
@@ -0,0 +1,15 @@
+var topsort = require("./topsort");
+
+module.exports = isAcyclic;
+
+function isAcyclic(g) {
+  try {
+    topsort(g);
+  } catch (e) {
+    if (e instanceof topsort.CycleException) {
+      return false;
+    }
+    throw e;
+  }
+  return true;
+}
diff --git a/debian/missing-source/graphlib/lib/alg/postorder.js b/debian/missing-source/graphlib/lib/alg/postorder.js
new file mode 100644
index 0000000..1d82313
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/postorder.js
@@ -0,0 +1,7 @@
+var dfs = require("./dfs");
+
+module.exports = postorder;
+
+function postorder(g, vs) {
+  return dfs(g, vs, "post");
+}
diff --git a/debian/missing-source/graphlib/lib/alg/preorder.js b/debian/missing-source/graphlib/lib/alg/preorder.js
new file mode 100644
index 0000000..cf333cd
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/preorder.js
@@ -0,0 +1,7 @@
+var dfs = require("./dfs");
+
+module.exports = preorder;
+
+function preorder(g, vs) {
+  return dfs(g, vs, "pre");
+}
diff --git a/debian/missing-source/graphlib/lib/alg/prim.js b/debian/missing-source/graphlib/lib/alg/prim.js
new file mode 100644
index 0000000..8fd90b8
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/prim.js
@@ -0,0 +1,52 @@
+var _ = require("../lodash"),
+    Graph = require("../graph"),
+    PriorityQueue = require("../data/priority-queue");
+
+module.exports = prim;
+
+function prim(g, weightFunc) {
+  var result = new Graph(),
+      parents = {},
+      pq = new PriorityQueue(),
+      v;
+
+  function updateNeighbors(edge) {
+    var w = edge.v === v ? edge.w : edge.v,
+        pri = pq.priority(w);
+    if (pri !== undefined) {
+      var edgeWeight = weightFunc(edge);
+      if (edgeWeight < pri) {
+        parents[w] = v;
+        pq.decrease(w, edgeWeight);
+      }
+    }
+  }
+
+  if (g.nodeCount() === 0) {
+    return result;
+  }
+
+  _.each(g.nodes(), function(v) {
+    pq.add(v, Number.POSITIVE_INFINITY);
+    result.setNode(v);
+  });
+
+  // Start from an arbitrary node
+  pq.decrease(g.nodes()[0], 0);
+
+  var init = false;
+  while (pq.size() > 0) {
+    v = pq.removeMin();
+    if (_.has(parents, v)) {
+      result.setEdge(v, parents[v]);
+    } else if (init) {
+      throw new Error("Input graph is not connected: " + g);
+    } else {
+      init = true;
+    }
+
+    g.nodeEdges(v).forEach(updateNeighbors);
+  }
+
+  return result;
+}
diff --git a/debian/missing-source/graphlib/lib/alg/tarjan.js b/debian/missing-source/graphlib/lib/alg/tarjan.js
new file mode 100644
index 0000000..6756e74
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/tarjan.js
@@ -0,0 +1,47 @@
+var _ = require("../lodash");
+
+module.exports = tarjan;
+
+function tarjan(g) {
+  var index = 0,
+      stack = [],
+      visited = {}, // node id -> { onStack, lowlink, index }
+      results = [];
+
+  function dfs(v) {
+    var entry = visited[v] = {
+      onStack: true,
+      lowlink: index,
+      index: index++
+    };
+    stack.push(v);
+
+    g.successors(v).forEach(function(w) {
+      if (!_.has(visited, w)) {
+        dfs(w);
+        entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
+      } else if (visited[w].onStack) {
+        entry.lowlink = Math.min(entry.lowlink, visited[w].index);
+      }
+    });
+
+    if (entry.lowlink === entry.index) {
+      var cmpt = [],
+          w;
+      do {
+        w = stack.pop();
+        visited[w].onStack = false;
+        cmpt.push(w);
+      } while (v !== w);
+      results.push(cmpt);
+    }
+  }
+
+  g.nodes().forEach(function(v) {
+    if (!_.has(visited, v)) {
+      dfs(v);
+    }
+  });
+
+  return results;
+}
diff --git a/debian/missing-source/graphlib/lib/alg/topsort.js b/debian/missing-source/graphlib/lib/alg/topsort.js
new file mode 100644
index 0000000..0964b17
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/alg/topsort.js
@@ -0,0 +1,34 @@
+var _ = require("../lodash");
+
+module.exports = topsort;
+topsort.CycleException = CycleException;
+
+function topsort(g) {
+  var visited = {},
+      stack = {},
+      results = [];
+
+  function visit(node) {
+    if (_.has(stack, node)) {
+      throw new CycleException();
+    }
+
+    if (!_.has(visited, node)) {
+      stack[node] = true;
+      visited[node] = true;
+      _.each(g.predecessors(node), visit);
+      delete stack[node];
+      results.push(node);
+    }
+  }
+
+  _.each(g.sinks(), visit);
+
+  if (_.size(visited) !== g.nodeCount()) {
+    throw new CycleException();
+  }
+
+  return results;
+}
+
+function CycleException() {}
diff --git a/debian/missing-source/graphlib/lib/data/priority-queue.js b/debian/missing-source/graphlib/lib/data/priority-queue.js
new file mode 100644
index 0000000..b58ae82
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/data/priority-queue.js
@@ -0,0 +1,152 @@
+var _ = require("../lodash");
+
+module.exports = PriorityQueue;
+
+/**
+ * A min-priority queue data structure. This algorithm is derived from Cormen,
+ * et al., "Introduction to Algorithms". The basic idea of a min-priority
+ * queue is that you can efficiently (in O(1) time) get the smallest key in
+ * the queue. Adding and removing elements takes O(log n) time. A key can
+ * have its priority decreased in O(log n) time.
+ */
+function PriorityQueue() {
+  this._arr = [];
+  this._keyIndices = {};
+}
+
+/**
+ * Returns the number of elements in the queue. Takes `O(1)` time.
+ */
+PriorityQueue.prototype.size = function() {
+  return this._arr.length;
+};
+
+/**
+ * Returns the keys that are in the queue. Takes `O(n)` time.
+ */
+PriorityQueue.prototype.keys = function() {
+  return this._arr.map(function(x) { return x.key; });
+};
+
+/**
+ * Returns `true` if **key** is in the queue and `false` if not.
+ */
+PriorityQueue.prototype.has = function(key) {
+  return _.has(this._keyIndices, key);
+};
+
+/**
+ * Returns the priority for **key**. If **key** is not present in the queue
+ * then this function returns `undefined`. Takes `O(1)` time.
+ *
+ * @param {Object} key
+ */
+PriorityQueue.prototype.priority = function(key) {
+  var index = this._keyIndices[key];
+  if (index !== undefined) {
+    return this._arr[index].priority;
+  }
+};
+
+/**
+ * Returns the key for the minimum element in this queue. If the queue is
+ * empty this function throws an Error. Takes `O(1)` time.
+ */
+PriorityQueue.prototype.min = function() {
+  if (this.size() === 0) {
+    throw new Error("Queue underflow");
+  }
+  return this._arr[0].key;
+};
+
+/**
+ * Inserts a new key into the priority queue. If the key already exists in
+ * the queue this function returns `false`; otherwise it will return `true`.
+ * Takes `O(n)` time.
+ *
+ * @param {Object} key the key to add
+ * @param {Number} priority the initial priority for the key
+ */
+PriorityQueue.prototype.add = function(key, priority) {
+  var keyIndices = this._keyIndices;
+  key = String(key);
+  if (!_.has(keyIndices, key)) {
+    var arr = this._arr;
+    var index = arr.length;
+    keyIndices[key] = index;
+    arr.push({key: key, priority: priority});
+    this._decrease(index);
+    return true;
+  }
+  return false;
+};
+
+/**
+ * Removes and returns the smallest key in the queue. Takes `O(log n)` time.
+ */
+PriorityQueue.prototype.removeMin = function() {
+  this._swap(0, this._arr.length - 1);
+  var min = this._arr.pop();
+  delete this._keyIndices[min.key];
+  this._heapify(0);
+  return min.key;
+};
+
+/**
+ * Decreases the priority for **key** to **priority**. If the new priority is
+ * greater than the previous priority, this function will throw an Error.
+ *
+ * @param {Object} key the key for which to raise priority
+ * @param {Number} priority the new priority for the key
+ */
+PriorityQueue.prototype.decrease = function(key, priority) {
+  var index = this._keyIndices[key];
+  if (priority > this._arr[index].priority) {
+    throw new Error("New priority is greater than current priority. " +
+        "Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority);
+  }
+  this._arr[index].priority = priority;
+  this._decrease(index);
+};
+
+PriorityQueue.prototype._heapify = function(i) {
+  var arr = this._arr;
+  var l = 2 * i,
+      r = l + 1,
+      largest = i;
+  if (l < arr.length) {
+    largest = arr[l].priority < arr[largest].priority ? l : largest;
+    if (r < arr.length) {
+      largest = arr[r].priority < arr[largest].priority ? r : largest;
+    }
+    if (largest !== i) {
+      this._swap(i, largest);
+      this._heapify(largest);
+    }
+  }
+};
+
+PriorityQueue.prototype._decrease = function(index) {
+  var arr = this._arr;
+  var priority = arr[index].priority;
+  var parent;
+  while (index !== 0) {
+    parent = index >> 1;
+    if (arr[parent].priority < priority) {
+      break;
+    }
+    this._swap(index, parent);
+    index = parent;
+  }
+};
+
+PriorityQueue.prototype._swap = function(i, j) {
+  var arr = this._arr;
+  var keyIndices = this._keyIndices;
+  var origArrI = arr[i];
+  var origArrJ = arr[j];
+  arr[i] = origArrJ;
+  arr[j] = origArrI;
+  keyIndices[origArrJ.key] = i;
+  keyIndices[origArrI.key] = j;
+};
diff --git a/debian/missing-source/graphlib/lib/graph.js b/debian/missing-source/graphlib/lib/graph.js
new file mode 100644
index 0000000..22d384c
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/graph.js
@@ -0,0 +1,519 @@
+"use strict";
+
+var _ = require("./lodash");
+
+module.exports = Graph;
+
+var DEFAULT_EDGE_NAME = "\x00",
+    GRAPH_NODE = "\x00",
+    EDGE_KEY_DELIM = "\x01";
+
+// Implementation notes:
+//
+//  * Node id query functions should return string ids for the nodes
+//  * Edge id query functions should return an "edgeObj", edge object, that is
+//    composed of enough information to uniquely identify an edge: {v, w, name}.
+//  * Internally we use an "edgeId", a stringified form of the edgeObj, to
+//    reference edges. This is because we need a performant way to look these
+//    edges up and, object properties, which have string keys, are the closest
+//    we're going to get to a performant hashtable in JavaScript.
+
+function Graph(opts) {
+  this._isDirected = _.has(opts, "directed") ? opts.directed : true;
+  this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false;
+  this._isCompound = _.has(opts, "compound") ? opts.compound : false;
+
+  // Label for the graph itself
+  this._label = undefined;
+
+  // Defaults to be set when creating a new node
+  this._defaultNodeLabelFn = _.constant(undefined);
+
+  // Defaults to be set when creating a new edge
+  this._defaultEdgeLabelFn = _.constant(undefined);
+
+  // v -> label
+  this._nodes = {};
+
+  if (this._isCompound) {
+    // v -> parent
+    this._parent = {};
+
+    // v -> children
+    this._children = {};
+    this._children[GRAPH_NODE] = {};
+  }
+
+  // v -> edgeObj
+  this._in = {};
+
+  // u -> v -> Number
+  this._preds = {};
+
+  // v -> edgeObj
+  this._out = {};
+
+  // v -> w -> Number
+  this._sucs = {};
+
+  // e -> edgeObj
+  this._edgeObjs = {};
+
+  // e -> label
+  this._edgeLabels = {};
+}
+
+/* Number of nodes in the graph. Should only be changed by the implementation. */
+Graph.prototype._nodeCount = 0;
+
+/* Number of edges in the graph. Should only be changed by the implementation. */
+Graph.prototype._edgeCount = 0;
+
+
+/* === Graph functions ========= */
+
+Graph.prototype.isDirected = function() {
+  return this._isDirected;
+};
+
+Graph.prototype.isMultigraph = function() {
+  return this._isMultigraph;
+};
+
+Graph.prototype.isCompound = function() {
+  return this._isCompound;
+};
+
+Graph.prototype.setGraph = function(label) {
+  this._label = label;
+  return this;
+};
+
+Graph.prototype.graph = function() {
+  return this._label;
+};
+
+
+/* === Node functions ========== */
+
+Graph.prototype.setDefaultNodeLabel = function(newDefault) {
+  if (!_.isFunction(newDefault)) {
+    newDefault = _.constant(newDefault);
+  }
+  this._defaultNodeLabelFn = newDefault;
+  return this;
+};
+
+Graph.prototype.nodeCount = function() {
+  return this._nodeCount;
+};
+
+Graph.prototype.nodes = function() {
+  return _.keys(this._nodes);
+};
+
+Graph.prototype.sources = function() {
+  return _.filter(this.nodes(), function(v) {
+    return _.isEmpty(this._in[v]);
+  }, this);
+};
+
+Graph.prototype.sinks = function() {
+  return _.filter(this.nodes(), function(v) {
+    return _.isEmpty(this._out[v]);
+  }, this);
+};
+
+Graph.prototype.setNodes = function(vs, value) {
+  var args = arguments;
+  _.each(vs, function(v) {
+    if (args.length > 1) {
+      this.setNode(v, value);
+    } else {
+      this.setNode(v);
+    }
+  }, this);
+  return this;
+};
+
+Graph.prototype.setNode = function(v, value) {
+  if (_.has(this._nodes, v)) {
+    if (arguments.length > 1) {
+      this._nodes[v] = value;
+    }
+    return this;
+  }
+
+  this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
+  if (this._isCompound) {
+    this._parent[v] = GRAPH_NODE;
+    this._children[v] = {};
+    this._children[GRAPH_NODE][v] = true;
+  }
+  this._in[v] = {};
+  this._preds[v] = {};
+  this._out[v] = {};
+  this._sucs[v] = {};
+  ++this._nodeCount;
+  return this;
+};
+
+Graph.prototype.node = function(v) {
+  return this._nodes[v];
+};
+
+Graph.prototype.hasNode = function(v) {
+  return _.has(this._nodes, v);
+};
+
+Graph.prototype.removeNode =  function(v) {
+  var self = this;
+  if (_.has(this._nodes, v)) {
+    var removeEdge = function(e) { self.removeEdge(self._edgeObjs[e]); };
+    delete this._nodes[v];
+    if (this._isCompound) {
+      this._removeFromParentsChildList(v);
+      delete this._parent[v];
+      _.each(this.children(v), function(child) {
+        this.setParent(child);
+      }, this);
+      delete this._children[v];
+    }
+    _.each(_.keys(this._in[v]), removeEdge);
+    delete this._in[v];
+    delete this._preds[v];
+    _.each(_.keys(this._out[v]), removeEdge);
+    delete this._out[v];
+    delete this._sucs[v];
+    --this._nodeCount;
+  }
+  return this;
+};
+
+Graph.prototype.setParent = function(v, parent) {
+  if (!this._isCompound) {
+    throw new Error("Cannot set parent in a non-compound graph");
+  }
+
+  if (_.isUndefined(parent)) {
+    parent = GRAPH_NODE;
+  } else {
+    // Coerce parent to string
+    parent += "";
+    for (var ancestor = parent;
+         !_.isUndefined(ancestor);
+         ancestor = this.parent(ancestor)) {
+      if (ancestor === v) {
+        throw new Error("Setting " + parent+ " as parent of " + v +
+                        " would create create a cycle");
+      }
+    }
+
+    this.setNode(parent);
+  }
+
+  this.setNode(v);
+  this._removeFromParentsChildList(v);
+  this._parent[v] = parent;
+  this._children[parent][v] = true;
+  return this;
+};
+
+Graph.prototype._removeFromParentsChildList = function(v) {
+  delete this._children[this._parent[v]][v];
+};
+
+Graph.prototype.parent = function(v) {
+  if (this._isCompound) {
+    var parent = this._parent[v];
+    if (parent !== GRAPH_NODE) {
+      return parent;
+    }
+  }
+};
+
+Graph.prototype.children = function(v) {
+  if (_.isUndefined(v)) {
+    v = GRAPH_NODE;
+  }
+
+  if (this._isCompound) {
+    var children = this._children[v];
+    if (children) {
+      return _.keys(children);
+    }
+  } else if (v === GRAPH_NODE) {
+    return this.nodes();
+  } else if (this.hasNode(v)) {
+    return [];
+  }
+};
+
+Graph.prototype.predecessors = function(v) {
+  var predsV = this._preds[v];
+  if (predsV) {
+    return _.keys(predsV);
+  }
+};
+
+Graph.prototype.successors = function(v) {
+  var sucsV = this._sucs[v];
+  if (sucsV) {
+    return _.keys(sucsV);
+  }
+};
+
+Graph.prototype.neighbors = function(v) {
+  var preds = this.predecessors(v);
+  if (preds) {
+    return _.union(preds, this.successors(v));
+  }
+};
+
+Graph.prototype.filterNodes = function(filter) {
+  var copy = new this.constructor({
+    directed: this._isDirected,
+    multigraph: this._isMultigraph,
+    compound: this._isCompound
+  });
+
+  copy.setGraph(this.graph());
+
+  _.each(this._nodes, function(value, v) {
+    if (filter(v)) {
+      copy.setNode(v, value);
+    }
+  }, this);
+
+  _.each(this._edgeObjs, function(e) {
+    if (copy.hasNode(e.v) && copy.hasNode(e.w)) {
+      copy.setEdge(e, this.edge(e));
+    }
+  }, this);
+
+  var self = this;
+  var parents = {};
+  function findParent(v) {
+    var parent = self.parent(v);
+    if (parent === undefined || copy.hasNode(parent)) {
+      parents[v] = parent;
+      return parent;
+    } else if (parent in parents) {
+      return parents[parent];
+    } else {
+      return findParent(parent);
+    }
+  }
+
+  if (this._isCompound) {
+    _.each(copy.nodes(), function(v) {
+      copy.setParent(v, findParent(v));
+    });
+  }
+
+  return copy;
+};
+
+/* === Edge functions ========== */
+
+Graph.prototype.setDefaultEdgeLabel = function(newDefault) {
+  if (!_.isFunction(newDefault)) {
+    newDefault = _.constant(newDefault);
+  }
+  this._defaultEdgeLabelFn = newDefault;
+  return this;
+};
+
+Graph.prototype.edgeCount = function() {
+  return this._edgeCount;
+};
+
+Graph.prototype.edges = function() {
+  return _.values(this._edgeObjs);
+};
+
+Graph.prototype.setPath = function(vs, value) {
+  var self = this,
+      args = arguments;
+  _.reduce(vs, function(v, w) {
+    if (args.length > 1) {
+      self.setEdge(v, w, value);
+    } else {
+      self.setEdge(v, w);
+    }
+    return w;
+  });
+  return this;
+};
+
+/*
+ * setEdge(v, w, [value, [name]])
+ * setEdge({ v, w, [name] }, [value])
+ */
+Graph.prototype.setEdge = function() {
+  var v, w, name, value,
+      valueSpecified = false,
+      arg0 = arguments[0];
+
+  if (typeof arg0 === "object" && arg0 !== null && "v" in arg0) {
+    v = arg0.v;
+    w = arg0.w;
+    name = arg0.name;
+    if (arguments.length === 2) {
+      value = arguments[1];
+      valueSpecified = true;
+    }
+  } else {
+    v = arg0;
+    w = arguments[1];
+    name = arguments[3];
+    if (arguments.length > 2) {
+      value = arguments[2];
+      valueSpecified = true;
+    }
+  }
+
+  v = "" + v;
+  w = "" + w;
+  if (!_.isUndefined(name)) {
+    name = "" + name;
+  }
+
+  var e = edgeArgsToId(this._isDirected, v, w, name);
+  if (_.has(this._edgeLabels, e)) {
+    if (valueSpecified) {
+      this._edgeLabels[e] = value;
+    }
+    return this;
+  }
+
+  if (!_.isUndefined(name) && !this._isMultigraph) {
+    throw new Error("Cannot set a named edge when isMultigraph = false");
+  }
+
+  // It didn't exist, so we need to create it.
+  // First ensure the nodes exist.
+  this.setNode(v);
+  this.setNode(w);
+
+  this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name);
+
+  var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
+  // Ensure we add undirected edges in a consistent way.
+  v = edgeObj.v;
+  w = edgeObj.w;
+
+  Object.freeze(edgeObj);
+  this._edgeObjs[e] = edgeObj;
+  incrementOrInitEntry(this._preds[w], v);
+  incrementOrInitEntry(this._sucs[v], w);
+  this._in[w][e] = edgeObj;
+  this._out[v][e] = edgeObj;
+  this._edgeCount++;
+  return this;
+};
+
+Graph.prototype.edge = function(v, w, name) {
+  var e = (arguments.length === 1
+            ? edgeObjToId(this._isDirected, arguments[0])
+            : edgeArgsToId(this._isDirected, v, w, name));
+  return this._edgeLabels[e];
+};
+
+Graph.prototype.hasEdge = function(v, w, name) {
+  var e = (arguments.length === 1
+            ? edgeObjToId(this._isDirected, arguments[0])
+            : edgeArgsToId(this._isDirected, v, w, name));
+  return _.has(this._edgeLabels, e);
+};
+
+Graph.prototype.removeEdge = function(v, w, name) {
+  var e = (arguments.length === 1
+            ? edgeObjToId(this._isDirected, arguments[0])
+            : edgeArgsToId(this._isDirected, v, w, name)),
+      edge = this._edgeObjs[e];
+  if (edge) {
+    v = edge.v;
+    w = edge.w;
+    delete this._edgeLabels[e];
+    delete this._edgeObjs[e];
+    decrementOrRemoveEntry(this._preds[w], v);
+    decrementOrRemoveEntry(this._sucs[v], w);
+    delete this._in[w][e];
+    delete this._out[v][e];
+    this._edgeCount--;
+  }
+  return this;
+};
+
+Graph.prototype.inEdges = function(v, u) {
+  var inV = this._in[v];
+  if (inV) {
+    var edges = _.values(inV);
+    if (!u) {
+      return edges;
+    }
+    return _.filter(edges, function(edge) { return edge.v === u; });
+  }
+};
+
+Graph.prototype.outEdges = function(v, w) {
+  var outV = this._out[v];
+  if (outV) {
+    var edges = _.values(outV);
+    if (!w) {
+      return edges;
+    }
+    return _.filter(edges, function(edge) { return edge.w === w; });
+  }
+};
+
+Graph.prototype.nodeEdges = function(v, w) {
+  var inEdges = this.inEdges(v, w);
+  if (inEdges) {
+    return inEdges.concat(this.outEdges(v, w));
+  }
+};
+
+function incrementOrInitEntry(map, k) {
+  if (map[k]) {
+    map[k]++;
+  } else {
+    map[k] = 1;
+  }
+}
+
+function decrementOrRemoveEntry(map, k) {
+  if (!--map[k]) { delete map[k]; }
+}
+
+function edgeArgsToId(isDirected, v_, w_, name) {
+  var v = "" + v_;
+  var w = "" + w_;
+  if (!isDirected && v > w) {
+    var tmp = v;
+    v = w;
+    w = tmp;
+  }
+  return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM +
+             (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name);
+}
+
+function edgeArgsToObj(isDirected, v_, w_, name) {
+  var v = "" + v_;
+  var w = "" + w_;
+  if (!isDirected && v > w) {
+    var tmp = v;
+    v = w;
+    w = tmp;
+  }
+  var edgeObj =  { v: v, w: w };
+  if (name) {
+    edgeObj.name = name;
+  }
+  return edgeObj;
+}
+
+function edgeObjToId(isDirected, edgeObj) {
+  return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
+}
diff --git a/debian/missing-source/graphlib/lib/index.js b/debian/missing-source/graphlib/lib/index.js
new file mode 100644
index 0000000..756e0ab
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/index.js
@@ -0,0 +1,5 @@
+// Includes only the "core" of graphlib
+module.exports = {
+  Graph: require("./graph"),
+  version: require("./version")
+};
diff --git a/debian/missing-source/graphlib/lib/json.js b/debian/missing-source/graphlib/lib/json.js
new file mode 100644
index 0000000..2e2b112
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/json.js
@@ -0,0 +1,66 @@
+var _ = require("./lodash"),
+    Graph = require("./graph");
+
+module.exports = {
+  write: write,
+  read: read
+};
+
+function write(g) {
+  var json = {
+    options: {
+      directed: g.isDirected(),
+      multigraph: g.isMultigraph(),
+      compound: g.isCompound()
+    },
+    nodes: writeNodes(g),
+    edges: writeEdges(g)
+  };
+  if (!_.isUndefined(g.graph())) {
+    json.value = _.clone(g.graph());
+  }
+  return json;
+}
+
+function writeNodes(g) {
+  return _.map(g.nodes(), function(v) {
+    var nodeValue = g.node(v),
+        parent = g.parent(v),
+        node = { v: v };
+    if (!_.isUndefined(nodeValue)) {
+      node.value = nodeValue;
+    }
+    if (!_.isUndefined(parent)) {
+      node.parent = parent;
+    }
+    return node;
+  });
+}
+
+function writeEdges(g) {
+  return _.map(g.edges(), function(e) {
+    var edgeValue = g.edge(e),
+        edge = { v: e.v, w: e.w };
+    if (!_.isUndefined(e.name)) {
+      edge.name = e.name;
+    }
+    if (!_.isUndefined(edgeValue)) {
+      edge.value = edgeValue;
+    }
+    return edge;
+  });
+}
+
+function read(json) {
+  var g = new Graph(json.options).setGraph(json.value);
+  _.each(json.nodes, function(entry) {
+    g.setNode(entry.v, entry.value);
+    if (entry.parent) {
+      g.setParent(entry.v, entry.parent);
+    }
+  });
+  _.each(json.edges, function(entry) {
+    g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value);
+  });
+  return g;
+}
diff --git a/debian/missing-source/graphlib/lib/lodash.js b/debian/missing-source/graphlib/lib/lodash.js
new file mode 100644
index 0000000..c27a416
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/lodash.js
@@ -0,0 +1,15 @@
+/* global window */
+
+var lodash;
+
+if (typeof require === "function") {
+  try {
+    lodash = require("lodash");
+  } catch (e) {}
+}
+
+if (!lodash) {
+  lodash = window._;
+}
+
+module.exports = lodash;
diff --git a/debian/missing-source/graphlib/lib/version.js b/debian/missing-source/graphlib/lib/version.js
new file mode 100644
index 0000000..4a374e1
--- /dev/null
+++ b/debian/missing-source/graphlib/lib/version.js
@@ -0,0 +1 @@
+module.exports = '1.0.7';
diff --git a/debian/missing-source/graphlib/package.json b/debian/missing-source/graphlib/package.json
new file mode 100644
index 0000000..d1495ef
--- /dev/null
+++ b/debian/missing-source/graphlib/package.json
@@ -0,0 +1,40 @@
+{
+  "name": "graphlib",
+  "version": "1.0.7",
+  "description": "A directed and undirected multi-graph library",
+  "author": "Chris Pettitt <cpettitt at gmail.com>",
+  "main": "index.js",
+  "keywords": [
+    "graph",
+    "algorithms"
+  ],
+  "dependencies": {
+    "lodash": "^3.10.0"
+  },
+  "devDependencies": {
+    "benchmark": "^1.0.0",
+    "browserify": "^6.1.0",
+    "chai": "^1.9.2",
+    "istanbul": "^0.3.2",
+    "jscs": "^1.7.3",
+    "jshint": "^2.5.6",
+    "jshint-stylish": "^1.0.0",
+    "karma": "^0.12.37",
+    "karma-chrome-launcher": "^0.2.0",
+    "karma-firefox-launcher": "^0.1.6",
+    "karma-mocha": "^0.2.0",
+    "karma-phantomjs-launcher": "^0.2.0",
+    "karma-safari-launcher": "^0.1.1",
+    "mocha": "^1.21.5",
+    "phantomjs": "^1.9.17",
+    "seedrandom": "^2.4.2",
+    "semver": "^4.1.0",
+    "sprintf": "^0.1.4",
+    "uglify-js": "^2.4.15"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/cpettitt/graphlib.git"
+  },
+  "license": "MIT"
+}
diff --git a/debian/missing-source/graphlib/src/bench.js b/debian/missing-source/graphlib/src/bench.js
new file mode 100755
index 0000000..096b625
--- /dev/null
+++ b/debian/missing-source/graphlib/src/bench.js
@@ -0,0 +1,170 @@
+#!/usr/bin/env node
+
+var Benchmark = require("benchmark"),
+    seedrandom = require("seedrandom"),
+    sprintf = require("sprintf").sprintf;
+
+var seed = process.env.SEED;
+seedrandom(seed, { global: true });
+if (seed) {
+  console.log("SEED: %s (%d)", seed, Math.random());
+}
+
+var Graph = require("..").Graph,
+    alg = require("..").alg;
+
+var NODE_SIZES = [100],
+    EDGE_DENSITY = 0.2,
+    KEY_SIZE = 10;
+
+function runBenchmark(name, fn) {
+  var options = {};
+  options.onComplete = function(bench) {
+    var target = bench.target,
+        hz = target.hz,
+        stats = target.stats,
+        rme = stats.rme,
+        samples = stats.sample.length,
+        msg = sprintf("    %25s: %13s ops/sec \xb1 %s%% (%3d run(s) sampled)",
+                      target.name,
+                      Benchmark.formatNumber(hz.toFixed(2)),
+                      rme.toFixed(2),
+                      samples);
+    console.log(msg);
+  };
+  options.onError = function(bench) {
+    console.error("    " + bench.target.error);
+  };
+  options.setup = function() {
+    this.count = Math.random() * 1000;
+    this.nextInt = function(range) {
+      return Math.floor(this.count++ % range );
+    };
+  };
+  new Benchmark(name, fn, options).run();
+}
+
+function keys(count) {
+  var ks = [],
+      k;
+  for (var i = 0; i < count; ++i) {
+    k = "";
+    for (var j = 0; j < KEY_SIZE; ++j) {
+      k += String.fromCharCode(97 + Math.floor(Math.random() * 26));
+    }
+    ks.push(k);
+  }
+  return ks;
+}
+
+function buildGraph(numNodes, edgeDensity) {
+  var g = new Graph(),
+      numEdges = numNodes * numNodes * edgeDensity,
+      ks = keys(numNodes);
+
+  ks.forEach(function(k) { g.setNode(k); });
+
+  for (var i = 0; i < numEdges; ++i) {
+    var v, w;
+    do {
+      v = ks[Math.floor(Math.random() * ks.length)];
+      w = ks[Math.floor(Math.random() * ks.length)];
+    } while (g.hasEdge(v, w));
+    g.setEdge(v, w);
+  }
+  return g;
+}
+
+NODE_SIZES.forEach(function(size) {
+  var g = buildGraph(size, EDGE_DENSITY),
+      nodes = g.nodes(),
+      edges = g.edges(),
+      nameSuffix = "(" + size + "," + EDGE_DENSITY + ")";
+
+  runBenchmark("nodes" + nameSuffix, function() {
+    g.nodes();
+  });
+
+  runBenchmark("sources" + nameSuffix, function() {
+    g.sources();
+  });
+
+  runBenchmark("sinks" + nameSuffix, function() {
+    g.sinks();
+  });
+
+  runBenchmark("filterNodes all" + nameSuffix, function() {
+    g.filterNodes(function() { return true; });
+  });
+
+  runBenchmark("filterNodes none" + nameSuffix, function() {
+    g.filterNodes(function() { return false; });
+  });
+
+  runBenchmark("setNode" + nameSuffix, function() {
+    g.setNode("key", "label");
+  });
+
+  runBenchmark("node" + nameSuffix, function() {
+    g.node(nodes[this.nextInt(nodes.length)]);
+  });
+
+  runBenchmark("set + removeNode" + nameSuffix, function() {
+    g.setNode("key");
+    g.removeNode("key");
+  });
+
+  runBenchmark("predecessors" + nameSuffix, function() {
+    g.predecessors(nodes[this.nextInt(nodes.length)]);
+  });
+
+  runBenchmark("successors" + nameSuffix, function() {
+    g.successors(nodes[this.nextInt(nodes.length)]);
+  });
+
+  runBenchmark("neighbors" + nameSuffix, function() {
+    g.neighbors(nodes[this.nextInt(nodes.length)]);
+  });
+
+  runBenchmark("edges" + nameSuffix, function() {
+    g.edges();
+  });
+
+  runBenchmark("setPath" + nameSuffix, function() {
+    g.setPath(["a", "b", "c", "d", "e"]);
+  });
+
+  runBenchmark("setEdge" + nameSuffix, function() {
+    g.setEdge("from", "to", "label");
+  });
+
+  runBenchmark("edge" + nameSuffix, function() {
+    var edge = edges[this.nextInt(edges.length)];
+    g.edge(edge);
+  });
+
+  runBenchmark("set + removeEdge" + nameSuffix, function() {
+    g.setEdge("from", "to");
+    g.removeEdge("from", "to");
+  });
+
+  runBenchmark("inEdges" + nameSuffix, function() {
+    g.inEdges(nodes[this.nextInt(nodes.length)]);
+  });
+
+  runBenchmark("outEdges" + nameSuffix, function() {
+    g.outEdges(nodes[this.nextInt(nodes.length)]);
+  });
+
+  runBenchmark("nodeEdges" + nameSuffix, function() {
+    g.nodeEdges(nodes[this.nextInt(nodes.length)]);
+  });
+
+  runBenchmark("components" + nameSuffix, function() {
+    alg.components(g);
+  });
+
+  runBenchmark("dijkstraAll" + nameSuffix, function() {
+    alg.dijkstraAll(g);
+  });
+});
diff --git a/debian/missing-source/graphlib/src/release/bump-version.js b/debian/missing-source/graphlib/src/release/bump-version.js
new file mode 100755
index 0000000..80f7b3d
--- /dev/null
+++ b/debian/missing-source/graphlib/src/release/bump-version.js
@@ -0,0 +1,26 @@
+#!/usr/bin/env node
+
+/*
+ * Bumps the minor version and sets the prelease tag.
+ */
+
+var fs = require("fs"),
+    semver = require("semver");
+
+var packageFile = fs.readFileSync("package.json");
+var packageJson = JSON.parse(packageFile);
+
+if (!("version" in packageJson)) {
+  bail("ERROR: Could not find version in package.json");
+}
+
+var ver = semver.parse(packageJson.version);
+packageJson.version = ver.inc("patch").toString() + "-pre";
+
+fs.writeFileSync("package.json", JSON.stringify(packageJson, undefined, 2));
+
+// Write an error message to stderr and then exit immediately with an error.
+function bail(msg) {
+  stderr.write(msg + "\n");
+  process.exit(1);
+}
diff --git a/debian/missing-source/graphlib/src/release/check-version.js b/debian/missing-source/graphlib/src/release/check-version.js
new file mode 100755
index 0000000..1890158
--- /dev/null
+++ b/debian/missing-source/graphlib/src/release/check-version.js
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+
+/*
+ * Prints the current version from the specified package-file to stdout or
+ * fails with an error if either the version cannot be determined or it is
+ * a pre-release.
+ */
+
+var fs = require("fs"),
+    semver = require("semver");
+
+var packageFile = fs.readFileSync("package.json");
+var packageJson = JSON.parse(packageFile);
+
+if (!("version" in packageJson)) {
+  bail("ERROR: Could not find version in package.json");
+}
+
+var ver = semver.parse(packageJson.version),
+    preRelease = process.env.PRE_RELEASE;
+
+if (ver.prerelease.length > 0 && !preRelease) {
+  bail("ERROR: version is a pre-release: " + ver);
+}
+
+console.log(ver.toString());
+
+// Write an error message to stderr and then exit immediately with an error.
+function bail(msg) {
+  process.stderr.write(msg + "\n");
+  process.exit(1);
+}
diff --git a/debian/missing-source/graphlib/src/release/make-bower.json.js b/debian/missing-source/graphlib/src/release/make-bower.json.js
new file mode 100755
index 0000000..2726091
--- /dev/null
+++ b/debian/missing-source/graphlib/src/release/make-bower.json.js
@@ -0,0 +1,29 @@
+#!/usr/bin/env node
+
+// Renders the bower.json template and prints it to stdout
+
+var packageJson = require("../../package.json");
+
+var template = {
+  name: packageJson.name,
+  version: packageJson.version,
+  main: ["dist/" + packageJson.name + ".core.js"],
+  ignore: [
+    ".*",
+    "README.md",
+    "CHANGELOG.md",
+    "Makefile",
+    "browser.js",
+    "dist/" + packageJson.name + ".js",
+    "dist/" + packageJson.name + ".min.js",
+    "index.js",
+    "karma*",
+    "lib/**",
+    "package.json",
+    "src/**",
+    "test/**"
+  ],
+  dependencies: packageJson.dependencies
+};
+
+console.log(JSON.stringify(template, null, 2));
diff --git a/debian/missing-source/graphlib/src/release/make-version.js b/debian/missing-source/graphlib/src/release/make-version.js
new file mode 100755
index 0000000..39f2642
--- /dev/null
+++ b/debian/missing-source/graphlib/src/release/make-version.js
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+var package = require('../../package.json');
+console.log('module.exports = \'' + package.version + '\';');
diff --git a/debian/missing-source/graphlib/src/release/release.sh b/debian/missing-source/graphlib/src/release/release.sh
new file mode 100755
index 0000000..106a9a3
--- /dev/null
+++ b/debian/missing-source/graphlib/src/release/release.sh
@@ -0,0 +1,67 @@
+# Fail on error
+set -e
+[ -n "$DEBUG"] && set -x
+
+bail() {
+    echo $1 >&2
+    exit 1
+}
+
+# Initial config
+PROJECT=$1
+PROJECT_ROOT=`pwd`
+PAGES_DIR=/tmp/$PROJECT-pages
+DIST_DIR=$2
+
+# Check version. Is this a release? If not abort
+VERSION=$(./src/release/check-version.js)
+SHORT_VERSION=$(echo $VERSION | cut -f1 -d-)
+
+echo Attemping to publish version: $VERSION
+
+# Preflight checks
+[ -n "$PROJECT" ] || bail "No project name was specified."
+[ -n "$DIST_DIR" ] || bail "No dist dir was specified."
+[ -z "`git tag -l v$VERSION`" ] || bail "Version already published. Skipping publish."
+[ "`git rev-parse HEAD`" = "`git rev-parse master`" ] || [ -n "$PRE_RELEASE" ] || bail "ERROR: You must release from the master branch"
+[ -z "`git status --porcelain`" ] || bail "ERROR: Dirty index on working tree. Use git status to check"
+
+# Publish to pages
+rm -rf $PAGES_DIR
+git clone git at github.com:cpettitt/cpettitt.github.com.git $PAGES_DIR
+
+TMP_TARGET=$PAGES_DIR/project/$PROJECT/latest
+rm -rf $TMP_TARGET
+mkdir -p $TMP_TARGET
+cp -r $DIST_DIR/*.js $TMP_TARGET
+
+TMP_TARGET=$PAGES_DIR/project/$PROJECT/v$VERSION
+rm -rf $TMP_TARGET
+mkdir -p $TMP_TARGET
+cp -r $DIST_DIR/*.js $TMP_TARGET
+
+cd $PAGES_DIR/project/$PROJECT
+git add -A
+git commit -m "Publishing $PROJECT v$VERSION"
+git push -f origin master
+cd $PROJECT_ROOT
+echo "Published $PROJECT to pages"
+
+# Publish tag
+git tag v$VERSION
+git push origin
+git push origin v$VERSION
+echo Published $PROJECT v$VERSION
+
+# Publish to npm
+npm publish
+echo Published to npm
+
+# Update patch level version + commit
+./src/release/bump-version.js
+make lib/version.js
+git commit package.json lib/version.js -m "Bump version and set as pre-release"
+git push origin
+echo Updated patch version
+
+echo Release complete!
diff --git a/debian/missing-source/graphlib/test/alg/all-shortest-paths-test.js b/debian/missing-source/graphlib/test/alg/all-shortest-paths-test.js
new file mode 100644
index 0000000..0831c1e
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/all-shortest-paths-test.js
@@ -0,0 +1,126 @@
+var expect = require("../chai").expect,
+    Graph = require("../..").Graph;
+
+exports.tests = tests;
+
+function tests(sp) {
+  describe("allShortestPaths", function() {
+    it("returns 0 for the node itself", function() {
+      var g = new Graph();
+      g.setNode("a");
+      expect(sp(g)).to.eql({ a: { a: { distance: 0 } }});
+    });
+
+    it("returns the distance and path from all nodes to other nodes", function() {
+      var g = new Graph();
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      expect(sp(g)).to.eql({
+        a: {
+          a: { distance: 0 },
+          b: { distance: 1, predecessor: "a" },
+          c: { distance: 2, predecessor: "b" }
+        },
+        b: {
+          a: { distance: Number.POSITIVE_INFINITY },
+          b: { distance: 0 },
+          c: { distance: 1, predecessor: "b" }
+        },
+        c: {
+          a: { distance: Number.POSITIVE_INFINITY },
+          b: { distance: Number.POSITIVE_INFINITY },
+          c: { distance: 0 }
+        }
+      });
+    });
+
+    it("uses an optionally supplied weight function", function() {
+      var g = new Graph();
+      g.setEdge("a", "b", 2);
+      g.setEdge("b", "c", 3);
+
+      expect(sp(g, weightFn(g))).to.eql({
+        a: {
+          a: { distance: 0 },
+          b: { distance: 2, predecessor: "a" },
+          c: { distance: 5, predecessor: "b" }
+        },
+        b: {
+          a: { distance: Number.POSITIVE_INFINITY },
+          b: { distance: 0 },
+          c: { distance: 3, predecessor: "b" }
+        },
+        c: {
+          a: { distance: Number.POSITIVE_INFINITY },
+          b: { distance: Number.POSITIVE_INFINITY },
+          c: { distance: 0 }
+        }
+      });
+    });
+
+    it("uses an optionally supplied incident function", function() {
+      var g = new Graph();
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+
+      expect(sp(g, undefined, function(v) { return g.inEdges(v); })).to.eql({
+        a: {
+          a: { distance: 0 },
+          b: { distance: Number.POSITIVE_INFINITY },
+          c: { distance: Number.POSITIVE_INFINITY }
+        },
+        b: {
+          a: { distance: 1, predecessor: "b" },
+          b: { distance: 0 },
+          c: { distance: Number.POSITIVE_INFINITY }
+        },
+        c: {
+          a: { distance: 2, predecessor: "b" },
+          b: { distance: 1, predecessor: "c" },
+          c: { distance: 0 }
+        }
+      });
+    });
+
+    it("works with undirected graphs", function() {
+      var g = new Graph({ directed: false });
+      g.setEdge("a", "b", 1);
+      g.setEdge("b", "c", 2);
+      g.setEdge("c", "a", 4);
+      g.setEdge("b", "d", 6);
+
+      expect(sp(g, weightFn(g), g.nodeEdges.bind(g))).to.eql({
+        a: {
+          a: { distance: 0 },
+          b: { distance: 1, predecessor: "a" },
+          c: { distance: 3, predecessor: "b" },
+          d: { distance: 7, predecessor: "b" },
+        },
+        b: {
+          a: { distance: 1, predecessor: "b" },
+          b: { distance: 0 },
+          c: { distance: 2, predecessor: "b" },
+          d: { distance: 6, predecessor: "b" },
+        },
+        c: {
+          a: { distance: 3, predecessor: "b" },
+          b: { distance: 2, predecessor: "c" },
+          c: { distance: 0 },
+          d: { distance: 8, predecessor: "b" },
+        },
+        d: {
+          a: { distance: 7, predecessor: "b" },
+          b: { distance: 6, predecessor: "d" },
+          c: { distance: 8, predecessor: "b" },
+          d: { distance: 0 },
+        }
+      });
+    });
+  });
+}
+
+function weightFn(g) {
+  return function(e) {
+    return g.edge(e);
+  };
+}
diff --git a/debian/missing-source/graphlib/test/alg/components-test.js b/debian/missing-source/graphlib/test/alg/components-test.js
new file mode 100644
index 0000000..9e4766c
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/components-test.js
@@ -0,0 +1,39 @@
+var expect = require("../chai").expect,
+    _ = require("lodash"),
+    Graph = require("../..").Graph,
+    components = require("../..").alg.components;
+
+describe("alg.components", function() {
+  it("returns an empty list for an empty graph", function() {
+    expect(components(new Graph({ directed: false }))).to.be.empty;
+  });
+
+  it("returns singleton lists for unconnected nodes", function() {
+    var g = new Graph({ directed: false });
+    g.setNode("a");
+    g.setNode("b");
+
+    var result = _.sortBy(components(g), function(arr) { return _.min(arr); });
+    expect(result).to.eql([["a"], ["b"]]);
+  });
+
+  it("returns a list of nodes in a component", function() {
+    var g = new Graph({ directed: false });
+    g.setEdge("a", "b");
+    g.setEdge("b", "c");
+
+    var result = _.map(components(g), function(xs) { return _.sortBy(xs); });
+    expect(result).to.eql([["a", "b", "c"]]);
+  });
+
+  it("returns nodes connected by a neighbor relationship in a digraph", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "c", "a"]);
+    g.setEdge("d", "c");
+    g.setEdge("e", "f");
+
+    var result = _.sortBy(_.map(components(g), function(xs) { return _.sortBy(xs); }),
+                          "0");
+    expect(result).to.eql([["a", "b", "c", "d"], ["e", "f"]]);
+  });
+});
diff --git a/debian/missing-source/graphlib/test/alg/dijkstra-all-test.js b/debian/missing-source/graphlib/test/alg/dijkstra-all-test.js
new file mode 100644
index 0000000..289bbe3
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/dijkstra-all-test.js
@@ -0,0 +1,24 @@
+var expect = require("../chai").expect,
+    Graph = require("../..").Graph,
+    dijkstraAll = require("../..").alg.dijkstraAll,
+    allShortestPathsTest = require("./all-shortest-paths-test");
+
+describe("alg.dijkstraAll", function() {
+  allShortestPathsTest.tests(dijkstraAll);
+
+  it("throws an Error if it encounters a negative edge weight", function() {
+    var g = new Graph();
+    g.setEdge("a", "b",  1);
+    g.setEdge("a", "c", -2);
+    g.setEdge("b", "d",  3);
+    g.setEdge("c", "d",  3);
+
+    expect(function() { dijkstraAll(g, weight(g)); }).to.throw();
+  });
+});
+
+function weight(g) {
+  return function(e) {
+    return g.getEdge(e);
+  };
+}
diff --git a/debian/missing-source/graphlib/test/alg/dijkstra-test.js b/debian/missing-source/graphlib/test/alg/dijkstra-test.js
new file mode 100644
index 0000000..fd69100
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/dijkstra-test.js
@@ -0,0 +1,90 @@
+var expect = require("../chai").expect;
+
+var Graph = require("../..").Graph,
+    dijkstra = require("../..").alg.dijkstra;
+
+describe("alg.dijkstra", function() {
+  it("assigns distance 0 for the source node", function() {
+    var g = new Graph();
+    g.setNode("source");
+    expect(dijkstra(g, "source")).to.eql({ source: { distance: 0 } });
+  });
+
+  it("returns Number.POSITIVE_INFINITY for unconnected nodes", function() {
+    var g = new Graph();
+    g.setNode("a");
+    g.setNode("b");
+    expect(dijkstra(g, "a")).to.eql({
+      a: { distance: 0 },
+      b: { distance: Number.POSITIVE_INFINITY }
+    });
+  });
+
+  it("returns the distance and path from the source node to other nodes", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "c"]);
+    g.setEdge("b", "d");
+    expect(dijkstra(g, "a")).to.eql({
+      a: { distance: 0 },
+      b: { distance: 1, predecessor: "a" },
+      c: { distance: 2, predecessor: "b" },
+      d: { distance: 2, predecessor: "b" }
+    });
+  });
+
+  it("works for undirected graphs", function() {
+    var g = new Graph({ directed: false });
+    g.setPath(["a", "b", "c"]);
+    g.setEdge("b", "d");
+    expect(dijkstra(g, "a")).to.eql({
+      a: { distance: 0 },
+      b: { distance: 1, predecessor: "a" },
+      c: { distance: 2, predecessor: "b" },
+      d: { distance: 2, predecessor: "b" }
+    });
+  });
+
+  it("uses an optionally supplied weight function", function() {
+    var g = new Graph();
+    g.setEdge("a", "b", 1);
+    g.setEdge("a", "c", 2);
+    g.setEdge("b", "d", 3);
+    g.setEdge("c", "d", 3);
+
+    expect(dijkstra(g, "a", weightFn(g))).to.eql({
+      a: { distance: 0 },
+      b: { distance: 1, predecessor: "a" },
+      c: { distance: 2, predecessor: "a" },
+      d: { distance: 4, predecessor: "b" }
+    });
+  });
+
+  it("uses an optionally supplied edge function", function() {
+    var g = new Graph();
+    g.setPath(["a", "c", "d"]);
+    g.setEdge("b", "c");
+
+    expect(dijkstra(g, "d", undefined, function(e) { return g.inEdges(e); }), {
+      a: { distance: 2, predecessor: "c" },
+      b: { distance: 2, predecessor: "c" },
+      c: { distance: 1, predecessor: "d" },
+      d: { distance: 0 }
+    });
+  });
+
+  it("throws an Error if it encounters a negative edge weight", function() {
+    var g = new Graph();
+    g.setEdge("a", "b",  1);
+    g.setEdge("a", "c", -2);
+    g.setEdge("b", "d",  3);
+    g.setEdge("c", "d",  3);
+
+    expect(function() { dijkstra(g, "a", weightFn(g)); }).to.throw();
+  });
+});
+
+function weightFn(g) {
+  return function(e) {
+    return g.edge(e);
+  };
+}
diff --git a/debian/missing-source/graphlib/test/alg/find-cycles-test.js b/debian/missing-source/graphlib/test/alg/find-cycles-test.js
new file mode 100644
index 0000000..ce1f701
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/find-cycles-test.js
@@ -0,0 +1,50 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("../..").Graph,
+    findCycles = require("../..").alg.findCycles;
+
+describe("alg.findCycles", function() {
+  it("returns an empty array for an empty graph", function() {
+    expect(findCycles(new Graph())).to.eql([]);
+  });
+
+  it("returns an empty array if the graph has no cycles", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "c"]);
+    expect(findCycles(g)).to.eql([]);
+  });
+
+  it("returns a single entry for a cycle of 1 node", function() {
+    var g = new Graph();
+    g.setPath(["a", "a"]);
+    expect(sort(findCycles(g))).to.eql([["a"]]);
+  });
+
+  it("returns a single entry for a cycle of 2 nodes", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "a"]);
+    expect(sort(findCycles(g))).to.eql([["a", "b"]]);
+  });
+
+  it("returns a single entry for a triangle", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "c", "a"]);
+    expect(sort(findCycles(g))).to.eql([["a", "b", "c"]]);
+  });
+
+  it("returns multiple entries for multiple cycles", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "a"]);
+    g.setPath(["c", "d", "e", "c"]);
+    g.setPath(["f", "g", "g"]);
+    g.setNode("h");
+    expect(sort(findCycles(g))).to.eql([["a", "b"], ["c", "d", "e"], ["g"]]);
+  });
+});
+
+// A helper that sorts components and their contents
+function sort(cmpts) {
+  return _.sortBy(_.map(cmpts, function(cmpt) {
+    return _.sortBy(cmpt);
+  }), function(cmpts) { return cmpts[0]; });
+}
diff --git a/debian/missing-source/graphlib/test/alg/floyd-warshall-test.js b/debian/missing-source/graphlib/test/alg/floyd-warshall-test.js
new file mode 100644
index 0000000..fb1686b
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/floyd-warshall-test.js
@@ -0,0 +1,62 @@
+var expect = require("../chai").expect,
+    Graph = require("../..").Graph,
+    floydWarshall = require("../..").alg.floydWarshall,
+    allShortestPathsTest = require("./all-shortest-paths-test");
+
+describe("alg.floydWarshall", function() {
+  allShortestPathsTest.tests(floydWarshall);
+
+  it("handles negative weights", function() {
+    var g = new Graph();
+    g.setEdge("a", "b",  1);
+    g.setEdge("a", "c", -2);
+    g.setEdge("b", "d",  3);
+    g.setEdge("c", "d",  3);
+
+    expect(floydWarshall(g, weightFn(g))).to.eql({
+      a: {
+        a: { distance:  0 },
+        b: { distance:  1, predecessor: "a" },
+        c: { distance: -2, predecessor: "a" },
+        d: { distance:  1, predecessor: "c" }
+      },
+      b: {
+        a: { distance: Number.POSITIVE_INFINITY },
+        b: { distance: 0 },
+        c: { distance: Number.POSITIVE_INFINITY },
+        d: { distance: 3, predecessor: "b" }
+      },
+      c: {
+        a: { distance: Number.POSITIVE_INFINITY },
+        b: { distance: Number.POSITIVE_INFINITY },
+        c: { distance: 0 },
+        d: { distance: 3, predecessor: "c" }
+      },
+      d: {
+        a: { distance: Number.POSITIVE_INFINITY },
+        b: { distance: Number.POSITIVE_INFINITY },
+        c: { distance: Number.POSITIVE_INFINITY },
+        d: { distance: 0 }
+      }
+    });
+  });
+
+  it("does include negative weight self edges", function() {
+    var g = new Graph();
+    g.setEdge("a", "a", -1);
+
+    // In the case of a negative cycle the distance is not well-defined beyond
+    // having a negative value along the diagonal.
+    expect(floydWarshall(g, weightFn(g))).to.eql({
+      a: {
+        a: { distance: -2, predecessor: "a" }
+      }
+    });
+  });
+});
+
+function weightFn(g) {
+  return function(edge) {
+    return g.edge(edge);
+  };
+}
diff --git a/debian/missing-source/graphlib/test/alg/is-acyclic-test.js b/debian/missing-source/graphlib/test/alg/is-acyclic-test.js
new file mode 100644
index 0000000..3627265
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/is-acyclic-test.js
@@ -0,0 +1,27 @@
+var expect = require("../chai").expect,
+    Graph = require("../..").Graph,
+    isAcyclic = require("../..").alg.isAcyclic;
+
+describe("alg.isAcyclic", function() {
+  it("returns true if the graph has no cycles", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "c"]);
+    expect(isAcyclic(g)).to.be.true;
+  });
+
+  it("returns false if the graph has at least one cycle", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "c", "a"]);
+    expect(isAcyclic(g)).to.be.false;
+  });
+
+  it("returns false if the graph has a cycle of 1 node", function() {
+    var g = new Graph();
+    g.setPath(["a", "a"]);
+    expect(isAcyclic(g)).to.be.false;
+  });
+
+  it("rethrows non-CycleException errors", function() {
+    expect(function() { isAcyclic(undefined); }).to.throw();
+  });
+});
diff --git a/debian/missing-source/graphlib/test/alg/postorder-test.js b/debian/missing-source/graphlib/test/alg/postorder-test.js
new file mode 100644
index 0000000..a930947
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/postorder-test.js
@@ -0,0 +1,54 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("../..").Graph,
+    postorder = require("../..").alg.postorder;
+
+describe("alg.postorder", function() {
+  it("returns the root for a singleton graph", function() {
+    var g = new Graph();
+    g.setNode("a");
+    expect(postorder(g, "a")).to.eql(["a"]);
+  });
+
+  it("visits each node in the graph once", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "d", "e"]);
+    g.setPath(["a", "c", "d", "e"]);
+
+    var nodes = postorder(g, "a");
+    expect(_.sortBy(nodes)).to.eql(["a", "b", "c", "d", "e"]);
+  });
+
+  it("works for a tree", function() {
+    var g = new Graph();
+    g.setEdge("a", "b");
+    g.setPath(["a", "c", "d"]);
+    g.setEdge("c", "e");
+
+    var nodes = postorder(g, "a");
+    expect(_.sortBy(nodes)).to.eql(["a", "b", "c", "d", "e"]);
+    expect(nodes.indexOf("b")).to.be.lt(nodes.indexOf("a"));
+    expect(nodes.indexOf("c")).to.be.lt(nodes.indexOf("a"));
+    expect(nodes.indexOf("d")).to.be.lt(nodes.indexOf("c"));
+    expect(nodes.indexOf("e")).to.be.lt(nodes.indexOf("c"));
+  });
+
+  it("works for an array of roots", function() {
+    var g = new Graph();
+    g.setEdge("a", "b");
+    g.setEdge("c", "d");
+    g.setNode("e");
+    g.setNode("f");
+
+    var nodes = postorder(g, ["a", "b", "c", "e"]);
+    expect(_.sortBy(nodes)).to.eql(["a", "b", "c", "d", "e"]);
+    expect(nodes.indexOf("b")).to.be.lt(nodes.indexOf("a"));
+    expect(nodes.indexOf("d")).to.be.lt(nodes.indexOf("c"));
+  });
+
+  it("fails if root is not in the graph", function() {
+    var g = new Graph();
+    g.setNode("a");
+    expect(function() { postorder(g, "b"); }).to.throw();
+  });
+});
diff --git a/debian/missing-source/graphlib/test/alg/preorder-test.js b/debian/missing-source/graphlib/test/alg/preorder-test.js
new file mode 100644
index 0000000..ca39143
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/preorder-test.js
@@ -0,0 +1,54 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("../..").Graph,
+    preorder = require("../..").alg.preorder;
+
+describe("alg.preorder", function() {
+  it("returns the root for a singleton graph", function() {
+    var g = new Graph();
+    g.setNode("a");
+    expect(preorder(g, "a")).to.eql(["a"]);
+  });
+
+  it("visits each node in the graph once", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "d", "e"]);
+    g.setPath(["a", "c", "d", "e"]);
+
+    var nodes = preorder(g, "a");
+    expect(_.sortBy(nodes)).to.eql(["a", "b", "c", "d", "e"]);
+  });
+
+  it("works for a tree", function() {
+    var g = new Graph();
+    g.setEdge("a", "b");
+    g.setPath(["a", "c", "d"]);
+    g.setEdge("c", "e");
+
+    var nodes = preorder(g, "a");
+    expect(_.sortBy(nodes)).to.eql(["a", "b", "c", "d", "e"]);
+    expect(nodes.indexOf("b")).to.be.gt(nodes.indexOf("a"));
+    expect(nodes.indexOf("c")).to.be.gt(nodes.indexOf("a"));
+    expect(nodes.indexOf("d")).to.be.gt(nodes.indexOf("c"));
+    expect(nodes.indexOf("e")).to.be.gt(nodes.indexOf("c"));
+  });
+
+  it("works for an array of roots", function() {
+    var g = new Graph();
+    g.setEdge("a", "b");
+    g.setEdge("c", "d");
+    g.setNode("e");
+    g.setNode("f");
+
+    var nodes = preorder(g, ["a", "c", "e"]);
+    expect(_.sortBy(nodes)).to.eql(["a", "b", "c", "d", "e"]);
+    expect(nodes.indexOf("b")).to.be.gt(nodes.indexOf("a"));
+    expect(nodes.indexOf("d")).to.be.gt(nodes.indexOf("c"));
+  });
+
+  it("fails if root is not in the graph", function() {
+    var g = new Graph();
+    g.setNode("a");
+    expect(function() { preorder(g, "b"); }).to.throw();
+  });
+});
diff --git a/debian/missing-source/graphlib/test/alg/prim-test.js b/debian/missing-source/graphlib/test/alg/prim-test.js
new file mode 100644
index 0000000..b10247f
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/prim-test.js
@@ -0,0 +1,56 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("../..").Graph,
+    prim = require("../..").alg.prim;
+
+describe("alg.prim", function() {
+  it("returns an empty graph for an empty input", function() {
+    var source = new Graph();
+
+    var g = prim(source, weightFn(source));
+    expect(g.nodeCount()).to.equal(0);
+    expect(g.edgeCount()).to.equal(0);
+  });
+
+  it("returns a single node graph for a graph with a single node", function() {
+    var source = new Graph();
+    source.setNode("a");
+
+    var g = prim(source, weightFn(source));
+    expect(g.nodes()).to.eql(["a"]);
+    expect(g.edgeCount()).to.equal(0);
+  });
+
+  it("returns a deterministic result given an optimal solution", function() {
+    var source = new Graph();
+    source.setEdge("a", "b",  1);
+    source.setEdge("b", "c",  2);
+    source.setEdge("b", "d",  3);
+    // This edge should not be in the min spanning tree
+    source.setEdge("c", "d", 20);
+    // This edge should not be in the min spanning tree
+    source.setEdge("c", "e", 60);
+    source.setEdge("d", "e",  1);
+
+    var g = prim(source, weightFn(source));
+    expect(_.sortBy(g.neighbors("a"))).to.eql(["b"]);
+    expect(_.sortBy(g.neighbors("b"))).to.eql(["a", "c", "d"]);
+    expect(_.sortBy(g.neighbors("c"))).to.eql(["b"]);
+    expect(_.sortBy(g.neighbors("d"))).to.eql(["b", "e"]);
+    expect(_.sortBy(g.neighbors("e"))).to.eql(["d"]);
+  });
+
+  it("throws an Error for unconnected graphs", function() {
+    var source = new Graph();
+    source.setNode("a");
+    source.setNode("b");
+
+    expect(function() { prim(source, weightFn(source)); }).to.throw();
+  });
+});
+
+function weightFn(g) {
+  return function(edge) {
+    return g.edge(edge);
+  };
+}
diff --git a/debian/missing-source/graphlib/test/alg/tarjan-test.js b/debian/missing-source/graphlib/test/alg/tarjan-test.js
new file mode 100644
index 0000000..3363c16
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/tarjan-test.js
@@ -0,0 +1,44 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    Graph = require("../..").Graph,
+    tarjan = require("../..").alg.tarjan;
+
+describe("alg.tarjan", function() {
+  it("returns an empty array for an empty graph", function() {
+    expect(tarjan(new Graph())).to.eql([]);
+  });
+
+  it("returns singletons for nodes not in a strongly connected component", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "c"]);
+    g.setEdge("d", "c");
+    expect(sort(tarjan(g))).to.eql([["a"], ["b"], ["c"], ["d"]]);
+  });
+
+  it("returns a single component for a cycle of 1 edge", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "a"]);
+    expect(sort(tarjan(g))).to.eql([["a", "b"]]);
+  });
+
+  it("returns a single component for a triangle", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "c", "a"]);
+    expect(sort(tarjan(g))).to.eql([["a", "b", "c"]]);
+  });
+
+  it("can find multiple components", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "a"]);
+    g.setPath(["c", "d", "e", "c"]);
+    g.setNode("f");
+    expect(sort(tarjan(g))).to.eql([["a", "b"], ["c", "d", "e"], ["f"]]);
+  });
+});
+
+// A helper that sorts components and their contents
+function sort(cmpts) {
+  return _.sortBy(_.map(cmpts, function(cmpt) {
+    return _.sortBy(cmpt);
+  }), function(cmpts) { return cmpts[0]; });
+}
diff --git a/debian/missing-source/graphlib/test/alg/topsort-test.js b/debian/missing-source/graphlib/test/alg/topsort-test.js
new file mode 100644
index 0000000..aac90b4
--- /dev/null
+++ b/debian/missing-source/graphlib/test/alg/topsort-test.js
@@ -0,0 +1,49 @@
+var expect = require("../chai").expect,
+    _ = require("lodash");
+
+var Graph = require("../..").Graph,
+    topsort = require("../..").alg.topsort;
+
+describe("alg.topsort", function() {
+  it("returns an empty array for an empty graph", function() {
+    expect(topsort(new Graph())).to.be.empty;
+  });
+
+  it("sorts nodes such that earlier nodes have directed edges to later nodes", function() {
+    var g = new Graph();
+    g.setPath(["b", "c", "a"]);
+    expect(topsort(g)).to.eql(["b", "c", "a"]);
+  });
+
+  it("works for a diamond", function() {
+    var g = new Graph();
+    g.setPath(["a", "b", "d"]);
+    g.setPath(["a", "c", "d"]);
+
+    var result = topsort(g);
+    expect(_.indexOf(result, "a")).to.equal(0);
+    expect(_.indexOf(result, "b")).to.be.lt(_.indexOf(result, "d"));
+    expect(_.indexOf(result, "c")).to.be.lt(_.indexOf(result, "d"));
+    expect(_.indexOf(result, "d")).to.equal(3);
+  });
+
+  it("throws CycleException if there is a cycle #1", function() {
+    var g = new Graph();
+    g.setPath(["b", "c", "a", "b"]);
+    expect(function() { topsort(g); }).to.throw(topsort.CycleException);
+  });
+
+  it("throws CycleException if there is a cycle #2", function() {
+    var g = new Graph();
+    g.setPath(["b", "c", "a", "b"]);
+    g.setEdge("b", "d");
+    expect(function() { topsort(g); }).to.throw(topsort.CycleException);
+  });
+
+  it("throws CycleException if there is a cycle #3", function() {
+    var g = new Graph();
+    g.setPath(["b", "c", "a", "b"]);
+    g.setNode("d");
+    expect(function() { topsort(g); }).to.throw(topsort.CycleException);
+  });
+});
diff --git a/debian/missing-source/graphlib/test/bundle-test.js b/debian/missing-source/graphlib/test/bundle-test.js
new file mode 100644
index 0000000..d9e3aa8
--- /dev/null
+++ b/debian/missing-source/graphlib/test/bundle-test.js
@@ -0,0 +1,39 @@
+/* global chai, graphlib */
+
+// These are smoke tests to make sure the bundles look like they are working
+// correctly.
+
+var expect = chai.expect;
+
+describe("bundle", function() {
+  it("exports graphlib", function() {
+    expect(graphlib).to.be.an("object");
+    expect(graphlib.Graph).to.be.a("function");
+    expect(graphlib.json).to.be.a("object");
+    expect(graphlib.alg).to.be.a("object");
+    expect(graphlib.version).to.be.a("string");
+  });
+
+  it("can do simple graph operations", function() {
+    var g = new graphlib.Graph();
+    g.setNode("a");
+    g.setNode("b");
+    g.setEdge("a", "b");
+    expect(g.hasNode("a")).to.be.true;
+    expect(g.hasNode("b")).to.be.true;
+    expect(g.hasEdge("a", "b")).to.be.true;
+  });
+
+  it("can serialize to json and back", function() {
+    var g = new graphlib.Graph();
+    g.setNode("a");
+    g.setNode("b");
+    g.setEdge("a", "b");
+
+    var json = graphlib.json.write(g);
+    var g2 = graphlib.json.read(json);
+    expect(g2.hasNode("a")).to.be.true;
+    expect(g2.hasNode("b")).to.be.true;
+    expect(g2.hasEdge("a", "b")).to.be.true;
+  });
+});
diff --git a/debian/missing-source/graphlib/test/chai.js b/debian/missing-source/graphlib/test/chai.js
new file mode 100644
index 0000000..ba88ca6
--- /dev/null
+++ b/debian/missing-source/graphlib/test/chai.js
@@ -0,0 +1,5 @@
+var chai = require("chai");
+
+module.exports = chai;
+
+chai.config.includeStack = true;
diff --git a/debian/missing-source/graphlib/test/data/priority-queue-test.js b/debian/missing-source/graphlib/test/data/priority-queue-test.js
new file mode 100644
index 0000000..d31b4c6
--- /dev/null
+++ b/debian/missing-source/graphlib/test/data/priority-queue-test.js
@@ -0,0 +1,131 @@
+var _ = require("lodash"),
+    expect = require("../chai").expect,
+    PriorityQueue = require("../../lib/data/priority-queue");
+
+describe("data.PriorityQueue", function() {
+  var pq;
+
+  beforeEach(function() {
+    pq = new PriorityQueue();
+  });
+
+  describe("size", function() {
+    it("returns 0 for an empty queue", function() {
+      expect(pq.size()).to.equal(0);
+    });
+
+    it("returns the number of elements in the queue", function() {
+      pq.add("a", 1);
+      expect(pq.size()).to.equal(1);
+      pq.add("b", 2);
+      expect(pq.size()).to.equal(2);
+    });
+  });
+
+  describe("keys", function() {
+    it("returns all of the keys in the queue", function() {
+      pq.add("a", 1);
+      pq.add(1, 2);
+      pq.add(false, 3);
+      pq.add(undefined, 4);
+      pq.add(null, 5);
+      expect(_.sortBy(pq.keys())).to.eql(
+                _.sortBy(["a", "1", "false", "undefined", "null"]));
+    });
+  });
+
+  describe("has", function() {
+    it("returns true if the key is in the queue", function() {
+      pq.add("a", 1);
+      expect(pq.has("a")).to.be.true;
+    });
+
+    it("returns false if the key is not in the queue", function() {
+      expect(pq.has("a")).to.be.false;
+    });
+  });
+
+  describe("priority", function() {
+    it("returns the current priority for the key", function() {
+      pq.add("a", 1);
+      pq.add("b", 2);
+      expect(pq.priority("a")).to.equal(1);
+      expect(pq.priority("b")).to.equal(2);
+    });
+
+    it("returns undefined if the key is not in the queue", function() {
+      expect(pq.priority("foo")).to.be.undefined;
+    });
+  });
+
+  describe("min", function() {
+    it("throws an error if there is no element in the queue", function() {
+      expect(function() { pq.min(); }).to.throw();
+    });
+
+    it("returns the smallest element", function() {
+      pq.add("b", 2);
+      pq.add("a", 1);
+      expect(pq.min()).to.equal("a");
+    });
+
+    it("does not remove the minimum element from the queue", function() {
+      pq.add("b", 2);
+      pq.add("a", 1);
+      pq.min();
+      expect(pq.size()).to.equal(2);
+    });
+  });
+
+  describe("add", function() {
+    it("adds the key to the queue", function() {
+      pq.add("a", 1);
+      expect(pq.keys()).to.eql(["a"]);
+    });
+
+    it("returns true if the key was added", function() {
+      expect(pq.add("a", 1)).to.be.true;
+    });
+
+    it("returns false if the key already exists in the queue", function() {
+      pq.add("a", 1);
+      expect(pq.add("a", 1)).to.be.false;
+    });
+  });
+
+  describe("removeMin", function() {
+    it("removes the minimum element from the queue", function() {
+      pq.add("b", 2);
+      pq.add("a", 1);
+      pq.add("c", 3);
+      pq.add("e", 5);
+      pq.add("d", 4);
+      expect(pq.removeMin()).to.equal("a");
+      expect(pq.removeMin()).to.equal("b");
+      expect(pq.removeMin()).to.equal("c");
+      expect(pq.removeMin()).to.equal("d");
+      expect(pq.removeMin()).to.equal("e");
+    });
+
+    it("throws an error if there is no element in the queue", function() {
+      expect(function() { pq.removeMin(); }).to.throw();
+    });
+  });
+
+  describe("decrease", function() {
+    it("decreases the priority of a key", function() {
+      pq.add("a", 1);
+      pq.decrease("a", -1);
+      expect(pq.priority("a")).to.equal(-1);
+    });
+
+    it("raises an error if the key is not in the queue", function() {
+      expect(function() { pq.decrease("a", -1); }).to.throw();
+    });
+
+    it("raises an error if the new priority is greater than current", function() {
+      pq.add("a", 1);
+      expect(function() { pq.decrease("a", 2); }).to.throw();
+    });
+  });
+});
diff --git a/debian/missing-source/graphlib/test/graph-test.js b/debian/missing-source/graphlib/test/graph-test.js
new file mode 100644
index 0000000..c78bd7b
--- /dev/null
+++ b/debian/missing-source/graphlib/test/graph-test.js
@@ -0,0 +1,945 @@
+var _ = require("lodash"),
+    expect = require("./chai").expect,
+    Graph = require("..").Graph;
+
+describe("Graph", function() {
+  var g;
+
+  beforeEach(function() {
+    g = new Graph();
+  });
+
+  describe("initial state", function() {
+    it("has no nodes", function() {
+      expect(g.nodeCount()).to.equal(0);
+    });
+
+    it("has no edges", function() {
+      expect(g.edgeCount()).to.equal(0);
+    });
+
+    it("has no attributes", function() {
+      expect(g.graph()).to.be.undefined;
+    });
+
+    it("defaults to a simple directed graph", function() {
+      expect(g.isDirected()).to.be.true;
+      expect(g.isCompound()).to.be.false;
+      expect(g.isMultigraph()).to.be.false;
+    });
+
+    it("can be set to undirected", function() {
+      var g = new Graph({ directed: false });
+      expect(g.isDirected()).to.be.false;
+      expect(g.isCompound()).to.be.false;
+      expect(g.isMultigraph()).to.be.false;
+    });
+
+    it("can be set to a compound graph", function() {
+      var g = new Graph({ compound: true });
+      expect(g.isDirected()).to.be.true;
+      expect(g.isCompound()).to.be.true;
+      expect(g.isMultigraph()).to.be.false;
+    });
+
+    it("can be set to a mulitgraph", function() {
+      var g = new Graph({ multigraph: true });
+      expect(g.isDirected()).to.be.true;
+      expect(g.isCompound()).to.be.false;
+      expect(g.isMultigraph()).to.be.true;
+    });
+  });
+
+  describe("setGraph", function() {
+    it("can be used to get and set properties for the graph", function() {
+      g.setGraph("foo");
+      expect(g.graph()).to.equal("foo");
+    });
+
+    it("is chainable", function() {
+      expect(g.setGraph("foo")).to.equal(g);
+    });
+  });
+
+  describe("nodes", function() {
+    it("is empty if there are no nodes in the graph", function() {
+      expect(g.nodes()).to.eql([]);
+    });
+
+    it("returns the ids of nodes in the graph", function() {
+      g.setNode("a");
+      g.setNode("b");
+      expect(_.sortBy(g.nodes())).to.eql(["a", "b"]);
+    });
+  });
+
+  describe("sources", function() {
+    it("returns nodes in the graph that have no in-edges", function() {
+      g.setPath(["a", "b", "c"]);
+      g.setNode("d");
+      expect(_.sortBy(g.sources())).to.eql(["a", "d"]);
+    });
+  });
+
+  describe("sinks", function() {
+    it("returns nodes in the graph that have no out-edges", function() {
+      g.setPath(["a", "b", "c"]);
+      g.setNode("d");
+      expect(_.sortBy(g.sinks())).to.eql(["c", "d"]);
+    });
+  });
+
+  describe("filterNodes", function() {
+    it("returns an identical graph when the filter selects everything", function() {
+      g.setGraph("graph label");
+      g.setNode("a", 123);
+      g.setPath(["a", "b", "c"]);
+      g.setEdge("a", "c", 456);
+      var g2 = g.filterNodes(function() { return true; });
+      expect(_.sortBy(g2.nodes())).eqls(["a", "b", "c"]);
+      expect(_.sortBy(g2.successors("a"))).eqls(["b", "c"]);
+      expect(_.sortBy(g2.successors("b"))).eqls(["c"]);
+      expect(g2.node("a")).eqls(123);
+      expect(g2.edge("a", "c")).eqls(456);
+      expect(g2.graph()).eqls("graph label");
+    });
+
+    it("returns an empty graph when the filter selects nothing", function() {
+      g.setPath(["a", "b", "c"]);
+      var g2 = g.filterNodes(function() { return false; });
+      expect(g2.nodes()).eqls([]);
+      expect(g2.edges()).eqls([]);
+    });
+
+    it("only includes nodes for which the filter returns true", function() {
+      g.setNodes(["a", "b"]);
+      var g2 = g.filterNodes(function(v) { return v === "a"; });
+      expect(g2.nodes()).eqls(["a"]);
+    });
+
+    it("removes edges that are connected to removed nodes", function() {
+      g.setEdge("a", "b");
+      var g2 = g.filterNodes(function(v) { return v === "a"; });
+      expect(_.sortBy(g2.nodes())).eqls(["a"]);
+      expect(g2.edges()).eqls([]);
+    });
+
+    it("preserves the directed option", function() {
+      g = new Graph({ directed: true });
+      expect(g.filterNodes(function() { return true; }).isDirected()).to.be.true;
+
+      g = new Graph({ directed: false });
+      expect(g.filterNodes(function() { return true; }).isDirected()).to.be.false;
+    });
+
+    it("preserves the multigraph option", function() {
+      g = new Graph({ multigraph: true });
+      expect(g.filterNodes(function() { return true; }).isMultigraph()).to.be.true;
+
+      g = new Graph({ multigraph: false });
+      expect(g.filterNodes(function() { return true; }).isMultigraph()).to.be.false;
+    });
+
+    it("preserves the compound option", function() {
+      g = new Graph({ compound: true });
+      expect(g.filterNodes(function() { return true; }).isCompound()).to.be.true;
+
+      g = new Graph({ compound: false });
+      expect(g.filterNodes(function() { return true; }).isCompound()).to.be.false;
+    });
+
+    it("includes subgraphs", function() {
+      g = new Graph({ compound: true });
+      g.setParent("a", "parent");
+
+      var g2 = g.filterNodes(function() { return true; });
+      expect(g2.parent("a")).eqls("parent");
+    });
+
+    it("includes multi-level subgraphs", function() {
+      g = new Graph({ compound: true });
+      g.setParent("a", "parent");
+      g.setParent("parent", "root");
+
+      var g2 = g.filterNodes(function() { return true; });
+      expect(g2.parent("a")).eqls("parent");
+      expect(g2.parent("parent")).eqls("root");
+    });
+
+    it("promotes a node to a higher subgraph if its parent is not included", function() {
+      g = new Graph({ compound: true });
+      g.setParent("a", "parent");
+      g.setParent("parent", "root");
+
+      var g2 = g.filterNodes(function(v) { return v !== "parent"; });
+      expect(g2.parent("a")).eqls("root");
+    });
+  });
+
+  describe("setNodes", function() {
+    it("creates multiple nodes", function() {
+      g.setNodes(["a", "b", "c"]);
+      expect(g.hasNode("a")).to.be.true;
+      expect(g.hasNode("b")).to.be.true;
+      expect(g.hasNode("c")).to.be.true;
+    });
+
+    it("can set a value for all of the nodes", function() {
+      g.setNodes(["a", "b", "c"], "foo");
+      expect(g.node("a")).to.equal("foo");
+      expect(g.node("b")).to.equal("foo");
+      expect(g.node("c")).to.equal("foo");
+    });
+
+    it("is chainable", function() {
+      expect(g.setNodes(["a", "b", "c"])).to.equal(g);
+    });
+  });
+
+  describe("setNode", function() {
+    it("creates the node if it isn't part of the graph", function() {
+      g.setNode("a");
+      expect(g.hasNode("a")).to.be.true;
+      expect(g.node("a")).to.be.undefined;
+      expect(g.nodeCount()).to.equal(1);
+    });
+
+    it("can set a value for the node", function() {
+      g.setNode("a", "foo");
+      expect(g.node("a")).to.equal("foo");
+    });
+
+    it("does not change the node's value with a 1-arg invocation", function() {
+      g.setNode("a", "foo");
+      g.setNode("a");
+      expect(g.node("a")).to.equal("foo");
+    });
+
+    it("can remove the node's value by passing undefined", function() {
+      g.setNode("a", undefined);
+      expect(g.node("a")).to.be.undefined;
+    });
+
+    it("is idempotent", function() {
+      g.setNode("a", "foo");
+      g.setNode("a", "foo");
+      expect(g.node("a")).to.equal("foo");
+      expect(g.nodeCount()).to.equal(1);
+    });
+
+    it("uses the stringified form of the id", function() {
+      g.setNode(1);
+      expect(g.hasNode(1)).to.be.true;
+      expect(g.hasNode("1")).to.be.true;
+      expect(g.nodes()).eqls(["1"]);
+    });
+
+    it("is chainable", function() {
+      expect(g.setNode("a")).to.equal(g);
+    });
+  });
+
+  describe("setNodeDefaults", function() {
+    it("sets a default label for new nodes", function() {
+      g.setDefaultNodeLabel("foo");
+      g.setNode("a");
+      expect(g.node("a")).to.equal("foo");
+    });
+
+    it("does not change existing nodes", function() {
+      g.setNode("a");
+      g.setDefaultNodeLabel("foo");
+      expect(g.node("a")).to.be.undefined;
+    });
+
+    it("is not used if an explicit value is set", function() {
+      g.setDefaultNodeLabel("foo");
+      g.setNode("a", "bar");
+      expect(g.node("a")).to.equal("bar");
+    });
+
+    it("can take a function", function() {
+      g.setDefaultNodeLabel(function() { return "foo"; });
+      g.setNode("a");
+      expect(g.node("a")).to.equal("foo");
+    });
+
+    it("can take a function that takes the node's name", function() {
+      g.setDefaultNodeLabel(function(v) { return v + "-foo"; });
+      g.setNode("a");
+      expect(g.node("a")).to.equal("a-foo");
+    });
+
+    it("is chainable", function() {
+      expect(g.setDefaultNodeLabel("foo")).to.equal(g);
+    });
+  });
+
+  describe("node", function() {
+    it("returns undefined if the node isn't part of the graph", function() {
+      expect(g.node("a")).to.be.undefined;
+    });
+
+    it("returns the value of the node if it is part of the graph", function() {
+      g.setNode("a", "foo");
+      expect(g.node("a")).to.equal("foo");
+    });
+  });
+
+  describe("removeNode", function() {
+    it("does nothing if the node is not in the graph", function() {
+      expect(g.nodeCount()).to.equal(0);
+      g.removeNode("a");
+      expect(g.hasNode("a")).to.be.false;
+      expect(g.nodeCount()).to.equal(0);
+    });
+
+    it("removes the node if it is in the graph", function() {
+      g.setNode("a");
+      g.removeNode("a");
+      expect(g.hasNode("a")).to.be.false;
+      expect(g.nodeCount()).to.equal(0);
+    });
+
+    it("is idempotent", function() {
+      g.setNode("a");
+      g.removeNode("a");
+      g.removeNode("a");
+      expect(g.hasNode("a")).to.be.false;
+      expect(g.nodeCount()).to.equal(0);
+    });
+
+    it("removes edges incident on the node", function() {
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      g.removeNode("b");
+      expect(g.edgeCount()).to.equal(0);
+    });
+
+    it("removes parent / child relationships for the node", function() {
+      var g = new Graph({ compound: true });
+      g.setParent("c", "b");
+      g.setParent("b", "a");
+      g.removeNode("b");
+      expect(g.parent("b")).to.be.undefined;
+      expect(g.children("b")).to.be.undefined;
+      expect(g.children("a")).to.not.include("b");
+      expect(g.parent("c")).to.be.undefined;
+    });
+
+    it("is chainable", function() {
+      expect(g.removeNode("a")).to.equal(g);
+    });
+  });
+
+  describe("setParent", function() {
+    beforeEach(function() {
+      g = new Graph({ compound: true });
+    });
+
+    it("throws if the graph is not compound", function() {
+      expect(function() { new Graph().setParent("a", "parent"); }).to.throw();
+    });
+
+    it("creates the parent if it does not exist", function() {
+      g.setNode("a");
+      g.setParent("a", "parent");
+      expect(g.hasNode("parent")).to.be.true;
+      expect(g.parent("a")).to.equal("parent");
+    });
+
+    it("creates the child if it does not exist", function() {
+      g.setNode("parent");
+      g.setParent("a", "parent");
+      expect(g.hasNode("a")).to.be.true;
+      expect(g.parent("a")).to.equal("parent");
+    });
+
+    it("has the parent as undefined if it has never been invoked", function() {
+      g.setNode("a");
+      expect(g.parent("a")).to.be.undefined;
+    });
+
+    it("moves the node from the previous parent", function() {
+      g.setParent("a", "parent");
+      g.setParent("a", "parent2");
+      expect(g.parent("a")).to.equal("parent2");
+      expect(g.children("parent")).to.eql([]);
+      expect(g.children("parent2")).to.eql(["a"]);
+    });
+
+    it("removes the parent if the parent is undefined", function() {
+      g.setParent("a", "parent");
+      g.setParent("a", undefined);
+      expect(g.parent("a")).to.be.undefined;
+      expect(_.sortBy(g.children())).to.eql(["a", "parent"]);
+    });
+
+    it("removes the parent if no parent was specified", function() {
+      g.setParent("a", "parent");
+      g.setParent("a");
+      expect(g.parent("a")).to.be.undefined;
+      expect(_.sortBy(g.children())).to.eql(["a", "parent"]);
+    });
+
+    it("is idempotent to remove a parent", function() {
+      g.setParent("a", "parent");
+      g.setParent("a");
+      g.setParent("a");
+      expect(g.parent("a")).to.be.undefined;
+      expect(_.sortBy(g.children())).to.eql(["a", "parent"]);
+    });
+
+    it("uses the stringified form of the id", function() {
+      g.setParent(2, 1);
+      g.setParent(3, 2);
+      expect(g.parent(2)).equals("1");
+      expect(g.parent("2")).equals("1");
+      expect(g.parent(3)).equals("2");
+    });
+
+    it("preserves the tree invariant", function() {
+      g.setParent("c", "b");
+      g.setParent("b", "a");
+      expect(function() { g.setParent("a", "c"); }).to.throw();
+    });
+
+    it("is chainable", function() {
+      expect(g.setParent("a", "parent")).to.equal(g);
+    });
+  });
+
+  describe("parent", function() {
+    beforeEach(function() {
+      g = new Graph({ compound: true });
+    });
+
+    it("returns undefined if the graph is not compound", function() {
+      expect(new Graph({ compound: false }).parent("a")).to.be.undefined;
+    });
+
+    it("returns undefined if the node is not in the graph", function() {
+      expect(g.parent("a")).to.be.undefined;
+    });
+
+    it("defaults to undefined for new nodes", function() {
+      g.setNode("a");
+      expect(g.parent("a")).to.be.undefined;
+    });
+
+    it("returns the current parent assignment", function() {
+      g.setNode("a");
+      g.setNode("parent");
+      g.setParent("a", "parent");
+      expect(g.parent("a")).to.equal("parent");
+    });
+  });
+
+  describe("children", function() {
+    beforeEach(function() {
+      g = new Graph({ compound: true });
+    });
+
+    it("returns undefined if the node is not in the graph", function() {
+      expect(g.children("a")).to.be.undefined;
+    });
+
+    it("defaults to en empty list for new nodes", function() {
+      g.setNode("a");
+      expect(g.children("a")).to.eql([]);
+    });
+
+    it("returns undefined for a non-compound graph without the node", function() {
+      var g = new Graph();
+      expect(g.children("a")).to.be.undefined;
+    });
+
+    it("returns an empty list for a non-compound graph with the node", function() {
+      var g = new Graph();
+      g.setNode("a");
+      expect(g.children("a")).eqls([]);
+    });
+
+    it ("returns all nodes for the root of a non-compound graph", function() {
+      var g = new Graph();
+      g.setNode("a");
+      g.setNode("b");
+      expect(_.sortBy(g.children())).eqls(["a", "b"]);
+    });
+
+    it("returns children for the node", function() {
+      g.setParent("a", "parent");
+      g.setParent("b", "parent");
+      expect(_.sortBy(g.children("parent"))).to.eql(["a", "b"]);
+    });
+
+    it("returns all nodes without a parent when the parent is not set", function() {
+      g.setNode("a");
+      g.setNode("b");
+      g.setNode("c");
+      g.setNode("parent");
+      g.setParent("a", "parent");
+      expect(_.sortBy(g.children())).to.eql(["b", "c", "parent"]);
+      expect(_.sortBy(g.children(undefined))).to.eql(["b", "c", "parent"]);
+    });
+  });
+
+  describe("predecessors", function() {
+    it("returns undefined for a node that is not in the graph", function() {
+      expect(g.predecessors("a")).to.be.undefined;
+    });
+
+    it("returns the predecessors of a node", function() {
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      g.setEdge("a", "a");
+      expect(_.sortBy(g.predecessors("a"))).to.eql(["a"]);
+      expect(_.sortBy(g.predecessors("b"))).to.eql(["a"]);
+      expect(_.sortBy(g.predecessors("c"))).to.eql(["b"]);
+    });
+  });
+
+  describe("successors", function() {
+    it("returns undefined for a node that is not in the graph", function() {
+      expect(g.successors("a")).to.be.undefined;
+    });
+
+    it("returns the successors of a node", function() {
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      g.setEdge("a", "a");
+      expect(_.sortBy(g.successors("a"))).to.eql(["a", "b"]);
+      expect(_.sortBy(g.successors("b"))).to.eql(["c"]);
+      expect(_.sortBy(g.successors("c"))).to.eql([]);
+    });
+  });
+
+  describe("neighbors", function() {
+    it("returns undefined for a node that is not in the graph", function() {
+      expect(g.neighbors("a")).to.be.undefined;
+    });
+
+    it("returns the neighbors of a node", function() {
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      g.setEdge("a", "a");
+      expect(_.sortBy(g.neighbors("a"))).to.eql(["a", "b"]);
+      expect(_.sortBy(g.neighbors("b"))).to.eql(["a", "c"]);
+      expect(_.sortBy(g.neighbors("c"))).to.eql(["b"]);
+    });
+  });
+
+  describe("edges", function() {
+    it("is empty if there are no edges in the graph", function() {
+      expect(g.edges()).to.eql([]);
+    });
+
+    it("returns the keys for edges in the graph", function() {
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      expect(_.sortBy(g.edges()), ["v", "w"]).to.eql([
+        { v: "a", w: "b" },
+        { v: "b", w: "c" }
+      ]);
+    });
+  });
+
+  describe("setPath", function() {
+    it("creates a path of mutiple edges", function() {
+      g.setPath(["a", "b", "c"]);
+      expect(g.hasEdge("a", "b")).to.be.true;
+      expect(g.hasEdge("b", "c")).to.be.true;
+    });
+
+    it("can set a value for all of the edges", function() {
+      g.setPath(["a", "b", "c"], "foo");
+      expect(g.edge("a", "b")).to.equal("foo");
+      expect(g.edge("b", "c")).to.equal("foo");
+    });
+
+    it("is chainable", function() {
+      expect(g.setPath(["a", "b", "c"])).to.equal(g);
+    });
+  });
+
+  describe("setEdge", function() {
+    it("creates the edge if it isn't part of the graph", function() {
+      g.setNode("a");
+      g.setNode("b");
+      g.setEdge("a", "b");
+      expect(g.edge("a", "b")).to.be.undefined;
+      expect(g.hasEdge("a", "b")).to.be.true;
+      expect(g.hasEdge({ v: "a", w: "b" })).to.be.true;
+      expect(g.edgeCount()).to.equal(1);
+    });
+
+    it("creates the nodes for the edge if they are not part of the graph", function() {
+      g.setEdge("a", "b");
+      expect(g.hasNode("a")).to.be.true;
+      expect(g.hasNode("b")).to.be.true;
+      expect(g.nodeCount()).to.equal(2);
+    });
+
+    it("creates a multi-edge if if it isn't part of the graph", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b", undefined, "name");
+      expect(g.hasEdge("a", "b")).to.be.false;
+      expect(g.hasEdge("a", "b", "name")).to.be.true;
+    });
+
+    it("throws if a multi-edge is used with a non-multigraph", function() {
+      expect(function() { g.setEdge("a", "b", undefined, "name"); }).to.throw();
+    });
+
+    it("changes the value for an edge if it is already in the graph", function() {
+      g.setEdge("a", "b", "foo");
+      g.setEdge("a", "b", "bar");
+      expect(g.edge("a", "b")).to.equal("bar");
+    });
+
+    it ("deletes the value for the edge if the value arg is undefined", function() {
+      g.setEdge("a", "b", "foo");
+      g.setEdge("a", "b", undefined);
+      expect(g.edge("a", "b")).to.be.undefined;
+      expect(g.hasEdge("a", "b")).to.be.true;
+    });
+
+    it("changes the value for a multi-edge if it is already in the graph", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b", "value", "name");
+      g.setEdge("a", "b", undefined, "name");
+      expect(g.edge("a", "b", "name")).to.be.undefined;
+      expect(g.hasEdge("a", "b", "name")).to.be.true;
+    });
+
+    it("can take an edge object as the first parameter", function() {
+      g.setEdge({ v: "a", w: "b" }, "value");
+      expect(g.edge("a", "b")).to.equal("value");
+    });
+
+    it("can take an multi-edge object as the first parameter", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge({ v: "a", w: "b", name: "name" }, "value");
+      expect(g.edge("a", "b", "name")).to.equal("value");
+    });
+
+    it("uses the stringified form of the id #1", function() {
+      g.setEdge(1, 2, "foo");
+      expect(g.edges()).eqls([{ v: "1", w: "2" }]);
+      expect(g.edge("1", "2")).to.equal("foo");
+      expect(g.edge(1, 2)).to.equal("foo");
+    });
+
+    it("uses the stringified form of the id #2", function() {
+      g = new Graph({ multigraph: true });
+      g.setEdge(1, 2, "foo", undefined);
+      expect(g.edges()).eqls([{ v: "1", w: "2" }]);
+      expect(g.edge("1", "2")).to.equal("foo");
+      expect(g.edge(1, 2)).to.equal("foo");
+    });
+
+    it("uses the stringified form of the id with a name", function() {
+      g = new Graph({ multigraph: true });
+      g.setEdge(1, 2, "foo", 3);
+      expect(g.edge("1", "2", "3")).to.equal("foo");
+      expect(g.edge(1, 2, 3)).to.equal("foo");
+      expect(g.edges()).eqls([{ v: "1", w: "2", name: "3" }]);
+    });
+
+    it("treats edges in opposite directions as distinct in a digraph", function() {
+      g.setEdge("a", "b");
+      expect(g.hasEdge("a", "b")).to.be.true;
+      expect(g.hasEdge("b", "a")).to.be.false;
+    });
+
+    it("handles undirected graph edges", function() {
+      var g = new Graph({ directed: false });
+      g.setEdge("a", "b", "foo");
+      expect(g.edge("a", "b")).to.equal("foo");
+      expect(g.edge("b", "a")).to.equal("foo");
+    });
+
+    it("handles undirected edges where id has different order than Stringified id", function() {
+      var g = new Graph({ directed: false });
+      g.setEdge(9, 10, "foo");
+      expect(g.hasEdge("9", "10")).to.be.true;
+      expect(g.hasEdge(9, 10)).to.be.true;
+      expect(g.hasEdge("10", "9")).to.be.true;
+      expect(g.hasEdge(10, 9)).to.be.true;
+      expect(g.edge("9", "10")).eqls("foo");
+      expect(g.edge(9, 10)).eqls("foo");
+    });
+
+    it("is chainable", function() {
+      expect(g.setEdge("a", "b")).to.equal(g);
+    });
+  });
+
+  describe("setDefaultEdgeLabel", function() {
+    it("sets a default label for new edges", function() {
+      g.setDefaultEdgeLabel("foo");
+      g.setEdge("a", "b");
+      expect(g.edge("a", "b")).to.equal("foo");
+    });
+
+    it("does not change existing edges", function() {
+      g.setEdge("a", "b");
+      g.setDefaultEdgeLabel("foo");
+      expect(g.edge("a", "b")).to.be.undefined;
+    });
+
+    it("is not used if an explicit value is set", function() {
+      g.setDefaultEdgeLabel("foo");
+      g.setEdge("a", "b", "bar");
+      expect(g.edge("a", "b")).to.equal("bar");
+    });
+
+    it("can take a function", function() {
+      g.setDefaultEdgeLabel(function() { return "foo"; });
+      g.setEdge("a", "b");
+      expect(g.edge("a", "b")).to.equal("foo");
+    });
+
+    it("can take a function that takes the edge's endpoints and name", function() {
+      var g = new Graph({ multigraph: true });
+      g.setDefaultEdgeLabel(function(v, w, name) {
+        return v + "-" + w + "-" + name + "-foo";
+      });
+      g.setEdge({ v: "a", w: "b", name: "name"});
+      expect(g.edge("a", "b", "name")).to.equal("a-b-name-foo");
+    });
+
+    it("does not set a default value for a multi-edge that already exists", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b", "old", "name");
+      g.setDefaultEdgeLabel(function() { return "should not set this"; });
+      g.setEdge({ v: "a", w: "b", name: "name"});
+      expect(g.edge("a", "b", "name")).to.equal("old");
+    });
+
+    it("is chainable", function() {
+      expect(g.setDefaultEdgeLabel("foo")).to.equal(g);
+    });
+  });
+
+  describe("edge", function() {
+    it("returns undefined if the edge isn't part of the graph", function() {
+      expect(g.edge("a", "b")).to.be.undefined;
+      expect(g.edge({ v: "a", w: "b" })).to.be.undefined;
+      expect(g.edge("a", "b", "foo")).to.be.undefined;
+    });
+
+    it("returns the value of the edge if it is part of the graph", function() {
+      g.setEdge("a", "b", { foo: "bar" });
+      expect(g.edge("a", "b")).to.eql({ foo: "bar" });
+      expect(g.edge({ v: "a", w: "b" })).to.eql({ foo: "bar" });
+      expect(g.edge("b", "a")).to.be.undefined;
+    });
+
+    it("returns the value of a multi-edge if it is part of the graph", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b", { bar: "baz" }, "foo");
+      expect(g.edge("a", "b", "foo")).to.eql({ bar: "baz" });
+      expect(g.edge("a", "b")).to.be.undefined;
+    });
+
+    it("returns an edge in either direction in an undirected graph", function() {
+      var g = new Graph({ directed: false });
+      g.setEdge("a", "b", { foo: "bar" });
+      expect(g.edge("a", "b")).to.eql({ foo: "bar" });
+      expect(g.edge("b", "a")).to.eql({ foo: "bar" });
+    });
+  });
+
+  describe("removeEdge", function() {
+    it("has no effect if the edge is not in the graph", function() {
+      g.removeEdge("a", "b");
+      expect(g.hasEdge("a", "b")).to.be.false;
+      expect(g.edgeCount()).to.equal(0);
+    });
+
+    it("can remove an edge by edgeObj", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge({ v: "a", w: "b", name: "foo" });
+      g.removeEdge({ v: "a", w: "b", name: "foo" });
+      expect(g.hasEdge("a", "b", "foo")).to.be.false;
+      expect(g.edgeCount()).to.equal(0);
+    });
+
+    it("can remove an edge by separate ids", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge({ v: "a", w: "b", name: "foo" });
+      g.removeEdge("a", "b", "foo");
+      expect(g.hasEdge("a", "b", "foo")).to.be.false;
+      expect(g.edgeCount()).to.equal(0);
+    });
+
+    it("correctly removes neighbors", function() {
+      g.setEdge("a", "b");
+      g.removeEdge("a", "b");
+      expect(g.successors("a")).to.eql([]);
+      expect(g.neighbors("a")).to.eql([]);
+      expect(g.predecessors("b")).to.eql([]);
+      expect(g.neighbors("b")).to.eql([]);
+    });
+
+    it("correctly decrements neighbor counts", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b");
+      g.setEdge({ v: "a", w: "b", name: "foo" });
+      g.removeEdge("a", "b");
+      expect(g.hasEdge("a", "b", "foo"));
+      expect(g.successors("a")).to.eql(["b"]);
+      expect(g.neighbors("a")).to.eql(["b"]);
+      expect(g.predecessors("b")).to.eql(["a"]);
+      expect(g.neighbors("b")).to.eql(["a"]);
+    });
+
+    it("works with undirected graphs", function() {
+      var g = new Graph({ directed: false });
+      g.setEdge("h", "g");
+      g.removeEdge("g", "h");
+      expect(g.neighbors("g")).to.eql([]);
+      expect(g.neighbors("h")).to.eql([]);
+    });
+
+    it("is chainable", function() {
+      g.setEdge("a", "b");
+      expect(g.removeEdge("a", "b")).to.equal(g);
+    });
+  });
+
+  describe("inEdges", function() {
+    it("returns undefined for a node that is not in the graph", function() {
+      expect(g.inEdges("a")).to.be.undefined;
+    });
+
+    it("returns the edges that point at the specified node", function() {
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      expect(g.inEdges("a")).to.eql([]);
+      expect(g.inEdges("b")).to.eql([{ v: "a", w: "b" }]);
+      expect(g.inEdges("c")).to.eql([{ v: "b", w: "c" }]);
+    });
+
+    it("works for multigraphs", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b");
+      g.setEdge("a", "b", undefined, "bar");
+      g.setEdge("a", "b", undefined, "foo");
+      expect(g.inEdges("a")).to.eql([]);
+      expect(_.sortBy(g.inEdges("b"), "name")).to.eql([
+        { v: "a", w: "b", name: "bar" },
+        { v: "a", w: "b", name: "foo" },
+        { v: "a", w: "b" }
+      ]);
+    });
+
+    it("can return only edges from a specified node", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b");
+      g.setEdge("a", "b", undefined, "foo");
+      g.setEdge("a", "c");
+      g.setEdge("b", "c");
+      g.setEdge("z", "a");
+      g.setEdge("z", "b");
+      expect(g.inEdges("a", "b")).to.eql([]);
+      expect(_.sortBy(g.inEdges("b", "a"), "name")).to.eql([
+        { v: "a", w: "b", name: "foo" },
+        { v: "a", w: "b" }
+      ]);
+    });
+  });
+
+  describe("outEdges", function() {
+    it("returns undefined for a node that is not in the graph", function() {
+      expect(g.outEdges("a")).to.be.undefined;
+    });
+
+    it("returns all edges that this node points at", function() {
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      expect(g.outEdges("a")).to.eql([{ v: "a", w: "b" }]);
+      expect(g.outEdges("b")).to.eql([{ v: "b", w: "c" }]);
+      expect(g.outEdges("c")).to.eql([]);
+    });
+
+    it("works for multigraphs", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b");
+      g.setEdge("a", "b", undefined, "bar");
+      g.setEdge("a", "b", undefined, "foo");
+      expect(_.sortBy(g.outEdges("a"), "name")).to.eql([
+        { v: "a", w: "b", name: "bar" },
+        { v: "a", w: "b", name: "foo" },
+        { v: "a", w: "b" }
+      ]);
+      expect(g.outEdges("b")).to.eql([]);
+    });
+
+    it("can return only edges to a specified node", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b");
+      g.setEdge("a", "b", undefined, "foo");
+      g.setEdge("a", "c");
+      g.setEdge("b", "c");
+      g.setEdge("z", "a");
+      g.setEdge("z", "b");
+      expect(_.sortBy(g.outEdges("a", "b"), "name")).to.eql([
+        { v: "a", w: "b", name: "foo" },
+        { v: "a", w: "b" }
+      ]);
+      expect(g.outEdges("b", "a")).to.eql([]);
+    });
+  });
+
+  describe("nodeEdges", function() {
+    it("returns undefined for a node that is not in the graph", function() {
+      expect(g.nodeEdges("a")).to.be.undefined;
+    });
+
+    it("returns all edges that this node points at", function() {
+      g.setEdge("a", "b");
+      g.setEdge("b", "c");
+      expect(g.nodeEdges("a")).to.eql([{ v: "a", w: "b" }]);
+      expect(_.sortBy(g.nodeEdges("b"), ["v", "w"]))
+        .to.eql([{ v: "a", w: "b" }, { v: "b", w: "c" }]);
+      expect(g.nodeEdges("c")).to.eql([{ v: "b", w: "c" }]);
+    });
+
+    it("works for multigraphs", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b");
+      g.setEdge({ v: "a", w: "b", name: "bar" });
+      g.setEdge({ v: "a", w: "b", name: "foo" });
+      expect(_.sortBy(g.nodeEdges("a"), "name")).to.eql([
+        { v: "a", w: "b", name: "bar" },
+        { v: "a", w: "b", name: "foo" },
+        { v: "a", w: "b" }
+      ]);
+      expect(_.sortBy(g.nodeEdges("b"), "name")).to.eql([
+        { v: "a", w: "b", name: "bar" },
+        { v: "a", w: "b", name: "foo" },
+        { v: "a", w: "b" }
+      ]);
+    });
+
+    it("can return only edges between specific nodes", function() {
+      var g = new Graph({ multigraph: true });
+      g.setEdge("a", "b");
+      g.setEdge({ v: "a", w: "b", name: "foo" });
+      g.setEdge("a", "c");
+      g.setEdge("b", "c");
+      g.setEdge("z", "a");
+      g.setEdge("z", "b");
+      expect(_.sortBy(g.nodeEdges("a", "b"), "name")).to.eql([
+        { v: "a", w: "b", name: "foo" },
+        { v: "a", w: "b" }
+      ]);
+      expect(_.sortBy(g.nodeEdges("b", "a"), "name")).to.eql([
+        { v: "a", w: "b", name: "foo" },
+        { v: "a", w: "b" }
+      ]);
+    });
+  });
+});
diff --git a/debian/missing-source/graphlib/test/json-test.js b/debian/missing-source/graphlib/test/json-test.js
new file mode 100644
index 0000000..ac107d3
--- /dev/null
+++ b/debian/missing-source/graphlib/test/json-test.js
@@ -0,0 +1,64 @@
+var expect = require("./chai").expect,
+    Graph = require("..").Graph,
+    read = require("..").json.read,
+    write = require("..").json.write;
+
+describe("json", function() {
+  it("preserves the graph options", function() {
+    expect(rw(new Graph({ directed: true })).isDirected()).to.be.true;
+    expect(rw(new Graph({ directed: false })).isDirected()).to.be.false;
+    expect(rw(new Graph({ multigraph: true })).isMultigraph()).to.be.true;
+    expect(rw(new Graph({ multigraph: false })).isMultigraph()).to.be.false;
+    expect(rw(new Graph({ compound: true })).isCompound()).to.be.true;
+    expect(rw(new Graph({ compound: false })).isCompound()).to.be.false;
+  });
+
+  it("preserves the graph value, if any", function() {
+    expect(rw(new Graph().setGraph(1)).graph()).equals(1);
+    expect(rw(new Graph().setGraph({ foo: "bar" })).graph()).eqls({ foo: "bar" });
+    expect(rw(new Graph()).graph()).to.be.undefined;
+  });
+
+  it("preserves nodes", function() {
+    expect(rw(new Graph().setNode("a")).hasNode("a")).to.be.true;
+    expect(rw(new Graph().setNode("a")).node("a")).to.be.undefined;
+    expect(rw(new Graph().setNode("a", 1)).node("a")).equals(1);
+    expect(rw(new Graph().setNode("a", { foo: "bar" })).node("a"))
+      .eqls({ foo: "bar" });
+  });
+
+  it("preserves simple edges", function() {
+    expect(rw(new Graph().setEdge("a", "b")).hasEdge("a", "b")).to.be.true;
+    expect(rw(new Graph().setEdge("a", "b")).edge("a", "b")).to.be.undefined;
+    expect(rw(new Graph().setEdge("a", "b", 1)).edge("a", "b")).equals(1);
+    expect(rw(new Graph().setEdge("a", "b", { foo: "bar" })).edge("a", "b"))
+      .eqls({ foo: "bar" });
+  });
+
+  it("preserves multi-edges", function() {
+    var g = new Graph({ multigraph: true });
+
+    g.setEdge({ v: "a", w: "b", name: "foo" });
+    expect(rw(g).hasEdge("a", "b", "foo")).to.be.true;
+
+    g.setEdge({ v: "a", w: "b", name: "foo" });
+    expect(rw(g).edge("a", "b", "foo")).to.be.undefined;
+
+    g.setEdge({ v: "a", w: "b", name: "foo" }, 1);
+    expect(rw(g).edge("a", "b", "foo")).equals(1);
+
+    g.setEdge({ v: "a", w: "b", name: "foo" }, { foo: "bar" });
+    expect(rw(g).edge("a", "b", "foo")).eqls({ foo: "bar" });
+  });
+
+  it("preserves parent / child relationships", function() {
+    expect(rw(new Graph({ compound: true }).setNode("a")).parent("a"))
+      .to.be.undefined;
+    expect(rw(new Graph({ compound: true }).setParent("a", "parent")).parent("a"))
+      .to.equal("parent");
+  });
+});
+
+function rw(g) {
+  return read(write(g));
+}
diff --git a/debian/missing-source/graphlib/test/version-test.js b/debian/missing-source/graphlib/test/version-test.js
new file mode 100644
index 0000000..e8b2d20
--- /dev/null
+++ b/debian/missing-source/graphlib/test/version-test.js
@@ -0,0 +1,8 @@
+var expect = require('./chai').expect;
+
+describe('version', function() {
+  it('should match the version from package.json', function() {
+    var packageVersion = require('../package').version;
+    expect(require('../lib/version')).to.equal(packageVersion);
+  });
+});
diff --git a/debian/missing-source/js_fixes.diff b/debian/missing-source/js_fixes.diff
new file mode 100644
index 0000000..ecc88ed
--- /dev/null
+++ b/debian/missing-source/js_fixes.diff
@@ -0,0 +1,80 @@
+Changes made to these JavaScript modules to allow skipping the tests (which have not-in-Debian dependencies) and allow use of browserify-lite and old pegjs.  (Already applied in this source tree)
+
+Generated files deleted: */dist/*, graphlib-dot/bower.json, graphlib-dot/lib/dot-grammar.js, graphlib-dot/lib/version.js
+
+diff -upr a/graphlib-dot/lib/read-one.js b/graphlib-dot/lib/read-one.js
+--- a/graphlib-dot/lib/read-one.js
++++ b/graphlib-dot/lib/read-one.js
+@@ -2,7 +2,7 @@ var grammar = require("./dot-grammar"),
+     buildGraph = require("./build-graph");
+ 
+ module.exports = function readOne(str) {
+-  var parseTree = grammar.parse(str, { startRule: "graphStmt" });
++  var parseTree = grammar.parse(str, "graphStmt");
+   return buildGraph(parseTree);
+ };
+ 
+diff -upr a/graphlib-dot/Makefile b/graphlib-dot/Makefile
+--- a/graphlib-dot/Makefile
++++ b/graphlib-dot/Makefile
+@@ -1,14 +1,14 @@
+ MOD = graphlib-dot
+ 
+ NPM = npm
+-BROWSERIFY = ./node_modules/browserify/bin/cmd.js
++BROWSERIFY = browserify-lite
+ ISTANBUL = ./node_modules/istanbul/lib/cli.js
+ JSHINT = ./node_modules/jshint/bin/jshint
+ JSCS = ./node_modules/jscs/bin/jscs
+ KARMA = ./node_modules/karma/bin/karma
+ MOCHA = ./node_modules/mocha/bin/_mocha
+-PEGJS = ./node_modules/pegjs/bin/pegjs
+-UGLIFY = ./node_modules/uglify-js/bin/uglifyjs
++PEGJS = pegjs
++UGLIFY = uglifyjs
+ 
+ ISTANBUL_OPTS = --dir $(COVERAGE_DIR) --report html
+ JSHINT_OPTS = --reporter node_modules/jshint-stylish/stylish.js
+@@ -21,8 +21,7 @@ DIST_DIR = dist
+ SRC_FILES = index.js lib/dot-grammar.js lib/version.js $(shell find lib -type f -name '*.js')
+ TEST_FILES = $(shell find test -type f -name '*.js' | grep -v 'bundle-test.js')
+ BUILD_FILES = $(addprefix $(BUILD_DIR)/, \
+-						$(MOD).js $(MOD).min.js \
+-						$(MOD).core.js $(MOD).core.min.js)
++						$(MOD).js $(MOD).min.js)
+ 
+ DIRS = $(BUILD_DIR)
+ 
+@@ -31,7 +30,7 @@ DIRS = $(BUILD_DIR)
+ all: unit-test
+ 
+ lib/dot-grammar.js: src/dot-grammar.pegjs
+-	$(PEGJS) --allowed-start-rules "start,graphStmt" -e 'module.exports' $< $@
++	$(PEGJS) -e 'module.exports' $< $@
+ 
+ lib/version.js: package.json
+ 	@src/release/make-version.js > $@
+@@ -53,19 +52,19 @@ browser-test: $(BUILD_DIR)/$(MOD).js $(B
+ bower.json: package.json src/release/make-bower.json.js
+ 	@src/release/make-bower.json.js > $@
+ 
+-$(BUILD_DIR)/$(MOD).js: browser.js $(SRC_FILES) | unit-test
+-	@$(BROWSERIFY) $< > $@
++$(BUILD_DIR)/$(MOD).js: browser.js $(SRC_FILES) | $(BUILD_DIR)
++	@$(BROWSERIFY) ./$< --outfile $@
+ 
+ $(BUILD_DIR)/$(MOD).min.js: $(BUILD_DIR)/$(MOD).js
+ 	@$(UGLIFY) $< --comments '@license' > $@
+ 
+-$(BUILD_DIR)/$(MOD).core.js: browser.js | unit-test
++$(BUILD_DIR)/$(MOD).core.js: browser.js | $(BUILD_DIR)
+ 	@$(BROWSERIFY) $< > $@ --no-bundle-external
+ 
+ $(BUILD_DIR)/$(MOD).core.min.js: $(BUILD_DIR)/$(MOD).core.js
+ 	@$(UGLIFY) $< --comments '@license' > $@
+ 
+-dist: $(BUILD_FILES) | bower.json test
++dist: $(BUILD_FILES) | bower.json
+ 	@rm -rf $@
+ 	@mkdir -p $@
+ 	cp $^ $@
diff --git a/debian/rules b/debian/rules
index bbe4f51..2ef0455 100755
--- a/debian/rules
+++ b/debian/rules
@@ -2,18 +2,26 @@
 #export DH_VERBOSE=1
 #export DEB_BUILD_OPTIONS=nocheck
 export PYBUILD_NAME=theano
+export NODE_PATH=$(CURDIR)/debian/missing-source
 
 %:
 	dh $@ --with python2,python3,sphinxdoc --buildsystem=pybuild
 
 override_dh_auto_clean:
-	rm -f theano/d3viz/js/*.min.js doc/library/d3viz/examples/d3viz/js/*.min.js
+	rm -rf theano/d3viz/js/*.min.js doc/library/d3viz/examples/d3viz/js/*.min.js debian/missing-source/*.js debian/missing-source/lodash debian/missing-source/graphlib-dot/bower.json debian/missing-source/graphlib-dot/lib/dot-grammar.js debian/missing-source/graphlib-dot/lib/version.js
+	make -C debian/missing-source/graphlib-dot clean
 	dh_auto_clean
 
 override_dh_auto_build:
-	uglifyjs debian/missing-source/dagre-d3.js -c -o theano/d3viz/js/dagre-d3.min.js
-	uglifyjs debian/missing-source/graphlib-dot.js -c -o theano/d3viz/js/graphlib-dot.min.js
+	ln -s /usr/lib/nodejs/lodash-compat debian/missing-source/lodash
+	#graphlib-dot.js
+	make -C debian/missing-source/graphlib-dot --always-make dist
+	cp debian/missing-source/graphlib-dot/dist/graphlib-dot.min.js theano/d3viz/js
+	#dagre-d3.js
+	browserify-lite ./debian/missing-source/dagre-d3/index.js --outfile debian/missing-source/dagre-d3.js --standalone dagreD3
+	uglifyjs debian/missing-source/dagre-d3.js --comments '@license' -o theano/d3viz/js/dagre-d3.min.js
 	cp theano/d3viz/js/*.min.js doc/library/d3viz/examples/d3viz/js
+	#theano itself doesn't need a build as such
 
 export PYBUILD_INSTALL_ARGS=--install-scripts=/usr/share/{package}
 
@@ -38,3 +46,6 @@ override_dh_sphinxdoc:
 
 override_dh_compress:
 	dh_compress -X.py -X.ipynb -X.pdf # save theano-doc/html/_downloads
+
+override_dh_gencontrol:
+	dh_gencontrol -- -VjavascriptBU="$(shell dpkg-query -f '$${source:Package} (= $${source:Version}), \n' -W node-lodash-compat)"
diff --git a/debian/source.lintian-overrides b/debian/source.lintian-overrides
deleted file mode 100644
index 69419e4..0000000
--- a/debian/source.lintian-overrides
+++ /dev/null
@@ -1,7 +0,0 @@
-# prevent complaints on added sources in deb/missing-source
-theano source: insane-line-length-in-source-file debian/missing-source/dagre-d3.js line length is 805 characters (>512)
-theano source: source-contains-prebuilt-javascript-object debian/missing-source/dagre-d3.js line length is 805 characters (>512)
-theano source: source-is-missing debian/missing-source/dagre-d3.js line length is 805 characters (>512)
-theano source: insane-line-length-in-source-file debian/missing-source/graphlib-dot.js line length is 480 characters (>256)
-theano source: source-contains-prebuilt-javascript-object debian/missing-source/graphlib-dot.js line length is 480 characters (>256)
-theano source: source-is-missing debian/missing-source/graphlib-dot.js line length is 480 characters (>256)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/theano.git



More information about the debian-science-commits mailing list