[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