blob: b62dde66ad8ebeec9f7dfe35b9c17ef580f33978 [file] [log] [blame]
Nils Diewald0e6992a2015-04-14 20:13:52 +00001!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.dagre=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 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){
2/*
3Copyright (c) 2012-2014 Chris Pettitt
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
22*/
23
24module.exports = {
25 graphlib: require("./lib/graphlib"),
26
27 layout: require("./lib/layout"),
28 debug: require("./lib/debug"),
29 util: {
30 time: require("./lib/util").time,
31 notime: require("./lib/util").notime
32 },
33 version: require("./lib/version")
34};
35
36},{"./lib/debug":6,"./lib/graphlib":7,"./lib/layout":9,"./lib/util":29,"./lib/version":30}],2:[function(require,module,exports){
37"use strict";
38
39var _ = require("./lodash"),
40 greedyFAS = require("./greedy-fas");
41
42module.exports = {
43 run: run,
44 undo: undo
45};
46
47function run(g) {
48 var fas = (g.graph().acyclicer === "greedy"
49 ? greedyFAS(g, weightFn(g))
50 : dfsFAS(g));
51 _.each(fas, function(e) {
52 var label = g.edge(e);
53 g.removeEdge(e);
54 label.forwardName = e.name;
55 label.reversed = true;
56 g.setEdge(e.w, e.v, label, _.uniqueId("rev"));
57 });
58
59 function weightFn(g) {
60 return function(e) {
61 return g.edge(e).weight;
62 };
63 }
64}
65
66function dfsFAS(g) {
67 var fas = [],
68 stack = {},
69 visited = {};
70
71 function dfs(v) {
72 if (_.has(visited, v)) {
73 return;
74 }
75 visited[v] = true;
76 stack[v] = true;
77 _.each(g.outEdges(v), function(e) {
78 if (_.has(stack, e.w)) {
79 fas.push(e);
80 } else {
81 dfs(e.w);
82 }
83 });
84 delete stack[v];
85 }
86
87 _.each(g.nodes(), dfs);
88 return fas;
89}
90
91function undo(g) {
92 _.each(g.edges(), function(e) {
93 var label = g.edge(e);
94 if (label.reversed) {
95 g.removeEdge(e);
96
97 var forwardName = label.forwardName;
98 delete label.reversed;
99 delete label.forwardName;
100 g.setEdge(e.w, e.v, label, forwardName);
101 }
102 });
103}
104
105},{"./greedy-fas":8,"./lodash":10}],3:[function(require,module,exports){
106var _ = require("./lodash"),
107 util = require("./util");
108
109module.exports = addBorderSegments;
110
111function addBorderSegments(g) {
112 function dfs(v) {
113 var children = g.children(v),
114 node = g.node(v);
115 if (children.length) {
116 _.each(children, dfs);
117 }
118
119 if (_.has(node, "minRank")) {
120 node.borderLeft = [];
121 node.borderRight = [];
122 for (var rank = node.minRank, maxRank = node.maxRank + 1;
123 rank < maxRank;
124 ++rank) {
125 addBorderNode(g, "borderLeft", "_bl", v, node, rank);
126 addBorderNode(g, "borderRight", "_br", v, node, rank);
127 }
128 }
129 }
130
131 _.each(g.children(), dfs);
132}
133
134function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
135 var label = { width: 0, height: 0, rank: rank },
136 prev = sgNode[prop][rank - 1],
137 curr = util.addDummyNode(g, "border", label, prefix);
138 sgNode[prop][rank] = curr;
139 g.setParent(curr, sg);
140 if (prev) {
141 g.setEdge(prev, curr, { weight: 1 });
142 }
143}
144
145},{"./lodash":10,"./util":29}],4:[function(require,module,exports){
146"use strict";
147
148var _ = require("./lodash");
149
150module.exports = {
151 adjust: adjust,
152 undo: undo
153};
154
155function adjust(g) {
156 var rankDir = g.graph().rankdir.toLowerCase();
157 if (rankDir === "lr" || rankDir === "rl") {
158 swapWidthHeight(g);
159 }
160}
161
162function undo(g) {
163 var rankDir = g.graph().rankdir.toLowerCase();
164 if (rankDir === "bt" || rankDir === "rl") {
165 reverseY(g);
166 }
167
168 if (rankDir === "lr" || rankDir === "rl") {
169 swapXY(g);
170 swapWidthHeight(g);
171 }
172}
173
174function swapWidthHeight(g) {
175 _.each(g.nodes(), function(v) { swapWidthHeightOne(g.node(v)); });
176 _.each(g.edges(), function(e) { swapWidthHeightOne(g.edge(e)); });
177}
178
179function swapWidthHeightOne(attrs) {
180 var w = attrs.width;
181 attrs.width = attrs.height;
182 attrs.height = w;
183}
184
185function reverseY(g) {
186 _.each(g.nodes(), function(v) { reverseYOne(g.node(v)); });
187
188 _.each(g.edges(), function(e) {
189 var edge = g.edge(e);
190 _.each(edge.points, reverseYOne);
191 if (_.has(edge, "y")) {
192 reverseYOne(edge);
193 }
194 });
195}
196
197function reverseYOne(attrs) {
198 attrs.y = -attrs.y;
199}
200
201function swapXY(g) {
202 _.each(g.nodes(), function(v) { swapXYOne(g.node(v)); });
203
204 _.each(g.edges(), function(e) {
205 var edge = g.edge(e);
206 _.each(edge.points, swapXYOne);
207 if (_.has(edge, "x")) {
208 swapXYOne(edge);
209 }
210 });
211}
212
213function swapXYOne(attrs) {
214 var x = attrs.x;
215 attrs.x = attrs.y;
216 attrs.y = x;
217}
218
219},{"./lodash":10}],5:[function(require,module,exports){
220/*
221 * Simple doubly linked list implementation derived from Cormen, et al.,
222 * "Introduction to Algorithms".
223 */
224
225module.exports = List;
226
227function List() {
228 var sentinel = {};
229 sentinel._next = sentinel._prev = sentinel;
230 this._sentinel = sentinel;
231}
232
233List.prototype.dequeue = function() {
234 var sentinel = this._sentinel,
235 entry = sentinel._prev;
236 if (entry !== sentinel) {
237 unlink(entry);
238 return entry;
239 }
240};
241
242List.prototype.enqueue = function(entry) {
243 var sentinel = this._sentinel;
244 if (entry._prev && entry._next) {
245 unlink(entry);
246 }
247 entry._next = sentinel._next;
248 sentinel._next._prev = entry;
249 sentinel._next = entry;
250 entry._prev = sentinel;
251};
252
253List.prototype.toString = function() {
254 var strs = [],
255 sentinel = this._sentinel,
256 curr = sentinel._prev;
257 while (curr !== sentinel) {
258 strs.push(JSON.stringify(curr, filterOutLinks));
259 curr = curr._prev;
260 }
261 return "[" + strs.join(", ") + "]";
262};
263
264function unlink(entry) {
265 entry._prev._next = entry._next;
266 entry._next._prev = entry._prev;
267 delete entry._next;
268 delete entry._prev;
269}
270
271function filterOutLinks(k, v) {
272 if (k !== "_next" && k !== "_prev") {
273 return v;
274 }
275}
276
277},{}],6:[function(require,module,exports){
278var _ = require("./lodash"),
279 util = require("./util"),
280 Graph = require("./graphlib").Graph;
281
282module.exports = {
283 debugOrdering: debugOrdering
284};
285
286/* istanbul ignore next */
287function debugOrdering(g) {
288 var layerMatrix = util.buildLayerMatrix(g);
289
290 var h = new Graph({ compound: true, multigraph: true }).setGraph({});
291
292 _.each(g.nodes(), function(v) {
293 h.setNode(v, { label: v });
294 h.setParent(v, "layer" + g.node(v).rank);
295 });
296
297 _.each(g.edges(), function(e) {
298 h.setEdge(e.v, e.w, {}, e.name);
299 });
300
301 _.each(layerMatrix, function(layer, i) {
302 var layerV = "layer" + i;
303 h.setNode(layerV, { rank: "same" });
304 _.reduce(layer, function(u, v) {
305 h.setEdge(u, v, { style: "invis" });
306 return v;
307 });
308 });
309
310 return h;
311}
312
313},{"./graphlib":7,"./lodash":10,"./util":29}],7:[function(require,module,exports){
314/* global window */
315
316var graphlib;
317
318if (require) {
319 try {
320 graphlib = require("graphlib");
321 } catch (e) {}
322}
323
324if (!graphlib) {
325 graphlib = window.graphlib;
326}
327
328module.exports = graphlib;
329
330},{"graphlib":31}],8:[function(require,module,exports){
331var _ = require("./lodash"),
332 Graph = require("./graphlib").Graph,
333 List = require("./data/list");
334
335/*
336 * A greedy heuristic for finding a feedback arc set for a graph. A feedback
337 * arc set is a set of edges that can be removed to make a graph acyclic.
338 * The algorithm comes from: P. Eades, X. Lin, and W. F. Smyth, "A fast and
339 * effective heuristic for the feedback arc set problem." This implementation
340 * adjusts that from the paper to allow for weighted edges.
341 */
342module.exports = greedyFAS;
343
344var DEFAULT_WEIGHT_FN = _.constant(1);
345
346function greedyFAS(g, weightFn) {
347 if (g.nodeCount() <= 1) {
348 return [];
349 }
350 var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
351 var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
352
353 // Expand multi-edges
354 return _.flatten(_.map(results, function(e) {
355 return g.outEdges(e.v, e.w);
356 }), true);
357}
358
359function doGreedyFAS(g, buckets, zeroIdx) {
360 var results = [],
361 sources = buckets[buckets.length - 1],
362 sinks = buckets[0];
363
364 var entry;
365 while (g.nodeCount()) {
366 while ((entry = sinks.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
367 while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
368 if (g.nodeCount()) {
369 for (var i = buckets.length - 2; i > 0; --i) {
370 entry = buckets[i].dequeue();
371 if (entry) {
372 results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
373 break;
374 }
375 }
376 }
377 }
378
379 return results;
380}
381
382function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
383 var results = collectPredecessors ? [] : undefined;
384
385 _.each(g.inEdges(entry.v), function(edge) {
386 var weight = g.edge(edge),
387 uEntry = g.node(edge.v);
388
389 if (collectPredecessors) {
390 results.push({ v: edge.v, w: edge.w });
391 }
392
393 uEntry.out -= weight;
394 assignBucket(buckets, zeroIdx, uEntry);
395 });
396
397 _.each(g.outEdges(entry.v), function(edge) {
398 var weight = g.edge(edge),
399 w = edge.w,
400 wEntry = g.node(w);
401 wEntry["in"] -= weight;
402 assignBucket(buckets, zeroIdx, wEntry);
403 });
404
405 g.removeNode(entry.v);
406
407 return results;
408}
409
410function buildState(g, weightFn) {
411 var fasGraph = new Graph(),
412 maxIn = 0,
413 maxOut = 0;
414
415 _.each(g.nodes(), function(v) {
416 fasGraph.setNode(v, { v: v, "in": 0, out: 0 });
417 });
418
419 // Aggregate weights on nodes, but also sum the weights across multi-edges
420 // into a single edge for the fasGraph.
421 _.each(g.edges(), function(e) {
422 var prevWeight = fasGraph.edge(e.v, e.w) || 0,
423 weight = weightFn(e),
424 edgeWeight = prevWeight + weight;
425 fasGraph.setEdge(e.v, e.w, edgeWeight);
426 maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
427 maxIn = Math.max(maxIn, fasGraph.node(e.w)["in"] += weight);
428 });
429
430 var buckets = _.range(maxOut + maxIn + 3).map(function() { return new List(); });
431 var zeroIdx = maxIn + 1;
432
433 _.each(fasGraph.nodes(), function(v) {
434 assignBucket(buckets, zeroIdx, fasGraph.node(v));
435 });
436
437 return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
438}
439
440function assignBucket(buckets, zeroIdx, entry) {
441 if (!entry.out) {
442 buckets[0].enqueue(entry);
443 } else if (!entry["in"]) {
444 buckets[buckets.length - 1].enqueue(entry);
445 } else {
446 buckets[entry.out - entry["in"] + zeroIdx].enqueue(entry);
447 }
448}
449
450},{"./data/list":5,"./graphlib":7,"./lodash":10}],9:[function(require,module,exports){
451"use strict";
452
453var _ = require("./lodash"),
454 acyclic = require("./acyclic"),
455 normalize = require("./normalize"),
456 rank = require("./rank"),
457 normalizeRanks = require("./util").normalizeRanks,
458 parentDummyChains = require("./parent-dummy-chains"),
459 removeEmptyRanks = require("./util").removeEmptyRanks,
460 nestingGraph = require("./nesting-graph"),
461 addBorderSegments = require("./add-border-segments"),
462 coordinateSystem = require("./coordinate-system"),
463 order = require("./order"),
464 position = require("./position"),
465 util = require("./util"),
466 Graph = require("./graphlib").Graph;
467
468module.exports = layout;
469
470function layout(g, opts) {
471 var time = opts && opts.debugTiming ? util.time : util.notime;
472 time("layout", function() {
473 var layoutGraph = time(" buildLayoutGraph",
474 function() { return buildLayoutGraph(g); });
475 time(" runLayout", function() { runLayout(layoutGraph, time); });
476 time(" updateInputGraph", function() { updateInputGraph(g, layoutGraph); });
477 });
478}
479
480function runLayout(g, time) {
481 time(" makeSpaceForEdgeLabels", function() { makeSpaceForEdgeLabels(g); });
482 time(" removeSelfEdges", function() { removeSelfEdges(g); });
483 time(" acyclic", function() { acyclic.run(g); });
484 time(" nestingGraph.run", function() { nestingGraph.run(g); });
485 time(" rank", function() { rank(util.asNonCompoundGraph(g)); });
486 time(" injectEdgeLabelProxies", function() { injectEdgeLabelProxies(g); });
487 time(" removeEmptyRanks", function() { removeEmptyRanks(g); });
488 time(" nestingGraph.cleanup", function() { nestingGraph.cleanup(g); });
489 time(" normalizeRanks", function() { normalizeRanks(g); });
490 time(" assignRankMinMax", function() { assignRankMinMax(g); });
491 time(" removeEdgeLabelProxies", function() { removeEdgeLabelProxies(g); });
492 time(" normalize.run", function() { normalize.run(g); });
493 time(" parentDummyChains", function() { parentDummyChains(g); });
494 time(" addBorderSegments", function() { addBorderSegments(g); });
495 time(" order", function() { order(g); });
496 time(" insertSelfEdges", function() { insertSelfEdges(g); });
497 time(" adjustCoordinateSystem", function() { coordinateSystem.adjust(g); });
498 time(" position", function() { position(g); });
499 time(" positionSelfEdges", function() { positionSelfEdges(g); });
500 time(" removeBorderNodes", function() { removeBorderNodes(g); });
501 time(" normalize.undo", function() { normalize.undo(g); });
502 time(" fixupEdgeLabelCoords", function() { fixupEdgeLabelCoords(g); });
503 time(" undoCoordinateSystem", function() { coordinateSystem.undo(g); });
504 time(" translateGraph", function() { translateGraph(g); });
505 time(" assignNodeIntersects", function() { assignNodeIntersects(g); });
506 time(" reversePoints", function() { reversePointsForReversedEdges(g); });
507 time(" acyclic.undo", function() { acyclic.undo(g); });
508}
509
510/*
511 * Copies final layout information from the layout graph back to the input
512 * graph. This process only copies whitelisted attributes from the layout graph
513 * to the input graph, so it serves as a good place to determine what
514 * attributes can influence layout.
515 */
516function updateInputGraph(inputGraph, layoutGraph) {
517 _.each(inputGraph.nodes(), function(v) {
518 var inputLabel = inputGraph.node(v),
519 layoutLabel = layoutGraph.node(v);
520
521 if (inputLabel) {
522 inputLabel.x = layoutLabel.x;
523 inputLabel.y = layoutLabel.y;
524
525 if (layoutGraph.children(v).length) {
526 inputLabel.width = layoutLabel.width;
527 inputLabel.height = layoutLabel.height;
528 }
529 }
530 });
531
532 _.each(inputGraph.edges(), function(e) {
533 var inputLabel = inputGraph.edge(e),
534 layoutLabel = layoutGraph.edge(e);
535
536 inputLabel.points = layoutLabel.points;
537 if (_.has(layoutLabel, "x")) {
538 inputLabel.x = layoutLabel.x;
539 inputLabel.y = layoutLabel.y;
540 }
541 });
542
543 inputGraph.graph().width = layoutGraph.graph().width;
544 inputGraph.graph().height = layoutGraph.graph().height;
545}
546
547var graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"],
548 graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" },
549 graphAttrs = ["acyclicer", "ranker", "rankdir", "align"],
550 nodeNumAttrs = ["width", "height"],
551 nodeDefaults = { width: 0, height: 0 },
552 edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"],
553 edgeDefaults = {
554 minlen: 1, weight: 1, width: 0, height: 0,
555 labeloffset: 10, labelpos: "r"
556 },
557 edgeAttrs = ["labelpos"];
558
559/*
560 * Constructs a new graph from the input graph, which can be used for layout.
561 * This process copies only whitelisted attributes from the input graph to the
562 * layout graph. Thus this function serves as a good place to determine what
563 * attributes can influence layout.
564 */
565function buildLayoutGraph(inputGraph) {
566 var g = new Graph({ multigraph: true, compound: true }),
567 graph = canonicalize(inputGraph.graph());
568
569 g.setGraph(_.merge({},
570 graphDefaults,
571 selectNumberAttrs(graph, graphNumAttrs),
572 _.pick(graph, graphAttrs)));
573
574 _.each(inputGraph.nodes(), function(v) {
575 var node = canonicalize(inputGraph.node(v));
576 g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults));
577 g.setParent(v, inputGraph.parent(v));
578 });
579
580 _.each(inputGraph.edges(), function(e) {
581 var edge = canonicalize(inputGraph.edge(e));
582 g.setEdge(e, _.merge({},
583 edgeDefaults,
584 selectNumberAttrs(edge, edgeNumAttrs),
585 _.pick(edge, edgeAttrs)));
586 });
587
588 return g;
589}
590
591/*
592 * This idea comes from the Gansner paper: to account for edge labels in our
593 * layout we split each rank in half by doubling minlen and halving ranksep.
594 * Then we can place labels at these mid-points between nodes.
595 *
596 * We also add some minimal padding to the width to push the label for the edge
597 * away from the edge itself a bit.
598 */
599function makeSpaceForEdgeLabels(g) {
600 var graph = g.graph();
601 graph.ranksep /= 2;
602 _.each(g.edges(), function(e) {
603 var edge = g.edge(e);
604 edge.minlen *= 2;
605 if (edge.labelpos.toLowerCase() !== "c") {
606 if (graph.rankdir === "TB" || graph.rankdir === "BT") {
607 edge.width += edge.labeloffset;
608 } else {
609 edge.height += edge.labeloffset;
610 }
611 }
612 });
613}
614
615/*
616 * Creates temporary dummy nodes that capture the rank in which each edge's
617 * label is going to, if it has one of non-zero width and height. We do this
618 * so that we can safely remove empty ranks while preserving balance for the
619 * label's position.
620 */
621function injectEdgeLabelProxies(g) {
622 _.each(g.edges(), function(e) {
623 var edge = g.edge(e);
624 if (edge.width && edge.height) {
625 var v = g.node(e.v),
626 w = g.node(e.w),
627 label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e };
628 util.addDummyNode(g, "edge-proxy", label, "_ep");
629 }
630 });
631}
632
633function assignRankMinMax(g) {
634 var maxRank = 0;
635 _.each(g.nodes(), function(v) {
636 var node = g.node(v);
637 if (node.borderTop) {
638 node.minRank = g.node(node.borderTop).rank;
639 node.maxRank = g.node(node.borderBottom).rank;
640 maxRank = _.max(maxRank, node.maxRank);
641 }
642 });
643 g.graph().maxRank = maxRank;
644}
645
646function removeEdgeLabelProxies(g) {
647 _.each(g.nodes(), function(v) {
648 var node = g.node(v);
649 if (node.dummy === "edge-proxy") {
650 g.edge(node.e).labelRank = node.rank;
651 g.removeNode(v);
652 }
653 });
654}
655
656function translateGraph(g) {
657 var minX = Number.POSITIVE_INFINITY,
658 maxX = 0,
659 minY = Number.POSITIVE_INFINITY,
660 maxY = 0,
661 graphLabel = g.graph(),
662 marginX = graphLabel.marginx || 0,
663 marginY = graphLabel.marginy || 0;
664
665 function getExtremes(attrs) {
666 var x = attrs.x,
667 y = attrs.y,
668 w = attrs.width,
669 h = attrs.height;
670 minX = Math.min(minX, x - w / 2);
671 maxX = Math.max(maxX, x + w / 2);
672 minY = Math.min(minY, y - h / 2);
673 maxY = Math.max(maxY, y + h / 2);
674 }
675
676 _.each(g.nodes(), function(v) { getExtremes(g.node(v)); });
677 _.each(g.edges(), function(e) {
678 var edge = g.edge(e);
679 if (_.has(edge, "x")) {
680 getExtremes(edge);
681 }
682 });
683
684 minX -= marginX;
685 minY -= marginY;
686
687 _.each(g.nodes(), function(v) {
688 var node = g.node(v);
689 node.x -= minX;
690 node.y -= minY;
691 });
692
693 _.each(g.edges(), function(e) {
694 var edge = g.edge(e);
695 _.each(edge.points, function(p) {
696 p.x -= minX;
697 p.y -= minY;
698 });
699 if (_.has(edge, "x")) { edge.x -= minX; }
700 if (_.has(edge, "y")) { edge.y -= minY; }
701 });
702
703 graphLabel.width = maxX - minX + marginX;
704 graphLabel.height = maxY - minY + marginY;
705}
706
707function assignNodeIntersects(g) {
708 _.each(g.edges(), function(e) {
709 var edge = g.edge(e),
710 nodeV = g.node(e.v),
711 nodeW = g.node(e.w),
712 p1, p2;
713 if (!edge.points) {
714 edge.points = [];
715 p1 = nodeW;
716 p2 = nodeV;
717 } else {
718 p1 = edge.points[0];
719 p2 = edge.points[edge.points.length - 1];
720 }
721 edge.points.unshift(util.intersectRect(nodeV, p1));
722 edge.points.push(util.intersectRect(nodeW, p2));
723 });
724}
725
726function fixupEdgeLabelCoords(g) {
727 _.each(g.edges(), function(e) {
728 var edge = g.edge(e);
729 if (_.has(edge, "x")) {
730 if (edge.labelpos === "l" || edge.labelpos === "r") {
731 edge.width -= edge.labeloffset;
732 }
733 switch (edge.labelpos) {
734 case "l": edge.x -= edge.width / 2 + edge.labeloffset; break;
735 case "r": edge.x += edge.width / 2 + edge.labeloffset; break;
736 }
737 }
738 });
739}
740
741function reversePointsForReversedEdges(g) {
742 _.each(g.edges(), function(e) {
743 var edge = g.edge(e);
744 if (edge.reversed) {
745 edge.points.reverse();
746 }
747 });
748}
749
750function removeBorderNodes(g) {
751 _.each(g.nodes(), function(v) {
752 if (g.children(v).length) {
753 var node = g.node(v),
754 t = g.node(node.borderTop),
755 b = g.node(node.borderBottom),
756 l = g.node(_.last(node.borderLeft)),
757 r = g.node(_.last(node.borderRight));
758
759 node.width = Math.abs(r.x - l.x);
760 node.height = Math.abs(b.y - t.y);
761 node.x = l.x + node.width / 2;
762 node.y = t.y + node.height / 2;
763 }
764 });
765
766 _.each(g.nodes(), function(v) {
767 if (g.node(v).dummy === "border") {
768 g.removeNode(v);
769 }
770 });
771}
772
773function removeSelfEdges(g) {
774 _.each(g.edges(), function(e) {
775 if (e.v === e.w) {
776 var node = g.node(e.v);
777 if (!node.selfEdges) {
778 node.selfEdges = [];
779 }
780 node.selfEdges.push({ e: e, label: g.edge(e) });
781 g.removeEdge(e);
782 }
783 });
784}
785
786function insertSelfEdges(g) {
787 var layers = util.buildLayerMatrix(g);
788 _.each(layers, function(layer) {
789 var orderShift = 0;
790 _.each(layer, function(v, i) {
791 var node = g.node(v);
792 node.order = i + orderShift;
793 _.each(node.selfEdges, function(selfEdge) {
794 util.addDummyNode(g, "selfedge", {
795 width: selfEdge.label.width,
796 height: selfEdge.label.height,
797 rank: node.rank,
798 order: i + (++orderShift),
799 e: selfEdge.e,
800 label: selfEdge.label
801 }, "_se");
802 });
803 delete node.selfEdges;
804 });
805 });
806}
807
808function positionSelfEdges(g) {
809 _.each(g.nodes(), function(v) {
810 var node = g.node(v);
811 if (node.dummy === "selfedge") {
812 var selfNode = g.node(node.e.v),
813 x = selfNode.x + selfNode.width / 2,
814 y = selfNode.y,
815 dx = node.x - x,
816 dy = selfNode.height / 2;
817 g.setEdge(node.e, node.label);
818 g.removeNode(v);
819 node.label.points = [
820 { x: x + 2 * dx / 3, y: y - dy },
821 { x: x + 5 * dx / 6, y: y - dy },
822 { x: x + dx , y: y },
823 { x: x + 5 * dx / 6, y: y + dy },
824 { x: x + 2 * dx / 3, y: y + dy },
825 ];
826 node.label.x = node.x;
827 node.label.y = node.y;
828 }
829 });
830}
831
832function selectNumberAttrs(obj, attrs) {
833 return _.mapValues(_.pick(obj, attrs), Number);
834}
835
836function canonicalize(attrs) {
837 var newAttrs = {};
838 _.each(attrs, function(v, k) {
839 newAttrs[k.toLowerCase()] = v;
840 });
841 return newAttrs;
842}
843
844},{"./acyclic":2,"./add-border-segments":3,"./coordinate-system":4,"./graphlib":7,"./lodash":10,"./nesting-graph":11,"./normalize":12,"./order":17,"./parent-dummy-chains":22,"./position":24,"./rank":26,"./util":29}],10:[function(require,module,exports){
845/* global window */
846
847var lodash;
848
849if (require) {
850 try {
851 lodash = require("lodash");
852 } catch (e) {}
853}
854
855if (!lodash) {
856 lodash = window._;
857}
858
859module.exports = lodash;
860
861},{"lodash":51}],11:[function(require,module,exports){
862var _ = require("./lodash"),
863 util = require("./util");
864
865module.exports = {
866 run: run,
867 cleanup: cleanup
868};
869
870/*
871 * A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
872 * adds appropriate edges to ensure that all cluster nodes are placed between
873 * these boundries, and ensures that the graph is connected.
874 *
875 * In addition we ensure, through the use of the minlen property, that nodes
876 * and subgraph border nodes to not end up on the same rank.
877 *
878 * Preconditions:
879 *
880 * 1. Input graph is a DAG
881 * 2. Nodes in the input graph has a minlen attribute
882 *
883 * Postconditions:
884 *
885 * 1. Input graph is connected.
886 * 2. Dummy nodes are added for the tops and bottoms of subgraphs.
887 * 3. The minlen attribute for nodes is adjusted to ensure nodes do not
888 * get placed on the same rank as subgraph border nodes.
889 *
890 * The nesting graph idea comes from Sander, "Layout of Compound Directed
891 * Graphs."
892 */
893function run(g) {
894 var root = util.addDummyNode(g, "root", {}, "_root"),
895 depths = treeDepths(g),
896 height = _.max(depths) - 1,
897 nodeSep = 2 * height + 1;
898
899 g.graph().nestingRoot = root;
900
901 // Multiply minlen by nodeSep to align nodes on non-border ranks.
902 _.each(g.edges(), function(e) { g.edge(e).minlen *= nodeSep; });
903
904 // Calculate a weight that is sufficient to keep subgraphs vertically compact
905 var weight = sumWeights(g) + 1;
906
907 // Create border nodes and link them up
908 _.each(g.children(), function(child) {
909 dfs(g, root, nodeSep, weight, height, depths, child);
910 });
911
912 // Save the multiplier for node layers for later removal of empty border
913 // layers.
914 g.graph().nodeRankFactor = nodeSep;
915}
916
917function dfs(g, root, nodeSep, weight, height, depths, v) {
918 var children = g.children(v);
919 if (!children.length) {
920 if (v !== root) {
921 g.setEdge(root, v, { weight: 0, minlen: nodeSep });
922 }
923 return;
924 }
925
926 var top = util.addBorderNode(g, "_bt"),
927 bottom = util.addBorderNode(g, "_bb"),
928 label = g.node(v);
929
930 g.setParent(top, v);
931 label.borderTop = top;
932 g.setParent(bottom, v);
933 label.borderBottom = bottom;
934
935 _.each(children, function(child) {
936 dfs(g, root, nodeSep, weight, height, depths, child);
937
938 var childNode = g.node(child),
939 childTop = childNode.borderTop ? childNode.borderTop : child,
940 childBottom = childNode.borderBottom ? childNode.borderBottom : child,
941 thisWeight = childNode.borderTop ? weight : 2 * weight,
942 minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
943
944 g.setEdge(top, childTop, {
945 weight: thisWeight,
946 minlen: minlen,
947 nestingEdge: true
948 });
949
950 g.setEdge(childBottom, bottom, {
951 weight: thisWeight,
952 minlen: minlen,
953 nestingEdge: true
954 });
955 });
956
957 if (!g.parent(v)) {
958 g.setEdge(root, top, { weight: 0, minlen: height + depths[v] });
959 }
960}
961
962function treeDepths(g) {
963 var depths = {};
964 function dfs(v, depth) {
965 var children = g.children(v);
966 if (children && children.length) {
967 _.each(children, function(child) {
968 dfs(child, depth + 1);
969 });
970 }
971 depths[v] = depth;
972 }
973 _.each(g.children(), function(v) { dfs(v, 1); });
974 return depths;
975}
976
977function sumWeights(g) {
978 return _.reduce(g.edges(), function(acc, e) {
979 return acc + g.edge(e).weight;
980 }, 0);
981}
982
983function cleanup(g) {
984 var graphLabel = g.graph();
985 g.removeNode(graphLabel.nestingRoot);
986 delete graphLabel.nestingRoot;
987 _.each(g.edges(), function(e) {
988 var edge = g.edge(e);
989 if (edge.nestingEdge) {
990 g.removeEdge(e);
991 }
992 });
993}
994
995},{"./lodash":10,"./util":29}],12:[function(require,module,exports){
996"use strict";
997
998var _ = require("./lodash"),
999 util = require("./util");
1000
1001module.exports = {
1002 run: run,
1003 undo: undo
1004};
1005
1006/*
1007 * Breaks any long edges in the graph into short segments that span 1 layer
1008 * each. This operation is undoable with the denormalize function.
1009 *
1010 * Pre-conditions:
1011 *
1012 * 1. The input graph is a DAG.
1013 * 2. Each node in the graph has a "rank" property.
1014 *
1015 * Post-condition:
1016 *
1017 * 1. All edges in the graph have a length of 1.
1018 * 2. Dummy nodes are added where edges have been split into segments.
1019 * 3. The graph is augmented with a "dummyChains" attribute which contains
1020 * the first dummy in each chain of dummy nodes produced.
1021 */
1022function run(g) {
1023 g.graph().dummyChains = [];
1024 _.each(g.edges(), function(edge) { normalizeEdge(g, edge); });
1025}
1026
1027function normalizeEdge(g, e) {
1028 var v = e.v,
1029 vRank = g.node(v).rank,
1030 w = e.w,
1031 wRank = g.node(w).rank,
1032 name = e.name,
1033 edgeLabel = g.edge(e),
1034 labelRank = edgeLabel.labelRank;
1035
1036 if (wRank === vRank + 1) return;
1037
1038 g.removeEdge(e);
1039
1040 var dummy, attrs, i;
1041 for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
1042 edgeLabel.points = [];
1043 attrs = {
1044 width: 0, height: 0,
1045 edgeLabel: edgeLabel, edgeObj: e,
1046 rank: vRank
1047 };
1048 dummy = util.addDummyNode(g, "edge", attrs, "_d");
1049 if (vRank === labelRank) {
1050 attrs.width = edgeLabel.width;
1051 attrs.height = edgeLabel.height;
1052 attrs.dummy = "edge-label";
1053 attrs.labelpos = edgeLabel.labelpos;
1054 }
1055 g.setEdge(v, dummy, { weight: edgeLabel.weight }, name);
1056 if (i === 0) {
1057 g.graph().dummyChains.push(dummy);
1058 }
1059 v = dummy;
1060 }
1061
1062 g.setEdge(v, w, { weight: edgeLabel.weight }, name);
1063}
1064
1065function undo(g) {
1066 _.each(g.graph().dummyChains, function(v) {
1067 var node = g.node(v),
1068 origLabel = node.edgeLabel,
1069 w;
1070 g.setEdge(node.edgeObj, origLabel);
1071 while (node.dummy) {
1072 w = g.successors(v)[0];
1073 g.removeNode(v);
1074 origLabel.points.push({ x: node.x, y: node.y });
1075 if (node.dummy === "edge-label") {
1076 origLabel.x = node.x;
1077 origLabel.y = node.y;
1078 origLabel.width = node.width;
1079 origLabel.height = node.height;
1080 }
1081 v = w;
1082 node = g.node(v);
1083 }
1084 });
1085}
1086
1087},{"./lodash":10,"./util":29}],13:[function(require,module,exports){
1088var _ = require("../lodash");
1089
1090module.exports = addSubgraphConstraints;
1091
1092function addSubgraphConstraints(g, cg, vs) {
1093 var prev = {},
1094 rootPrev;
1095
1096 _.each(vs, function(v) {
1097 var child = g.parent(v),
1098 parent,
1099 prevChild;
1100 while (child) {
1101 parent = g.parent(child);
1102 if (parent) {
1103 prevChild = prev[parent];
1104 prev[parent] = child;
1105 } else {
1106 prevChild = rootPrev;
1107 rootPrev = child;
1108 }
1109 if (prevChild && prevChild !== child) {
1110 cg.setEdge(prevChild, child);
1111 return;
1112 }
1113 child = parent;
1114 }
1115 });
1116
1117 /*
1118 function dfs(v) {
1119 var children = v ? g.children(v) : g.children();
1120 if (children.length) {
1121 var min = Number.POSITIVE_INFINITY,
1122 subgraphs = [];
1123 _.each(children, function(child) {
1124 var childMin = dfs(child);
1125 if (g.children(child).length) {
1126 subgraphs.push({ v: child, order: childMin });
1127 }
1128 min = Math.min(min, childMin);
1129 });
1130 _.reduce(_.sortBy(subgraphs, "order"), function(prev, curr) {
1131 cg.setEdge(prev.v, curr.v);
1132 return curr;
1133 });
1134 return min;
1135 }
1136 return g.node(v).order;
1137 }
1138 dfs(undefined);
1139 */
1140}
1141
1142},{"../lodash":10}],14:[function(require,module,exports){
1143var _ = require("../lodash");
1144
1145module.exports = barycenter;
1146
1147function barycenter(g, movable) {
1148 return _.map(movable, function(v) {
1149 var inV = g.inEdges(v);
1150 if (!inV.length) {
1151 return { v: v };
1152 } else {
1153 var result = _.reduce(inV, function(acc, e) {
1154 var edge = g.edge(e),
1155 nodeU = g.node(e.v);
1156 return {
1157 sum: acc.sum + (edge.weight * nodeU.order),
1158 weight: acc.weight + edge.weight
1159 };
1160 }, { sum: 0, weight: 0 });
1161
1162 return {
1163 v: v,
1164 barycenter: result.sum / result.weight,
1165 weight: result.weight
1166 };
1167 }
1168 });
1169}
1170
1171
1172},{"../lodash":10}],15:[function(require,module,exports){
1173var _ = require("../lodash"),
1174 Graph = require("../graphlib").Graph;
1175
1176module.exports = buildLayerGraph;
1177
1178/*
1179 * Constructs a graph that can be used to sort a layer of nodes. The graph will
1180 * contain all base and subgraph nodes from the request layer in their original
1181 * hierarchy and any edges that are incident on these nodes and are of the type
1182 * requested by the "relationship" parameter.
1183 *
1184 * Nodes from the requested rank that do not have parents are assigned a root
1185 * node in the output graph, which is set in the root graph attribute. This
1186 * makes it easy to walk the hierarchy of movable nodes during ordering.
1187 *
1188 * Pre-conditions:
1189 *
1190 * 1. Input graph is a DAG
1191 * 2. Base nodes in the input graph have a rank attribute
1192 * 3. Subgraph nodes in the input graph has minRank and maxRank attributes
1193 * 4. Edges have an assigned weight
1194 *
1195 * Post-conditions:
1196 *
1197 * 1. Output graph has all nodes in the movable rank with preserved
1198 * hierarchy.
1199 * 2. Root nodes in the movable layer are made children of the node
1200 * indicated by the root attribute of the graph.
1201 * 3. Non-movable nodes incident on movable nodes, selected by the
1202 * relationship parameter, are included in the graph (without hierarchy).
1203 * 4. Edges incident on movable nodes, selected by the relationship
1204 * parameter, are added to the output graph.
1205 * 5. The weights for copied edges are aggregated as need, since the output
1206 * graph is not a multi-graph.
1207 */
1208function buildLayerGraph(g, rank, relationship) {
1209 var root = createRootNode(g),
1210 result = new Graph({ compound: true }).setGraph({ root: root })
1211 .setDefaultNodeLabel(function(v) { return g.node(v); });
1212
1213 _.each(g.nodes(), function(v) {
1214 var node = g.node(v),
1215 parent = g.parent(v);
1216
1217 if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
1218 result.setNode(v);
1219 result.setParent(v, parent || root);
1220
1221 // This assumes we have only short edges!
1222 _.each(g[relationship](v), function(e) {
1223 var u = e.v === v ? e.w : e.v,
1224 edge = result.edge(u, v),
1225 weight = !_.isUndefined(edge) ? edge.weight : 0;
1226 result.setEdge(u, v, { weight: g.edge(e).weight + weight });
1227 });
1228
1229 if (_.has(node, "minRank")) {
1230 result.setNode(v, {
1231 borderLeft: node.borderLeft[rank],
1232 borderRight: node.borderRight[rank]
1233 });
1234 }
1235 }
1236 });
1237
1238 return result;
1239}
1240
1241function createRootNode(g) {
1242 var v;
1243 while (g.hasNode((v = _.uniqueId("_root"))));
1244 return v;
1245}
1246
1247},{"../graphlib":7,"../lodash":10}],16:[function(require,module,exports){
1248"use strict";
1249
1250var _ = require("../lodash");
1251
1252module.exports = crossCount;
1253
1254/*
1255 * A function that takes a layering (an array of layers, each with an array of
1256 * ordererd nodes) and a graph and returns a weighted crossing count.
1257 *
1258 * Pre-conditions:
1259 *
1260 * 1. Input graph must be simple (not a multigraph), directed, and include
1261 * only simple edges.
1262 * 2. Edges in the input graph must have assigned weights.
1263 *
1264 * Post-conditions:
1265 *
1266 * 1. The graph and layering matrix are left unchanged.
1267 *
1268 * This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
1269 */
1270function crossCount(g, layering) {
1271 var cc = 0;
1272 for (var i = 1; i < layering.length; ++i) {
1273 cc += twoLayerCrossCount(g, layering[i-1], layering[i]);
1274 }
1275 return cc;
1276}
1277
1278function twoLayerCrossCount(g, northLayer, southLayer) {
1279 // Sort all of the edges between the north and south layers by their position
1280 // in the north layer and then the south. Map these edges to the position of
1281 // their head in the south layer.
1282 var southPos = _.zipObject(southLayer,
1283 _.map(southLayer, function (v, i) { return i; }));
1284 var southEntries = _.flatten(_.map(northLayer, function(v) {
1285 return _.chain(g.outEdges(v))
1286 .map(function(e) {
1287 return { pos: southPos[e.w], weight: g.edge(e).weight };
1288 })
1289 .sortBy("pos")
1290 .value();
1291 }), true);
1292
1293 // Build the accumulator tree
1294 var firstIndex = 1;
1295 while (firstIndex < southLayer.length) firstIndex <<= 1;
1296 var treeSize = 2 * firstIndex - 1;
1297 firstIndex -= 1;
1298 var tree = _.map(new Array(treeSize), function() { return 0; });
1299
1300 // Calculate the weighted crossings
1301 var cc = 0;
1302 _.each(southEntries.forEach(function(entry) {
1303 var index = entry.pos + firstIndex;
1304 tree[index] += entry.weight;
1305 var weightSum = 0;
1306 while (index > 0) {
1307 if (index % 2) {
1308 weightSum += tree[index + 1];
1309 }
1310 index = (index - 1) >> 1;
1311 tree[index] += entry.weight;
1312 }
1313 cc += entry.weight * weightSum;
1314 }));
1315
1316 return cc;
1317}
1318
1319},{"../lodash":10}],17:[function(require,module,exports){
1320"use strict";
1321
1322var _ = require("../lodash"),
1323 initOrder = require("./init-order"),
1324 crossCount = require("./cross-count"),
1325 sortSubgraph = require("./sort-subgraph"),
1326 buildLayerGraph = require("./build-layer-graph"),
1327 addSubgraphConstraints = require("./add-subgraph-constraints"),
1328 Graph = require("../graphlib").Graph,
1329 util = require("../util");
1330
1331module.exports = order;
1332
1333/*
1334 * Applies heuristics to minimize edge crossings in the graph and sets the best
1335 * order solution as an order attribute on each node.
1336 *
1337 * Pre-conditions:
1338 *
1339 * 1. Graph must be DAG
1340 * 2. Graph nodes must be objects with a "rank" attribute
1341 * 3. Graph edges must have the "weight" attribute
1342 *
1343 * Post-conditions:
1344 *
1345 * 1. Graph nodes will have an "order" attribute based on the results of the
1346 * algorithm.
1347 */
1348function order(g) {
1349 var maxRank = util.maxRank(g),
1350 downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank + 1), "inEdges"),
1351 upLayerGraphs = buildLayerGraphs(g, _.range(maxRank - 1, -1, -1), "outEdges");
1352
1353 var layering = initOrder(g);
1354 assignOrder(g, layering);
1355
1356 var bestCC = Number.POSITIVE_INFINITY,
1357 best;
1358
1359 for (var i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
1360 sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
1361
1362 layering = util.buildLayerMatrix(g);
1363 var cc = crossCount(g, layering);
1364 if (cc < bestCC) {
1365 lastBest = 0;
1366 best = _.cloneDeep(layering);
1367 bestCC = cc;
1368 }
1369 }
1370
1371 assignOrder(g, best);
1372}
1373
1374function buildLayerGraphs(g, ranks, relationship) {
1375 return _.map(ranks, function(rank) {
1376 return buildLayerGraph(g, rank, relationship);
1377 });
1378}
1379
1380function sweepLayerGraphs(layerGraphs, biasRight) {
1381 var cg = new Graph();
1382 _.each(layerGraphs, function(lg) {
1383 var root = lg.graph().root;
1384 var sorted = sortSubgraph(lg, root, cg, biasRight);
1385 _.each(sorted.vs, function(v, i) {
1386 lg.node(v).order = i;
1387 });
1388 addSubgraphConstraints(lg, cg, sorted.vs);
1389 });
1390}
1391
1392function assignOrder(g, layering) {
1393 _.each(layering, function(layer) {
1394 _.each(layer, function(v, i) {
1395 g.node(v).order = i;
1396 });
1397 });
1398}
1399
1400},{"../graphlib":7,"../lodash":10,"../util":29,"./add-subgraph-constraints":13,"./build-layer-graph":15,"./cross-count":16,"./init-order":18,"./sort-subgraph":20}],18:[function(require,module,exports){
1401"use strict";
1402
1403var _ = require("../lodash");
1404
1405module.exports = initOrder;
1406
1407/*
1408 * Assigns an initial order value for each node by performing a DFS search
1409 * starting from nodes in the first rank. Nodes are assigned an order in their
1410 * rank as they are first visited.
1411 *
1412 * This approach comes from Gansner, et al., "A Technique for Drawing Directed
1413 * Graphs."
1414 *
1415 * Returns a layering matrix with an array per layer and each layer sorted by
1416 * the order of its nodes.
1417 */
1418function initOrder(g) {
1419 var visited = {},
1420 simpleNodes = _.filter(g.nodes(), function(v) {
1421 return !g.children(v).length;
1422 }),
1423 maxRank = _.max(_.map(simpleNodes, function(v) { return g.node(v).rank; })),
1424 layers = _.map(_.range(maxRank + 1), function() { return []; });
1425
1426 function dfs(v) {
1427 if (_.has(visited, v)) return;
1428 visited[v] = true;
1429 var node = g.node(v);
1430 layers[node.rank].push(v);
1431 _.each(g.successors(v), dfs);
1432 }
1433
1434 var orderedVs = _.sortBy(simpleNodes, function(v) { return g.node(v).rank; });
1435 _.each(orderedVs, dfs);
1436
1437 return layers;
1438}
1439
1440},{"../lodash":10}],19:[function(require,module,exports){
1441"use strict";
1442
1443var _ = require("../lodash");
1444
1445module.exports = resolveConflicts;
1446
1447/*
1448 * Given a list of entries of the form {v, barycenter, weight} and a
1449 * constraint graph this function will resolve any conflicts between the
1450 * constraint graph and the barycenters for the entries. If the barycenters for
1451 * an entry would violate a constraint in the constraint graph then we coalesce
1452 * the nodes in the conflict into a new node that respects the contraint and
1453 * aggregates barycenter and weight information.
1454 *
1455 * This implementation is based on the description in Forster, "A Fast and
1456 * Simple Hueristic for Constrained Two-Level Crossing Reduction," thought it
1457 * differs in some specific details.
1458 *
1459 * Pre-conditions:
1460 *
1461 * 1. Each entry has the form {v, barycenter, weight}, or if the node has
1462 * no barycenter, then {v}.
1463 *
1464 * Returns:
1465 *
1466 * A new list of entries of the form {vs, i, barycenter, weight}. The list
1467 * `vs` may either be a singleton or it may be an aggregation of nodes
1468 * ordered such that they do not violate constraints from the constraint
1469 * graph. The property `i` is the lowest original index of any of the
1470 * elements in `vs`.
1471 */
1472function resolveConflicts(entries, cg) {
1473 var mappedEntries = {};
1474 _.each(entries, function(entry, i) {
1475 var tmp = mappedEntries[entry.v] = {
1476 indegree: 0,
1477 "in": [],
1478 out: [],
1479 vs: [entry.v],
1480 i: i
1481 };
1482 if (!_.isUndefined(entry.barycenter)) {
1483 tmp.barycenter = entry.barycenter;
1484 tmp.weight = entry.weight;
1485 }
1486 });
1487
1488 _.each(cg.edges(), function(e) {
1489 var entryV = mappedEntries[e.v],
1490 entryW = mappedEntries[e.w];
1491 if (!_.isUndefined(entryV) && !_.isUndefined(entryW)) {
1492 entryW.indegree++;
1493 entryV.out.push(mappedEntries[e.w]);
1494 }
1495 });
1496
1497 var sourceSet = _.filter(mappedEntries, function(entry) {
1498 return !entry.indegree;
1499 });
1500
1501 return doResolveConflicts(sourceSet);
1502}
1503
1504function doResolveConflicts(sourceSet) {
1505 var entries = [];
1506
1507 function handleIn(vEntry) {
1508 return function(uEntry) {
1509 if (uEntry.merged) {
1510 return;
1511 }
1512 if (_.isUndefined(uEntry.barycenter) ||
1513 _.isUndefined(vEntry.barycenter) ||
1514 uEntry.barycenter >= vEntry.barycenter) {
1515 mergeEntries(vEntry, uEntry);
1516 }
1517 };
1518 }
1519
1520 function handleOut(vEntry) {
1521 return function(wEntry) {
1522 wEntry["in"].push(vEntry);
1523 if (--wEntry.indegree === 0) {
1524 sourceSet.push(wEntry);
1525 }
1526 };
1527 }
1528
1529 while (sourceSet.length) {
1530 var entry = sourceSet.pop();
1531 entries.push(entry);
1532 _.each(entry["in"].reverse(), handleIn(entry));
1533 _.each(entry.out, handleOut(entry));
1534 }
1535
1536 return _.chain(entries)
1537 .filter(function(entry) { return !entry.merged; })
1538 .map(function(entry) {
1539 return _.pick(entry, ["vs", "i", "barycenter", "weight"]);
1540 })
1541 .value();
1542}
1543
1544function mergeEntries(target, source) {
1545 var sum = 0,
1546 weight = 0;
1547
1548 if (target.weight) {
1549 sum += target.barycenter * target.weight;
1550 weight += target.weight;
1551 }
1552
1553 if (source.weight) {
1554 sum += source.barycenter * source.weight;
1555 weight += source.weight;
1556 }
1557
1558 target.vs = source.vs.concat(target.vs);
1559 target.barycenter = sum / weight;
1560 target.weight = weight;
1561 target.i = Math.min(source.i, target.i);
1562 source.merged = true;
1563}
1564
1565},{"../lodash":10}],20:[function(require,module,exports){
1566var _ = require("../lodash"),
1567 barycenter = require("./barycenter"),
1568 resolveConflicts = require("./resolve-conflicts"),
1569 sort = require("./sort");
1570
1571module.exports = sortSubgraph;
1572
1573function sortSubgraph(g, v, cg, biasRight) {
1574 var movable = g.children(v),
1575 node = g.node(v),
1576 bl = node ? node.borderLeft : undefined,
1577 br = node ? node.borderRight: undefined,
1578 subgraphs = {};
1579
1580 if (bl) {
1581 movable = _.filter(movable, function(w) {
1582 return w !== bl && w !== br;
1583 });
1584 }
1585
1586 var barycenters = barycenter(g, movable);
1587 _.each(barycenters, function(entry) {
1588 if (g.children(entry.v).length) {
1589 var subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
1590 subgraphs[entry.v] = subgraphResult;
1591 if (_.has(subgraphResult, "barycenter")) {
1592 mergeBarycenters(entry, subgraphResult);
1593 }
1594 }
1595 });
1596
1597 var entries = resolveConflicts(barycenters, cg);
1598 expandSubgraphs(entries, subgraphs);
1599
1600 var result = sort(entries, biasRight);
1601
1602 if (bl) {
1603 result.vs = _.flatten([bl, result.vs, br], true);
1604 if (g.predecessors(bl).length) {
1605 var blPred = g.node(g.predecessors(bl)[0]),
1606 brPred = g.node(g.predecessors(br)[0]);
1607 if (!_.has(result, "barycenter")) {
1608 result.barycenter = 0;
1609 result.weight = 0;
1610 }
1611 result.barycenter = (result.barycenter * result.weight +
1612 blPred.order + brPred.order) / (result.weight + 2);
1613 result.weight += 2;
1614 }
1615 }
1616
1617 return result;
1618}
1619
1620function expandSubgraphs(entries, subgraphs) {
1621 _.each(entries, function(entry) {
1622 entry.vs = _.flatten(entry.vs.map(function(v) {
1623 if (subgraphs[v]) {
1624 return subgraphs[v].vs;
1625 }
1626 return v;
1627 }), true);
1628 });
1629}
1630
1631function mergeBarycenters(target, other) {
1632 if (!_.isUndefined(target.barycenter)) {
1633 target.barycenter = (target.barycenter * target.weight +
1634 other.barycenter * other.weight) /
1635 (target.weight + other.weight);
1636 target.weight += other.weight;
1637 } else {
1638 target.barycenter = other.barycenter;
1639 target.weight = other.weight;
1640 }
1641}
1642
1643},{"../lodash":10,"./barycenter":14,"./resolve-conflicts":19,"./sort":21}],21:[function(require,module,exports){
1644var _ = require("../lodash"),
1645 util = require("../util");
1646
1647module.exports = sort;
1648
1649function sort(entries, biasRight) {
1650 var parts = util.partition(entries, function(entry) {
1651 return _.has(entry, "barycenter");
1652 });
1653 var sortable = parts.lhs,
1654 unsortable = _.sortBy(parts.rhs, function(entry) { return -entry.i; }),
1655 vs = [],
1656 sum = 0,
1657 weight = 0,
1658 vsIndex = 0;
1659
1660 sortable.sort(compareWithBias(!!biasRight));
1661
1662 vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
1663
1664 _.each(sortable, function (entry) {
1665 vsIndex += entry.vs.length;
1666 vs.push(entry.vs);
1667 sum += entry.barycenter * entry.weight;
1668 weight += entry.weight;
1669 vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
1670 });
1671
1672 var result = { vs: _.flatten(vs, true) };
1673 if (weight) {
1674 result.barycenter = sum / weight;
1675 result.weight = weight;
1676 }
1677 return result;
1678}
1679
1680function consumeUnsortable(vs, unsortable, index) {
1681 var last;
1682 while (unsortable.length && (last = _.last(unsortable)).i <= index) {
1683 unsortable.pop();
1684 vs.push(last.vs);
1685 index++;
1686 }
1687 return index;
1688}
1689
1690function compareWithBias(bias) {
1691 return function(entryV, entryW) {
1692 if (entryV.barycenter < entryW.barycenter) {
1693 return -1;
1694 } else if (entryV.barycenter > entryW.barycenter) {
1695 return 1;
1696 }
1697
1698 return !bias ? entryV.i - entryW.i : entryW.i - entryV.i;
1699 };
1700}
1701
1702},{"../lodash":10,"../util":29}],22:[function(require,module,exports){
1703var _ = require("./lodash");
1704
1705module.exports = parentDummyChains;
1706
1707function parentDummyChains(g) {
1708 var postorderNums = postorder(g);
1709
1710 _.each(g.graph().dummyChains, function(v) {
1711 var node = g.node(v),
1712 edgeObj = node.edgeObj,
1713 pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w),
1714 path = pathData.path,
1715 lca = pathData.lca,
1716 pathIdx = 0,
1717 pathV = path[pathIdx],
1718 ascending = true;
1719
1720 while (v !== edgeObj.w) {
1721 node = g.node(v);
1722
1723 if (ascending) {
1724 while ((pathV = path[pathIdx]) !== lca &&
1725 g.node(pathV).maxRank < node.rank) {
1726 pathIdx++;
1727 }
1728
1729 if (pathV === lca) {
1730 ascending = false;
1731 }
1732 }
1733
1734 if (!ascending) {
1735 while (pathIdx < path.length - 1 &&
1736 g.node(pathV = path[pathIdx + 1]).minRank <= node.rank) {
1737 pathIdx++;
1738 }
1739 pathV = path[pathIdx];
1740 }
1741
1742 g.setParent(v, pathV);
1743 v = g.successors(v)[0];
1744 }
1745 });
1746}
1747
1748// Find a path from v to w through the lowest common ancestor (LCA). Return the
1749// full path and the LCA.
1750function findPath(g, postorderNums, v, w) {
1751 var vPath = [],
1752 wPath = [],
1753 low = Math.min(postorderNums[v].low, postorderNums[w].low),
1754 lim = Math.max(postorderNums[v].lim, postorderNums[w].lim),
1755 parent,
1756 lca;
1757
1758 // Traverse up from v to find the LCA
1759 parent = v;
1760 do {
1761 parent = g.parent(parent);
1762 vPath.push(parent);
1763 } while (parent &&
1764 (postorderNums[parent].low > low || lim > postorderNums[parent].lim));
1765 lca = parent;
1766
1767 // Traverse from w to LCA
1768 parent = w;
1769 while ((parent = g.parent(parent)) !== lca) {
1770 wPath.push(parent);
1771 }
1772
1773 return { path: vPath.concat(wPath.reverse()), lca: lca };
1774}
1775
1776function postorder(g) {
1777 var result = {},
1778 lim = 0;
1779
1780 function dfs(v) {
1781 var low = lim;
1782 _.each(g.children(v), dfs);
1783 result[v] = { low: low, lim: lim++ };
1784 }
1785 _.each(g.children(), dfs);
1786
1787 return result;
1788}
1789
1790},{"./lodash":10}],23:[function(require,module,exports){
1791"use strict";
1792
1793var _ = require("../lodash"),
1794 Graph = require("../graphlib").Graph,
1795 util = require("../util");
1796
1797/*
1798 * This module provides coordinate assignment based on Brandes and Köpf, "Fast
1799 * and Simple Horizontal Coordinate Assignment."
1800 */
1801
1802module.exports = {
1803 positionX: positionX,
1804 findType1Conflicts: findType1Conflicts,
1805 findType2Conflicts: findType2Conflicts,
1806 addConflict: addConflict,
1807 hasConflict: hasConflict,
1808 verticalAlignment: verticalAlignment,
1809 horizontalCompaction: horizontalCompaction,
1810 alignCoordinates: alignCoordinates,
1811 findSmallestWidthAlignment: findSmallestWidthAlignment,
1812 balance: balance
1813};
1814
1815/*
1816 * Marks all edges in the graph with a type-1 conflict with the "type1Conflict"
1817 * property. A type-1 conflict is one where a non-inner segment crosses an
1818 * inner segment. An inner segment is an edge with both incident nodes marked
1819 * with the "dummy" property.
1820 *
1821 * This algorithm scans layer by layer, starting with the second, for type-1
1822 * conflicts between the current layer and the previous layer. For each layer
1823 * it scans the nodes from left to right until it reaches one that is incident
1824 * on an inner segment. It then scans predecessors to determine if they have
1825 * edges that cross that inner segment. At the end a final scan is done for all
1826 * nodes on the current rank to see if they cross the last visited inner
1827 * segment.
1828 *
1829 * This algorithm (safely) assumes that a dummy node will only be incident on a
1830 * single node in the layers being scanned.
1831 */
1832function findType1Conflicts(g, layering) {
1833 var conflicts = {};
1834
1835 function visitLayer(prevLayer, layer) {
1836 var
1837 // last visited node in the previous layer that is incident on an inner
1838 // segment.
1839 k0 = 0,
1840 // Tracks the last node in this layer scanned for crossings with a type-1
1841 // segment.
1842 scanPos = 0,
1843 prevLayerLength = prevLayer.length,
1844 lastNode = _.last(layer);
1845
1846 _.each(layer, function(v, i) {
1847 var w = findOtherInnerSegmentNode(g, v),
1848 k1 = w ? g.node(w).order : prevLayerLength;
1849
1850 if (w || v === lastNode) {
1851 _.each(layer.slice(scanPos, i +1), function(scanNode) {
1852 _.each(g.predecessors(scanNode), function(u) {
1853 var uLabel = g.node(u),
1854 uPos = uLabel.order;
1855 if ((uPos < k0 || k1 < uPos) &&
1856 !(uLabel.dummy && g.node(scanNode).dummy)) {
1857 addConflict(conflicts, u, scanNode);
1858 }
1859 });
1860 });
1861 scanPos = i + 1;
1862 k0 = k1;
1863 }
1864 });
1865
1866 return layer;
1867 }
1868
1869 _.reduce(layering, visitLayer);
1870 return conflicts;
1871}
1872
1873function findType2Conflicts(g, layering) {
1874 var conflicts = {};
1875
1876 function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
1877 var v;
1878 _.each(_.range(southPos, southEnd), function(i) {
1879 v = south[i];
1880 if (g.node(v).dummy) {
1881 _.each(g.predecessors(v), function(u) {
1882 var uNode = g.node(u);
1883 if (uNode.dummy &&
1884 (uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
1885 addConflict(conflicts, u, v);
1886 }
1887 });
1888 }
1889 });
1890 }
1891
1892
1893 function visitLayer(north, south) {
1894 var prevNorthPos = -1,
1895 nextNorthPos,
1896 southPos = 0;
1897
1898 _.each(south, function(v, southLookahead) {
1899 if (g.node(v).dummy === "border") {
1900 var predecessors = g.predecessors(v);
1901 if (predecessors.length) {
1902 nextNorthPos = g.node(predecessors[0]).order;
1903 scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
1904 southPos = southLookahead;
1905 prevNorthPos = nextNorthPos;
1906 }
1907 }
1908 scan(south, southPos, south.length, nextNorthPos, north.length);
1909 });
1910
1911 return south;
1912 }
1913
1914 _.reduce(layering, visitLayer);
1915 return conflicts;
1916}
1917
1918function findOtherInnerSegmentNode(g, v) {
1919 if (g.node(v).dummy) {
1920 return _.find(g.predecessors(v), function(u) {
1921 return g.node(u).dummy;
1922 });
1923 }
1924}
1925
1926function addConflict(conflicts, v, w) {
1927 if (v > w) {
1928 var tmp = v;
1929 v = w;
1930 w = tmp;
1931 }
1932
1933 var conflictsV = conflicts[v];
1934 if (!conflictsV) {
1935 conflicts[v] = conflictsV = {};
1936 }
1937 conflictsV[w] = true;
1938}
1939
1940function hasConflict(conflicts, v, w) {
1941 if (v > w) {
1942 var tmp = v;
1943 v = w;
1944 w = tmp;
1945 }
1946 return _.has(conflicts[v], w);
1947}
1948
1949/*
1950 * Try to align nodes into vertical "blocks" where possible. This algorithm
1951 * attempts to align a node with one of its median neighbors. If the edge
1952 * connecting a neighbor is a type-1 conflict then we ignore that possibility.
1953 * If a previous node has already formed a block with a node after the node
1954 * we're trying to form a block with, we also ignore that possibility - our
1955 * blocks would be split in that scenario.
1956 */
1957function verticalAlignment(g, layering, conflicts, neighborFn) {
1958 var root = {},
1959 align = {},
1960 pos = {};
1961
1962 // We cache the position here based on the layering because the graph and
1963 // layering may be out of sync. The layering matrix is manipulated to
1964 // generate different extreme alignments.
1965 _.each(layering, function(layer) {
1966 _.each(layer, function(v, order) {
1967 root[v] = v;
1968 align[v] = v;
1969 pos[v] = order;
1970 });
1971 });
1972
1973 _.each(layering, function(layer) {
1974 var prevIdx = -1;
1975 _.each(layer, function(v) {
1976 var ws = neighborFn(v);
1977 if (ws.length) {
1978 ws = _.sortBy(ws, function(w) { return pos[w]; });
1979 var mp = (ws.length - 1) / 2;
1980 for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
1981 var w = ws[i];
1982 if (align[v] === v &&
1983 prevIdx < pos[w] &&
1984 !hasConflict(conflicts, v, w)) {
1985 align[w] = v;
1986 align[v] = root[v] = root[w];
1987 prevIdx = pos[w];
1988 }
1989 }
1990 }
1991 });
1992 });
1993
1994 return { root: root, align: align };
1995}
1996
1997function horizontalCompaction(g, layering, root, align, reverseSep) {
1998 // This portion of the algorithm differs from BK due to a number of problems.
1999 // Instead of their algorithm we construct a new block graph and do two
2000 // sweeps. The first sweep places blocks with the smallest possible
2001 // coordinates. The second sweep removes unused space by moving blocks to the
2002 // greatest coordinates without violating separation.
2003 var xs = {},
2004 blockG = buildBlockGraph(g, layering, root, reverseSep);
2005
2006 // First pass, assign smallest coordinates via DFS
2007 var visited = {};
2008 function pass1(v) {
2009 if (!_.has(visited, v)) {
2010 visited[v] = true;
2011 xs[v] = _.reduce(blockG.inEdges(v), function(max, e) {
2012 pass1(e.v);
2013 return Math.max(max, xs[e.v] + blockG.edge(e));
2014 }, 0);
2015 }
2016 }
2017 _.each(blockG.nodes(), pass1);
2018
2019 function pass2(v) {
2020 if (visited[v] !== 2) {
2021 visited[v]++;
2022 var min = _.reduce(blockG.outEdges(v), function(min, e) {
2023 pass2(e.w);
2024 return Math.min(min, xs[e.w] - blockG.edge(e));
2025 }, Number.POSITIVE_INFINITY);
2026 if (min !== Number.POSITIVE_INFINITY) {
2027 xs[v] = Math.max(xs[v], min);
2028 }
2029 }
2030 }
2031 _.each(blockG.nodes(), pass2);
2032
2033
2034 // Assign x coordinates to all nodes
2035 _.each(align, function(v) {
2036 xs[v] = xs[root[v]];
2037 });
2038
2039 return xs;
2040}
2041
2042
2043function buildBlockGraph(g, layering, root, reverseSep) {
2044 var blockGraph = new Graph(),
2045 graphLabel = g.graph(),
2046 sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
2047
2048 _.each(layering, function(layer) {
2049 var u;
2050 _.each(layer, function(v) {
2051 var vRoot = root[v];
2052 blockGraph.setNode(vRoot);
2053 if (u) {
2054 var uRoot = root[u],
2055 prevMax = blockGraph.edge(uRoot, vRoot);
2056 blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
2057 }
2058 u = v;
2059 });
2060 });
2061
2062 return blockGraph;
2063}
2064
2065/*
2066 * Returns the alignment that has the smallest width of the given alignments.
2067 */
2068function findSmallestWidthAlignment(g, xss) {
2069 return _.min(xss, function(xs) {
2070 var min = _.min(xs, function(x, v) { return x - width(g, v) / 2; }),
2071 max = _.max(xs, function(x, v) { return x + width(g, v) / 2; });
2072 return max - min;
2073 });
2074}
2075
2076/*
2077 * Align the coordinates of each of the layout alignments such that
2078 * left-biased alignments have their minimum coordinate at the same point as
2079 * the minimum coordinate of the smallest width alignment and right-biased
2080 * alignments have their maximum coordinate at the same point as the maximum
2081 * coordinate of the smallest width alignment.
2082 */
2083function alignCoordinates(xss, alignTo) {
2084 var alignToMin = _.min(alignTo),
2085 alignToMax = _.max(alignTo);
2086
2087 _.each(["u", "d"], function(vert) {
2088 _.each(["l", "r"], function(horiz) {
2089 var alignment = vert + horiz,
2090 xs = xss[alignment],
2091 delta;
2092 if (xs === alignTo) return;
2093
2094 delta = horiz === "l" ? alignToMin - _.min(xs) : alignToMax - _.max(xs);
2095
2096 if (delta) {
2097 xss[alignment] = _.mapValues(xs, function(x) { return x + delta; });
2098 }
2099 });
2100 });
2101}
2102
2103function balance(xss, align) {
2104 return _.mapValues(xss.ul, function(ignore, v) {
2105 if (align) {
2106 return xss[align.toLowerCase()][v];
2107 } else {
2108 var xs = _.sortBy(_.pluck(xss, v));
2109 return (xs[1] + xs[2]) / 2;
2110 }
2111 });
2112}
2113
2114function positionX(g) {
2115 var layering = util.buildLayerMatrix(g),
2116 conflicts = _.merge(findType1Conflicts(g, layering),
2117 findType2Conflicts(g, layering));
2118
2119 var xss = {},
2120 adjustedLayering;
2121 _.each(["u", "d"], function(vert) {
2122 adjustedLayering = vert === "u" ? layering : _.values(layering).reverse();
2123 _.each(["l", "r"], function(horiz) {
2124 if (horiz === "r") {
2125 adjustedLayering = _.map(adjustedLayering, function(inner) {
2126 return _.values(inner).reverse();
2127 });
2128 }
2129
2130 var neighborFn = _.bind(vert === "u" ? g.predecessors : g.successors, g);
2131 var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
2132 var xs = horizontalCompaction(g, adjustedLayering,
2133 align.root, align.align,
2134 horiz === "r");
2135 if (horiz === "r") {
2136 xs = _.mapValues(xs, function(x) { return -x; });
2137 }
2138 xss[vert + horiz] = xs;
2139 });
2140 });
2141
2142 var smallestWidth = findSmallestWidthAlignment(g, xss);
2143 alignCoordinates(xss, smallestWidth);
2144 return balance(xss, g.graph().align);
2145}
2146
2147function sep(nodeSep, edgeSep, reverseSep) {
2148 return function(g, v, w) {
2149 var vLabel = g.node(v),
2150 wLabel = g.node(w),
2151 sum = 0,
2152 delta;
2153
2154 sum += vLabel.width / 2;
2155 if (_.has(vLabel, "labelpos")) {
2156 switch (vLabel.labelpos.toLowerCase()) {
2157 case "l": delta = -vLabel.width / 2; break;
2158 case "r": delta = vLabel.width / 2; break;
2159 }
2160 }
2161 if (delta) {
2162 sum += reverseSep ? delta : -delta;
2163 }
2164 delta = 0;
2165
2166 sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
2167 sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
2168
2169 sum += wLabel.width / 2;
2170 if (_.has(wLabel, "labelpos")) {
2171 switch (wLabel.labelpos.toLowerCase()) {
2172 case "l": delta = wLabel.width / 2; break;
2173 case "r": delta = -wLabel.width / 2; break;
2174 }
2175 }
2176 if (delta) {
2177 sum += reverseSep ? delta : -delta;
2178 }
2179 delta = 0;
2180
2181 return sum;
2182 };
2183}
2184
2185function width(g, v) {
2186 return g.node(v).width;
2187}
2188
2189},{"../graphlib":7,"../lodash":10,"../util":29}],24:[function(require,module,exports){
2190"use strict";
2191
2192var _ = require("../lodash"),
2193 util = require("../util"),
2194 positionX = require("./bk").positionX;
2195
2196module.exports = position;
2197
2198function position(g) {
2199 g = util.asNonCompoundGraph(g);
2200
2201 positionY(g);
2202 _.each(positionX(g), function(x, v) {
2203 g.node(v).x = x;
2204 });
2205}
2206
2207function positionY(g) {
2208 var layering = util.buildLayerMatrix(g),
2209 rankSep = g.graph().ranksep,
2210 prevY = 0;
2211 _.each(layering, function(layer) {
2212 var maxHeight = _.max(_.map(layer, function(v) { return g.node(v).height; }));
2213 _.each(layer, function(v) {
2214 g.node(v).y = prevY + maxHeight / 2;
2215 });
2216 prevY += maxHeight + rankSep;
2217 });
2218}
2219
2220
2221},{"../lodash":10,"../util":29,"./bk":23}],25:[function(require,module,exports){
2222"use strict";
2223
2224var _ = require("../lodash"),
2225 Graph = require("../graphlib").Graph,
2226 slack = require("./util").slack;
2227
2228module.exports = feasibleTree;
2229
2230/*
2231 * Constructs a spanning tree with tight edges and adjusted the input node's
2232 * ranks to achieve this. A tight edge is one that is has a length that matches
2233 * its "minlen" attribute.
2234 *
2235 * The basic structure for this function is derived from Gansner, et al., "A
2236 * Technique for Drawing Directed Graphs."
2237 *
2238 * Pre-conditions:
2239 *
2240 * 1. Graph must be a DAG.
2241 * 2. Graph must be connected.
2242 * 3. Graph must have at least one node.
2243 * 5. Graph nodes must have been previously assigned a "rank" property that
2244 * respects the "minlen" property of incident edges.
2245 * 6. Graph edges must have a "minlen" property.
2246 *
2247 * Post-conditions:
2248 *
2249 * - Graph nodes will have their rank adjusted to ensure that all edges are
2250 * tight.
2251 *
2252 * Returns a tree (undirected graph) that is constructed using only "tight"
2253 * edges.
2254 */
2255function feasibleTree(g) {
2256 var t = new Graph({ directed: false });
2257
2258 // Choose arbitrary node from which to start our tree
2259 var start = g.nodes()[0],
2260 size = g.nodeCount();
2261 t.setNode(start, {});
2262
2263 var edge, delta;
2264 while (tightTree(t, g) < size) {
2265 edge = findMinSlackEdge(t, g);
2266 delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
2267 shiftRanks(t, g, delta);
2268 }
2269
2270 return t;
2271}
2272
2273/*
2274 * Finds a maximal tree of tight edges and returns the number of nodes in the
2275 * tree.
2276 */
2277function tightTree(t, g) {
2278 function dfs(v) {
2279 _.each(g.nodeEdges(v), function(e) {
2280 var edgeV = e.v,
2281 w = (v === edgeV) ? e.w : edgeV;
2282 if (!t.hasNode(w) && !slack(g, e)) {
2283 t.setNode(w, {});
2284 t.setEdge(v, w, {});
2285 dfs(w);
2286 }
2287 });
2288 }
2289
2290 _.each(t.nodes(), dfs);
2291 return t.nodeCount();
2292}
2293
2294/*
2295 * Finds the edge with the smallest slack that is incident on tree and returns
2296 * it.
2297 */
2298function findMinSlackEdge(t, g) {
2299 return _.min(g.edges(), function(e) {
2300 if (t.hasNode(e.v) !== t.hasNode(e.w)) {
2301 return slack(g, e);
2302 }
2303 });
2304}
2305
2306function shiftRanks(t, g, delta) {
2307 _.each(t.nodes(), function(v) {
2308 g.node(v).rank += delta;
2309 });
2310}
2311
2312},{"../graphlib":7,"../lodash":10,"./util":28}],26:[function(require,module,exports){
2313"use strict";
2314
2315var rankUtil = require("./util"),
2316 longestPath = rankUtil.longestPath,
2317 feasibleTree = require("./feasible-tree"),
2318 networkSimplex = require("./network-simplex");
2319
2320module.exports = rank;
2321
2322/*
2323 * Assigns a rank to each node in the input graph that respects the "minlen"
2324 * constraint specified on edges between nodes.
2325 *
2326 * This basic structure is derived from Gansner, et al., "A Technique for
2327 * Drawing Directed Graphs."
2328 *
2329 * Pre-conditions:
2330 *
2331 * 1. Graph must be a connected DAG
2332 * 2. Graph nodes must be objects
2333 * 3. Graph edges must have "weight" and "minlen" attributes
2334 *
2335 * Post-conditions:
2336 *
2337 * 1. Graph nodes will have a "rank" attribute based on the results of the
2338 * algorithm. Ranks can start at any index (including negative), we'll
2339 * fix them up later.
2340 */
2341function rank(g) {
2342 switch(g.graph().ranker) {
2343 case "network-simplex": networkSimplexRanker(g); break;
2344 case "tight-tree": tightTreeRanker(g); break;
2345 case "longest-path": longestPathRanker(g); break;
2346 default: networkSimplexRanker(g);
2347 }
2348}
2349
2350// A fast and simple ranker, but results are far from optimal.
2351var longestPathRanker = longestPath;
2352
2353function tightTreeRanker(g) {
2354 longestPath(g);
2355 feasibleTree(g);
2356}
2357
2358function networkSimplexRanker(g) {
2359 networkSimplex(g);
2360}
2361
2362},{"./feasible-tree":25,"./network-simplex":27,"./util":28}],27:[function(require,module,exports){
2363"use strict";
2364
2365var _ = require("../lodash"),
2366 feasibleTree = require("./feasible-tree"),
2367 slack = require("./util").slack,
2368 initRank = require("./util").longestPath,
2369 preorder = require("../graphlib").alg.preorder,
2370 postorder = require("../graphlib").alg.postorder,
2371 simplify = require("../util").simplify;
2372
2373module.exports = networkSimplex;
2374
2375// Expose some internals for testing purposes
2376networkSimplex.initLowLimValues = initLowLimValues;
2377networkSimplex.initCutValues = initCutValues;
2378networkSimplex.calcCutValue = calcCutValue;
2379networkSimplex.leaveEdge = leaveEdge;
2380networkSimplex.enterEdge = enterEdge;
2381networkSimplex.exchangeEdges = exchangeEdges;
2382
2383/*
2384 * The network simplex algorithm assigns ranks to each node in the input graph
2385 * and iteratively improves the ranking to reduce the length of edges.
2386 *
2387 * Preconditions:
2388 *
2389 * 1. The input graph must be a DAG.
2390 * 2. All nodes in the graph must have an object value.
2391 * 3. All edges in the graph must have "minlen" and "weight" attributes.
2392 *
2393 * Postconditions:
2394 *
2395 * 1. All nodes in the graph will have an assigned "rank" attribute that has
2396 * been optimized by the network simplex algorithm. Ranks start at 0.
2397 *
2398 *
2399 * A rough sketch of the algorithm is as follows:
2400 *
2401 * 1. Assign initial ranks to each node. We use the longest path algorithm,
2402 * which assigns ranks to the lowest position possible. In general this
2403 * leads to very wide bottom ranks and unnecessarily long edges.
2404 * 2. Construct a feasible tight tree. A tight tree is one such that all
2405 * edges in the tree have no slack (difference between length of edge
2406 * and minlen for the edge). This by itself greatly improves the assigned
2407 * rankings by shorting edges.
2408 * 3. Iteratively find edges that have negative cut values. Generally a
2409 * negative cut value indicates that the edge could be removed and a new
2410 * tree edge could be added to produce a more compact graph.
2411 *
2412 * Much of the algorithms here are derived from Gansner, et al., "A Technique
2413 * for Drawing Directed Graphs." The structure of the file roughly follows the
2414 * structure of the overall algorithm.
2415 */
2416function networkSimplex(g) {
2417 g = simplify(g);
2418 initRank(g);
2419 var t = feasibleTree(g);
2420 initLowLimValues(t);
2421 initCutValues(t, g);
2422
2423 var e, f;
2424 while ((e = leaveEdge(t))) {
2425 f = enterEdge(t, g, e);
2426 exchangeEdges(t, g, e, f);
2427 }
2428}
2429
2430/*
2431 * Initializes cut values for all edges in the tree.
2432 */
2433function initCutValues(t, g) {
2434 var vs = postorder(t, t.nodes());
2435 vs = vs.slice(0, vs.length - 1);
2436 _.each(vs, function(v) {
2437 assignCutValue(t, g, v);
2438 });
2439}
2440
2441function assignCutValue(t, g, child) {
2442 var childLab = t.node(child),
2443 parent = childLab.parent;
2444 t.edge(child, parent).cutvalue = calcCutValue(t, g, child);
2445}
2446
2447/*
2448 * Given the tight tree, its graph, and a child in the graph calculate and
2449 * return the cut value for the edge between the child and its parent.
2450 */
2451function calcCutValue(t, g, child) {
2452 var childLab = t.node(child),
2453 parent = childLab.parent,
2454 // True if the child is on the tail end of the edge in the directed graph
2455 childIsTail = true,
2456 // The graph's view of the tree edge we're inspecting
2457 graphEdge = g.edge(child, parent),
2458 // The accumulated cut value for the edge between this node and its parent
2459 cutValue = 0;
2460
2461 if (!graphEdge) {
2462 childIsTail = false;
2463 graphEdge = g.edge(parent, child);
2464 }
2465
2466 cutValue = graphEdge.weight;
2467
2468 _.each(g.nodeEdges(child), function(e) {
2469 var isOutEdge = e.v === child,
2470 other = isOutEdge ? e.w : e.v;
2471
2472 if (other !== parent) {
2473 var pointsToHead = isOutEdge === childIsTail,
2474 otherWeight = g.edge(e).weight;
2475
2476 cutValue += pointsToHead ? otherWeight : -otherWeight;
2477 if (isTreeEdge(t, child, other)) {
2478 var otherCutValue = t.edge(child, other).cutvalue;
2479 cutValue += pointsToHead ? -otherCutValue : otherCutValue;
2480 }
2481 }
2482 });
2483
2484 return cutValue;
2485}
2486
2487function initLowLimValues(tree, root) {
2488 if (arguments.length < 2) {
2489 root = tree.nodes()[0];
2490 }
2491 dfsAssignLowLim(tree, {}, 1, root);
2492}
2493
2494function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
2495 var low = nextLim,
2496 label = tree.node(v);
2497
2498 visited[v] = true;
2499 _.each(tree.neighbors(v), function(w) {
2500 if (!_.has(visited, w)) {
2501 nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
2502 }
2503 });
2504
2505 label.low = low;
2506 label.lim = nextLim++;
2507 if (parent) {
2508 label.parent = parent;
2509 } else {
2510 // TODO should be able to remove this when we incrementally update low lim
2511 delete label.parent;
2512 }
2513
2514 return nextLim;
2515}
2516
2517function leaveEdge(tree) {
2518 return _.find(tree.edges(), function(e) {
2519 return tree.edge(e).cutvalue < 0;
2520 });
2521}
2522
2523function enterEdge(t, g, edge) {
2524 var v = edge.v,
2525 w = edge.w;
2526
2527 // For the rest of this function we assume that v is the tail and w is the
2528 // head, so if we don't have this edge in the graph we should flip it to
2529 // match the correct orientation.
2530 if (!g.hasEdge(v, w)) {
2531 v = edge.w;
2532 w = edge.v;
2533 }
2534
2535 var vLabel = t.node(v),
2536 wLabel = t.node(w),
2537 tailLabel = vLabel,
2538 flip = false;
2539
2540 // If the root is in the tail of the edge then we need to flip the logic that
2541 // checks for the head and tail nodes in the candidates function below.
2542 if (vLabel.lim > wLabel.lim) {
2543 tailLabel = wLabel;
2544 flip = true;
2545 }
2546
2547 var candidates = _.filter(g.edges(), function(edge) {
2548 return flip === isDescendant(t, t.node(edge.v), tailLabel) &&
2549 flip !== isDescendant(t, t.node(edge.w), tailLabel);
2550 });
2551
2552 return _.min(candidates, function(edge) { return slack(g, edge); });
2553}
2554
2555function exchangeEdges(t, g, e, f) {
2556 var v = e.v,
2557 w = e.w;
2558 t.removeEdge(v, w);
2559 t.setEdge(f.v, f.w, {});
2560 initLowLimValues(t);
2561 initCutValues(t, g);
2562 updateRanks(t, g);
2563}
2564
2565function updateRanks(t, g) {
2566 var root = _.find(t.nodes(), function(v) { return !g.node(v).parent; }),
2567 vs = preorder(t, root);
2568 vs = vs.slice(1);
2569 _.each(vs, function(v) {
2570 var parent = t.node(v).parent,
2571 edge = g.edge(v, parent),
2572 flipped = false;
2573
2574 if (!edge) {
2575 edge = g.edge(parent, v);
2576 flipped = true;
2577 }
2578
2579 g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen);
2580 });
2581}
2582
2583/*
2584 * Returns true if the edge is in the tree.
2585 */
2586function isTreeEdge(tree, u, v) {
2587 return tree.hasEdge(u, v);
2588}
2589
2590/*
2591 * Returns true if the specified node is descendant of the root node per the
2592 * assigned low and lim attributes in the tree.
2593 */
2594function isDescendant(tree, vLabel, rootLabel) {
2595 return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim;
2596}
2597
2598},{"../graphlib":7,"../lodash":10,"../util":29,"./feasible-tree":25,"./util":28}],28:[function(require,module,exports){
2599"use strict";
2600
2601var _ = require("../lodash");
2602
2603module.exports = {
2604 longestPath: longestPath,
2605 slack: slack
2606};
2607
2608/*
2609 * Initializes ranks for the input graph using the longest path algorithm. This
2610 * algorithm scales well and is fast in practice, it yields rather poor
2611 * solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
2612 * ranks wide and leaving edges longer than necessary. However, due to its
2613 * speed, this algorithm is good for getting an initial ranking that can be fed
2614 * into other algorithms.
2615 *
2616 * This algorithm does not normalize layers because it will be used by other
2617 * algorithms in most cases. If using this algorithm directly, be sure to
2618 * run normalize at the end.
2619 *
2620 * Pre-conditions:
2621 *
2622 * 1. Input graph is a DAG.
2623 * 2. Input graph node labels can be assigned properties.
2624 *
2625 * Post-conditions:
2626 *
2627 * 1. Each node will be assign an (unnormalized) "rank" property.
2628 */
2629function longestPath(g) {
2630 var visited = {};
2631
2632 function dfs(v) {
2633 var label = g.node(v);
2634 if (_.has(visited, v)) {
2635 return label.rank;
2636 }
2637 visited[v] = true;
2638
2639 var rank = _.min(_.map(g.outEdges(v), function(e) {
2640 return dfs(e.w) - g.edge(e).minlen;
2641 }));
2642
2643 if (rank === Number.POSITIVE_INFINITY) {
2644 rank = 0;
2645 }
2646
2647 return (label.rank = rank);
2648 }
2649
2650 _.each(g.sources(), dfs);
2651}
2652
2653/*
2654 * Returns the amount of slack for the given edge. The slack is defined as the
2655 * difference between the length of the edge and its minimum length.
2656 */
2657function slack(g, e) {
2658 return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
2659}
2660
2661},{"../lodash":10}],29:[function(require,module,exports){
2662"use strict";
2663
2664var _ = require("./lodash"),
2665 Graph = require("./graphlib").Graph;
2666
2667module.exports = {
2668 addDummyNode: addDummyNode,
2669 simplify: simplify,
2670 asNonCompoundGraph: asNonCompoundGraph,
2671 successorWeights: successorWeights,
2672 predecessorWeights: predecessorWeights,
2673 intersectRect: intersectRect,
2674 buildLayerMatrix: buildLayerMatrix,
2675 normalizeRanks: normalizeRanks,
2676 removeEmptyRanks: removeEmptyRanks,
2677 addBorderNode: addBorderNode,
2678 maxRank: maxRank,
2679 partition: partition,
2680 time: time,
2681 notime: notime
2682};
2683
2684/*
2685 * Adds a dummy node to the graph and return v.
2686 */
2687function addDummyNode(g, type, attrs, name) {
2688 var v;
2689 do {
2690 v = _.uniqueId(name);
2691 } while (g.hasNode(v));
2692
2693 attrs.dummy = type;
2694 g.setNode(v, attrs);
2695 return v;
2696}
2697
2698/*
2699 * Returns a new graph with only simple edges. Handles aggregation of data
2700 * associated with multi-edges.
2701 */
2702function simplify(g) {
2703 var simplified = new Graph().setGraph(g.graph());
2704 _.each(g.nodes(), function(v) { simplified.setNode(v, g.node(v)); });
2705 _.each(g.edges(), function(e) {
2706 var simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 },
2707 label = g.edge(e);
2708 simplified.setEdge(e.v, e.w, {
2709 weight: simpleLabel.weight + label.weight,
2710 minlen: Math.max(simpleLabel.minlen, label.minlen)
2711 });
2712 });
2713 return simplified;
2714}
2715
2716function asNonCompoundGraph(g) {
2717 var simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
2718 _.each(g.nodes(), function(v) {
2719 if (!g.children(v).length) {
2720 simplified.setNode(v, g.node(v));
2721 }
2722 });
2723 _.each(g.edges(), function(e) {
2724 simplified.setEdge(e, g.edge(e));
2725 });
2726 return simplified;
2727}
2728
2729function successorWeights(g) {
2730 var weightMap = _.map(g.nodes(), function(v) {
2731 var sucs = {};
2732 _.each(g.outEdges(v), function(e) {
2733 sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight;
2734 });
2735 return sucs;
2736 });
2737 return _.zipObject(g.nodes(), weightMap);
2738}
2739
2740function predecessorWeights(g) {
2741 var weightMap = _.map(g.nodes(), function(v) {
2742 var preds = {};
2743 _.each(g.inEdges(v), function(e) {
2744 preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight;
2745 });
2746 return preds;
2747 });
2748 return _.zipObject(g.nodes(), weightMap);
2749}
2750
2751/*
2752 * Finds where a line starting at point ({x, y}) would intersect a rectangle
2753 * ({x, y, width, height}) if it were pointing at the rectangle's center.
2754 */
2755function intersectRect(rect, point) {
2756 var x = rect.x;
2757 var y = rect.y;
2758
2759 // Rectangle intersection algorithm from:
2760 // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
2761 var dx = point.x - x;
2762 var dy = point.y - y;
2763 var w = rect.width / 2;
2764 var h = rect.height / 2;
2765
2766 if (!dx && !dy) {
2767 throw new Error("Not possible to find intersection inside of the rectangle");
2768 }
2769
2770 var sx, sy;
2771 if (Math.abs(dy) * w > Math.abs(dx) * h) {
2772 // Intersection is top or bottom of rect.
2773 if (dy < 0) {
2774 h = -h;
2775 }
2776 sx = h * dx / dy;
2777 sy = h;
2778 } else {
2779 // Intersection is left or right of rect.
2780 if (dx < 0) {
2781 w = -w;
2782 }
2783 sx = w;
2784 sy = w * dy / dx;
2785 }
2786
2787 return { x: x + sx, y: y + sy };
2788}
2789
2790/*
2791 * Given a DAG with each node assigned "rank" and "order" properties, this
2792 * function will produce a matrix with the ids of each node.
2793 */
2794function buildLayerMatrix(g) {
2795 var layering = _.map(_.range(maxRank(g) + 1), function() { return []; });
2796 _.each(g.nodes(), function(v) {
2797 var node = g.node(v),
2798 rank = node.rank;
2799 if (!_.isUndefined(rank)) {
2800 layering[rank][node.order] = v;
2801 }
2802 });
2803 return layering;
2804}
2805
2806/*
2807 * Adjusts the ranks for all nodes in the graph such that all nodes v have
2808 * rank(v) >= 0 and at least one node w has rank(w) = 0.
2809 */
2810function normalizeRanks(g) {
2811 var min = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
2812 _.each(g.nodes(), function(v) {
2813 var node = g.node(v);
2814 if (_.has(node, "rank")) {
2815 node.rank -= min;
2816 }
2817 });
2818}
2819
2820function removeEmptyRanks(g) {
2821 // Ranks may not start at 0, so we need to offset them
2822 var offset = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
2823
2824 var layers = [];
2825 _.each(g.nodes(), function(v) {
2826 var rank = g.node(v).rank - offset;
2827 if (!_.has(layers, rank)) {
2828 layers[rank] = [];
2829 }
2830 layers[rank].push(v);
2831 });
2832
2833 var delta = 0,
2834 nodeRankFactor = g.graph().nodeRankFactor;
2835 _.each(layers, function(vs, i) {
2836 if (_.isUndefined(vs) && i % nodeRankFactor !== 0) {
2837 --delta;
2838 } else if (delta) {
2839 _.each(vs, function(v) { g.node(v).rank += delta; });
2840 }
2841 });
2842}
2843
2844function addBorderNode(g, prefix, rank, order) {
2845 var node = {
2846 width: 0,
2847 height: 0
2848 };
2849 if (arguments.length >= 4) {
2850 node.rank = rank;
2851 node.order = order;
2852 }
2853 return addDummyNode(g, "border", node, prefix);
2854}
2855
2856function maxRank(g) {
2857 return _.max(_.map(g.nodes(), function(v) {
2858 var rank = g.node(v).rank;
2859 if (!_.isUndefined(rank)) {
2860 return rank;
2861 }
2862 }));
2863}
2864
2865/*
2866 * Partition a collection into two groups: `lhs` and `rhs`. If the supplied
2867 * function returns true for an entry it goes into `lhs`. Otherwise it goes
2868 * into `rhs.
2869 */
2870function partition(collection, fn) {
2871 var result = { lhs: [], rhs: [] };
2872 _.each(collection, function(value) {
2873 if (fn(value)) {
2874 result.lhs.push(value);
2875 } else {
2876 result.rhs.push(value);
2877 }
2878 });
2879 return result;
2880}
2881
2882/*
2883 * Returns a new function that wraps `fn` with a timer. The wrapper logs the
2884 * time it takes to execute the function.
2885 */
2886function time(name, fn) {
2887 var start = _.now();
2888 try {
2889 return fn();
2890 } finally {
2891 console.log(name + " time: " + (_.now() - start) + "ms");
2892 }
2893}
2894
2895function notime(name, fn) {
2896 return fn();
2897}
2898
2899},{"./graphlib":7,"./lodash":10}],30:[function(require,module,exports){
2900module.exports = "0.7.1";
2901
2902},{}],31:[function(require,module,exports){
2903/**
2904 * Copyright (c) 2014, Chris Pettitt
2905 * All rights reserved.
2906 *
2907 * Redistribution and use in source and binary forms, with or without
2908 * modification, are permitted provided that the following conditions are met:
2909 *
2910 * 1. Redistributions of source code must retain the above copyright notice, this
2911 * list of conditions and the following disclaimer.
2912 *
2913 * 2. Redistributions in binary form must reproduce the above copyright notice,
2914 * this list of conditions and the following disclaimer in the documentation
2915 * and/or other materials provided with the distribution.
2916 *
2917 * 3. Neither the name of the copyright holder nor the names of its contributors
2918 * may be used to endorse or promote products derived from this software without
2919 * specific prior written permission.
2920 *
2921 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2922 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2923 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2924 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2925 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2926 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2927 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2928 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2929 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2930 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2931 */
2932
2933var lib = require("./lib");
2934
2935module.exports = {
2936 Graph: lib.Graph,
2937 json: require("./lib/json"),
2938 alg: require("./lib/alg"),
2939 version: lib.version
2940};
2941
2942},{"./lib":47,"./lib/alg":38,"./lib/json":48}],32:[function(require,module,exports){
2943var _ = require("../lodash");
2944
2945module.exports = components;
2946
2947function components(g) {
2948 var visited = {},
2949 cmpts = [],
2950 cmpt;
2951
2952 function dfs(v) {
2953 if (_.has(visited, v)) return;
2954 visited[v] = true;
2955 cmpt.push(v);
2956 _.each(g.successors(v), dfs);
2957 _.each(g.predecessors(v), dfs);
2958 }
2959
2960 _.each(g.nodes(), function(v) {
2961 cmpt = [];
2962 dfs(v);
2963 if (cmpt.length) {
2964 cmpts.push(cmpt);
2965 }
2966 });
2967
2968 return cmpts;
2969}
2970
2971},{"../lodash":49}],33:[function(require,module,exports){
2972var _ = require("../lodash");
2973
2974module.exports = dfs;
2975
2976/*
2977 * A helper that preforms a pre- or post-order traversal on the input graph
2978 * and returns the nodes in the order they were visited. This algorithm treats
2979 * the input as undirected.
2980 *
2981 * Order must be one of "pre" or "post".
2982 */
2983function dfs(g, vs, order) {
2984 if (!_.isArray(vs)) {
2985 vs = [vs];
2986 }
2987
2988 var acc = [],
2989 visited = {};
2990 _.each(vs, function(v) {
2991 if (!g.hasNode(v)) {
2992 throw new Error("Graph does not have node: " + v);
2993 }
2994
2995 doDfs(g, v, order === "post", visited, acc);
2996 });
2997 return acc;
2998}
2999
3000function doDfs(g, v, postorder, visited, acc) {
3001 if (!_.has(visited, v)) {
3002 visited[v] = true;
3003
3004 if (!postorder) { acc.push(v); }
3005 _.each(g.neighbors(v), function(w) {
3006 doDfs(g, w, postorder, visited, acc);
3007 });
3008 if (postorder) { acc.push(v); }
3009 }
3010}
3011
3012},{"../lodash":49}],34:[function(require,module,exports){
3013var dijkstra = require("./dijkstra"),
3014 _ = require("../lodash");
3015
3016module.exports = dijkstraAll;
3017
3018function dijkstraAll(g, weightFunc, edgeFunc) {
3019 return _.transform(g.nodes(), function(acc, v) {
3020 acc[v] = dijkstra(g, v, weightFunc, edgeFunc);
3021 }, {});
3022}
3023
3024},{"../lodash":49,"./dijkstra":35}],35:[function(require,module,exports){
3025var _ = require("../lodash"),
3026 PriorityQueue = require("../data/priority-queue");
3027
3028module.exports = dijkstra;
3029
3030var DEFAULT_WEIGHT_FUNC = _.constant(1);
3031
3032function dijkstra(g, source, weightFn, edgeFn) {
3033 return runDijkstra(g, String(source),
3034 weightFn || DEFAULT_WEIGHT_FUNC,
3035 edgeFn || function(v) { return g.outEdges(v); });
3036}
3037
3038function runDijkstra(g, source, weightFn, edgeFn) {
3039 var results = {},
3040 pq = new PriorityQueue(),
3041 v, vEntry;
3042
3043 var updateNeighbors = function(edge) {
3044 var w = edge.v !== v ? edge.v : edge.w,
3045 wEntry = results[w],
3046 weight = weightFn(edge),
3047 distance = vEntry.distance + weight;
3048
3049 if (weight < 0) {
3050 throw new Error("dijkstra does not allow negative edge weights. " +
3051 "Bad edge: " + edge + " Weight: " + weight);
3052 }
3053
3054 if (distance < wEntry.distance) {
3055 wEntry.distance = distance;
3056 wEntry.predecessor = v;
3057 pq.decrease(w, distance);
3058 }
3059 };
3060
3061 g.nodes().forEach(function(v) {
3062 var distance = v === source ? 0 : Number.POSITIVE_INFINITY;
3063 results[v] = { distance: distance };
3064 pq.add(v, distance);
3065 });
3066
3067 while (pq.size() > 0) {
3068 v = pq.removeMin();
3069 vEntry = results[v];
3070 if (vEntry.distance === Number.POSITIVE_INFINITY) {
3071 break;
3072 }
3073
3074 edgeFn(v).forEach(updateNeighbors);
3075 }
3076
3077 return results;
3078}
3079
3080},{"../data/priority-queue":45,"../lodash":49}],36:[function(require,module,exports){
3081var _ = require("../lodash"),
3082 tarjan = require("./tarjan");
3083
3084module.exports = findCycles;
3085
3086function findCycles(g) {
3087 return _.filter(tarjan(g), function(cmpt) { return cmpt.length > 1; });
3088}
3089
3090},{"../lodash":49,"./tarjan":43}],37:[function(require,module,exports){
3091var _ = require("../lodash");
3092
3093module.exports = floydWarshall;
3094
3095var DEFAULT_WEIGHT_FUNC = _.constant(1);
3096
3097function floydWarshall(g, weightFn, edgeFn) {
3098 return runFloydWarshall(g,
3099 weightFn || DEFAULT_WEIGHT_FUNC,
3100 edgeFn || function(v) { return g.outEdges(v); });
3101}
3102
3103function runFloydWarshall(g, weightFn, edgeFn) {
3104 var results = {},
3105 nodes = g.nodes();
3106
3107 nodes.forEach(function(v) {
3108 results[v] = {};
3109 results[v][v] = { distance: 0 };
3110 nodes.forEach(function(w) {
3111 if (v !== w) {
3112 results[v][w] = { distance: Number.POSITIVE_INFINITY };
3113 }
3114 });
3115 edgeFn(v).forEach(function(edge) {
3116 var w = edge.v === v ? edge.w : edge.v,
3117 d = weightFn(edge);
3118 results[v][w] = { distance: d, predecessor: v };
3119 });
3120 });
3121
3122 nodes.forEach(function(k) {
3123 var rowK = results[k];
3124 nodes.forEach(function(i) {
3125 var rowI = results[i];
3126 nodes.forEach(function(j) {
3127 var ik = rowI[k];
3128 var kj = rowK[j];
3129 var ij = rowI[j];
3130 var altDistance = ik.distance + kj.distance;
3131 if (altDistance < ij.distance) {
3132 ij.distance = altDistance;
3133 ij.predecessor = kj.predecessor;
3134 }
3135 });
3136 });
3137 });
3138
3139 return results;
3140}
3141
3142},{"../lodash":49}],38:[function(require,module,exports){
3143module.exports = {
3144 components: require("./components"),
3145 dijkstra: require("./dijkstra"),
3146 dijkstraAll: require("./dijkstra-all"),
3147 findCycles: require("./find-cycles"),
3148 floydWarshall: require("./floyd-warshall"),
3149 isAcyclic: require("./is-acyclic"),
3150 postorder: require("./postorder"),
3151 preorder: require("./preorder"),
3152 prim: require("./prim"),
3153 tarjan: require("./tarjan"),
3154 topsort: require("./topsort")
3155};
3156
3157},{"./components":32,"./dijkstra":35,"./dijkstra-all":34,"./find-cycles":36,"./floyd-warshall":37,"./is-acyclic":39,"./postorder":40,"./preorder":41,"./prim":42,"./tarjan":43,"./topsort":44}],39:[function(require,module,exports){
3158var topsort = require("./topsort");
3159
3160module.exports = isAcyclic;
3161
3162function isAcyclic(g) {
3163 try {
3164 topsort(g);
3165 } catch (e) {
3166 if (e instanceof topsort.CycleException) {
3167 return false;
3168 }
3169 throw e;
3170 }
3171 return true;
3172}
3173
3174},{"./topsort":44}],40:[function(require,module,exports){
3175var dfs = require("./dfs");
3176
3177module.exports = postorder;
3178
3179function postorder(g, vs) {
3180 return dfs(g, vs, "post");
3181}
3182
3183},{"./dfs":33}],41:[function(require,module,exports){
3184var dfs = require("./dfs");
3185
3186module.exports = preorder;
3187
3188function preorder(g, vs) {
3189 return dfs(g, vs, "pre");
3190}
3191
3192},{"./dfs":33}],42:[function(require,module,exports){
3193var _ = require("../lodash"),
3194 Graph = require("../graph"),
3195 PriorityQueue = require("../data/priority-queue");
3196
3197module.exports = prim;
3198
3199function prim(g, weightFunc) {
3200 var result = new Graph(),
3201 parents = {},
3202 pq = new PriorityQueue(),
3203 v;
3204
3205 function updateNeighbors(edge) {
3206 var w = edge.v === v ? edge.w : edge.v,
3207 pri = pq.priority(w);
3208 if (pri !== undefined) {
3209 var edgeWeight = weightFunc(edge);
3210 if (edgeWeight < pri) {
3211 parents[w] = v;
3212 pq.decrease(w, edgeWeight);
3213 }
3214 }
3215 }
3216
3217 if (g.nodeCount() === 0) {
3218 return result;
3219 }
3220
3221 _.each(g.nodes(), function(v) {
3222 pq.add(v, Number.POSITIVE_INFINITY);
3223 result.setNode(v);
3224 });
3225
3226 // Start from an arbitrary node
3227 pq.decrease(g.nodes()[0], 0);
3228
3229 var init = false;
3230 while (pq.size() > 0) {
3231 v = pq.removeMin();
3232 if (_.has(parents, v)) {
3233 result.setEdge(v, parents[v]);
3234 } else if (init) {
3235 throw new Error("Input graph is not connected: " + g);
3236 } else {
3237 init = true;
3238 }
3239
3240 g.nodeEdges(v).forEach(updateNeighbors);
3241 }
3242
3243 return result;
3244}
3245
3246},{"../data/priority-queue":45,"../graph":46,"../lodash":49}],43:[function(require,module,exports){
3247var _ = require("../lodash");
3248
3249module.exports = tarjan;
3250
3251function tarjan(g) {
3252 var index = 0,
3253 stack = [],
3254 visited = {}, // node id -> { onStack, lowlink, index }
3255 results = [];
3256
3257 function dfs(v) {
3258 var entry = visited[v] = {
3259 onStack: true,
3260 lowlink: index,
3261 index: index++
3262 };
3263 stack.push(v);
3264
3265 g.successors(v).forEach(function(w) {
3266 if (!_.has(visited, w)) {
3267 dfs(w);
3268 entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
3269 } else if (visited[w].onStack) {
3270 entry.lowlink = Math.min(entry.lowlink, visited[w].index);
3271 }
3272 });
3273
3274 if (entry.lowlink === entry.index) {
3275 var cmpt = [],
3276 w;
3277 do {
3278 w = stack.pop();
3279 visited[w].onStack = false;
3280 cmpt.push(w);
3281 } while (v !== w);
3282 results.push(cmpt);
3283 }
3284 }
3285
3286 g.nodes().forEach(function(v) {
3287 if (!_.has(visited, v)) {
3288 dfs(v);
3289 }
3290 });
3291
3292 return results;
3293}
3294
3295},{"../lodash":49}],44:[function(require,module,exports){
3296var _ = require("../lodash");
3297
3298module.exports = topsort;
3299topsort.CycleException = CycleException;
3300
3301function topsort(g) {
3302 var visited = {},
3303 stack = {},
3304 results = [];
3305
3306 function visit(node) {
3307 if (_.has(stack, node)) {
3308 throw new CycleException();
3309 }
3310
3311 if (!_.has(visited, node)) {
3312 stack[node] = true;
3313 visited[node] = true;
3314 _.each(g.predecessors(node), visit);
3315 delete stack[node];
3316 results.push(node);
3317 }
3318 }
3319
3320 _.each(g.sinks(), visit);
3321
3322 if (_.size(visited) !== g.nodeCount()) {
3323 throw new CycleException();
3324 }
3325
3326 return results;
3327}
3328
3329function CycleException() {}
3330
3331},{"../lodash":49}],45:[function(require,module,exports){
3332var _ = require("../lodash");
3333
3334module.exports = PriorityQueue;
3335
3336/**
3337 * A min-priority queue data structure. This algorithm is derived from Cormen,
3338 * et al., "Introduction to Algorithms". The basic idea of a min-priority
3339 * queue is that you can efficiently (in O(1) time) get the smallest key in
3340 * the queue. Adding and removing elements takes O(log n) time. A key can
3341 * have its priority decreased in O(log n) time.
3342 */
3343function PriorityQueue() {
3344 this._arr = [];
3345 this._keyIndices = {};
3346}
3347
3348/**
3349 * Returns the number of elements in the queue. Takes `O(1)` time.
3350 */
3351PriorityQueue.prototype.size = function() {
3352 return this._arr.length;
3353};
3354
3355/**
3356 * Returns the keys that are in the queue. Takes `O(n)` time.
3357 */
3358PriorityQueue.prototype.keys = function() {
3359 return this._arr.map(function(x) { return x.key; });
3360};
3361
3362/**
3363 * Returns `true` if **key** is in the queue and `false` if not.
3364 */
3365PriorityQueue.prototype.has = function(key) {
3366 return _.has(this._keyIndices, key);
3367};
3368
3369/**
3370 * Returns the priority for **key**. If **key** is not present in the queue
3371 * then this function returns `undefined`. Takes `O(1)` time.
3372 *
3373 * @param {Object} key
3374 */
3375PriorityQueue.prototype.priority = function(key) {
3376 var index = this._keyIndices[key];
3377 if (index !== undefined) {
3378 return this._arr[index].priority;
3379 }
3380};
3381
3382/**
3383 * Returns the key for the minimum element in this queue. If the queue is
3384 * empty this function throws an Error. Takes `O(1)` time.
3385 */
3386PriorityQueue.prototype.min = function() {
3387 if (this.size() === 0) {
3388 throw new Error("Queue underflow");
3389 }
3390 return this._arr[0].key;
3391};
3392
3393/**
3394 * Inserts a new key into the priority queue. If the key already exists in
3395 * the queue this function returns `false`; otherwise it will return `true`.
3396 * Takes `O(n)` time.
3397 *
3398 * @param {Object} key the key to add
3399 * @param {Number} priority the initial priority for the key
3400 */
3401PriorityQueue.prototype.add = function(key, priority) {
3402 var keyIndices = this._keyIndices;
3403 key = String(key);
3404 if (!_.has(keyIndices, key)) {
3405 var arr = this._arr;
3406 var index = arr.length;
3407 keyIndices[key] = index;
3408 arr.push({key: key, priority: priority});
3409 this._decrease(index);
3410 return true;
3411 }
3412 return false;
3413};
3414
3415/**
3416 * Removes and returns the smallest key in the queue. Takes `O(log n)` time.
3417 */
3418PriorityQueue.prototype.removeMin = function() {
3419 this._swap(0, this._arr.length - 1);
3420 var min = this._arr.pop();
3421 delete this._keyIndices[min.key];
3422 this._heapify(0);
3423 return min.key;
3424};
3425
3426/**
3427 * Decreases the priority for **key** to **priority**. If the new priority is
3428 * greater than the previous priority, this function will throw an Error.
3429 *
3430 * @param {Object} key the key for which to raise priority
3431 * @param {Number} priority the new priority for the key
3432 */
3433PriorityQueue.prototype.decrease = function(key, priority) {
3434 var index = this._keyIndices[key];
3435 if (priority > this._arr[index].priority) {
3436 throw new Error("New priority is greater than current priority. " +
3437 "Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority);
3438 }
3439 this._arr[index].priority = priority;
3440 this._decrease(index);
3441};
3442
3443PriorityQueue.prototype._heapify = function(i) {
3444 var arr = this._arr;
3445 var l = 2 * i,
3446 r = l + 1,
3447 largest = i;
3448 if (l < arr.length) {
3449 largest = arr[l].priority < arr[largest].priority ? l : largest;
3450 if (r < arr.length) {
3451 largest = arr[r].priority < arr[largest].priority ? r : largest;
3452 }
3453 if (largest !== i) {
3454 this._swap(i, largest);
3455 this._heapify(largest);
3456 }
3457 }
3458};
3459
3460PriorityQueue.prototype._decrease = function(index) {
3461 var arr = this._arr;
3462 var priority = arr[index].priority;
3463 var parent;
3464 while (index !== 0) {
3465 parent = index >> 1;
3466 if (arr[parent].priority < priority) {
3467 break;
3468 }
3469 this._swap(index, parent);
3470 index = parent;
3471 }
3472};
3473
3474PriorityQueue.prototype._swap = function(i, j) {
3475 var arr = this._arr;
3476 var keyIndices = this._keyIndices;
3477 var origArrI = arr[i];
3478 var origArrJ = arr[j];
3479 arr[i] = origArrJ;
3480 arr[j] = origArrI;
3481 keyIndices[origArrJ.key] = i;
3482 keyIndices[origArrI.key] = j;
3483};
3484
3485},{"../lodash":49}],46:[function(require,module,exports){
3486"use strict";
3487
3488var _ = require("./lodash");
3489
3490module.exports = Graph;
3491
3492var DEFAULT_EDGE_NAME = "\x00",
3493 GRAPH_NODE = "\x00",
3494 EDGE_KEY_DELIM = "\x01";
3495
3496// Implementation notes:
3497//
3498// * Node id query functions should return string ids for the nodes
3499// * Edge id query functions should return an "edgeObj", edge object, that is
3500// composed of enough information to uniquely identify an edge: {v, w, name}.
3501// * Internally we use an "edgeId", a stringified form of the edgeObj, to
3502// reference edges. This is because we need a performant way to look these
3503// edges up and, object properties, which have string keys, are the closest
3504// we're going to get to a performant hashtable in JavaScript.
3505
3506function Graph(opts) {
3507 this._isDirected = _.has(opts, "directed") ? opts.directed : true;
3508 this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false;
3509 this._isCompound = _.has(opts, "compound") ? opts.compound : false;
3510
3511 // Label for the graph itself
3512 this._label = undefined;
3513
3514 // Defaults to be set when creating a new node
3515 this._defaultNodeLabelFn = _.constant(undefined);
3516
3517 // Defaults to be set when creating a new edge
3518 this._defaultEdgeLabelFn = _.constant(undefined);
3519
3520 // v -> label
3521 this._nodes = {};
3522
3523 if (this._isCompound) {
3524 // v -> parent
3525 this._parent = {};
3526
3527 // v -> children
3528 this._children = {};
3529 this._children[GRAPH_NODE] = {};
3530 }
3531
3532 // v -> edgeObj
3533 this._in = {};
3534
3535 // u -> v -> Number
3536 this._preds = {};
3537
3538 // v -> edgeObj
3539 this._out = {};
3540
3541 // v -> w -> Number
3542 this._sucs = {};
3543
3544 // e -> edgeObj
3545 this._edgeObjs = {};
3546
3547 // e -> label
3548 this._edgeLabels = {};
3549}
3550
3551/* Number of nodes in the graph. Should only be changed by the implementation. */
3552Graph.prototype._nodeCount = 0;
3553
3554/* Number of edges in the graph. Should only be changed by the implementation. */
3555Graph.prototype._edgeCount = 0;
3556
3557
3558/* === Graph functions ========= */
3559
3560Graph.prototype.isDirected = function() {
3561 return this._isDirected;
3562};
3563
3564Graph.prototype.isMultigraph = function() {
3565 return this._isMultigraph;
3566};
3567
3568Graph.prototype.isCompound = function() {
3569 return this._isCompound;
3570};
3571
3572Graph.prototype.setGraph = function(label) {
3573 this._label = label;
3574 return this;
3575};
3576
3577Graph.prototype.graph = function() {
3578 return this._label;
3579};
3580
3581
3582/* === Node functions ========== */
3583
3584Graph.prototype.setDefaultNodeLabel = function(newDefault) {
3585 if (!_.isFunction(newDefault)) {
3586 newDefault = _.constant(newDefault);
3587 }
3588 this._defaultNodeLabelFn = newDefault;
3589 return this;
3590};
3591
3592Graph.prototype.nodeCount = function() {
3593 return this._nodeCount;
3594};
3595
3596Graph.prototype.nodes = function() {
3597 return _.keys(this._nodes);
3598};
3599
3600Graph.prototype.sources = function() {
3601 return _.filter(this.nodes(), function(v) {
3602 return _.isEmpty(this._in[v]);
3603 }, this);
3604};
3605
3606Graph.prototype.sinks = function() {
3607 return _.filter(this.nodes(), function(v) {
3608 return _.isEmpty(this._out[v]);
3609 }, this);
3610};
3611
3612Graph.prototype.setNodes = function(vs, value) {
3613 var args = arguments;
3614 _.each(vs, function(v) {
3615 if (args.length > 1) {
3616 this.setNode(v, value);
3617 } else {
3618 this.setNode(v);
3619 }
3620 }, this);
3621 return this;
3622};
3623
3624Graph.prototype.setNode = function(v, value) {
3625 if (_.has(this._nodes, v)) {
3626 if (arguments.length > 1) {
3627 this._nodes[v] = value;
3628 }
3629 return this;
3630 }
3631
3632 this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
3633 if (this._isCompound) {
3634 this._parent[v] = GRAPH_NODE;
3635 this._children[v] = {};
3636 this._children[GRAPH_NODE][v] = true;
3637 }
3638 this._in[v] = {};
3639 this._preds[v] = {};
3640 this._out[v] = {};
3641 this._sucs[v] = {};
3642 ++this._nodeCount;
3643 return this;
3644};
3645
3646Graph.prototype.node = function(v) {
3647 return this._nodes[v];
3648};
3649
3650Graph.prototype.hasNode = function(v) {
3651 return _.has(this._nodes, v);
3652};
3653
3654Graph.prototype.removeNode = function(v) {
3655 var self = this;
3656 if (_.has(this._nodes, v)) {
3657 var removeEdge = function(e) { self.removeEdge(self._edgeObjs[e]); };
3658 delete this._nodes[v];
3659 if (this._isCompound) {
3660 this._removeFromParentsChildList(v);
3661 delete this._parent[v];
3662 _.each(this.children(v), function(child) {
3663 this.setParent(child);
3664 }, this);
3665 delete this._children[v];
3666 }
3667 _.each(_.keys(this._in[v]), removeEdge);
3668 delete this._in[v];
3669 delete this._preds[v];
3670 _.each(_.keys(this._out[v]), removeEdge);
3671 delete this._out[v];
3672 delete this._sucs[v];
3673 --this._nodeCount;
3674 }
3675 return this;
3676};
3677
3678Graph.prototype.setParent = function(v, parent) {
3679 if (!this._isCompound) {
3680 throw new Error("Cannot set parent in a non-compound graph");
3681 }
3682
3683 if (_.isUndefined(parent)) {
3684 parent = GRAPH_NODE;
3685 } else {
3686 for (var ancestor = parent;
3687 !_.isUndefined(ancestor);
3688 ancestor = this.parent(ancestor)) {
3689 if (ancestor === v) {
3690 throw new Error("Setting " + parent+ " as parent of " + v +
3691 " would create create a cycle");
3692 }
3693 }
3694
3695 this.setNode(parent);
3696 }
3697
3698 this.setNode(v);
3699 this._removeFromParentsChildList(v);
3700 this._parent[v] = parent;
3701 this._children[parent][v] = true;
3702 return this;
3703};
3704
3705Graph.prototype._removeFromParentsChildList = function(v) {
3706 delete this._children[this._parent[v]][v];
3707};
3708
3709Graph.prototype.parent = function(v) {
3710 if (this._isCompound) {
3711 var parent = this._parent[v];
3712 if (parent !== GRAPH_NODE) {
3713 return parent;
3714 }
3715 }
3716};
3717
3718Graph.prototype.children = function(v) {
3719 if (_.isUndefined(v)) {
3720 v = GRAPH_NODE;
3721 }
3722
3723 if (this._isCompound) {
3724 var children = this._children[v];
3725 if (children) {
3726 return _.keys(children);
3727 }
3728 } else if (v === GRAPH_NODE) {
3729 return this.nodes();
3730 } else if (this.hasNode(v)) {
3731 return [];
3732 }
3733};
3734
3735Graph.prototype.predecessors = function(v) {
3736 var predsV = this._preds[v];
3737 if (predsV) {
3738 return _.keys(predsV);
3739 }
3740};
3741
3742Graph.prototype.successors = function(v) {
3743 var sucsV = this._sucs[v];
3744 if (sucsV) {
3745 return _.keys(sucsV);
3746 }
3747};
3748
3749Graph.prototype.neighbors = function(v) {
3750 var preds = this.predecessors(v);
3751 if (preds) {
3752 return _.union(preds, this.successors(v));
3753 }
3754};
3755
3756/* === Edge functions ========== */
3757
3758Graph.prototype.setDefaultEdgeLabel = function(newDefault) {
3759 if (!_.isFunction(newDefault)) {
3760 newDefault = _.constant(newDefault);
3761 }
3762 this._defaultEdgeLabelFn = newDefault;
3763 return this;
3764};
3765
3766Graph.prototype.edgeCount = function() {
3767 return this._edgeCount;
3768};
3769
3770Graph.prototype.edges = function() {
3771 return _.values(this._edgeObjs);
3772};
3773
3774Graph.prototype.setPath = function(vs, value) {
3775 var self = this,
3776 args = arguments;
3777 _.reduce(vs, function(v, w) {
3778 if (args.length > 1) {
3779 self.setEdge(v, w, value);
3780 } else {
3781 self.setEdge(v, w);
3782 }
3783 return w;
3784 });
3785 return this;
3786};
3787
3788/*
3789 * setEdge(v, w, [value, [name]])
3790 * setEdge({ v, w, [name] }, [value])
3791 */
3792Graph.prototype.setEdge = function() {
3793 var v, w, name, value,
3794 valueSpecified = false;
3795
3796 if (_.isPlainObject(arguments[0])) {
3797 v = arguments[0].v;
3798 w = arguments[0].w;
3799 name = arguments[0].name;
3800 if (arguments.length === 2) {
3801 value = arguments[1];
3802 valueSpecified = true;
3803 }
3804 } else {
3805 v = arguments[0];
3806 w = arguments[1];
3807 name = arguments[3];
3808 if (arguments.length > 2) {
3809 value = arguments[2];
3810 valueSpecified = true;
3811 }
3812 }
3813
3814 v = "" + v;
3815 w = "" + w;
3816 if (!_.isUndefined(name)) {
3817 name = "" + name;
3818 }
3819
3820 var e = edgeArgsToId(this._isDirected, v, w, name);
3821 if (_.has(this._edgeLabels, e)) {
3822 if (valueSpecified) {
3823 this._edgeLabels[e] = value;
3824 }
3825 return this;
3826 }
3827
3828 if (!_.isUndefined(name) && !this._isMultigraph) {
3829 throw new Error("Cannot set a named edge when isMultigraph = false");
3830 }
3831
3832 // It didn't exist, so we need to create it.
3833 // First ensure the nodes exist.
3834 this.setNode(v);
3835 this.setNode(w);
3836
3837 this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name);
3838
3839 var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
3840 // Ensure we add undirected edges in a consistent way.
3841 v = edgeObj.v;
3842 w = edgeObj.w;
3843
3844 Object.freeze(edgeObj);
3845 this._edgeObjs[e] = edgeObj;
3846 incrementOrInitEntry(this._preds[w], v);
3847 incrementOrInitEntry(this._sucs[v], w);
3848 this._in[w][e] = edgeObj;
3849 this._out[v][e] = edgeObj;
3850 this._edgeCount++;
3851 return this;
3852};
3853
3854Graph.prototype.edge = function(v, w, name) {
3855 var e = (arguments.length === 1
3856 ? edgeObjToId(this._isDirected, arguments[0])
3857 : edgeArgsToId(this._isDirected, v, w, name));
3858 return this._edgeLabels[e];
3859};
3860
3861Graph.prototype.hasEdge = function(v, w, name) {
3862 var e = (arguments.length === 1
3863 ? edgeObjToId(this._isDirected, arguments[0])
3864 : edgeArgsToId(this._isDirected, v, w, name));
3865 return _.has(this._edgeLabels, e);
3866};
3867
3868Graph.prototype.removeEdge = function(v, w, name) {
3869 var e = (arguments.length === 1
3870 ? edgeObjToId(this._isDirected, arguments[0])
3871 : edgeArgsToId(this._isDirected, v, w, name)),
3872 edge = this._edgeObjs[e];
3873 if (edge) {
3874 v = edge.v;
3875 w = edge.w;
3876 delete this._edgeLabels[e];
3877 delete this._edgeObjs[e];
3878 decrementOrRemoveEntry(this._preds[w], v);
3879 decrementOrRemoveEntry(this._sucs[v], w);
3880 delete this._in[w][e];
3881 delete this._out[v][e];
3882 this._edgeCount--;
3883 }
3884 return this;
3885};
3886
3887Graph.prototype.inEdges = function(v, u) {
3888 var inV = this._in[v];
3889 if (inV) {
3890 var edges = _.values(inV);
3891 if (!u) {
3892 return edges;
3893 }
3894 return _.filter(edges, function(edge) { return edge.v === u; });
3895 }
3896};
3897
3898Graph.prototype.outEdges = function(v, w) {
3899 var outV = this._out[v];
3900 if (outV) {
3901 var edges = _.values(outV);
3902 if (!w) {
3903 return edges;
3904 }
3905 return _.filter(edges, function(edge) { return edge.w === w; });
3906 }
3907};
3908
3909Graph.prototype.nodeEdges = function(v, w) {
3910 var inEdges = this.inEdges(v, w);
3911 if (inEdges) {
3912 return inEdges.concat(this.outEdges(v, w));
3913 }
3914};
3915
3916function incrementOrInitEntry(map, k) {
3917 if (_.has(map, k)) {
3918 map[k]++;
3919 } else {
3920 map[k] = 1;
3921 }
3922}
3923
3924function decrementOrRemoveEntry(map, k) {
3925 if (!--map[k]) { delete map[k]; }
3926}
3927
3928function edgeArgsToId(isDirected, v, w, name) {
3929 if (!isDirected && v > w) {
3930 var tmp = v;
3931 v = w;
3932 w = tmp;
3933 }
3934 return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM +
3935 (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name);
3936}
3937
3938function edgeArgsToObj(isDirected, v, w, name) {
3939 if (!isDirected && v > w) {
3940 var tmp = v;
3941 v = w;
3942 w = tmp;
3943 }
3944 var edgeObj = { v: v, w: w };
3945 if (name) {
3946 edgeObj.name = name;
3947 }
3948 return edgeObj;
3949}
3950
3951function edgeObjToId(isDirected, edgeObj) {
3952 return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
3953}
3954
3955},{"./lodash":49}],47:[function(require,module,exports){
3956// Includes only the "core" of graphlib
3957module.exports = {
3958 Graph: require("./graph"),
3959 version: require("./version")
3960};
3961
3962},{"./graph":46,"./version":50}],48:[function(require,module,exports){
3963var _ = require("./lodash"),
3964 Graph = require("./graph");
3965
3966module.exports = {
3967 write: write,
3968 read: read
3969};
3970
3971function write(g) {
3972 var json = {
3973 options: {
3974 directed: g.isDirected(),
3975 multigraph: g.isMultigraph(),
3976 compound: g.isCompound()
3977 },
3978 nodes: writeNodes(g),
3979 edges: writeEdges(g)
3980 };
3981 if (!_.isUndefined(g.graph())) {
3982 json.value = _.clone(g.graph());
3983 }
3984 return json;
3985}
3986
3987function writeNodes(g) {
3988 return _.map(g.nodes(), function(v) {
3989 var nodeValue = g.node(v),
3990 parent = g.parent(v),
3991 node = { v: v };
3992 if (!_.isUndefined(nodeValue)) {
3993 node.value = nodeValue;
3994 }
3995 if (!_.isUndefined(parent)) {
3996 node.parent = parent;
3997 }
3998 return node;
3999 });
4000}
4001
4002function writeEdges(g) {
4003 return _.map(g.edges(), function(e) {
4004 var edgeValue = g.edge(e),
4005 edge = { v: e.v, w: e.w };
4006 if (!_.isUndefined(e.name)) {
4007 edge.name = e.name;
4008 }
4009 if (!_.isUndefined(edgeValue)) {
4010 edge.value = edgeValue;
4011 }
4012 return edge;
4013 });
4014}
4015
4016function read(json) {
4017 var g = new Graph(json.options).setGraph(json.value);
4018 _.each(json.nodes, function(entry) {
4019 g.setNode(entry.v, entry.value);
4020 if (entry.parent) {
4021 g.setParent(entry.v, entry.parent);
4022 }
4023 });
4024 _.each(json.edges, function(entry) {
4025 g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value);
4026 });
4027 return g;
4028}
4029
4030},{"./graph":46,"./lodash":49}],49:[function(require,module,exports){
4031module.exports=require(10)
4032},{"/Users/cpettitt/projects/dagre/lib/lodash.js":10,"lodash":51}],50:[function(require,module,exports){
4033module.exports = '1.0.1';
4034
4035},{}],51:[function(require,module,exports){
4036(function (global){
4037/**
4038 * @license
4039 * Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
4040 * Build: `lodash modern -o ./dist/lodash.js`
4041 * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
4042 * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
4043 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4044 * Available under MIT license <http://lodash.com/license>
4045 */
4046;(function() {
4047
4048 /** Used as a safe reference for `undefined` in pre ES5 environments */
4049 var undefined;
4050
4051 /** Used to pool arrays and objects used internally */
4052 var arrayPool = [],
4053 objectPool = [];
4054
4055 /** Used to generate unique IDs */
4056 var idCounter = 0;
4057
4058 /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
4059 var keyPrefix = +new Date + '';
4060
4061 /** Used as the size when optimizations are enabled for large arrays */
4062 var largeArraySize = 75;
4063
4064 /** Used as the max size of the `arrayPool` and `objectPool` */
4065 var maxPoolSize = 40;
4066
4067 /** Used to detect and test whitespace */
4068 var whitespace = (
4069 // whitespace
4070 ' \t\x0B\f\xA0\ufeff' +
4071
4072 // line terminators
4073 '\n\r\u2028\u2029' +
4074
4075 // unicode category "Zs" space separators
4076 '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
4077 );
4078
4079 /** Used to match empty string literals in compiled template source */
4080 var reEmptyStringLeading = /\b__p \+= '';/g,
4081 reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
4082 reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
4083
4084 /**
4085 * Used to match ES6 template delimiters
4086 * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
4087 */
4088 var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
4089
4090 /** Used to match regexp flags from their coerced string values */
4091 var reFlags = /\w*$/;
4092
4093 /** Used to detected named functions */
4094 var reFuncName = /^\s*function[ \n\r\t]+\w/;
4095
4096 /** Used to match "interpolate" template delimiters */
4097 var reInterpolate = /<%=([\s\S]+?)%>/g;
4098
4099 /** Used to match leading whitespace and zeros to be removed */
4100 var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
4101
4102 /** Used to ensure capturing order of template delimiters */
4103 var reNoMatch = /($^)/;
4104
4105 /** Used to detect functions containing a `this` reference */
4106 var reThis = /\bthis\b/;
4107
4108 /** Used to match unescaped characters in compiled string literals */
4109 var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
4110
4111 /** Used to assign default `context` object properties */
4112 var contextProps = [
4113 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
4114 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
4115 'parseInt', 'setTimeout'
4116 ];
4117
4118 /** Used to make template sourceURLs easier to identify */
4119 var templateCounter = 0;
4120
4121 /** `Object#toString` result shortcuts */
4122 var argsClass = '[object Arguments]',
4123 arrayClass = '[object Array]',
4124 boolClass = '[object Boolean]',
4125 dateClass = '[object Date]',
4126 funcClass = '[object Function]',
4127 numberClass = '[object Number]',
4128 objectClass = '[object Object]',
4129 regexpClass = '[object RegExp]',
4130 stringClass = '[object String]';
4131
4132 /** Used to identify object classifications that `_.clone` supports */
4133 var cloneableClasses = {};
4134 cloneableClasses[funcClass] = false;
4135 cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
4136 cloneableClasses[boolClass] = cloneableClasses[dateClass] =
4137 cloneableClasses[numberClass] = cloneableClasses[objectClass] =
4138 cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
4139
4140 /** Used as an internal `_.debounce` options object */
4141 var debounceOptions = {
4142 'leading': false,
4143 'maxWait': 0,
4144 'trailing': false
4145 };
4146
4147 /** Used as the property descriptor for `__bindData__` */
4148 var descriptor = {
4149 'configurable': false,
4150 'enumerable': false,
4151 'value': null,
4152 'writable': false
4153 };
4154
4155 /** Used to determine if values are of the language type Object */
4156 var objectTypes = {
4157 'boolean': false,
4158 'function': true,
4159 'object': true,
4160 'number': false,
4161 'string': false,
4162 'undefined': false
4163 };
4164
4165 /** Used to escape characters for inclusion in compiled string literals */
4166 var stringEscapes = {
4167 '\\': '\\',
4168 "'": "'",
4169 '\n': 'n',
4170 '\r': 'r',
4171 '\t': 't',
4172 '\u2028': 'u2028',
4173 '\u2029': 'u2029'
4174 };
4175
4176 /** Used as a reference to the global object */
4177 var root = (objectTypes[typeof window] && window) || this;
4178
4179 /** Detect free variable `exports` */
4180 var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
4181
4182 /** Detect free variable `module` */
4183 var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
4184
4185 /** Detect the popular CommonJS extension `module.exports` */
4186 var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
4187
4188 /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
4189 var freeGlobal = objectTypes[typeof global] && global;
4190 if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
4191 root = freeGlobal;
4192 }
4193
4194 /*--------------------------------------------------------------------------*/
4195
4196 /**
4197 * The base implementation of `_.indexOf` without support for binary searches
4198 * or `fromIndex` constraints.
4199 *
4200 * @private
4201 * @param {Array} array The array to search.
4202 * @param {*} value The value to search for.
4203 * @param {number} [fromIndex=0] The index to search from.
4204 * @returns {number} Returns the index of the matched value or `-1`.
4205 */
4206 function baseIndexOf(array, value, fromIndex) {
4207 var index = (fromIndex || 0) - 1,
4208 length = array ? array.length : 0;
4209
4210 while (++index < length) {
4211 if (array[index] === value) {
4212 return index;
4213 }
4214 }
4215 return -1;
4216 }
4217
4218 /**
4219 * An implementation of `_.contains` for cache objects that mimics the return
4220 * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
4221 *
4222 * @private
4223 * @param {Object} cache The cache object to inspect.
4224 * @param {*} value The value to search for.
4225 * @returns {number} Returns `0` if `value` is found, else `-1`.
4226 */
4227 function cacheIndexOf(cache, value) {
4228 var type = typeof value;
4229 cache = cache.cache;
4230
4231 if (type == 'boolean' || value == null) {
4232 return cache[value] ? 0 : -1;
4233 }
4234 if (type != 'number' && type != 'string') {
4235 type = 'object';
4236 }
4237 var key = type == 'number' ? value : keyPrefix + value;
4238 cache = (cache = cache[type]) && cache[key];
4239
4240 return type == 'object'
4241 ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
4242 : (cache ? 0 : -1);
4243 }
4244
4245 /**
4246 * Adds a given value to the corresponding cache object.
4247 *
4248 * @private
4249 * @param {*} value The value to add to the cache.
4250 */
4251 function cachePush(value) {
4252 var cache = this.cache,
4253 type = typeof value;
4254
4255 if (type == 'boolean' || value == null) {
4256 cache[value] = true;
4257 } else {
4258 if (type != 'number' && type != 'string') {
4259 type = 'object';
4260 }
4261 var key = type == 'number' ? value : keyPrefix + value,
4262 typeCache = cache[type] || (cache[type] = {});
4263
4264 if (type == 'object') {
4265 (typeCache[key] || (typeCache[key] = [])).push(value);
4266 } else {
4267 typeCache[key] = true;
4268 }
4269 }
4270 }
4271
4272 /**
4273 * Used by `_.max` and `_.min` as the default callback when a given
4274 * collection is a string value.
4275 *
4276 * @private
4277 * @param {string} value The character to inspect.
4278 * @returns {number} Returns the code unit of given character.
4279 */
4280 function charAtCallback(value) {
4281 return value.charCodeAt(0);
4282 }
4283
4284 /**
4285 * Used by `sortBy` to compare transformed `collection` elements, stable sorting
4286 * them in ascending order.
4287 *
4288 * @private
4289 * @param {Object} a The object to compare to `b`.
4290 * @param {Object} b The object to compare to `a`.
4291 * @returns {number} Returns the sort order indicator of `1` or `-1`.
4292 */
4293 function compareAscending(a, b) {
4294 var ac = a.criteria,
4295 bc = b.criteria,
4296 index = -1,
4297 length = ac.length;
4298
4299 while (++index < length) {
4300 var value = ac[index],
4301 other = bc[index];
4302
4303 if (value !== other) {
4304 if (value > other || typeof value == 'undefined') {
4305 return 1;
4306 }
4307 if (value < other || typeof other == 'undefined') {
4308 return -1;
4309 }
4310 }
4311 }
4312 // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
4313 // that causes it, under certain circumstances, to return the same value for
4314 // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
4315 //
4316 // This also ensures a stable sort in V8 and other engines.
4317 // See http://code.google.com/p/v8/issues/detail?id=90
4318 return a.index - b.index;
4319 }
4320
4321 /**
4322 * Creates a cache object to optimize linear searches of large arrays.
4323 *
4324 * @private
4325 * @param {Array} [array=[]] The array to search.
4326 * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
4327 */
4328 function createCache(array) {
4329 var index = -1,
4330 length = array.length,
4331 first = array[0],
4332 mid = array[(length / 2) | 0],
4333 last = array[length - 1];
4334
4335 if (first && typeof first == 'object' &&
4336 mid && typeof mid == 'object' && last && typeof last == 'object') {
4337 return false;
4338 }
4339 var cache = getObject();
4340 cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
4341
4342 var result = getObject();
4343 result.array = array;
4344 result.cache = cache;
4345 result.push = cachePush;
4346
4347 while (++index < length) {
4348 result.push(array[index]);
4349 }
4350 return result;
4351 }
4352
4353 /**
4354 * Used by `template` to escape characters for inclusion in compiled
4355 * string literals.
4356 *
4357 * @private
4358 * @param {string} match The matched character to escape.
4359 * @returns {string} Returns the escaped character.
4360 */
4361 function escapeStringChar(match) {
4362 return '\\' + stringEscapes[match];
4363 }
4364
4365 /**
4366 * Gets an array from the array pool or creates a new one if the pool is empty.
4367 *
4368 * @private
4369 * @returns {Array} The array from the pool.
4370 */
4371 function getArray() {
4372 return arrayPool.pop() || [];
4373 }
4374
4375 /**
4376 * Gets an object from the object pool or creates a new one if the pool is empty.
4377 *
4378 * @private
4379 * @returns {Object} The object from the pool.
4380 */
4381 function getObject() {
4382 return objectPool.pop() || {
4383 'array': null,
4384 'cache': null,
4385 'criteria': null,
4386 'false': false,
4387 'index': 0,
4388 'null': false,
4389 'number': null,
4390 'object': null,
4391 'push': null,
4392 'string': null,
4393 'true': false,
4394 'undefined': false,
4395 'value': null
4396 };
4397 }
4398
4399 /**
4400 * Releases the given array back to the array pool.
4401 *
4402 * @private
4403 * @param {Array} [array] The array to release.
4404 */
4405 function releaseArray(array) {
4406 array.length = 0;
4407 if (arrayPool.length < maxPoolSize) {
4408 arrayPool.push(array);
4409 }
4410 }
4411
4412 /**
4413 * Releases the given object back to the object pool.
4414 *
4415 * @private
4416 * @param {Object} [object] The object to release.
4417 */
4418 function releaseObject(object) {
4419 var cache = object.cache;
4420 if (cache) {
4421 releaseObject(cache);
4422 }
4423 object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
4424 if (objectPool.length < maxPoolSize) {
4425 objectPool.push(object);
4426 }
4427 }
4428
4429 /**
4430 * Slices the `collection` from the `start` index up to, but not including,
4431 * the `end` index.
4432 *
4433 * Note: This function is used instead of `Array#slice` to support node lists
4434 * in IE < 9 and to ensure dense arrays are returned.
4435 *
4436 * @private
4437 * @param {Array|Object|string} collection The collection to slice.
4438 * @param {number} start The start index.
4439 * @param {number} end The end index.
4440 * @returns {Array} Returns the new array.
4441 */
4442 function slice(array, start, end) {
4443 start || (start = 0);
4444 if (typeof end == 'undefined') {
4445 end = array ? array.length : 0;
4446 }
4447 var index = -1,
4448 length = end - start || 0,
4449 result = Array(length < 0 ? 0 : length);
4450
4451 while (++index < length) {
4452 result[index] = array[start + index];
4453 }
4454 return result;
4455 }
4456
4457 /*--------------------------------------------------------------------------*/
4458
4459 /**
4460 * Create a new `lodash` function using the given context object.
4461 *
4462 * @static
4463 * @memberOf _
4464 * @category Utilities
4465 * @param {Object} [context=root] The context object.
4466 * @returns {Function} Returns the `lodash` function.
4467 */
4468 function runInContext(context) {
4469 // Avoid issues with some ES3 environments that attempt to use values, named
4470 // after built-in constructors like `Object`, for the creation of literals.
4471 // ES5 clears this up by stating that literals must use built-in constructors.
4472 // See http://es5.github.io/#x11.1.5.
4473 context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
4474
4475 /** Native constructor references */
4476 var Array = context.Array,
4477 Boolean = context.Boolean,
4478 Date = context.Date,
4479 Function = context.Function,
4480 Math = context.Math,
4481 Number = context.Number,
4482 Object = context.Object,
4483 RegExp = context.RegExp,
4484 String = context.String,
4485 TypeError = context.TypeError;
4486
4487 /**
4488 * Used for `Array` method references.
4489 *
4490 * Normally `Array.prototype` would suffice, however, using an array literal
4491 * avoids issues in Narwhal.
4492 */
4493 var arrayRef = [];
4494
4495 /** Used for native method references */
4496 var objectProto = Object.prototype;
4497
4498 /** Used to restore the original `_` reference in `noConflict` */
4499 var oldDash = context._;
4500
4501 /** Used to resolve the internal [[Class]] of values */
4502 var toString = objectProto.toString;
4503
4504 /** Used to detect if a method is native */
4505 var reNative = RegExp('^' +
4506 String(toString)
4507 .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
4508 .replace(/toString| for [^\]]+/g, '.*?') + '$'
4509 );
4510
4511 /** Native method shortcuts */
4512 var ceil = Math.ceil,
4513 clearTimeout = context.clearTimeout,
4514 floor = Math.floor,
4515 fnToString = Function.prototype.toString,
4516 getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
4517 hasOwnProperty = objectProto.hasOwnProperty,
4518 push = arrayRef.push,
4519 setTimeout = context.setTimeout,
4520 splice = arrayRef.splice,
4521 unshift = arrayRef.unshift;
4522
4523 /** Used to set meta data on functions */
4524 var defineProperty = (function() {
4525 // IE 8 only accepts DOM elements
4526 try {
4527 var o = {},
4528 func = isNative(func = Object.defineProperty) && func,
4529 result = func(o, o, o) && func;
4530 } catch(e) { }
4531 return result;
4532 }());
4533
4534 /* Native method shortcuts for methods with the same name as other `lodash` methods */
4535 var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
4536 nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
4537 nativeIsFinite = context.isFinite,
4538 nativeIsNaN = context.isNaN,
4539 nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
4540 nativeMax = Math.max,
4541 nativeMin = Math.min,
4542 nativeParseInt = context.parseInt,
4543 nativeRandom = Math.random;
4544
4545 /** Used to lookup a built-in constructor by [[Class]] */
4546 var ctorByClass = {};
4547 ctorByClass[arrayClass] = Array;
4548 ctorByClass[boolClass] = Boolean;
4549 ctorByClass[dateClass] = Date;
4550 ctorByClass[funcClass] = Function;
4551 ctorByClass[objectClass] = Object;
4552 ctorByClass[numberClass] = Number;
4553 ctorByClass[regexpClass] = RegExp;
4554 ctorByClass[stringClass] = String;
4555
4556 /*--------------------------------------------------------------------------*/
4557
4558 /**
4559 * Creates a `lodash` object which wraps the given value to enable intuitive
4560 * method chaining.
4561 *
4562 * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
4563 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
4564 * and `unshift`
4565 *
4566 * Chaining is supported in custom builds as long as the `value` method is
4567 * implicitly or explicitly included in the build.
4568 *
4569 * The chainable wrapper functions are:
4570 * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
4571 * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
4572 * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
4573 * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
4574 * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
4575 * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
4576 * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
4577 * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
4578 * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
4579 * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
4580 * and `zip`
4581 *
4582 * The non-chainable wrapper functions are:
4583 * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
4584 * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
4585 * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
4586 * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
4587 * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
4588 * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
4589 * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
4590 * `template`, `unescape`, `uniqueId`, and `value`
4591 *
4592 * The wrapper functions `first` and `last` return wrapped values when `n` is
4593 * provided, otherwise they return unwrapped values.
4594 *
4595 * Explicit chaining can be enabled by using the `_.chain` method.
4596 *
4597 * @name _
4598 * @constructor
4599 * @category Chaining
4600 * @param {*} value The value to wrap in a `lodash` instance.
4601 * @returns {Object} Returns a `lodash` instance.
4602 * @example
4603 *
4604 * var wrapped = _([1, 2, 3]);
4605 *
4606 * // returns an unwrapped value
4607 * wrapped.reduce(function(sum, num) {
4608 * return sum + num;
4609 * });
4610 * // => 6
4611 *
4612 * // returns a wrapped value
4613 * var squares = wrapped.map(function(num) {
4614 * return num * num;
4615 * });
4616 *
4617 * _.isArray(squares);
4618 * // => false
4619 *
4620 * _.isArray(squares.value());
4621 * // => true
4622 */
4623 function lodash(value) {
4624 // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
4625 return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
4626 ? value
4627 : new lodashWrapper(value);
4628 }
4629
4630 /**
4631 * A fast path for creating `lodash` wrapper objects.
4632 *
4633 * @private
4634 * @param {*} value The value to wrap in a `lodash` instance.
4635 * @param {boolean} chainAll A flag to enable chaining for all methods
4636 * @returns {Object} Returns a `lodash` instance.
4637 */
4638 function lodashWrapper(value, chainAll) {
4639 this.__chain__ = !!chainAll;
4640 this.__wrapped__ = value;
4641 }
4642 // ensure `new lodashWrapper` is an instance of `lodash`
4643 lodashWrapper.prototype = lodash.prototype;
4644
4645 /**
4646 * An object used to flag environments features.
4647 *
4648 * @static
4649 * @memberOf _
4650 * @type Object
4651 */
4652 var support = lodash.support = {};
4653
4654 /**
4655 * Detect if functions can be decompiled by `Function#toString`
4656 * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
4657 *
4658 * @memberOf _.support
4659 * @type boolean
4660 */
4661 support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
4662
4663 /**
4664 * Detect if `Function#name` is supported (all but IE).
4665 *
4666 * @memberOf _.support
4667 * @type boolean
4668 */
4669 support.funcNames = typeof Function.name == 'string';
4670
4671 /**
4672 * By default, the template delimiters used by Lo-Dash are similar to those in
4673 * embedded Ruby (ERB). Change the following template settings to use alternative
4674 * delimiters.
4675 *
4676 * @static
4677 * @memberOf _
4678 * @type Object
4679 */
4680 lodash.templateSettings = {
4681
4682 /**
4683 * Used to detect `data` property values to be HTML-escaped.
4684 *
4685 * @memberOf _.templateSettings
4686 * @type RegExp
4687 */
4688 'escape': /<%-([\s\S]+?)%>/g,
4689
4690 /**
4691 * Used to detect code to be evaluated.
4692 *
4693 * @memberOf _.templateSettings
4694 * @type RegExp
4695 */
4696 'evaluate': /<%([\s\S]+?)%>/g,
4697
4698 /**
4699 * Used to detect `data` property values to inject.
4700 *
4701 * @memberOf _.templateSettings
4702 * @type RegExp
4703 */
4704 'interpolate': reInterpolate,
4705
4706 /**
4707 * Used to reference the data object in the template text.
4708 *
4709 * @memberOf _.templateSettings
4710 * @type string
4711 */
4712 'variable': '',
4713
4714 /**
4715 * Used to import variables into the compiled template.
4716 *
4717 * @memberOf _.templateSettings
4718 * @type Object
4719 */
4720 'imports': {
4721
4722 /**
4723 * A reference to the `lodash` function.
4724 *
4725 * @memberOf _.templateSettings.imports
4726 * @type Function
4727 */
4728 '_': lodash
4729 }
4730 };
4731
4732 /*--------------------------------------------------------------------------*/
4733
4734 /**
4735 * The base implementation of `_.bind` that creates the bound function and
4736 * sets its meta data.
4737 *
4738 * @private
4739 * @param {Array} bindData The bind data array.
4740 * @returns {Function} Returns the new bound function.
4741 */
4742 function baseBind(bindData) {
4743 var func = bindData[0],
4744 partialArgs = bindData[2],
4745 thisArg = bindData[4];
4746
4747 function bound() {
4748 // `Function#bind` spec
4749 // http://es5.github.io/#x15.3.4.5
4750 if (partialArgs) {
4751 // avoid `arguments` object deoptimizations by using `slice` instead
4752 // of `Array.prototype.slice.call` and not assigning `arguments` to a
4753 // variable as a ternary expression
4754 var args = slice(partialArgs);
4755 push.apply(args, arguments);
4756 }
4757 // mimic the constructor's `return` behavior
4758 // http://es5.github.io/#x13.2.2
4759 if (this instanceof bound) {
4760 // ensure `new bound` is an instance of `func`
4761 var thisBinding = baseCreate(func.prototype),
4762 result = func.apply(thisBinding, args || arguments);
4763 return isObject(result) ? result : thisBinding;
4764 }
4765 return func.apply(thisArg, args || arguments);
4766 }
4767 setBindData(bound, bindData);
4768 return bound;
4769 }
4770
4771 /**
4772 * The base implementation of `_.clone` without argument juggling or support
4773 * for `thisArg` binding.
4774 *
4775 * @private
4776 * @param {*} value The value to clone.
4777 * @param {boolean} [isDeep=false] Specify a deep clone.
4778 * @param {Function} [callback] The function to customize cloning values.
4779 * @param {Array} [stackA=[]] Tracks traversed source objects.
4780 * @param {Array} [stackB=[]] Associates clones with source counterparts.
4781 * @returns {*} Returns the cloned value.
4782 */
4783 function baseClone(value, isDeep, callback, stackA, stackB) {
4784 if (callback) {
4785 var result = callback(value);
4786 if (typeof result != 'undefined') {
4787 return result;
4788 }
4789 }
4790 // inspect [[Class]]
4791 var isObj = isObject(value);
4792 if (isObj) {
4793 var className = toString.call(value);
4794 if (!cloneableClasses[className]) {
4795 return value;
4796 }
4797 var ctor = ctorByClass[className];
4798 switch (className) {
4799 case boolClass:
4800 case dateClass:
4801 return new ctor(+value);
4802
4803 case numberClass:
4804 case stringClass:
4805 return new ctor(value);
4806
4807 case regexpClass:
4808 result = ctor(value.source, reFlags.exec(value));
4809 result.lastIndex = value.lastIndex;
4810 return result;
4811 }
4812 } else {
4813 return value;
4814 }
4815 var isArr = isArray(value);
4816 if (isDeep) {
4817 // check for circular references and return corresponding clone
4818 var initedStack = !stackA;
4819 stackA || (stackA = getArray());
4820 stackB || (stackB = getArray());
4821
4822 var length = stackA.length;
4823 while (length--) {
4824 if (stackA[length] == value) {
4825 return stackB[length];
4826 }
4827 }
4828 result = isArr ? ctor(value.length) : {};
4829 }
4830 else {
4831 result = isArr ? slice(value) : assign({}, value);
4832 }
4833 // add array properties assigned by `RegExp#exec`
4834 if (isArr) {
4835 if (hasOwnProperty.call(value, 'index')) {
4836 result.index = value.index;
4837 }
4838 if (hasOwnProperty.call(value, 'input')) {
4839 result.input = value.input;
4840 }
4841 }
4842 // exit for shallow clone
4843 if (!isDeep) {
4844 return result;
4845 }
4846 // add the source value to the stack of traversed objects
4847 // and associate it with its clone
4848 stackA.push(value);
4849 stackB.push(result);
4850
4851 // recursively populate clone (susceptible to call stack limits)
4852 (isArr ? forEach : forOwn)(value, function(objValue, key) {
4853 result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
4854 });
4855
4856 if (initedStack) {
4857 releaseArray(stackA);
4858 releaseArray(stackB);
4859 }
4860 return result;
4861 }
4862
4863 /**
4864 * The base implementation of `_.create` without support for assigning
4865 * properties to the created object.
4866 *
4867 * @private
4868 * @param {Object} prototype The object to inherit from.
4869 * @returns {Object} Returns the new object.
4870 */
4871 function baseCreate(prototype, properties) {
4872 return isObject(prototype) ? nativeCreate(prototype) : {};
4873 }
4874 // fallback for browsers without `Object.create`
4875 if (!nativeCreate) {
4876 baseCreate = (function() {
4877 function Object() {}
4878 return function(prototype) {
4879 if (isObject(prototype)) {
4880 Object.prototype = prototype;
4881 var result = new Object;
4882 Object.prototype = null;
4883 }
4884 return result || context.Object();
4885 };
4886 }());
4887 }
4888
4889 /**
4890 * The base implementation of `_.createCallback` without support for creating
4891 * "_.pluck" or "_.where" style callbacks.
4892 *
4893 * @private
4894 * @param {*} [func=identity] The value to convert to a callback.
4895 * @param {*} [thisArg] The `this` binding of the created callback.
4896 * @param {number} [argCount] The number of arguments the callback accepts.
4897 * @returns {Function} Returns a callback function.
4898 */
4899 function baseCreateCallback(func, thisArg, argCount) {
4900 if (typeof func != 'function') {
4901 return identity;
4902 }
4903 // exit early for no `thisArg` or already bound by `Function#bind`
4904 if (typeof thisArg == 'undefined' || !('prototype' in func)) {
4905 return func;
4906 }
4907 var bindData = func.__bindData__;
4908 if (typeof bindData == 'undefined') {
4909 if (support.funcNames) {
4910 bindData = !func.name;
4911 }
4912 bindData = bindData || !support.funcDecomp;
4913 if (!bindData) {
4914 var source = fnToString.call(func);
4915 if (!support.funcNames) {
4916 bindData = !reFuncName.test(source);
4917 }
4918 if (!bindData) {
4919 // checks if `func` references the `this` keyword and stores the result
4920 bindData = reThis.test(source);
4921 setBindData(func, bindData);
4922 }
4923 }
4924 }
4925 // exit early if there are no `this` references or `func` is bound
4926 if (bindData === false || (bindData !== true && bindData[1] & 1)) {
4927 return func;
4928 }
4929 switch (argCount) {
4930 case 1: return function(value) {
4931 return func.call(thisArg, value);
4932 };
4933 case 2: return function(a, b) {
4934 return func.call(thisArg, a, b);
4935 };
4936 case 3: return function(value, index, collection) {
4937 return func.call(thisArg, value, index, collection);
4938 };
4939 case 4: return function(accumulator, value, index, collection) {
4940 return func.call(thisArg, accumulator, value, index, collection);
4941 };
4942 }
4943 return bind(func, thisArg);
4944 }
4945
4946 /**
4947 * The base implementation of `createWrapper` that creates the wrapper and
4948 * sets its meta data.
4949 *
4950 * @private
4951 * @param {Array} bindData The bind data array.
4952 * @returns {Function} Returns the new function.
4953 */
4954 function baseCreateWrapper(bindData) {
4955 var func = bindData[0],
4956 bitmask = bindData[1],
4957 partialArgs = bindData[2],
4958 partialRightArgs = bindData[3],
4959 thisArg = bindData[4],
4960 arity = bindData[5];
4961
4962 var isBind = bitmask & 1,
4963 isBindKey = bitmask & 2,
4964 isCurry = bitmask & 4,
4965 isCurryBound = bitmask & 8,
4966 key = func;
4967
4968 function bound() {
4969 var thisBinding = isBind ? thisArg : this;
4970 if (partialArgs) {
4971 var args = slice(partialArgs);
4972 push.apply(args, arguments);
4973 }
4974 if (partialRightArgs || isCurry) {
4975 args || (args = slice(arguments));
4976 if (partialRightArgs) {
4977 push.apply(args, partialRightArgs);
4978 }
4979 if (isCurry && args.length < arity) {
4980 bitmask |= 16 & ~32;
4981 return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
4982 }
4983 }
4984 args || (args = arguments);
4985 if (isBindKey) {
4986 func = thisBinding[key];
4987 }
4988 if (this instanceof bound) {
4989 thisBinding = baseCreate(func.prototype);
4990 var result = func.apply(thisBinding, args);
4991 return isObject(result) ? result : thisBinding;
4992 }
4993 return func.apply(thisBinding, args);
4994 }
4995 setBindData(bound, bindData);
4996 return bound;
4997 }
4998
4999 /**
5000 * The base implementation of `_.difference` that accepts a single array
5001 * of values to exclude.
5002 *
5003 * @private
5004 * @param {Array} array The array to process.
5005 * @param {Array} [values] The array of values to exclude.
5006 * @returns {Array} Returns a new array of filtered values.
5007 */
5008 function baseDifference(array, values) {
5009 var index = -1,
5010 indexOf = getIndexOf(),
5011 length = array ? array.length : 0,
5012 isLarge = length >= largeArraySize && indexOf === baseIndexOf,
5013 result = [];
5014
5015 if (isLarge) {
5016 var cache = createCache(values);
5017 if (cache) {
5018 indexOf = cacheIndexOf;
5019 values = cache;
5020 } else {
5021 isLarge = false;
5022 }
5023 }
5024 while (++index < length) {
5025 var value = array[index];
5026 if (indexOf(values, value) < 0) {
5027 result.push(value);
5028 }
5029 }
5030 if (isLarge) {
5031 releaseObject(values);
5032 }
5033 return result;
5034 }
5035
5036 /**
5037 * The base implementation of `_.flatten` without support for callback
5038 * shorthands or `thisArg` binding.
5039 *
5040 * @private
5041 * @param {Array} array The array to flatten.
5042 * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
5043 * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
5044 * @param {number} [fromIndex=0] The index to start from.
5045 * @returns {Array} Returns a new flattened array.
5046 */
5047 function baseFlatten(array, isShallow, isStrict, fromIndex) {
5048 var index = (fromIndex || 0) - 1,
5049 length = array ? array.length : 0,
5050 result = [];
5051
5052 while (++index < length) {
5053 var value = array[index];
5054
5055 if (value && typeof value == 'object' && typeof value.length == 'number'
5056 && (isArray(value) || isArguments(value))) {
5057 // recursively flatten arrays (susceptible to call stack limits)
5058 if (!isShallow) {
5059 value = baseFlatten(value, isShallow, isStrict);
5060 }
5061 var valIndex = -1,
5062 valLength = value.length,
5063 resIndex = result.length;
5064
5065 result.length += valLength;
5066 while (++valIndex < valLength) {
5067 result[resIndex++] = value[valIndex];
5068 }
5069 } else if (!isStrict) {
5070 result.push(value);
5071 }
5072 }
5073 return result;
5074 }
5075
5076 /**
5077 * The base implementation of `_.isEqual`, without support for `thisArg` binding,
5078 * that allows partial "_.where" style comparisons.
5079 *
5080 * @private
5081 * @param {*} a The value to compare.
5082 * @param {*} b The other value to compare.
5083 * @param {Function} [callback] The function to customize comparing values.
5084 * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
5085 * @param {Array} [stackA=[]] Tracks traversed `a` objects.
5086 * @param {Array} [stackB=[]] Tracks traversed `b` objects.
5087 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
5088 */
5089 function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
5090 // used to indicate that when comparing objects, `a` has at least the properties of `b`
5091 if (callback) {
5092 var result = callback(a, b);
5093 if (typeof result != 'undefined') {
5094 return !!result;
5095 }
5096 }
5097 // exit early for identical values
5098 if (a === b) {
5099 // treat `+0` vs. `-0` as not equal
5100 return a !== 0 || (1 / a == 1 / b);
5101 }
5102 var type = typeof a,
5103 otherType = typeof b;
5104
5105 // exit early for unlike primitive values
5106 if (a === a &&
5107 !(a && objectTypes[type]) &&
5108 !(b && objectTypes[otherType])) {
5109 return false;
5110 }
5111 // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
5112 // http://es5.github.io/#x15.3.4.4
5113 if (a == null || b == null) {
5114 return a === b;
5115 }
5116 // compare [[Class]] names
5117 var className = toString.call(a),
5118 otherClass = toString.call(b);
5119
5120 if (className == argsClass) {
5121 className = objectClass;
5122 }
5123 if (otherClass == argsClass) {
5124 otherClass = objectClass;
5125 }
5126 if (className != otherClass) {
5127 return false;
5128 }
5129 switch (className) {
5130 case boolClass:
5131 case dateClass:
5132 // coerce dates and booleans to numbers, dates to milliseconds and booleans
5133 // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
5134 return +a == +b;
5135
5136 case numberClass:
5137 // treat `NaN` vs. `NaN` as equal
5138 return (a != +a)
5139 ? b != +b
5140 // but treat `+0` vs. `-0` as not equal
5141 : (a == 0 ? (1 / a == 1 / b) : a == +b);
5142
5143 case regexpClass:
5144 case stringClass:
5145 // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
5146 // treat string primitives and their corresponding object instances as equal
5147 return a == String(b);
5148 }
5149 var isArr = className == arrayClass;
5150 if (!isArr) {
5151 // unwrap any `lodash` wrapped values
5152 var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
5153 bWrapped = hasOwnProperty.call(b, '__wrapped__');
5154
5155 if (aWrapped || bWrapped) {
5156 return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
5157 }
5158 // exit for functions and DOM nodes
5159 if (className != objectClass) {
5160 return false;
5161 }
5162 // in older versions of Opera, `arguments` objects have `Array` constructors
5163 var ctorA = a.constructor,
5164 ctorB = b.constructor;
5165
5166 // non `Object` object instances with different constructors are not equal
5167 if (ctorA != ctorB &&
5168 !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
5169 ('constructor' in a && 'constructor' in b)
5170 ) {
5171 return false;
5172 }
5173 }
5174 // assume cyclic structures are equal
5175 // the algorithm for detecting cyclic structures is adapted from ES 5.1
5176 // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
5177 var initedStack = !stackA;
5178 stackA || (stackA = getArray());
5179 stackB || (stackB = getArray());
5180
5181 var length = stackA.length;
5182 while (length--) {
5183 if (stackA[length] == a) {
5184 return stackB[length] == b;
5185 }
5186 }
5187 var size = 0;
5188 result = true;
5189
5190 // add `a` and `b` to the stack of traversed objects
5191 stackA.push(a);
5192 stackB.push(b);
5193
5194 // recursively compare objects and arrays (susceptible to call stack limits)
5195 if (isArr) {
5196 // compare lengths to determine if a deep comparison is necessary
5197 length = a.length;
5198 size = b.length;
5199 result = size == length;
5200
5201 if (result || isWhere) {
5202 // deep compare the contents, ignoring non-numeric properties
5203 while (size--) {
5204 var index = length,
5205 value = b[size];
5206
5207 if (isWhere) {
5208 while (index--) {
5209 if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
5210 break;
5211 }
5212 }
5213 } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
5214 break;
5215 }
5216 }
5217 }
5218 }
5219 else {
5220 // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
5221 // which, in this case, is more costly
5222 forIn(b, function(value, key, b) {
5223 if (hasOwnProperty.call(b, key)) {
5224 // count the number of properties.
5225 size++;
5226 // deep compare each property value.
5227 return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
5228 }
5229 });
5230
5231 if (result && !isWhere) {
5232 // ensure both objects have the same number of properties
5233 forIn(a, function(value, key, a) {
5234 if (hasOwnProperty.call(a, key)) {
5235 // `size` will be `-1` if `a` has more properties than `b`
5236 return (result = --size > -1);
5237 }
5238 });
5239 }
5240 }
5241 stackA.pop();
5242 stackB.pop();
5243
5244 if (initedStack) {
5245 releaseArray(stackA);
5246 releaseArray(stackB);
5247 }
5248 return result;
5249 }
5250
5251 /**
5252 * The base implementation of `_.merge` without argument juggling or support
5253 * for `thisArg` binding.
5254 *
5255 * @private
5256 * @param {Object} object The destination object.
5257 * @param {Object} source The source object.
5258 * @param {Function} [callback] The function to customize merging properties.
5259 * @param {Array} [stackA=[]] Tracks traversed source objects.
5260 * @param {Array} [stackB=[]] Associates values with source counterparts.
5261 */
5262 function baseMerge(object, source, callback, stackA, stackB) {
5263 (isArray(source) ? forEach : forOwn)(source, function(source, key) {
5264 var found,
5265 isArr,
5266 result = source,
5267 value = object[key];
5268
5269 if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
5270 // avoid merging previously merged cyclic sources
5271 var stackLength = stackA.length;
5272 while (stackLength--) {
5273 if ((found = stackA[stackLength] == source)) {
5274 value = stackB[stackLength];
5275 break;
5276 }
5277 }
5278 if (!found) {
5279 var isShallow;
5280 if (callback) {
5281 result = callback(value, source);
5282 if ((isShallow = typeof result != 'undefined')) {
5283 value = result;
5284 }
5285 }
5286 if (!isShallow) {
5287 value = isArr
5288 ? (isArray(value) ? value : [])
5289 : (isPlainObject(value) ? value : {});
5290 }
5291 // add `source` and associated `value` to the stack of traversed objects
5292 stackA.push(source);
5293 stackB.push(value);
5294
5295 // recursively merge objects and arrays (susceptible to call stack limits)
5296 if (!isShallow) {
5297 baseMerge(value, source, callback, stackA, stackB);
5298 }
5299 }
5300 }
5301 else {
5302 if (callback) {
5303 result = callback(value, source);
5304 if (typeof result == 'undefined') {
5305 result = source;
5306 }
5307 }
5308 if (typeof result != 'undefined') {
5309 value = result;
5310 }
5311 }
5312 object[key] = value;
5313 });
5314 }
5315
5316 /**
5317 * The base implementation of `_.random` without argument juggling or support
5318 * for returning floating-point numbers.
5319 *
5320 * @private
5321 * @param {number} min The minimum possible value.
5322 * @param {number} max The maximum possible value.
5323 * @returns {number} Returns a random number.
5324 */
5325 function baseRandom(min, max) {
5326 return min + floor(nativeRandom() * (max - min + 1));
5327 }
5328
5329 /**
5330 * The base implementation of `_.uniq` without support for callback shorthands
5331 * or `thisArg` binding.
5332 *
5333 * @private
5334 * @param {Array} array The array to process.
5335 * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
5336 * @param {Function} [callback] The function called per iteration.
5337 * @returns {Array} Returns a duplicate-value-free array.
5338 */
5339 function baseUniq(array, isSorted, callback) {
5340 var index = -1,
5341 indexOf = getIndexOf(),
5342 length = array ? array.length : 0,
5343 result = [];
5344
5345 var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
5346 seen = (callback || isLarge) ? getArray() : result;
5347
5348 if (isLarge) {
5349 var cache = createCache(seen);
5350 indexOf = cacheIndexOf;
5351 seen = cache;
5352 }
5353 while (++index < length) {
5354 var value = array[index],
5355 computed = callback ? callback(value, index, array) : value;
5356
5357 if (isSorted
5358 ? !index || seen[seen.length - 1] !== computed
5359 : indexOf(seen, computed) < 0
5360 ) {
5361 if (callback || isLarge) {
5362 seen.push(computed);
5363 }
5364 result.push(value);
5365 }
5366 }
5367 if (isLarge) {
5368 releaseArray(seen.array);
5369 releaseObject(seen);
5370 } else if (callback) {
5371 releaseArray(seen);
5372 }
5373 return result;
5374 }
5375
5376 /**
5377 * Creates a function that aggregates a collection, creating an object composed
5378 * of keys generated from the results of running each element of the collection
5379 * through a callback. The given `setter` function sets the keys and values
5380 * of the composed object.
5381 *
5382 * @private
5383 * @param {Function} setter The setter function.
5384 * @returns {Function} Returns the new aggregator function.
5385 */
5386 function createAggregator(setter) {
5387 return function(collection, callback, thisArg) {
5388 var result = {};
5389 callback = lodash.createCallback(callback, thisArg, 3);
5390
5391 var index = -1,
5392 length = collection ? collection.length : 0;
5393
5394 if (typeof length == 'number') {
5395 while (++index < length) {
5396 var value = collection[index];
5397 setter(result, value, callback(value, index, collection), collection);
5398 }
5399 } else {
5400 forOwn(collection, function(value, key, collection) {
5401 setter(result, value, callback(value, key, collection), collection);
5402 });
5403 }
5404 return result;
5405 };
5406 }
5407
5408 /**
5409 * Creates a function that, when called, either curries or invokes `func`
5410 * with an optional `this` binding and partially applied arguments.
5411 *
5412 * @private
5413 * @param {Function|string} func The function or method name to reference.
5414 * @param {number} bitmask The bitmask of method flags to compose.
5415 * The bitmask may be composed of the following flags:
5416 * 1 - `_.bind`
5417 * 2 - `_.bindKey`
5418 * 4 - `_.curry`
5419 * 8 - `_.curry` (bound)
5420 * 16 - `_.partial`
5421 * 32 - `_.partialRight`
5422 * @param {Array} [partialArgs] An array of arguments to prepend to those
5423 * provided to the new function.
5424 * @param {Array} [partialRightArgs] An array of arguments to append to those
5425 * provided to the new function.
5426 * @param {*} [thisArg] The `this` binding of `func`.
5427 * @param {number} [arity] The arity of `func`.
5428 * @returns {Function} Returns the new function.
5429 */
5430 function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
5431 var isBind = bitmask & 1,
5432 isBindKey = bitmask & 2,
5433 isCurry = bitmask & 4,
5434 isCurryBound = bitmask & 8,
5435 isPartial = bitmask & 16,
5436 isPartialRight = bitmask & 32;
5437
5438 if (!isBindKey && !isFunction(func)) {
5439 throw new TypeError;
5440 }
5441 if (isPartial && !partialArgs.length) {
5442 bitmask &= ~16;
5443 isPartial = partialArgs = false;
5444 }
5445 if (isPartialRight && !partialRightArgs.length) {
5446 bitmask &= ~32;
5447 isPartialRight = partialRightArgs = false;
5448 }
5449 var bindData = func && func.__bindData__;
5450 if (bindData && bindData !== true) {
5451 // clone `bindData`
5452 bindData = slice(bindData);
5453 if (bindData[2]) {
5454 bindData[2] = slice(bindData[2]);
5455 }
5456 if (bindData[3]) {
5457 bindData[3] = slice(bindData[3]);
5458 }
5459 // set `thisBinding` is not previously bound
5460 if (isBind && !(bindData[1] & 1)) {
5461 bindData[4] = thisArg;
5462 }
5463 // set if previously bound but not currently (subsequent curried functions)
5464 if (!isBind && bindData[1] & 1) {
5465 bitmask |= 8;
5466 }
5467 // set curried arity if not yet set
5468 if (isCurry && !(bindData[1] & 4)) {
5469 bindData[5] = arity;
5470 }
5471 // append partial left arguments
5472 if (isPartial) {
5473 push.apply(bindData[2] || (bindData[2] = []), partialArgs);
5474 }
5475 // append partial right arguments
5476 if (isPartialRight) {
5477 unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
5478 }
5479 // merge flags
5480 bindData[1] |= bitmask;
5481 return createWrapper.apply(null, bindData);
5482 }
5483 // fast path for `_.bind`
5484 var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
5485 return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
5486 }
5487
5488 /**
5489 * Used by `escape` to convert characters to HTML entities.
5490 *
5491 * @private
5492 * @param {string} match The matched character to escape.
5493 * @returns {string} Returns the escaped character.
5494 */
5495 function escapeHtmlChar(match) {
5496 return htmlEscapes[match];
5497 }
5498
5499 /**
5500 * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
5501 * customized, this method returns the custom method, otherwise it returns
5502 * the `baseIndexOf` function.
5503 *
5504 * @private
5505 * @returns {Function} Returns the "indexOf" function.
5506 */
5507 function getIndexOf() {
5508 var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
5509 return result;
5510 }
5511
5512 /**
5513 * Checks if `value` is a native function.
5514 *
5515 * @private
5516 * @param {*} value The value to check.
5517 * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
5518 */
5519 function isNative(value) {
5520 return typeof value == 'function' && reNative.test(value);
5521 }
5522
5523 /**
5524 * Sets `this` binding data on a given function.
5525 *
5526 * @private
5527 * @param {Function} func The function to set data on.
5528 * @param {Array} value The data array to set.
5529 */
5530 var setBindData = !defineProperty ? noop : function(func, value) {
5531 descriptor.value = value;
5532 defineProperty(func, '__bindData__', descriptor);
5533 };
5534
5535 /**
5536 * A fallback implementation of `isPlainObject` which checks if a given value
5537 * is an object created by the `Object` constructor, assuming objects created
5538 * by the `Object` constructor have no inherited enumerable properties and that
5539 * there are no `Object.prototype` extensions.
5540 *
5541 * @private
5542 * @param {*} value The value to check.
5543 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
5544 */
5545 function shimIsPlainObject(value) {
5546 var ctor,
5547 result;
5548
5549 // avoid non Object objects, `arguments` objects, and DOM elements
5550 if (!(value && toString.call(value) == objectClass) ||
5551 (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
5552 return false;
5553 }
5554 // In most environments an object's own properties are iterated before
5555 // its inherited properties. If the last iterated property is an object's
5556 // own property then there are no inherited enumerable properties.
5557 forIn(value, function(value, key) {
5558 result = key;
5559 });
5560 return typeof result == 'undefined' || hasOwnProperty.call(value, result);
5561 }
5562
5563 /**
5564 * Used by `unescape` to convert HTML entities to characters.
5565 *
5566 * @private
5567 * @param {string} match The matched character to unescape.
5568 * @returns {string} Returns the unescaped character.
5569 */
5570 function unescapeHtmlChar(match) {
5571 return htmlUnescapes[match];
5572 }
5573
5574 /*--------------------------------------------------------------------------*/
5575
5576 /**
5577 * Checks if `value` is an `arguments` object.
5578 *
5579 * @static
5580 * @memberOf _
5581 * @category Objects
5582 * @param {*} value The value to check.
5583 * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
5584 * @example
5585 *
5586 * (function() { return _.isArguments(arguments); })(1, 2, 3);
5587 * // => true
5588 *
5589 * _.isArguments([1, 2, 3]);
5590 * // => false
5591 */
5592 function isArguments(value) {
5593 return value && typeof value == 'object' && typeof value.length == 'number' &&
5594 toString.call(value) == argsClass || false;
5595 }
5596
5597 /**
5598 * Checks if `value` is an array.
5599 *
5600 * @static
5601 * @memberOf _
5602 * @type Function
5603 * @category Objects
5604 * @param {*} value The value to check.
5605 * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
5606 * @example
5607 *
5608 * (function() { return _.isArray(arguments); })();
5609 * // => false
5610 *
5611 * _.isArray([1, 2, 3]);
5612 * // => true
5613 */
5614 var isArray = nativeIsArray || function(value) {
5615 return value && typeof value == 'object' && typeof value.length == 'number' &&
5616 toString.call(value) == arrayClass || false;
5617 };
5618
5619 /**
5620 * A fallback implementation of `Object.keys` which produces an array of the
5621 * given object's own enumerable property names.
5622 *
5623 * @private
5624 * @type Function
5625 * @param {Object} object The object to inspect.
5626 * @returns {Array} Returns an array of property names.
5627 */
5628 var shimKeys = function(object) {
5629 var index, iterable = object, result = [];
5630 if (!iterable) return result;
5631 if (!(objectTypes[typeof object])) return result;
5632 for (index in iterable) {
5633 if (hasOwnProperty.call(iterable, index)) {
5634 result.push(index);
5635 }
5636 }
5637 return result
5638 };
5639
5640 /**
5641 * Creates an array composed of the own enumerable property names of an object.
5642 *
5643 * @static
5644 * @memberOf _
5645 * @category Objects
5646 * @param {Object} object The object to inspect.
5647 * @returns {Array} Returns an array of property names.
5648 * @example
5649 *
5650 * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
5651 * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
5652 */
5653 var keys = !nativeKeys ? shimKeys : function(object) {
5654 if (!isObject(object)) {
5655 return [];
5656 }
5657 return nativeKeys(object);
5658 };
5659
5660 /**
5661 * Used to convert characters to HTML entities:
5662 *
5663 * Though the `>` character is escaped for symmetry, characters like `>` and `/`
5664 * don't require escaping in HTML and have no special meaning unless they're part
5665 * of a tag or an unquoted attribute value.
5666 * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
5667 */
5668 var htmlEscapes = {
5669 '&': '&amp;',
5670 '<': '&lt;',
5671 '>': '&gt;',
5672 '"': '&quot;',
5673 "'": '&#39;'
5674 };
5675
5676 /** Used to convert HTML entities to characters */
5677 var htmlUnescapes = invert(htmlEscapes);
5678
5679 /** Used to match HTML entities and HTML characters */
5680 var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
5681 reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
5682
5683 /*--------------------------------------------------------------------------*/
5684
5685 /**
5686 * Assigns own enumerable properties of source object(s) to the destination
5687 * object. Subsequent sources will overwrite property assignments of previous
5688 * sources. If a callback is provided it will be executed to produce the
5689 * assigned values. The callback is bound to `thisArg` and invoked with two
5690 * arguments; (objectValue, sourceValue).
5691 *
5692 * @static
5693 * @memberOf _
5694 * @type Function
5695 * @alias extend
5696 * @category Objects
5697 * @param {Object} object The destination object.
5698 * @param {...Object} [source] The source objects.
5699 * @param {Function} [callback] The function to customize assigning values.
5700 * @param {*} [thisArg] The `this` binding of `callback`.
5701 * @returns {Object} Returns the destination object.
5702 * @example
5703 *
5704 * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
5705 * // => { 'name': 'fred', 'employer': 'slate' }
5706 *
5707 * var defaults = _.partialRight(_.assign, function(a, b) {
5708 * return typeof a == 'undefined' ? b : a;
5709 * });
5710 *
5711 * var object = { 'name': 'barney' };
5712 * defaults(object, { 'name': 'fred', 'employer': 'slate' });
5713 * // => { 'name': 'barney', 'employer': 'slate' }
5714 */
5715 var assign = function(object, source, guard) {
5716 var index, iterable = object, result = iterable;
5717 if (!iterable) return result;
5718 var args = arguments,
5719 argsIndex = 0,
5720 argsLength = typeof guard == 'number' ? 2 : args.length;
5721 if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
5722 var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
5723 } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
5724 callback = args[--argsLength];
5725 }
5726 while (++argsIndex < argsLength) {
5727 iterable = args[argsIndex];
5728 if (iterable && objectTypes[typeof iterable]) {
5729 var ownIndex = -1,
5730 ownProps = objectTypes[typeof iterable] && keys(iterable),
5731 length = ownProps ? ownProps.length : 0;
5732
5733 while (++ownIndex < length) {
5734 index = ownProps[ownIndex];
5735 result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
5736 }
5737 }
5738 }
5739 return result
5740 };
5741
5742 /**
5743 * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
5744 * be cloned, otherwise they will be assigned by reference. If a callback
5745 * is provided it will be executed to produce the cloned values. If the
5746 * callback returns `undefined` cloning will be handled by the method instead.
5747 * The callback is bound to `thisArg` and invoked with one argument; (value).
5748 *
5749 * @static
5750 * @memberOf _
5751 * @category Objects
5752 * @param {*} value The value to clone.
5753 * @param {boolean} [isDeep=false] Specify a deep clone.
5754 * @param {Function} [callback] The function to customize cloning values.
5755 * @param {*} [thisArg] The `this` binding of `callback`.
5756 * @returns {*} Returns the cloned value.
5757 * @example
5758 *
5759 * var characters = [
5760 * { 'name': 'barney', 'age': 36 },
5761 * { 'name': 'fred', 'age': 40 }
5762 * ];
5763 *
5764 * var shallow = _.clone(characters);
5765 * shallow[0] === characters[0];
5766 * // => true
5767 *
5768 * var deep = _.clone(characters, true);
5769 * deep[0] === characters[0];
5770 * // => false
5771 *
5772 * _.mixin({
5773 * 'clone': _.partialRight(_.clone, function(value) {
5774 * return _.isElement(value) ? value.cloneNode(false) : undefined;
5775 * })
5776 * });
5777 *
5778 * var clone = _.clone(document.body);
5779 * clone.childNodes.length;
5780 * // => 0
5781 */
5782 function clone(value, isDeep, callback, thisArg) {
5783 // allows working with "Collections" methods without using their `index`
5784 // and `collection` arguments for `isDeep` and `callback`
5785 if (typeof isDeep != 'boolean' && isDeep != null) {
5786 thisArg = callback;
5787 callback = isDeep;
5788 isDeep = false;
5789 }
5790 return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
5791 }
5792
5793 /**
5794 * Creates a deep clone of `value`. If a callback is provided it will be
5795 * executed to produce the cloned values. If the callback returns `undefined`
5796 * cloning will be handled by the method instead. The callback is bound to
5797 * `thisArg` and invoked with one argument; (value).
5798 *
5799 * Note: This method is loosely based on the structured clone algorithm. Functions
5800 * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
5801 * objects created by constructors other than `Object` are cloned to plain `Object` objects.
5802 * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
5803 *
5804 * @static
5805 * @memberOf _
5806 * @category Objects
5807 * @param {*} value The value to deep clone.
5808 * @param {Function} [callback] The function to customize cloning values.
5809 * @param {*} [thisArg] The `this` binding of `callback`.
5810 * @returns {*} Returns the deep cloned value.
5811 * @example
5812 *
5813 * var characters = [
5814 * { 'name': 'barney', 'age': 36 },
5815 * { 'name': 'fred', 'age': 40 }
5816 * ];
5817 *
5818 * var deep = _.cloneDeep(characters);
5819 * deep[0] === characters[0];
5820 * // => false
5821 *
5822 * var view = {
5823 * 'label': 'docs',
5824 * 'node': element
5825 * };
5826 *
5827 * var clone = _.cloneDeep(view, function(value) {
5828 * return _.isElement(value) ? value.cloneNode(true) : undefined;
5829 * });
5830 *
5831 * clone.node == view.node;
5832 * // => false
5833 */
5834 function cloneDeep(value, callback, thisArg) {
5835 return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
5836 }
5837
5838 /**
5839 * Creates an object that inherits from the given `prototype` object. If a
5840 * `properties` object is provided its own enumerable properties are assigned
5841 * to the created object.
5842 *
5843 * @static
5844 * @memberOf _
5845 * @category Objects
5846 * @param {Object} prototype The object to inherit from.
5847 * @param {Object} [properties] The properties to assign to the object.
5848 * @returns {Object} Returns the new object.
5849 * @example
5850 *
5851 * function Shape() {
5852 * this.x = 0;
5853 * this.y = 0;
5854 * }
5855 *
5856 * function Circle() {
5857 * Shape.call(this);
5858 * }
5859 *
5860 * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
5861 *
5862 * var circle = new Circle;
5863 * circle instanceof Circle;
5864 * // => true
5865 *
5866 * circle instanceof Shape;
5867 * // => true
5868 */
5869 function create(prototype, properties) {
5870 var result = baseCreate(prototype);
5871 return properties ? assign(result, properties) : result;
5872 }
5873
5874 /**
5875 * Assigns own enumerable properties of source object(s) to the destination
5876 * object for all destination properties that resolve to `undefined`. Once a
5877 * property is set, additional defaults of the same property will be ignored.
5878 *
5879 * @static
5880 * @memberOf _
5881 * @type Function
5882 * @category Objects
5883 * @param {Object} object The destination object.
5884 * @param {...Object} [source] The source objects.
5885 * @param- {Object} [guard] Allows working with `_.reduce` without using its
5886 * `key` and `object` arguments as sources.
5887 * @returns {Object} Returns the destination object.
5888 * @example
5889 *
5890 * var object = { 'name': 'barney' };
5891 * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
5892 * // => { 'name': 'barney', 'employer': 'slate' }
5893 */
5894 var defaults = function(object, source, guard) {
5895 var index, iterable = object, result = iterable;
5896 if (!iterable) return result;
5897 var args = arguments,
5898 argsIndex = 0,
5899 argsLength = typeof guard == 'number' ? 2 : args.length;
5900 while (++argsIndex < argsLength) {
5901 iterable = args[argsIndex];
5902 if (iterable && objectTypes[typeof iterable]) {
5903 var ownIndex = -1,
5904 ownProps = objectTypes[typeof iterable] && keys(iterable),
5905 length = ownProps ? ownProps.length : 0;
5906
5907 while (++ownIndex < length) {
5908 index = ownProps[ownIndex];
5909 if (typeof result[index] == 'undefined') result[index] = iterable[index];
5910 }
5911 }
5912 }
5913 return result
5914 };
5915
5916 /**
5917 * This method is like `_.findIndex` except that it returns the key of the
5918 * first element that passes the callback check, instead of the element itself.
5919 *
5920 * If a property name is provided for `callback` the created "_.pluck" style
5921 * callback will return the property value of the given element.
5922 *
5923 * If an object is provided for `callback` the created "_.where" style callback
5924 * will return `true` for elements that have the properties of the given object,
5925 * else `false`.
5926 *
5927 * @static
5928 * @memberOf _
5929 * @category Objects
5930 * @param {Object} object The object to search.
5931 * @param {Function|Object|string} [callback=identity] The function called per
5932 * iteration. If a property name or object is provided it will be used to
5933 * create a "_.pluck" or "_.where" style callback, respectively.
5934 * @param {*} [thisArg] The `this` binding of `callback`.
5935 * @returns {string|undefined} Returns the key of the found element, else `undefined`.
5936 * @example
5937 *
5938 * var characters = {
5939 * 'barney': { 'age': 36, 'blocked': false },
5940 * 'fred': { 'age': 40, 'blocked': true },
5941 * 'pebbles': { 'age': 1, 'blocked': false }
5942 * };
5943 *
5944 * _.findKey(characters, function(chr) {
5945 * return chr.age < 40;
5946 * });
5947 * // => 'barney' (property order is not guaranteed across environments)
5948 *
5949 * // using "_.where" callback shorthand
5950 * _.findKey(characters, { 'age': 1 });
5951 * // => 'pebbles'
5952 *
5953 * // using "_.pluck" callback shorthand
5954 * _.findKey(characters, 'blocked');
5955 * // => 'fred'
5956 */
5957 function findKey(object, callback, thisArg) {
5958 var result;
5959 callback = lodash.createCallback(callback, thisArg, 3);
5960 forOwn(object, function(value, key, object) {
5961 if (callback(value, key, object)) {
5962 result = key;
5963 return false;
5964 }
5965 });
5966 return result;
5967 }
5968
5969 /**
5970 * This method is like `_.findKey` except that it iterates over elements
5971 * of a `collection` in the opposite order.
5972 *
5973 * If a property name is provided for `callback` the created "_.pluck" style
5974 * callback will return the property value of the given element.
5975 *
5976 * If an object is provided for `callback` the created "_.where" style callback
5977 * will return `true` for elements that have the properties of the given object,
5978 * else `false`.
5979 *
5980 * @static
5981 * @memberOf _
5982 * @category Objects
5983 * @param {Object} object The object to search.
5984 * @param {Function|Object|string} [callback=identity] The function called per
5985 * iteration. If a property name or object is provided it will be used to
5986 * create a "_.pluck" or "_.where" style callback, respectively.
5987 * @param {*} [thisArg] The `this` binding of `callback`.
5988 * @returns {string|undefined} Returns the key of the found element, else `undefined`.
5989 * @example
5990 *
5991 * var characters = {
5992 * 'barney': { 'age': 36, 'blocked': true },
5993 * 'fred': { 'age': 40, 'blocked': false },
5994 * 'pebbles': { 'age': 1, 'blocked': true }
5995 * };
5996 *
5997 * _.findLastKey(characters, function(chr) {
5998 * return chr.age < 40;
5999 * });
6000 * // => returns `pebbles`, assuming `_.findKey` returns `barney`
6001 *
6002 * // using "_.where" callback shorthand
6003 * _.findLastKey(characters, { 'age': 40 });
6004 * // => 'fred'
6005 *
6006 * // using "_.pluck" callback shorthand
6007 * _.findLastKey(characters, 'blocked');
6008 * // => 'pebbles'
6009 */
6010 function findLastKey(object, callback, thisArg) {
6011 var result;
6012 callback = lodash.createCallback(callback, thisArg, 3);
6013 forOwnRight(object, function(value, key, object) {
6014 if (callback(value, key, object)) {
6015 result = key;
6016 return false;
6017 }
6018 });
6019 return result;
6020 }
6021
6022 /**
6023 * Iterates over own and inherited enumerable properties of an object,
6024 * executing the callback for each property. The callback is bound to `thisArg`
6025 * and invoked with three arguments; (value, key, object). Callbacks may exit
6026 * iteration early by explicitly returning `false`.
6027 *
6028 * @static
6029 * @memberOf _
6030 * @type Function
6031 * @category Objects
6032 * @param {Object} object The object to iterate over.
6033 * @param {Function} [callback=identity] The function called per iteration.
6034 * @param {*} [thisArg] The `this` binding of `callback`.
6035 * @returns {Object} Returns `object`.
6036 * @example
6037 *
6038 * function Shape() {
6039 * this.x = 0;
6040 * this.y = 0;
6041 * }
6042 *
6043 * Shape.prototype.move = function(x, y) {
6044 * this.x += x;
6045 * this.y += y;
6046 * };
6047 *
6048 * _.forIn(new Shape, function(value, key) {
6049 * console.log(key);
6050 * });
6051 * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
6052 */
6053 var forIn = function(collection, callback, thisArg) {
6054 var index, iterable = collection, result = iterable;
6055 if (!iterable) return result;
6056 if (!objectTypes[typeof iterable]) return result;
6057 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
6058 for (index in iterable) {
6059 if (callback(iterable[index], index, collection) === false) return result;
6060 }
6061 return result
6062 };
6063
6064 /**
6065 * This method is like `_.forIn` except that it iterates over elements
6066 * of a `collection` in the opposite order.
6067 *
6068 * @static
6069 * @memberOf _
6070 * @category Objects
6071 * @param {Object} object The object to iterate over.
6072 * @param {Function} [callback=identity] The function called per iteration.
6073 * @param {*} [thisArg] The `this` binding of `callback`.
6074 * @returns {Object} Returns `object`.
6075 * @example
6076 *
6077 * function Shape() {
6078 * this.x = 0;
6079 * this.y = 0;
6080 * }
6081 *
6082 * Shape.prototype.move = function(x, y) {
6083 * this.x += x;
6084 * this.y += y;
6085 * };
6086 *
6087 * _.forInRight(new Shape, function(value, key) {
6088 * console.log(key);
6089 * });
6090 * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
6091 */
6092 function forInRight(object, callback, thisArg) {
6093 var pairs = [];
6094
6095 forIn(object, function(value, key) {
6096 pairs.push(key, value);
6097 });
6098
6099 var length = pairs.length;
6100 callback = baseCreateCallback(callback, thisArg, 3);
6101 while (length--) {
6102 if (callback(pairs[length--], pairs[length], object) === false) {
6103 break;
6104 }
6105 }
6106 return object;
6107 }
6108
6109 /**
6110 * Iterates over own enumerable properties of an object, executing the callback
6111 * for each property. The callback is bound to `thisArg` and invoked with three
6112 * arguments; (value, key, object). Callbacks may exit iteration early by
6113 * explicitly returning `false`.
6114 *
6115 * @static
6116 * @memberOf _
6117 * @type Function
6118 * @category Objects
6119 * @param {Object} object The object to iterate over.
6120 * @param {Function} [callback=identity] The function called per iteration.
6121 * @param {*} [thisArg] The `this` binding of `callback`.
6122 * @returns {Object} Returns `object`.
6123 * @example
6124 *
6125 * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
6126 * console.log(key);
6127 * });
6128 * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
6129 */
6130 var forOwn = function(collection, callback, thisArg) {
6131 var index, iterable = collection, result = iterable;
6132 if (!iterable) return result;
6133 if (!objectTypes[typeof iterable]) return result;
6134 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
6135 var ownIndex = -1,
6136 ownProps = objectTypes[typeof iterable] && keys(iterable),
6137 length = ownProps ? ownProps.length : 0;
6138
6139 while (++ownIndex < length) {
6140 index = ownProps[ownIndex];
6141 if (callback(iterable[index], index, collection) === false) return result;
6142 }
6143 return result
6144 };
6145
6146 /**
6147 * This method is like `_.forOwn` except that it iterates over elements
6148 * of a `collection` in the opposite order.
6149 *
6150 * @static
6151 * @memberOf _
6152 * @category Objects
6153 * @param {Object} object The object to iterate over.
6154 * @param {Function} [callback=identity] The function called per iteration.
6155 * @param {*} [thisArg] The `this` binding of `callback`.
6156 * @returns {Object} Returns `object`.
6157 * @example
6158 *
6159 * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
6160 * console.log(key);
6161 * });
6162 * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
6163 */
6164 function forOwnRight(object, callback, thisArg) {
6165 var props = keys(object),
6166 length = props.length;
6167
6168 callback = baseCreateCallback(callback, thisArg, 3);
6169 while (length--) {
6170 var key = props[length];
6171 if (callback(object[key], key, object) === false) {
6172 break;
6173 }
6174 }
6175 return object;
6176 }
6177
6178 /**
6179 * Creates a sorted array of property names of all enumerable properties,
6180 * own and inherited, of `object` that have function values.
6181 *
6182 * @static
6183 * @memberOf _
6184 * @alias methods
6185 * @category Objects
6186 * @param {Object} object The object to inspect.
6187 * @returns {Array} Returns an array of property names that have function values.
6188 * @example
6189 *
6190 * _.functions(_);
6191 * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
6192 */
6193 function functions(object) {
6194 var result = [];
6195 forIn(object, function(value, key) {
6196 if (isFunction(value)) {
6197 result.push(key);
6198 }
6199 });
6200 return result.sort();
6201 }
6202
6203 /**
6204 * Checks if the specified property name exists as a direct property of `object`,
6205 * instead of an inherited property.
6206 *
6207 * @static
6208 * @memberOf _
6209 * @category Objects
6210 * @param {Object} object The object to inspect.
6211 * @param {string} key The name of the property to check.
6212 * @returns {boolean} Returns `true` if key is a direct property, else `false`.
6213 * @example
6214 *
6215 * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
6216 * // => true
6217 */
6218 function has(object, key) {
6219 return object ? hasOwnProperty.call(object, key) : false;
6220 }
6221
6222 /**
6223 * Creates an object composed of the inverted keys and values of the given object.
6224 *
6225 * @static
6226 * @memberOf _
6227 * @category Objects
6228 * @param {Object} object The object to invert.
6229 * @returns {Object} Returns the created inverted object.
6230 * @example
6231 *
6232 * _.invert({ 'first': 'fred', 'second': 'barney' });
6233 * // => { 'fred': 'first', 'barney': 'second' }
6234 */
6235 function invert(object) {
6236 var index = -1,
6237 props = keys(object),
6238 length = props.length,
6239 result = {};
6240
6241 while (++index < length) {
6242 var key = props[index];
6243 result[object[key]] = key;
6244 }
6245 return result;
6246 }
6247
6248 /**
6249 * Checks if `value` is a boolean value.
6250 *
6251 * @static
6252 * @memberOf _
6253 * @category Objects
6254 * @param {*} value The value to check.
6255 * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
6256 * @example
6257 *
6258 * _.isBoolean(null);
6259 * // => false
6260 */
6261 function isBoolean(value) {
6262 return value === true || value === false ||
6263 value && typeof value == 'object' && toString.call(value) == boolClass || false;
6264 }
6265
6266 /**
6267 * Checks if `value` is a date.
6268 *
6269 * @static
6270 * @memberOf _
6271 * @category Objects
6272 * @param {*} value The value to check.
6273 * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
6274 * @example
6275 *
6276 * _.isDate(new Date);
6277 * // => true
6278 */
6279 function isDate(value) {
6280 return value && typeof value == 'object' && toString.call(value) == dateClass || false;
6281 }
6282
6283 /**
6284 * Checks if `value` is a DOM element.
6285 *
6286 * @static
6287 * @memberOf _
6288 * @category Objects
6289 * @param {*} value The value to check.
6290 * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
6291 * @example
6292 *
6293 * _.isElement(document.body);
6294 * // => true
6295 */
6296 function isElement(value) {
6297 return value && value.nodeType === 1 || false;
6298 }
6299
6300 /**
6301 * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
6302 * length of `0` and objects with no own enumerable properties are considered
6303 * "empty".
6304 *
6305 * @static
6306 * @memberOf _
6307 * @category Objects
6308 * @param {Array|Object|string} value The value to inspect.
6309 * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
6310 * @example
6311 *
6312 * _.isEmpty([1, 2, 3]);
6313 * // => false
6314 *
6315 * _.isEmpty({});
6316 * // => true
6317 *
6318 * _.isEmpty('');
6319 * // => true
6320 */
6321 function isEmpty(value) {
6322 var result = true;
6323 if (!value) {
6324 return result;
6325 }
6326 var className = toString.call(value),
6327 length = value.length;
6328
6329 if ((className == arrayClass || className == stringClass || className == argsClass ) ||
6330 (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
6331 return !length;
6332 }
6333 forOwn(value, function() {
6334 return (result = false);
6335 });
6336 return result;
6337 }
6338
6339 /**
6340 * Performs a deep comparison between two values to determine if they are
6341 * equivalent to each other. If a callback is provided it will be executed
6342 * to compare values. If the callback returns `undefined` comparisons will
6343 * be handled by the method instead. The callback is bound to `thisArg` and
6344 * invoked with two arguments; (a, b).
6345 *
6346 * @static
6347 * @memberOf _
6348 * @category Objects
6349 * @param {*} a The value to compare.
6350 * @param {*} b The other value to compare.
6351 * @param {Function} [callback] The function to customize comparing values.
6352 * @param {*} [thisArg] The `this` binding of `callback`.
6353 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
6354 * @example
6355 *
6356 * var object = { 'name': 'fred' };
6357 * var copy = { 'name': 'fred' };
6358 *
6359 * object == copy;
6360 * // => false
6361 *
6362 * _.isEqual(object, copy);
6363 * // => true
6364 *
6365 * var words = ['hello', 'goodbye'];
6366 * var otherWords = ['hi', 'goodbye'];
6367 *
6368 * _.isEqual(words, otherWords, function(a, b) {
6369 * var reGreet = /^(?:hello|hi)$/i,
6370 * aGreet = _.isString(a) && reGreet.test(a),
6371 * bGreet = _.isString(b) && reGreet.test(b);
6372 *
6373 * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
6374 * });
6375 * // => true
6376 */
6377 function isEqual(a, b, callback, thisArg) {
6378 return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
6379 }
6380
6381 /**
6382 * Checks if `value` is, or can be coerced to, a finite number.
6383 *
6384 * Note: This is not the same as native `isFinite` which will return true for
6385 * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
6386 *
6387 * @static
6388 * @memberOf _
6389 * @category Objects
6390 * @param {*} value The value to check.
6391 * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
6392 * @example
6393 *
6394 * _.isFinite(-101);
6395 * // => true
6396 *
6397 * _.isFinite('10');
6398 * // => true
6399 *
6400 * _.isFinite(true);
6401 * // => false
6402 *
6403 * _.isFinite('');
6404 * // => false
6405 *
6406 * _.isFinite(Infinity);
6407 * // => false
6408 */
6409 function isFinite(value) {
6410 return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
6411 }
6412
6413 /**
6414 * Checks if `value` is a function.
6415 *
6416 * @static
6417 * @memberOf _
6418 * @category Objects
6419 * @param {*} value The value to check.
6420 * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
6421 * @example
6422 *
6423 * _.isFunction(_);
6424 * // => true
6425 */
6426 function isFunction(value) {
6427 return typeof value == 'function';
6428 }
6429
6430 /**
6431 * Checks if `value` is the language type of Object.
6432 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
6433 *
6434 * @static
6435 * @memberOf _
6436 * @category Objects
6437 * @param {*} value The value to check.
6438 * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
6439 * @example
6440 *
6441 * _.isObject({});
6442 * // => true
6443 *
6444 * _.isObject([1, 2, 3]);
6445 * // => true
6446 *
6447 * _.isObject(1);
6448 * // => false
6449 */
6450 function isObject(value) {
6451 // check if the value is the ECMAScript language type of Object
6452 // http://es5.github.io/#x8
6453 // and avoid a V8 bug
6454 // http://code.google.com/p/v8/issues/detail?id=2291
6455 return !!(value && objectTypes[typeof value]);
6456 }
6457
6458 /**
6459 * Checks if `value` is `NaN`.
6460 *
6461 * Note: This is not the same as native `isNaN` which will return `true` for
6462 * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
6463 *
6464 * @static
6465 * @memberOf _
6466 * @category Objects
6467 * @param {*} value The value to check.
6468 * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
6469 * @example
6470 *
6471 * _.isNaN(NaN);
6472 * // => true
6473 *
6474 * _.isNaN(new Number(NaN));
6475 * // => true
6476 *
6477 * isNaN(undefined);
6478 * // => true
6479 *
6480 * _.isNaN(undefined);
6481 * // => false
6482 */
6483 function isNaN(value) {
6484 // `NaN` as a primitive is the only value that is not equal to itself
6485 // (perform the [[Class]] check first to avoid errors with some host objects in IE)
6486 return isNumber(value) && value != +value;
6487 }
6488
6489 /**
6490 * Checks if `value` is `null`.
6491 *
6492 * @static
6493 * @memberOf _
6494 * @category Objects
6495 * @param {*} value The value to check.
6496 * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
6497 * @example
6498 *
6499 * _.isNull(null);
6500 * // => true
6501 *
6502 * _.isNull(undefined);
6503 * // => false
6504 */
6505 function isNull(value) {
6506 return value === null;
6507 }
6508
6509 /**
6510 * Checks if `value` is a number.
6511 *
6512 * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
6513 *
6514 * @static
6515 * @memberOf _
6516 * @category Objects
6517 * @param {*} value The value to check.
6518 * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
6519 * @example
6520 *
6521 * _.isNumber(8.4 * 5);
6522 * // => true
6523 */
6524 function isNumber(value) {
6525 return typeof value == 'number' ||
6526 value && typeof value == 'object' && toString.call(value) == numberClass || false;
6527 }
6528
6529 /**
6530 * Checks if `value` is an object created by the `Object` constructor.
6531 *
6532 * @static
6533 * @memberOf _
6534 * @category Objects
6535 * @param {*} value The value to check.
6536 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
6537 * @example
6538 *
6539 * function Shape() {
6540 * this.x = 0;
6541 * this.y = 0;
6542 * }
6543 *
6544 * _.isPlainObject(new Shape);
6545 * // => false
6546 *
6547 * _.isPlainObject([1, 2, 3]);
6548 * // => false
6549 *
6550 * _.isPlainObject({ 'x': 0, 'y': 0 });
6551 * // => true
6552 */
6553 var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
6554 if (!(value && toString.call(value) == objectClass)) {
6555 return false;
6556 }
6557 var valueOf = value.valueOf,
6558 objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
6559
6560 return objProto
6561 ? (value == objProto || getPrototypeOf(value) == objProto)
6562 : shimIsPlainObject(value);
6563 };
6564
6565 /**
6566 * Checks if `value` is a regular expression.
6567 *
6568 * @static
6569 * @memberOf _
6570 * @category Objects
6571 * @param {*} value The value to check.
6572 * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
6573 * @example
6574 *
6575 * _.isRegExp(/fred/);
6576 * // => true
6577 */
6578 function isRegExp(value) {
6579 return value && typeof value == 'object' && toString.call(value) == regexpClass || false;
6580 }
6581
6582 /**
6583 * Checks if `value` is a string.
6584 *
6585 * @static
6586 * @memberOf _
6587 * @category Objects
6588 * @param {*} value The value to check.
6589 * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
6590 * @example
6591 *
6592 * _.isString('fred');
6593 * // => true
6594 */
6595 function isString(value) {
6596 return typeof value == 'string' ||
6597 value && typeof value == 'object' && toString.call(value) == stringClass || false;
6598 }
6599
6600 /**
6601 * Checks if `value` is `undefined`.
6602 *
6603 * @static
6604 * @memberOf _
6605 * @category Objects
6606 * @param {*} value The value to check.
6607 * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
6608 * @example
6609 *
6610 * _.isUndefined(void 0);
6611 * // => true
6612 */
6613 function isUndefined(value) {
6614 return typeof value == 'undefined';
6615 }
6616
6617 /**
6618 * Creates an object with the same keys as `object` and values generated by
6619 * running each own enumerable property of `object` through the callback.
6620 * The callback is bound to `thisArg` and invoked with three arguments;
6621 * (value, key, object).
6622 *
6623 * If a property name is provided for `callback` the created "_.pluck" style
6624 * callback will return the property value of the given element.
6625 *
6626 * If an object is provided for `callback` the created "_.where" style callback
6627 * will return `true` for elements that have the properties of the given object,
6628 * else `false`.
6629 *
6630 * @static
6631 * @memberOf _
6632 * @category Objects
6633 * @param {Object} object The object to iterate over.
6634 * @param {Function|Object|string} [callback=identity] The function called
6635 * per iteration. If a property name or object is provided it will be used
6636 * to create a "_.pluck" or "_.where" style callback, respectively.
6637 * @param {*} [thisArg] The `this` binding of `callback`.
6638 * @returns {Array} Returns a new object with values of the results of each `callback` execution.
6639 * @example
6640 *
6641 * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
6642 * // => { 'a': 3, 'b': 6, 'c': 9 }
6643 *
6644 * var characters = {
6645 * 'fred': { 'name': 'fred', 'age': 40 },
6646 * 'pebbles': { 'name': 'pebbles', 'age': 1 }
6647 * };
6648 *
6649 * // using "_.pluck" callback shorthand
6650 * _.mapValues(characters, 'age');
6651 * // => { 'fred': 40, 'pebbles': 1 }
6652 */
6653 function mapValues(object, callback, thisArg) {
6654 var result = {};
6655 callback = lodash.createCallback(callback, thisArg, 3);
6656
6657 forOwn(object, function(value, key, object) {
6658 result[key] = callback(value, key, object);
6659 });
6660 return result;
6661 }
6662
6663 /**
6664 * Recursively merges own enumerable properties of the source object(s), that
6665 * don't resolve to `undefined` into the destination object. Subsequent sources
6666 * will overwrite property assignments of previous sources. If a callback is
6667 * provided it will be executed to produce the merged values of the destination
6668 * and source properties. If the callback returns `undefined` merging will
6669 * be handled by the method instead. The callback is bound to `thisArg` and
6670 * invoked with two arguments; (objectValue, sourceValue).
6671 *
6672 * @static
6673 * @memberOf _
6674 * @category Objects
6675 * @param {Object} object The destination object.
6676 * @param {...Object} [source] The source objects.
6677 * @param {Function} [callback] The function to customize merging properties.
6678 * @param {*} [thisArg] The `this` binding of `callback`.
6679 * @returns {Object} Returns the destination object.
6680 * @example
6681 *
6682 * var names = {
6683 * 'characters': [
6684 * { 'name': 'barney' },
6685 * { 'name': 'fred' }
6686 * ]
6687 * };
6688 *
6689 * var ages = {
6690 * 'characters': [
6691 * { 'age': 36 },
6692 * { 'age': 40 }
6693 * ]
6694 * };
6695 *
6696 * _.merge(names, ages);
6697 * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
6698 *
6699 * var food = {
6700 * 'fruits': ['apple'],
6701 * 'vegetables': ['beet']
6702 * };
6703 *
6704 * var otherFood = {
6705 * 'fruits': ['banana'],
6706 * 'vegetables': ['carrot']
6707 * };
6708 *
6709 * _.merge(food, otherFood, function(a, b) {
6710 * return _.isArray(a) ? a.concat(b) : undefined;
6711 * });
6712 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
6713 */
6714 function merge(object) {
6715 var args = arguments,
6716 length = 2;
6717
6718 if (!isObject(object)) {
6719 return object;
6720 }
6721 // allows working with `_.reduce` and `_.reduceRight` without using
6722 // their `index` and `collection` arguments
6723 if (typeof args[2] != 'number') {
6724 length = args.length;
6725 }
6726 if (length > 3 && typeof args[length - 2] == 'function') {
6727 var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
6728 } else if (length > 2 && typeof args[length - 1] == 'function') {
6729 callback = args[--length];
6730 }
6731 var sources = slice(arguments, 1, length),
6732 index = -1,
6733 stackA = getArray(),
6734 stackB = getArray();
6735
6736 while (++index < length) {
6737 baseMerge(object, sources[index], callback, stackA, stackB);
6738 }
6739 releaseArray(stackA);
6740 releaseArray(stackB);
6741 return object;
6742 }
6743
6744 /**
6745 * Creates a shallow clone of `object` excluding the specified properties.
6746 * Property names may be specified as individual arguments or as arrays of
6747 * property names. If a callback is provided it will be executed for each
6748 * property of `object` omitting the properties the callback returns truey
6749 * for. The callback is bound to `thisArg` and invoked with three arguments;
6750 * (value, key, object).
6751 *
6752 * @static
6753 * @memberOf _
6754 * @category Objects
6755 * @param {Object} object The source object.
6756 * @param {Function|...string|string[]} [callback] The properties to omit or the
6757 * function called per iteration.
6758 * @param {*} [thisArg] The `this` binding of `callback`.
6759 * @returns {Object} Returns an object without the omitted properties.
6760 * @example
6761 *
6762 * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
6763 * // => { 'name': 'fred' }
6764 *
6765 * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
6766 * return typeof value == 'number';
6767 * });
6768 * // => { 'name': 'fred' }
6769 */
6770 function omit(object, callback, thisArg) {
6771 var result = {};
6772 if (typeof callback != 'function') {
6773 var props = [];
6774 forIn(object, function(value, key) {
6775 props.push(key);
6776 });
6777 props = baseDifference(props, baseFlatten(arguments, true, false, 1));
6778
6779 var index = -1,
6780 length = props.length;
6781
6782 while (++index < length) {
6783 var key = props[index];
6784 result[key] = object[key];
6785 }
6786 } else {
6787 callback = lodash.createCallback(callback, thisArg, 3);
6788 forIn(object, function(value, key, object) {
6789 if (!callback(value, key, object)) {
6790 result[key] = value;
6791 }
6792 });
6793 }
6794 return result;
6795 }
6796
6797 /**
6798 * Creates a two dimensional array of an object's key-value pairs,
6799 * i.e. `[[key1, value1], [key2, value2]]`.
6800 *
6801 * @static
6802 * @memberOf _
6803 * @category Objects
6804 * @param {Object} object The object to inspect.
6805 * @returns {Array} Returns new array of key-value pairs.
6806 * @example
6807 *
6808 * _.pairs({ 'barney': 36, 'fred': 40 });
6809 * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
6810 */
6811 function pairs(object) {
6812 var index = -1,
6813 props = keys(object),
6814 length = props.length,
6815 result = Array(length);
6816
6817 while (++index < length) {
6818 var key = props[index];
6819 result[index] = [key, object[key]];
6820 }
6821 return result;
6822 }
6823
6824 /**
6825 * Creates a shallow clone of `object` composed of the specified properties.
6826 * Property names may be specified as individual arguments or as arrays of
6827 * property names. If a callback is provided it will be executed for each
6828 * property of `object` picking the properties the callback returns truey
6829 * for. The callback is bound to `thisArg` and invoked with three arguments;
6830 * (value, key, object).
6831 *
6832 * @static
6833 * @memberOf _
6834 * @category Objects
6835 * @param {Object} object The source object.
6836 * @param {Function|...string|string[]} [callback] The function called per
6837 * iteration or property names to pick, specified as individual property
6838 * names or arrays of property names.
6839 * @param {*} [thisArg] The `this` binding of `callback`.
6840 * @returns {Object} Returns an object composed of the picked properties.
6841 * @example
6842 *
6843 * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
6844 * // => { 'name': 'fred' }
6845 *
6846 * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
6847 * return key.charAt(0) != '_';
6848 * });
6849 * // => { 'name': 'fred' }
6850 */
6851 function pick(object, callback, thisArg) {
6852 var result = {};
6853 if (typeof callback != 'function') {
6854 var index = -1,
6855 props = baseFlatten(arguments, true, false, 1),
6856 length = isObject(object) ? props.length : 0;
6857
6858 while (++index < length) {
6859 var key = props[index];
6860 if (key in object) {
6861 result[key] = object[key];
6862 }
6863 }
6864 } else {
6865 callback = lodash.createCallback(callback, thisArg, 3);
6866 forIn(object, function(value, key, object) {
6867 if (callback(value, key, object)) {
6868 result[key] = value;
6869 }
6870 });
6871 }
6872 return result;
6873 }
6874
6875 /**
6876 * An alternative to `_.reduce` this method transforms `object` to a new
6877 * `accumulator` object which is the result of running each of its own
6878 * enumerable properties through a callback, with each callback execution
6879 * potentially mutating the `accumulator` object. The callback is bound to
6880 * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
6881 * Callbacks may exit iteration early by explicitly returning `false`.
6882 *
6883 * @static
6884 * @memberOf _
6885 * @category Objects
6886 * @param {Array|Object} object The object to iterate over.
6887 * @param {Function} [callback=identity] The function called per iteration.
6888 * @param {*} [accumulator] The custom accumulator value.
6889 * @param {*} [thisArg] The `this` binding of `callback`.
6890 * @returns {*} Returns the accumulated value.
6891 * @example
6892 *
6893 * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
6894 * num *= num;
6895 * if (num % 2) {
6896 * return result.push(num) < 3;
6897 * }
6898 * });
6899 * // => [1, 9, 25]
6900 *
6901 * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
6902 * result[key] = num * 3;
6903 * });
6904 * // => { 'a': 3, 'b': 6, 'c': 9 }
6905 */
6906 function transform(object, callback, accumulator, thisArg) {
6907 var isArr = isArray(object);
6908 if (accumulator == null) {
6909 if (isArr) {
6910 accumulator = [];
6911 } else {
6912 var ctor = object && object.constructor,
6913 proto = ctor && ctor.prototype;
6914
6915 accumulator = baseCreate(proto);
6916 }
6917 }
6918 if (callback) {
6919 callback = lodash.createCallback(callback, thisArg, 4);
6920 (isArr ? forEach : forOwn)(object, function(value, index, object) {
6921 return callback(accumulator, value, index, object);
6922 });
6923 }
6924 return accumulator;
6925 }
6926
6927 /**
6928 * Creates an array composed of the own enumerable property values of `object`.
6929 *
6930 * @static
6931 * @memberOf _
6932 * @category Objects
6933 * @param {Object} object The object to inspect.
6934 * @returns {Array} Returns an array of property values.
6935 * @example
6936 *
6937 * _.values({ 'one': 1, 'two': 2, 'three': 3 });
6938 * // => [1, 2, 3] (property order is not guaranteed across environments)
6939 */
6940 function values(object) {
6941 var index = -1,
6942 props = keys(object),
6943 length = props.length,
6944 result = Array(length);
6945
6946 while (++index < length) {
6947 result[index] = object[props[index]];
6948 }
6949 return result;
6950 }
6951
6952 /*--------------------------------------------------------------------------*/
6953
6954 /**
6955 * Creates an array of elements from the specified indexes, or keys, of the
6956 * `collection`. Indexes may be specified as individual arguments or as arrays
6957 * of indexes.
6958 *
6959 * @static
6960 * @memberOf _
6961 * @category Collections
6962 * @param {Array|Object|string} collection The collection to iterate over.
6963 * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
6964 * to retrieve, specified as individual indexes or arrays of indexes.
6965 * @returns {Array} Returns a new array of elements corresponding to the
6966 * provided indexes.
6967 * @example
6968 *
6969 * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
6970 * // => ['a', 'c', 'e']
6971 *
6972 * _.at(['fred', 'barney', 'pebbles'], 0, 2);
6973 * // => ['fred', 'pebbles']
6974 */
6975 function at(collection) {
6976 var args = arguments,
6977 index = -1,
6978 props = baseFlatten(args, true, false, 1),
6979 length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
6980 result = Array(length);
6981
6982 while(++index < length) {
6983 result[index] = collection[props[index]];
6984 }
6985 return result;
6986 }
6987
6988 /**
6989 * Checks if a given value is present in a collection using strict equality
6990 * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
6991 * offset from the end of the collection.
6992 *
6993 * @static
6994 * @memberOf _
6995 * @alias include
6996 * @category Collections
6997 * @param {Array|Object|string} collection The collection to iterate over.
6998 * @param {*} target The value to check for.
6999 * @param {number} [fromIndex=0] The index to search from.
7000 * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
7001 * @example
7002 *
7003 * _.contains([1, 2, 3], 1);
7004 * // => true
7005 *
7006 * _.contains([1, 2, 3], 1, 2);
7007 * // => false
7008 *
7009 * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
7010 * // => true
7011 *
7012 * _.contains('pebbles', 'eb');
7013 * // => true
7014 */
7015 function contains(collection, target, fromIndex) {
7016 var index = -1,
7017 indexOf = getIndexOf(),
7018 length = collection ? collection.length : 0,
7019 result = false;
7020
7021 fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
7022 if (isArray(collection)) {
7023 result = indexOf(collection, target, fromIndex) > -1;
7024 } else if (typeof length == 'number') {
7025 result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
7026 } else {
7027 forOwn(collection, function(value) {
7028 if (++index >= fromIndex) {
7029 return !(result = value === target);
7030 }
7031 });
7032 }
7033 return result;
7034 }
7035
7036 /**
7037 * Creates an object composed of keys generated from the results of running
7038 * each element of `collection` through the callback. The corresponding value
7039 * of each key is the number of times the key was returned by the callback.
7040 * The callback is bound to `thisArg` and invoked with three arguments;
7041 * (value, index|key, collection).
7042 *
7043 * If a property name is provided for `callback` the created "_.pluck" style
7044 * callback will return the property value of the given element.
7045 *
7046 * If an object is provided for `callback` the created "_.where" style callback
7047 * will return `true` for elements that have the properties of the given object,
7048 * else `false`.
7049 *
7050 * @static
7051 * @memberOf _
7052 * @category Collections
7053 * @param {Array|Object|string} collection The collection to iterate over.
7054 * @param {Function|Object|string} [callback=identity] The function called
7055 * per iteration. If a property name or object is provided it will be used
7056 * to create a "_.pluck" or "_.where" style callback, respectively.
7057 * @param {*} [thisArg] The `this` binding of `callback`.
7058 * @returns {Object} Returns the composed aggregate object.
7059 * @example
7060 *
7061 * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
7062 * // => { '4': 1, '6': 2 }
7063 *
7064 * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
7065 * // => { '4': 1, '6': 2 }
7066 *
7067 * _.countBy(['one', 'two', 'three'], 'length');
7068 * // => { '3': 2, '5': 1 }
7069 */
7070 var countBy = createAggregator(function(result, value, key) {
7071 (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
7072 });
7073
7074 /**
7075 * Checks if the given callback returns truey value for **all** elements of
7076 * a collection. The callback is bound to `thisArg` and invoked with three
7077 * arguments; (value, index|key, collection).
7078 *
7079 * If a property name is provided for `callback` the created "_.pluck" style
7080 * callback will return the property value of the given element.
7081 *
7082 * If an object is provided for `callback` the created "_.where" style callback
7083 * will return `true` for elements that have the properties of the given object,
7084 * else `false`.
7085 *
7086 * @static
7087 * @memberOf _
7088 * @alias all
7089 * @category Collections
7090 * @param {Array|Object|string} collection The collection to iterate over.
7091 * @param {Function|Object|string} [callback=identity] The function called
7092 * per iteration. If a property name or object is provided it will be used
7093 * to create a "_.pluck" or "_.where" style callback, respectively.
7094 * @param {*} [thisArg] The `this` binding of `callback`.
7095 * @returns {boolean} Returns `true` if all elements passed the callback check,
7096 * else `false`.
7097 * @example
7098 *
7099 * _.every([true, 1, null, 'yes']);
7100 * // => false
7101 *
7102 * var characters = [
7103 * { 'name': 'barney', 'age': 36 },
7104 * { 'name': 'fred', 'age': 40 }
7105 * ];
7106 *
7107 * // using "_.pluck" callback shorthand
7108 * _.every(characters, 'age');
7109 * // => true
7110 *
7111 * // using "_.where" callback shorthand
7112 * _.every(characters, { 'age': 36 });
7113 * // => false
7114 */
7115 function every(collection, callback, thisArg) {
7116 var result = true;
7117 callback = lodash.createCallback(callback, thisArg, 3);
7118
7119 var index = -1,
7120 length = collection ? collection.length : 0;
7121
7122 if (typeof length == 'number') {
7123 while (++index < length) {
7124 if (!(result = !!callback(collection[index], index, collection))) {
7125 break;
7126 }
7127 }
7128 } else {
7129 forOwn(collection, function(value, index, collection) {
7130 return (result = !!callback(value, index, collection));
7131 });
7132 }
7133 return result;
7134 }
7135
7136 /**
7137 * Iterates over elements of a collection, returning an array of all elements
7138 * the callback returns truey for. The callback is bound to `thisArg` and
7139 * invoked with three arguments; (value, index|key, collection).
7140 *
7141 * If a property name is provided for `callback` the created "_.pluck" style
7142 * callback will return the property value of the given element.
7143 *
7144 * If an object is provided for `callback` the created "_.where" style callback
7145 * will return `true` for elements that have the properties of the given object,
7146 * else `false`.
7147 *
7148 * @static
7149 * @memberOf _
7150 * @alias select
7151 * @category Collections
7152 * @param {Array|Object|string} collection The collection to iterate over.
7153 * @param {Function|Object|string} [callback=identity] The function called
7154 * per iteration. If a property name or object is provided it will be used
7155 * to create a "_.pluck" or "_.where" style callback, respectively.
7156 * @param {*} [thisArg] The `this` binding of `callback`.
7157 * @returns {Array} Returns a new array of elements that passed the callback check.
7158 * @example
7159 *
7160 * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
7161 * // => [2, 4, 6]
7162 *
7163 * var characters = [
7164 * { 'name': 'barney', 'age': 36, 'blocked': false },
7165 * { 'name': 'fred', 'age': 40, 'blocked': true }
7166 * ];
7167 *
7168 * // using "_.pluck" callback shorthand
7169 * _.filter(characters, 'blocked');
7170 * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
7171 *
7172 * // using "_.where" callback shorthand
7173 * _.filter(characters, { 'age': 36 });
7174 * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
7175 */
7176 function filter(collection, callback, thisArg) {
7177 var result = [];
7178 callback = lodash.createCallback(callback, thisArg, 3);
7179
7180 var index = -1,
7181 length = collection ? collection.length : 0;
7182
7183 if (typeof length == 'number') {
7184 while (++index < length) {
7185 var value = collection[index];
7186 if (callback(value, index, collection)) {
7187 result.push(value);
7188 }
7189 }
7190 } else {
7191 forOwn(collection, function(value, index, collection) {
7192 if (callback(value, index, collection)) {
7193 result.push(value);
7194 }
7195 });
7196 }
7197 return result;
7198 }
7199
7200 /**
7201 * Iterates over elements of a collection, returning the first element that
7202 * the callback returns truey for. The callback is bound to `thisArg` and
7203 * invoked with three arguments; (value, index|key, collection).
7204 *
7205 * If a property name is provided for `callback` the created "_.pluck" style
7206 * callback will return the property value of the given element.
7207 *
7208 * If an object is provided for `callback` the created "_.where" style callback
7209 * will return `true` for elements that have the properties of the given object,
7210 * else `false`.
7211 *
7212 * @static
7213 * @memberOf _
7214 * @alias detect, findWhere
7215 * @category Collections
7216 * @param {Array|Object|string} collection The collection to iterate over.
7217 * @param {Function|Object|string} [callback=identity] The function called
7218 * per iteration. If a property name or object is provided it will be used
7219 * to create a "_.pluck" or "_.where" style callback, respectively.
7220 * @param {*} [thisArg] The `this` binding of `callback`.
7221 * @returns {*} Returns the found element, else `undefined`.
7222 * @example
7223 *
7224 * var characters = [
7225 * { 'name': 'barney', 'age': 36, 'blocked': false },
7226 * { 'name': 'fred', 'age': 40, 'blocked': true },
7227 * { 'name': 'pebbles', 'age': 1, 'blocked': false }
7228 * ];
7229 *
7230 * _.find(characters, function(chr) {
7231 * return chr.age < 40;
7232 * });
7233 * // => { 'name': 'barney', 'age': 36, 'blocked': false }
7234 *
7235 * // using "_.where" callback shorthand
7236 * _.find(characters, { 'age': 1 });
7237 * // => { 'name': 'pebbles', 'age': 1, 'blocked': false }
7238 *
7239 * // using "_.pluck" callback shorthand
7240 * _.find(characters, 'blocked');
7241 * // => { 'name': 'fred', 'age': 40, 'blocked': true }
7242 */
7243 function find(collection, callback, thisArg) {
7244 callback = lodash.createCallback(callback, thisArg, 3);
7245
7246 var index = -1,
7247 length = collection ? collection.length : 0;
7248
7249 if (typeof length == 'number') {
7250 while (++index < length) {
7251 var value = collection[index];
7252 if (callback(value, index, collection)) {
7253 return value;
7254 }
7255 }
7256 } else {
7257 var result;
7258 forOwn(collection, function(value, index, collection) {
7259 if (callback(value, index, collection)) {
7260 result = value;
7261 return false;
7262 }
7263 });
7264 return result;
7265 }
7266 }
7267
7268 /**
7269 * This method is like `_.find` except that it iterates over elements
7270 * of a `collection` from right to left.
7271 *
7272 * @static
7273 * @memberOf _
7274 * @category Collections
7275 * @param {Array|Object|string} collection The collection to iterate over.
7276 * @param {Function|Object|string} [callback=identity] The function called
7277 * per iteration. If a property name or object is provided it will be used
7278 * to create a "_.pluck" or "_.where" style callback, respectively.
7279 * @param {*} [thisArg] The `this` binding of `callback`.
7280 * @returns {*} Returns the found element, else `undefined`.
7281 * @example
7282 *
7283 * _.findLast([1, 2, 3, 4], function(num) {
7284 * return num % 2 == 1;
7285 * });
7286 * // => 3
7287 */
7288 function findLast(collection, callback, thisArg) {
7289 var result;
7290 callback = lodash.createCallback(callback, thisArg, 3);
7291 forEachRight(collection, function(value, index, collection) {
7292 if (callback(value, index, collection)) {
7293 result = value;
7294 return false;
7295 }
7296 });
7297 return result;
7298 }
7299
7300 /**
7301 * Iterates over elements of a collection, executing the callback for each
7302 * element. The callback is bound to `thisArg` and invoked with three arguments;
7303 * (value, index|key, collection). Callbacks may exit iteration early by
7304 * explicitly returning `false`.
7305 *
7306 * Note: As with other "Collections" methods, objects with a `length` property
7307 * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
7308 * may be used for object iteration.
7309 *
7310 * @static
7311 * @memberOf _
7312 * @alias each
7313 * @category Collections
7314 * @param {Array|Object|string} collection The collection to iterate over.
7315 * @param {Function} [callback=identity] The function called per iteration.
7316 * @param {*} [thisArg] The `this` binding of `callback`.
7317 * @returns {Array|Object|string} Returns `collection`.
7318 * @example
7319 *
7320 * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
7321 * // => logs each number and returns '1,2,3'
7322 *
7323 * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
7324 * // => logs each number and returns the object (property order is not guaranteed across environments)
7325 */
7326 function forEach(collection, callback, thisArg) {
7327 var index = -1,
7328 length = collection ? collection.length : 0;
7329
7330 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
7331 if (typeof length == 'number') {
7332 while (++index < length) {
7333 if (callback(collection[index], index, collection) === false) {
7334 break;
7335 }
7336 }
7337 } else {
7338 forOwn(collection, callback);
7339 }
7340 return collection;
7341 }
7342
7343 /**
7344 * This method is like `_.forEach` except that it iterates over elements
7345 * of a `collection` from right to left.
7346 *
7347 * @static
7348 * @memberOf _
7349 * @alias eachRight
7350 * @category Collections
7351 * @param {Array|Object|string} collection The collection to iterate over.
7352 * @param {Function} [callback=identity] The function called per iteration.
7353 * @param {*} [thisArg] The `this` binding of `callback`.
7354 * @returns {Array|Object|string} Returns `collection`.
7355 * @example
7356 *
7357 * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
7358 * // => logs each number from right to left and returns '3,2,1'
7359 */
7360 function forEachRight(collection, callback, thisArg) {
7361 var length = collection ? collection.length : 0;
7362 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
7363 if (typeof length == 'number') {
7364 while (length--) {
7365 if (callback(collection[length], length, collection) === false) {
7366 break;
7367 }
7368 }
7369 } else {
7370 var props = keys(collection);
7371 length = props.length;
7372 forOwn(collection, function(value, key, collection) {
7373 key = props ? props[--length] : --length;
7374 return callback(collection[key], key, collection);
7375 });
7376 }
7377 return collection;
7378 }
7379
7380 /**
7381 * Creates an object composed of keys generated from the results of running
7382 * each element of a collection through the callback. The corresponding value
7383 * of each key is an array of the elements responsible for generating the key.
7384 * The callback is bound to `thisArg` and invoked with three arguments;
7385 * (value, index|key, collection).
7386 *
7387 * If a property name is provided for `callback` the created "_.pluck" style
7388 * callback will return the property value of the given element.
7389 *
7390 * If an object is provided for `callback` the created "_.where" style callback
7391 * will return `true` for elements that have the properties of the given object,
7392 * else `false`
7393 *
7394 * @static
7395 * @memberOf _
7396 * @category Collections
7397 * @param {Array|Object|string} collection The collection to iterate over.
7398 * @param {Function|Object|string} [callback=identity] The function called
7399 * per iteration. If a property name or object is provided it will be used
7400 * to create a "_.pluck" or "_.where" style callback, respectively.
7401 * @param {*} [thisArg] The `this` binding of `callback`.
7402 * @returns {Object} Returns the composed aggregate object.
7403 * @example
7404 *
7405 * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
7406 * // => { '4': [4.2], '6': [6.1, 6.4] }
7407 *
7408 * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
7409 * // => { '4': [4.2], '6': [6.1, 6.4] }
7410 *
7411 * // using "_.pluck" callback shorthand
7412 * _.groupBy(['one', 'two', 'three'], 'length');
7413 * // => { '3': ['one', 'two'], '5': ['three'] }
7414 */
7415 var groupBy = createAggregator(function(result, value, key) {
7416 (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
7417 });
7418
7419 /**
7420 * Creates an object composed of keys generated from the results of running
7421 * each element of the collection through the given callback. The corresponding
7422 * value of each key is the last element responsible for generating the key.
7423 * The callback is bound to `thisArg` and invoked with three arguments;
7424 * (value, index|key, collection).
7425 *
7426 * If a property name is provided for `callback` the created "_.pluck" style
7427 * callback will return the property value of the given element.
7428 *
7429 * If an object is provided for `callback` the created "_.where" style callback
7430 * will return `true` for elements that have the properties of the given object,
7431 * else `false`.
7432 *
7433 * @static
7434 * @memberOf _
7435 * @category Collections
7436 * @param {Array|Object|string} collection The collection to iterate over.
7437 * @param {Function|Object|string} [callback=identity] The function called
7438 * per iteration. If a property name or object is provided it will be used
7439 * to create a "_.pluck" or "_.where" style callback, respectively.
7440 * @param {*} [thisArg] The `this` binding of `callback`.
7441 * @returns {Object} Returns the composed aggregate object.
7442 * @example
7443 *
7444 * var keys = [
7445 * { 'dir': 'left', 'code': 97 },
7446 * { 'dir': 'right', 'code': 100 }
7447 * ];
7448 *
7449 * _.indexBy(keys, 'dir');
7450 * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
7451 *
7452 * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
7453 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
7454 *
7455 * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
7456 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
7457 */
7458 var indexBy = createAggregator(function(result, value, key) {
7459 result[key] = value;
7460 });
7461
7462 /**
7463 * Invokes the method named by `methodName` on each element in the `collection`
7464 * returning an array of the results of each invoked method. Additional arguments
7465 * will be provided to each invoked method. If `methodName` is a function it
7466 * will be invoked for, and `this` bound to, each element in the `collection`.
7467 *
7468 * @static
7469 * @memberOf _
7470 * @category Collections
7471 * @param {Array|Object|string} collection The collection to iterate over.
7472 * @param {Function|string} methodName The name of the method to invoke or
7473 * the function invoked per iteration.
7474 * @param {...*} [arg] Arguments to invoke the method with.
7475 * @returns {Array} Returns a new array of the results of each invoked method.
7476 * @example
7477 *
7478 * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
7479 * // => [[1, 5, 7], [1, 2, 3]]
7480 *
7481 * _.invoke([123, 456], String.prototype.split, '');
7482 * // => [['1', '2', '3'], ['4', '5', '6']]
7483 */
7484 function invoke(collection, methodName) {
7485 var args = slice(arguments, 2),
7486 index = -1,
7487 isFunc = typeof methodName == 'function',
7488 length = collection ? collection.length : 0,
7489 result = Array(typeof length == 'number' ? length : 0);
7490
7491 forEach(collection, function(value) {
7492 result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
7493 });
7494 return result;
7495 }
7496
7497 /**
7498 * Creates an array of values by running each element in the collection
7499 * through the callback. The callback is bound to `thisArg` and invoked with
7500 * three arguments; (value, index|key, collection).
7501 *
7502 * If a property name is provided for `callback` the created "_.pluck" style
7503 * callback will return the property value of the given element.
7504 *
7505 * If an object is provided for `callback` the created "_.where" style callback
7506 * will return `true` for elements that have the properties of the given object,
7507 * else `false`.
7508 *
7509 * @static
7510 * @memberOf _
7511 * @alias collect
7512 * @category Collections
7513 * @param {Array|Object|string} collection The collection to iterate over.
7514 * @param {Function|Object|string} [callback=identity] The function called
7515 * per iteration. If a property name or object is provided it will be used
7516 * to create a "_.pluck" or "_.where" style callback, respectively.
7517 * @param {*} [thisArg] The `this` binding of `callback`.
7518 * @returns {Array} Returns a new array of the results of each `callback` execution.
7519 * @example
7520 *
7521 * _.map([1, 2, 3], function(num) { return num * 3; });
7522 * // => [3, 6, 9]
7523 *
7524 * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
7525 * // => [3, 6, 9] (property order is not guaranteed across environments)
7526 *
7527 * var characters = [
7528 * { 'name': 'barney', 'age': 36 },
7529 * { 'name': 'fred', 'age': 40 }
7530 * ];
7531 *
7532 * // using "_.pluck" callback shorthand
7533 * _.map(characters, 'name');
7534 * // => ['barney', 'fred']
7535 */
7536 function map(collection, callback, thisArg) {
7537 var index = -1,
7538 length = collection ? collection.length : 0;
7539
7540 callback = lodash.createCallback(callback, thisArg, 3);
7541 if (typeof length == 'number') {
7542 var result = Array(length);
7543 while (++index < length) {
7544 result[index] = callback(collection[index], index, collection);
7545 }
7546 } else {
7547 result = [];
7548 forOwn(collection, function(value, key, collection) {
7549 result[++index] = callback(value, key, collection);
7550 });
7551 }
7552 return result;
7553 }
7554
7555 /**
7556 * Retrieves the maximum value of a collection. If the collection is empty or
7557 * falsey `-Infinity` is returned. If a callback is provided it will be executed
7558 * for each value in the collection to generate the criterion by which the value
7559 * is ranked. The callback is bound to `thisArg` and invoked with three
7560 * arguments; (value, index, collection).
7561 *
7562 * If a property name is provided for `callback` the created "_.pluck" style
7563 * callback will return the property value of the given element.
7564 *
7565 * If an object is provided for `callback` the created "_.where" style callback
7566 * will return `true` for elements that have the properties of the given object,
7567 * else `false`.
7568 *
7569 * @static
7570 * @memberOf _
7571 * @category Collections
7572 * @param {Array|Object|string} collection The collection to iterate over.
7573 * @param {Function|Object|string} [callback=identity] The function called
7574 * per iteration. If a property name or object is provided it will be used
7575 * to create a "_.pluck" or "_.where" style callback, respectively.
7576 * @param {*} [thisArg] The `this` binding of `callback`.
7577 * @returns {*} Returns the maximum value.
7578 * @example
7579 *
7580 * _.max([4, 2, 8, 6]);
7581 * // => 8
7582 *
7583 * var characters = [
7584 * { 'name': 'barney', 'age': 36 },
7585 * { 'name': 'fred', 'age': 40 }
7586 * ];
7587 *
7588 * _.max(characters, function(chr) { return chr.age; });
7589 * // => { 'name': 'fred', 'age': 40 };
7590 *
7591 * // using "_.pluck" callback shorthand
7592 * _.max(characters, 'age');
7593 * // => { 'name': 'fred', 'age': 40 };
7594 */
7595 function max(collection, callback, thisArg) {
7596 var computed = -Infinity,
7597 result = computed;
7598
7599 // allows working with functions like `_.map` without using
7600 // their `index` argument as a callback
7601 if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
7602 callback = null;
7603 }
7604 if (callback == null && isArray(collection)) {
7605 var index = -1,
7606 length = collection.length;
7607
7608 while (++index < length) {
7609 var value = collection[index];
7610 if (value > result) {
7611 result = value;
7612 }
7613 }
7614 } else {
7615 callback = (callback == null && isString(collection))
7616 ? charAtCallback
7617 : lodash.createCallback(callback, thisArg, 3);
7618
7619 forEach(collection, function(value, index, collection) {
7620 var current = callback(value, index, collection);
7621 if (current > computed) {
7622 computed = current;
7623 result = value;
7624 }
7625 });
7626 }
7627 return result;
7628 }
7629
7630 /**
7631 * Retrieves the minimum value of a collection. If the collection is empty or
7632 * falsey `Infinity` is returned. If a callback is provided it will be executed
7633 * for each value in the collection to generate the criterion by which the value
7634 * is ranked. The callback is bound to `thisArg` and invoked with three
7635 * arguments; (value, index, collection).
7636 *
7637 * If a property name is provided for `callback` the created "_.pluck" style
7638 * callback will return the property value of the given element.
7639 *
7640 * If an object is provided for `callback` the created "_.where" style callback
7641 * will return `true` for elements that have the properties of the given object,
7642 * else `false`.
7643 *
7644 * @static
7645 * @memberOf _
7646 * @category Collections
7647 * @param {Array|Object|string} collection The collection to iterate over.
7648 * @param {Function|Object|string} [callback=identity] The function called
7649 * per iteration. If a property name or object is provided it will be used
7650 * to create a "_.pluck" or "_.where" style callback, respectively.
7651 * @param {*} [thisArg] The `this` binding of `callback`.
7652 * @returns {*} Returns the minimum value.
7653 * @example
7654 *
7655 * _.min([4, 2, 8, 6]);
7656 * // => 2
7657 *
7658 * var characters = [
7659 * { 'name': 'barney', 'age': 36 },
7660 * { 'name': 'fred', 'age': 40 }
7661 * ];
7662 *
7663 * _.min(characters, function(chr) { return chr.age; });
7664 * // => { 'name': 'barney', 'age': 36 };
7665 *
7666 * // using "_.pluck" callback shorthand
7667 * _.min(characters, 'age');
7668 * // => { 'name': 'barney', 'age': 36 };
7669 */
7670 function min(collection, callback, thisArg) {
7671 var computed = Infinity,
7672 result = computed;
7673
7674 // allows working with functions like `_.map` without using
7675 // their `index` argument as a callback
7676 if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
7677 callback = null;
7678 }
7679 if (callback == null && isArray(collection)) {
7680 var index = -1,
7681 length = collection.length;
7682
7683 while (++index < length) {
7684 var value = collection[index];
7685 if (value < result) {
7686 result = value;
7687 }
7688 }
7689 } else {
7690 callback = (callback == null && isString(collection))
7691 ? charAtCallback
7692 : lodash.createCallback(callback, thisArg, 3);
7693
7694 forEach(collection, function(value, index, collection) {
7695 var current = callback(value, index, collection);
7696 if (current < computed) {
7697 computed = current;
7698 result = value;
7699 }
7700 });
7701 }
7702 return result;
7703 }
7704
7705 /**
7706 * Retrieves the value of a specified property from all elements in the collection.
7707 *
7708 * @static
7709 * @memberOf _
7710 * @type Function
7711 * @category Collections
7712 * @param {Array|Object|string} collection The collection to iterate over.
7713 * @param {string} property The name of the property to pluck.
7714 * @returns {Array} Returns a new array of property values.
7715 * @example
7716 *
7717 * var characters = [
7718 * { 'name': 'barney', 'age': 36 },
7719 * { 'name': 'fred', 'age': 40 }
7720 * ];
7721 *
7722 * _.pluck(characters, 'name');
7723 * // => ['barney', 'fred']
7724 */
7725 var pluck = map;
7726
7727 /**
7728 * Reduces a collection to a value which is the accumulated result of running
7729 * each element in the collection through the callback, where each successive
7730 * callback execution consumes the return value of the previous execution. If
7731 * `accumulator` is not provided the first element of the collection will be
7732 * used as the initial `accumulator` value. The callback is bound to `thisArg`
7733 * and invoked with four arguments; (accumulator, value, index|key, collection).
7734 *
7735 * @static
7736 * @memberOf _
7737 * @alias foldl, inject
7738 * @category Collections
7739 * @param {Array|Object|string} collection The collection to iterate over.
7740 * @param {Function} [callback=identity] The function called per iteration.
7741 * @param {*} [accumulator] Initial value of the accumulator.
7742 * @param {*} [thisArg] The `this` binding of `callback`.
7743 * @returns {*} Returns the accumulated value.
7744 * @example
7745 *
7746 * var sum = _.reduce([1, 2, 3], function(sum, num) {
7747 * return sum + num;
7748 * });
7749 * // => 6
7750 *
7751 * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
7752 * result[key] = num * 3;
7753 * return result;
7754 * }, {});
7755 * // => { 'a': 3, 'b': 6, 'c': 9 }
7756 */
7757 function reduce(collection, callback, accumulator, thisArg) {
7758 if (!collection) return accumulator;
7759 var noaccum = arguments.length < 3;
7760 callback = lodash.createCallback(callback, thisArg, 4);
7761
7762 var index = -1,
7763 length = collection.length;
7764
7765 if (typeof length == 'number') {
7766 if (noaccum) {
7767 accumulator = collection[++index];
7768 }
7769 while (++index < length) {
7770 accumulator = callback(accumulator, collection[index], index, collection);
7771 }
7772 } else {
7773 forOwn(collection, function(value, index, collection) {
7774 accumulator = noaccum
7775 ? (noaccum = false, value)
7776 : callback(accumulator, value, index, collection)
7777 });
7778 }
7779 return accumulator;
7780 }
7781
7782 /**
7783 * This method is like `_.reduce` except that it iterates over elements
7784 * of a `collection` from right to left.
7785 *
7786 * @static
7787 * @memberOf _
7788 * @alias foldr
7789 * @category Collections
7790 * @param {Array|Object|string} collection The collection to iterate over.
7791 * @param {Function} [callback=identity] The function called per iteration.
7792 * @param {*} [accumulator] Initial value of the accumulator.
7793 * @param {*} [thisArg] The `this` binding of `callback`.
7794 * @returns {*} Returns the accumulated value.
7795 * @example
7796 *
7797 * var list = [[0, 1], [2, 3], [4, 5]];
7798 * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
7799 * // => [4, 5, 2, 3, 0, 1]
7800 */
7801 function reduceRight(collection, callback, accumulator, thisArg) {
7802 var noaccum = arguments.length < 3;
7803 callback = lodash.createCallback(callback, thisArg, 4);
7804 forEachRight(collection, function(value, index, collection) {
7805 accumulator = noaccum
7806 ? (noaccum = false, value)
7807 : callback(accumulator, value, index, collection);
7808 });
7809 return accumulator;
7810 }
7811
7812 /**
7813 * The opposite of `_.filter` this method returns the elements of a
7814 * collection that the callback does **not** return truey for.
7815 *
7816 * If a property name is provided for `callback` the created "_.pluck" style
7817 * callback will return the property value of the given element.
7818 *
7819 * If an object is provided for `callback` the created "_.where" style callback
7820 * will return `true` for elements that have the properties of the given object,
7821 * else `false`.
7822 *
7823 * @static
7824 * @memberOf _
7825 * @category Collections
7826 * @param {Array|Object|string} collection The collection to iterate over.
7827 * @param {Function|Object|string} [callback=identity] The function called
7828 * per iteration. If a property name or object is provided it will be used
7829 * to create a "_.pluck" or "_.where" style callback, respectively.
7830 * @param {*} [thisArg] The `this` binding of `callback`.
7831 * @returns {Array} Returns a new array of elements that failed the callback check.
7832 * @example
7833 *
7834 * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
7835 * // => [1, 3, 5]
7836 *
7837 * var characters = [
7838 * { 'name': 'barney', 'age': 36, 'blocked': false },
7839 * { 'name': 'fred', 'age': 40, 'blocked': true }
7840 * ];
7841 *
7842 * // using "_.pluck" callback shorthand
7843 * _.reject(characters, 'blocked');
7844 * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
7845 *
7846 * // using "_.where" callback shorthand
7847 * _.reject(characters, { 'age': 36 });
7848 * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
7849 */
7850 function reject(collection, callback, thisArg) {
7851 callback = lodash.createCallback(callback, thisArg, 3);
7852 return filter(collection, function(value, index, collection) {
7853 return !callback(value, index, collection);
7854 });
7855 }
7856
7857 /**
7858 * Retrieves a random element or `n` random elements from a collection.
7859 *
7860 * @static
7861 * @memberOf _
7862 * @category Collections
7863 * @param {Array|Object|string} collection The collection to sample.
7864 * @param {number} [n] The number of elements to sample.
7865 * @param- {Object} [guard] Allows working with functions like `_.map`
7866 * without using their `index` arguments as `n`.
7867 * @returns {Array} Returns the random sample(s) of `collection`.
7868 * @example
7869 *
7870 * _.sample([1, 2, 3, 4]);
7871 * // => 2
7872 *
7873 * _.sample([1, 2, 3, 4], 2);
7874 * // => [3, 1]
7875 */
7876 function sample(collection, n, guard) {
7877 if (collection && typeof collection.length != 'number') {
7878 collection = values(collection);
7879 }
7880 if (n == null || guard) {
7881 return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
7882 }
7883 var result = shuffle(collection);
7884 result.length = nativeMin(nativeMax(0, n), result.length);
7885 return result;
7886 }
7887
7888 /**
7889 * Creates an array of shuffled values, using a version of the Fisher-Yates
7890 * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
7891 *
7892 * @static
7893 * @memberOf _
7894 * @category Collections
7895 * @param {Array|Object|string} collection The collection to shuffle.
7896 * @returns {Array} Returns a new shuffled collection.
7897 * @example
7898 *
7899 * _.shuffle([1, 2, 3, 4, 5, 6]);
7900 * // => [4, 1, 6, 3, 5, 2]
7901 */
7902 function shuffle(collection) {
7903 var index = -1,
7904 length = collection ? collection.length : 0,
7905 result = Array(typeof length == 'number' ? length : 0);
7906
7907 forEach(collection, function(value) {
7908 var rand = baseRandom(0, ++index);
7909 result[index] = result[rand];
7910 result[rand] = value;
7911 });
7912 return result;
7913 }
7914
7915 /**
7916 * Gets the size of the `collection` by returning `collection.length` for arrays
7917 * and array-like objects or the number of own enumerable properties for objects.
7918 *
7919 * @static
7920 * @memberOf _
7921 * @category Collections
7922 * @param {Array|Object|string} collection The collection to inspect.
7923 * @returns {number} Returns `collection.length` or number of own enumerable properties.
7924 * @example
7925 *
7926 * _.size([1, 2]);
7927 * // => 2
7928 *
7929 * _.size({ 'one': 1, 'two': 2, 'three': 3 });
7930 * // => 3
7931 *
7932 * _.size('pebbles');
7933 * // => 7
7934 */
7935 function size(collection) {
7936 var length = collection ? collection.length : 0;
7937 return typeof length == 'number' ? length : keys(collection).length;
7938 }
7939
7940 /**
7941 * Checks if the callback returns a truey value for **any** element of a
7942 * collection. The function returns as soon as it finds a passing value and
7943 * does not iterate over the entire collection. The callback is bound to
7944 * `thisArg` and invoked with three arguments; (value, index|key, collection).
7945 *
7946 * If a property name is provided for `callback` the created "_.pluck" style
7947 * callback will return the property value of the given element.
7948 *
7949 * If an object is provided for `callback` the created "_.where" style callback
7950 * will return `true` for elements that have the properties of the given object,
7951 * else `false`.
7952 *
7953 * @static
7954 * @memberOf _
7955 * @alias any
7956 * @category Collections
7957 * @param {Array|Object|string} collection The collection to iterate over.
7958 * @param {Function|Object|string} [callback=identity] The function called
7959 * per iteration. If a property name or object is provided it will be used
7960 * to create a "_.pluck" or "_.where" style callback, respectively.
7961 * @param {*} [thisArg] The `this` binding of `callback`.
7962 * @returns {boolean} Returns `true` if any element passed the callback check,
7963 * else `false`.
7964 * @example
7965 *
7966 * _.some([null, 0, 'yes', false], Boolean);
7967 * // => true
7968 *
7969 * var characters = [
7970 * { 'name': 'barney', 'age': 36, 'blocked': false },
7971 * { 'name': 'fred', 'age': 40, 'blocked': true }
7972 * ];
7973 *
7974 * // using "_.pluck" callback shorthand
7975 * _.some(characters, 'blocked');
7976 * // => true
7977 *
7978 * // using "_.where" callback shorthand
7979 * _.some(characters, { 'age': 1 });
7980 * // => false
7981 */
7982 function some(collection, callback, thisArg) {
7983 var result;
7984 callback = lodash.createCallback(callback, thisArg, 3);
7985
7986 var index = -1,
7987 length = collection ? collection.length : 0;
7988
7989 if (typeof length == 'number') {
7990 while (++index < length) {
7991 if ((result = callback(collection[index], index, collection))) {
7992 break;
7993 }
7994 }
7995 } else {
7996 forOwn(collection, function(value, index, collection) {
7997 return !(result = callback(value, index, collection));
7998 });
7999 }
8000 return !!result;
8001 }
8002
8003 /**
8004 * Creates an array of elements, sorted in ascending order by the results of
8005 * running each element in a collection through the callback. This method
8006 * performs a stable sort, that is, it will preserve the original sort order
8007 * of equal elements. The callback is bound to `thisArg` and invoked with
8008 * three arguments; (value, index|key, collection).
8009 *
8010 * If a property name is provided for `callback` the created "_.pluck" style
8011 * callback will return the property value of the given element.
8012 *
8013 * If an array of property names is provided for `callback` the collection
8014 * will be sorted by each property value.
8015 *
8016 * If an object is provided for `callback` the created "_.where" style callback
8017 * will return `true` for elements that have the properties of the given object,
8018 * else `false`.
8019 *
8020 * @static
8021 * @memberOf _
8022 * @category Collections
8023 * @param {Array|Object|string} collection The collection to iterate over.
8024 * @param {Array|Function|Object|string} [callback=identity] The function called
8025 * per iteration. If a property name or object is provided it will be used
8026 * to create a "_.pluck" or "_.where" style callback, respectively.
8027 * @param {*} [thisArg] The `this` binding of `callback`.
8028 * @returns {Array} Returns a new array of sorted elements.
8029 * @example
8030 *
8031 * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
8032 * // => [3, 1, 2]
8033 *
8034 * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
8035 * // => [3, 1, 2]
8036 *
8037 * var characters = [
8038 * { 'name': 'barney', 'age': 36 },
8039 * { 'name': 'fred', 'age': 40 },
8040 * { 'name': 'barney', 'age': 26 },
8041 * { 'name': 'fred', 'age': 30 }
8042 * ];
8043 *
8044 * // using "_.pluck" callback shorthand
8045 * _.map(_.sortBy(characters, 'age'), _.values);
8046 * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
8047 *
8048 * // sorting by multiple properties
8049 * _.map(_.sortBy(characters, ['name', 'age']), _.values);
8050 * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
8051 */
8052 function sortBy(collection, callback, thisArg) {
8053 var index = -1,
8054 isArr = isArray(callback),
8055 length = collection ? collection.length : 0,
8056 result = Array(typeof length == 'number' ? length : 0);
8057
8058 if (!isArr) {
8059 callback = lodash.createCallback(callback, thisArg, 3);
8060 }
8061 forEach(collection, function(value, key, collection) {
8062 var object = result[++index] = getObject();
8063 if (isArr) {
8064 object.criteria = map(callback, function(key) { return value[key]; });
8065 } else {
8066 (object.criteria = getArray())[0] = callback(value, key, collection);
8067 }
8068 object.index = index;
8069 object.value = value;
8070 });
8071
8072 length = result.length;
8073 result.sort(compareAscending);
8074 while (length--) {
8075 var object = result[length];
8076 result[length] = object.value;
8077 if (!isArr) {
8078 releaseArray(object.criteria);
8079 }
8080 releaseObject(object);
8081 }
8082 return result;
8083 }
8084
8085 /**
8086 * Converts the `collection` to an array.
8087 *
8088 * @static
8089 * @memberOf _
8090 * @category Collections
8091 * @param {Array|Object|string} collection The collection to convert.
8092 * @returns {Array} Returns the new converted array.
8093 * @example
8094 *
8095 * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
8096 * // => [2, 3, 4]
8097 */
8098 function toArray(collection) {
8099 if (collection && typeof collection.length == 'number') {
8100 return slice(collection);
8101 }
8102 return values(collection);
8103 }
8104
8105 /**
8106 * Performs a deep comparison of each element in a `collection` to the given
8107 * `properties` object, returning an array of all elements that have equivalent
8108 * property values.
8109 *
8110 * @static
8111 * @memberOf _
8112 * @type Function
8113 * @category Collections
8114 * @param {Array|Object|string} collection The collection to iterate over.
8115 * @param {Object} props The object of property values to filter by.
8116 * @returns {Array} Returns a new array of elements that have the given properties.
8117 * @example
8118 *
8119 * var characters = [
8120 * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
8121 * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
8122 * ];
8123 *
8124 * _.where(characters, { 'age': 36 });
8125 * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
8126 *
8127 * _.where(characters, { 'pets': ['dino'] });
8128 * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
8129 */
8130 var where = filter;
8131
8132 /*--------------------------------------------------------------------------*/
8133
8134 /**
8135 * Creates an array with all falsey values removed. The values `false`, `null`,
8136 * `0`, `""`, `undefined`, and `NaN` are all falsey.
8137 *
8138 * @static
8139 * @memberOf _
8140 * @category Arrays
8141 * @param {Array} array The array to compact.
8142 * @returns {Array} Returns a new array of filtered values.
8143 * @example
8144 *
8145 * _.compact([0, 1, false, 2, '', 3]);
8146 * // => [1, 2, 3]
8147 */
8148 function compact(array) {
8149 var index = -1,
8150 length = array ? array.length : 0,
8151 result = [];
8152
8153 while (++index < length) {
8154 var value = array[index];
8155 if (value) {
8156 result.push(value);
8157 }
8158 }
8159 return result;
8160 }
8161
8162 /**
8163 * Creates an array excluding all values of the provided arrays using strict
8164 * equality for comparisons, i.e. `===`.
8165 *
8166 * @static
8167 * @memberOf _
8168 * @category Arrays
8169 * @param {Array} array The array to process.
8170 * @param {...Array} [values] The arrays of values to exclude.
8171 * @returns {Array} Returns a new array of filtered values.
8172 * @example
8173 *
8174 * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
8175 * // => [1, 3, 4]
8176 */
8177 function difference(array) {
8178 return baseDifference(array, baseFlatten(arguments, true, true, 1));
8179 }
8180
8181 /**
8182 * This method is like `_.find` except that it returns the index of the first
8183 * element that passes the callback check, instead of the element itself.
8184 *
8185 * If a property name is provided for `callback` the created "_.pluck" style
8186 * callback will return the property value of the given element.
8187 *
8188 * If an object is provided for `callback` the created "_.where" style callback
8189 * will return `true` for elements that have the properties of the given object,
8190 * else `false`.
8191 *
8192 * @static
8193 * @memberOf _
8194 * @category Arrays
8195 * @param {Array} array The array to search.
8196 * @param {Function|Object|string} [callback=identity] The function called
8197 * per iteration. If a property name or object is provided it will be used
8198 * to create a "_.pluck" or "_.where" style callback, respectively.
8199 * @param {*} [thisArg] The `this` binding of `callback`.
8200 * @returns {number} Returns the index of the found element, else `-1`.
8201 * @example
8202 *
8203 * var characters = [
8204 * { 'name': 'barney', 'age': 36, 'blocked': false },
8205 * { 'name': 'fred', 'age': 40, 'blocked': true },
8206 * { 'name': 'pebbles', 'age': 1, 'blocked': false }
8207 * ];
8208 *
8209 * _.findIndex(characters, function(chr) {
8210 * return chr.age < 20;
8211 * });
8212 * // => 2
8213 *
8214 * // using "_.where" callback shorthand
8215 * _.findIndex(characters, { 'age': 36 });
8216 * // => 0
8217 *
8218 * // using "_.pluck" callback shorthand
8219 * _.findIndex(characters, 'blocked');
8220 * // => 1
8221 */
8222 function findIndex(array, callback, thisArg) {
8223 var index = -1,
8224 length = array ? array.length : 0;
8225
8226 callback = lodash.createCallback(callback, thisArg, 3);
8227 while (++index < length) {
8228 if (callback(array[index], index, array)) {
8229 return index;
8230 }
8231 }
8232 return -1;
8233 }
8234
8235 /**
8236 * This method is like `_.findIndex` except that it iterates over elements
8237 * of a `collection` from right to left.
8238 *
8239 * If a property name is provided for `callback` the created "_.pluck" style
8240 * callback will return the property value of the given element.
8241 *
8242 * If an object is provided for `callback` the created "_.where" style callback
8243 * will return `true` for elements that have the properties of the given object,
8244 * else `false`.
8245 *
8246 * @static
8247 * @memberOf _
8248 * @category Arrays
8249 * @param {Array} array The array to search.
8250 * @param {Function|Object|string} [callback=identity] The function called
8251 * per iteration. If a property name or object is provided it will be used
8252 * to create a "_.pluck" or "_.where" style callback, respectively.
8253 * @param {*} [thisArg] The `this` binding of `callback`.
8254 * @returns {number} Returns the index of the found element, else `-1`.
8255 * @example
8256 *
8257 * var characters = [
8258 * { 'name': 'barney', 'age': 36, 'blocked': true },
8259 * { 'name': 'fred', 'age': 40, 'blocked': false },
8260 * { 'name': 'pebbles', 'age': 1, 'blocked': true }
8261 * ];
8262 *
8263 * _.findLastIndex(characters, function(chr) {
8264 * return chr.age > 30;
8265 * });
8266 * // => 1
8267 *
8268 * // using "_.where" callback shorthand
8269 * _.findLastIndex(characters, { 'age': 36 });
8270 * // => 0
8271 *
8272 * // using "_.pluck" callback shorthand
8273 * _.findLastIndex(characters, 'blocked');
8274 * // => 2
8275 */
8276 function findLastIndex(array, callback, thisArg) {
8277 var length = array ? array.length : 0;
8278 callback = lodash.createCallback(callback, thisArg, 3);
8279 while (length--) {
8280 if (callback(array[length], length, array)) {
8281 return length;
8282 }
8283 }
8284 return -1;
8285 }
8286
8287 /**
8288 * Gets the first element or first `n` elements of an array. If a callback
8289 * is provided elements at the beginning of the array are returned as long
8290 * as the callback returns truey. The callback is bound to `thisArg` and
8291 * invoked with three arguments; (value, index, array).
8292 *
8293 * If a property name is provided for `callback` the created "_.pluck" style
8294 * callback will return the property value of the given element.
8295 *
8296 * If an object is provided for `callback` the created "_.where" style callback
8297 * will return `true` for elements that have the properties of the given object,
8298 * else `false`.
8299 *
8300 * @static
8301 * @memberOf _
8302 * @alias head, take
8303 * @category Arrays
8304 * @param {Array} array The array to query.
8305 * @param {Function|Object|number|string} [callback] The function called
8306 * per element or the number of elements to return. If a property name or
8307 * object is provided it will be used to create a "_.pluck" or "_.where"
8308 * style callback, respectively.
8309 * @param {*} [thisArg] The `this` binding of `callback`.
8310 * @returns {*} Returns the first element(s) of `array`.
8311 * @example
8312 *
8313 * _.first([1, 2, 3]);
8314 * // => 1
8315 *
8316 * _.first([1, 2, 3], 2);
8317 * // => [1, 2]
8318 *
8319 * _.first([1, 2, 3], function(num) {
8320 * return num < 3;
8321 * });
8322 * // => [1, 2]
8323 *
8324 * var characters = [
8325 * { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
8326 * { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
8327 * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
8328 * ];
8329 *
8330 * // using "_.pluck" callback shorthand
8331 * _.first(characters, 'blocked');
8332 * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
8333 *
8334 * // using "_.where" callback shorthand
8335 * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
8336 * // => ['barney', 'fred']
8337 */
8338 function first(array, callback, thisArg) {
8339 var n = 0,
8340 length = array ? array.length : 0;
8341
8342 if (typeof callback != 'number' && callback != null) {
8343 var index = -1;
8344 callback = lodash.createCallback(callback, thisArg, 3);
8345 while (++index < length && callback(array[index], index, array)) {
8346 n++;
8347 }
8348 } else {
8349 n = callback;
8350 if (n == null || thisArg) {
8351 return array ? array[0] : undefined;
8352 }
8353 }
8354 return slice(array, 0, nativeMin(nativeMax(0, n), length));
8355 }
8356
8357 /**
8358 * Flattens a nested array (the nesting can be to any depth). If `isShallow`
8359 * is truey, the array will only be flattened a single level. If a callback
8360 * is provided each element of the array is passed through the callback before
8361 * flattening. The callback is bound to `thisArg` and invoked with three
8362 * arguments; (value, index, array).
8363 *
8364 * If a property name is provided for `callback` the created "_.pluck" style
8365 * callback will return the property value of the given element.
8366 *
8367 * If an object is provided for `callback` the created "_.where" style callback
8368 * will return `true` for elements that have the properties of the given object,
8369 * else `false`.
8370 *
8371 * @static
8372 * @memberOf _
8373 * @category Arrays
8374 * @param {Array} array The array to flatten.
8375 * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
8376 * @param {Function|Object|string} [callback=identity] The function called
8377 * per iteration. If a property name or object is provided it will be used
8378 * to create a "_.pluck" or "_.where" style callback, respectively.
8379 * @param {*} [thisArg] The `this` binding of `callback`.
8380 * @returns {Array} Returns a new flattened array.
8381 * @example
8382 *
8383 * _.flatten([1, [2], [3, [[4]]]]);
8384 * // => [1, 2, 3, 4];
8385 *
8386 * _.flatten([1, [2], [3, [[4]]]], true);
8387 * // => [1, 2, 3, [[4]]];
8388 *
8389 * var characters = [
8390 * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
8391 * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
8392 * ];
8393 *
8394 * // using "_.pluck" callback shorthand
8395 * _.flatten(characters, 'pets');
8396 * // => ['hoppy', 'baby puss', 'dino']
8397 */
8398 function flatten(array, isShallow, callback, thisArg) {
8399 // juggle arguments
8400 if (typeof isShallow != 'boolean' && isShallow != null) {
8401 thisArg = callback;
8402 callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
8403 isShallow = false;
8404 }
8405 if (callback != null) {
8406 array = map(array, callback, thisArg);
8407 }
8408 return baseFlatten(array, isShallow);
8409 }
8410
8411 /**
8412 * Gets the index at which the first occurrence of `value` is found using
8413 * strict equality for comparisons, i.e. `===`. If the array is already sorted
8414 * providing `true` for `fromIndex` will run a faster binary search.
8415 *
8416 * @static
8417 * @memberOf _
8418 * @category Arrays
8419 * @param {Array} array The array to search.
8420 * @param {*} value The value to search for.
8421 * @param {boolean|number} [fromIndex=0] The index to search from or `true`
8422 * to perform a binary search on a sorted array.
8423 * @returns {number} Returns the index of the matched value or `-1`.
8424 * @example
8425 *
8426 * _.indexOf([1, 2, 3, 1, 2, 3], 2);
8427 * // => 1
8428 *
8429 * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
8430 * // => 4
8431 *
8432 * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
8433 * // => 2
8434 */
8435 function indexOf(array, value, fromIndex) {
8436 if (typeof fromIndex == 'number') {
8437 var length = array ? array.length : 0;
8438 fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
8439 } else if (fromIndex) {
8440 var index = sortedIndex(array, value);
8441 return array[index] === value ? index : -1;
8442 }
8443 return baseIndexOf(array, value, fromIndex);
8444 }
8445
8446 /**
8447 * Gets all but the last element or last `n` elements of an array. If a
8448 * callback is provided elements at the end of the array are excluded from
8449 * the result as long as the callback returns truey. The callback is bound
8450 * to `thisArg` and invoked with three arguments; (value, index, array).
8451 *
8452 * If a property name is provided for `callback` the created "_.pluck" style
8453 * callback will return the property value of the given element.
8454 *
8455 * If an object is provided for `callback` the created "_.where" style callback
8456 * will return `true` for elements that have the properties of the given object,
8457 * else `false`.
8458 *
8459 * @static
8460 * @memberOf _
8461 * @category Arrays
8462 * @param {Array} array The array to query.
8463 * @param {Function|Object|number|string} [callback=1] The function called
8464 * per element or the number of elements to exclude. If a property name or
8465 * object is provided it will be used to create a "_.pluck" or "_.where"
8466 * style callback, respectively.
8467 * @param {*} [thisArg] The `this` binding of `callback`.
8468 * @returns {Array} Returns a slice of `array`.
8469 * @example
8470 *
8471 * _.initial([1, 2, 3]);
8472 * // => [1, 2]
8473 *
8474 * _.initial([1, 2, 3], 2);
8475 * // => [1]
8476 *
8477 * _.initial([1, 2, 3], function(num) {
8478 * return num > 1;
8479 * });
8480 * // => [1]
8481 *
8482 * var characters = [
8483 * { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
8484 * { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
8485 * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
8486 * ];
8487 *
8488 * // using "_.pluck" callback shorthand
8489 * _.initial(characters, 'blocked');
8490 * // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }]
8491 *
8492 * // using "_.where" callback shorthand
8493 * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
8494 * // => ['barney', 'fred']
8495 */
8496 function initial(array, callback, thisArg) {
8497 var n = 0,
8498 length = array ? array.length : 0;
8499
8500 if (typeof callback != 'number' && callback != null) {
8501 var index = length;
8502 callback = lodash.createCallback(callback, thisArg, 3);
8503 while (index-- && callback(array[index], index, array)) {
8504 n++;
8505 }
8506 } else {
8507 n = (callback == null || thisArg) ? 1 : callback || n;
8508 }
8509 return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
8510 }
8511
8512 /**
8513 * Creates an array of unique values present in all provided arrays using
8514 * strict equality for comparisons, i.e. `===`.
8515 *
8516 * @static
8517 * @memberOf _
8518 * @category Arrays
8519 * @param {...Array} [array] The arrays to inspect.
8520 * @returns {Array} Returns an array of shared values.
8521 * @example
8522 *
8523 * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
8524 * // => [1, 2]
8525 */
8526 function intersection() {
8527 var args = [],
8528 argsIndex = -1,
8529 argsLength = arguments.length,
8530 caches = getArray(),
8531 indexOf = getIndexOf(),
8532 trustIndexOf = indexOf === baseIndexOf,
8533 seen = getArray();
8534
8535 while (++argsIndex < argsLength) {
8536 var value = arguments[argsIndex];
8537 if (isArray(value) || isArguments(value)) {
8538 args.push(value);
8539 caches.push(trustIndexOf && value.length >= largeArraySize &&
8540 createCache(argsIndex ? args[argsIndex] : seen));
8541 }
8542 }
8543 var array = args[0],
8544 index = -1,
8545 length = array ? array.length : 0,
8546 result = [];
8547
8548 outer:
8549 while (++index < length) {
8550 var cache = caches[0];
8551 value = array[index];
8552
8553 if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
8554 argsIndex = argsLength;
8555 (cache || seen).push(value);
8556 while (--argsIndex) {
8557 cache = caches[argsIndex];
8558 if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
8559 continue outer;
8560 }
8561 }
8562 result.push(value);
8563 }
8564 }
8565 while (argsLength--) {
8566 cache = caches[argsLength];
8567 if (cache) {
8568 releaseObject(cache);
8569 }
8570 }
8571 releaseArray(caches);
8572 releaseArray(seen);
8573 return result;
8574 }
8575
8576 /**
8577 * Gets the last element or last `n` elements of an array. If a callback is
8578 * provided elements at the end of the array are returned as long as the
8579 * callback returns truey. The callback is bound to `thisArg` and invoked
8580 * with three arguments; (value, index, array).
8581 *
8582 * If a property name is provided for `callback` the created "_.pluck" style
8583 * callback will return the property value of the given element.
8584 *
8585 * If an object is provided for `callback` the created "_.where" style callback
8586 * will return `true` for elements that have the properties of the given object,
8587 * else `false`.
8588 *
8589 * @static
8590 * @memberOf _
8591 * @category Arrays
8592 * @param {Array} array The array to query.
8593 * @param {Function|Object|number|string} [callback] The function called
8594 * per element or the number of elements to return. If a property name or
8595 * object is provided it will be used to create a "_.pluck" or "_.where"
8596 * style callback, respectively.
8597 * @param {*} [thisArg] The `this` binding of `callback`.
8598 * @returns {*} Returns the last element(s) of `array`.
8599 * @example
8600 *
8601 * _.last([1, 2, 3]);
8602 * // => 3
8603 *
8604 * _.last([1, 2, 3], 2);
8605 * // => [2, 3]
8606 *
8607 * _.last([1, 2, 3], function(num) {
8608 * return num > 1;
8609 * });
8610 * // => [2, 3]
8611 *
8612 * var characters = [
8613 * { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
8614 * { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
8615 * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
8616 * ];
8617 *
8618 * // using "_.pluck" callback shorthand
8619 * _.pluck(_.last(characters, 'blocked'), 'name');
8620 * // => ['fred', 'pebbles']
8621 *
8622 * // using "_.where" callback shorthand
8623 * _.last(characters, { 'employer': 'na' });
8624 * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
8625 */
8626 function last(array, callback, thisArg) {
8627 var n = 0,
8628 length = array ? array.length : 0;
8629
8630 if (typeof callback != 'number' && callback != null) {
8631 var index = length;
8632 callback = lodash.createCallback(callback, thisArg, 3);
8633 while (index-- && callback(array[index], index, array)) {
8634 n++;
8635 }
8636 } else {
8637 n = callback;
8638 if (n == null || thisArg) {
8639 return array ? array[length - 1] : undefined;
8640 }
8641 }
8642 return slice(array, nativeMax(0, length - n));
8643 }
8644
8645 /**
8646 * Gets the index at which the last occurrence of `value` is found using strict
8647 * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
8648 * as the offset from the end of the collection.
8649 *
8650 * If a property name is provided for `callback` the created "_.pluck" style
8651 * callback will return the property value of the given element.
8652 *
8653 * If an object is provided for `callback` the created "_.where" style callback
8654 * will return `true` for elements that have the properties of the given object,
8655 * else `false`.
8656 *
8657 * @static
8658 * @memberOf _
8659 * @category Arrays
8660 * @param {Array} array The array to search.
8661 * @param {*} value The value to search for.
8662 * @param {number} [fromIndex=array.length-1] The index to search from.
8663 * @returns {number} Returns the index of the matched value or `-1`.
8664 * @example
8665 *
8666 * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
8667 * // => 4
8668 *
8669 * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
8670 * // => 1
8671 */
8672 function lastIndexOf(array, value, fromIndex) {
8673 var index = array ? array.length : 0;
8674 if (typeof fromIndex == 'number') {
8675 index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
8676 }
8677 while (index--) {
8678 if (array[index] === value) {
8679 return index;
8680 }
8681 }
8682 return -1;
8683 }
8684
8685 /**
8686 * Removes all provided values from the given array using strict equality for
8687 * comparisons, i.e. `===`.
8688 *
8689 * @static
8690 * @memberOf _
8691 * @category Arrays
8692 * @param {Array} array The array to modify.
8693 * @param {...*} [value] The values to remove.
8694 * @returns {Array} Returns `array`.
8695 * @example
8696 *
8697 * var array = [1, 2, 3, 1, 2, 3];
8698 * _.pull(array, 2, 3);
8699 * console.log(array);
8700 * // => [1, 1]
8701 */
8702 function pull(array) {
8703 var args = arguments,
8704 argsIndex = 0,
8705 argsLength = args.length,
8706 length = array ? array.length : 0;
8707
8708 while (++argsIndex < argsLength) {
8709 var index = -1,
8710 value = args[argsIndex];
8711 while (++index < length) {
8712 if (array[index] === value) {
8713 splice.call(array, index--, 1);
8714 length--;
8715 }
8716 }
8717 }
8718 return array;
8719 }
8720
8721 /**
8722 * Creates an array of numbers (positive and/or negative) progressing from
8723 * `start` up to but not including `end`. If `start` is less than `stop` a
8724 * zero-length range is created unless a negative `step` is specified.
8725 *
8726 * @static
8727 * @memberOf _
8728 * @category Arrays
8729 * @param {number} [start=0] The start of the range.
8730 * @param {number} end The end of the range.
8731 * @param {number} [step=1] The value to increment or decrement by.
8732 * @returns {Array} Returns a new range array.
8733 * @example
8734 *
8735 * _.range(4);
8736 * // => [0, 1, 2, 3]
8737 *
8738 * _.range(1, 5);
8739 * // => [1, 2, 3, 4]
8740 *
8741 * _.range(0, 20, 5);
8742 * // => [0, 5, 10, 15]
8743 *
8744 * _.range(0, -4, -1);
8745 * // => [0, -1, -2, -3]
8746 *
8747 * _.range(1, 4, 0);
8748 * // => [1, 1, 1]
8749 *
8750 * _.range(0);
8751 * // => []
8752 */
8753 function range(start, end, step) {
8754 start = +start || 0;
8755 step = typeof step == 'number' ? step : (+step || 1);
8756
8757 if (end == null) {
8758 end = start;
8759 start = 0;
8760 }
8761 // use `Array(length)` so engines like Chakra and V8 avoid slower modes
8762 // http://youtu.be/XAqIpGU8ZZk#t=17m25s
8763 var index = -1,
8764 length = nativeMax(0, ceil((end - start) / (step || 1))),
8765 result = Array(length);
8766
8767 while (++index < length) {
8768 result[index] = start;
8769 start += step;
8770 }
8771 return result;
8772 }
8773
8774 /**
8775 * Removes all elements from an array that the callback returns truey for
8776 * and returns an array of removed elements. The callback is bound to `thisArg`
8777 * and invoked with three arguments; (value, index, array).
8778 *
8779 * If a property name is provided for `callback` the created "_.pluck" style
8780 * callback will return the property value of the given element.
8781 *
8782 * If an object is provided for `callback` the created "_.where" style callback
8783 * will return `true` for elements that have the properties of the given object,
8784 * else `false`.
8785 *
8786 * @static
8787 * @memberOf _
8788 * @category Arrays
8789 * @param {Array} array The array to modify.
8790 * @param {Function|Object|string} [callback=identity] The function called
8791 * per iteration. If a property name or object is provided it will be used
8792 * to create a "_.pluck" or "_.where" style callback, respectively.
8793 * @param {*} [thisArg] The `this` binding of `callback`.
8794 * @returns {Array} Returns a new array of removed elements.
8795 * @example
8796 *
8797 * var array = [1, 2, 3, 4, 5, 6];
8798 * var evens = _.remove(array, function(num) { return num % 2 == 0; });
8799 *
8800 * console.log(array);
8801 * // => [1, 3, 5]
8802 *
8803 * console.log(evens);
8804 * // => [2, 4, 6]
8805 */
8806 function remove(array, callback, thisArg) {
8807 var index = -1,
8808 length = array ? array.length : 0,
8809 result = [];
8810
8811 callback = lodash.createCallback(callback, thisArg, 3);
8812 while (++index < length) {
8813 var value = array[index];
8814 if (callback(value, index, array)) {
8815 result.push(value);
8816 splice.call(array, index--, 1);
8817 length--;
8818 }
8819 }
8820 return result;
8821 }
8822
8823 /**
8824 * The opposite of `_.initial` this method gets all but the first element or
8825 * first `n` elements of an array. If a callback function is provided elements
8826 * at the beginning of the array are excluded from the result as long as the
8827 * callback returns truey. The callback is bound to `thisArg` and invoked
8828 * with three arguments; (value, index, array).
8829 *
8830 * If a property name is provided for `callback` the created "_.pluck" style
8831 * callback will return the property value of the given element.
8832 *
8833 * If an object is provided for `callback` the created "_.where" style callback
8834 * will return `true` for elements that have the properties of the given object,
8835 * else `false`.
8836 *
8837 * @static
8838 * @memberOf _
8839 * @alias drop, tail
8840 * @category Arrays
8841 * @param {Array} array The array to query.
8842 * @param {Function|Object|number|string} [callback=1] The function called
8843 * per element or the number of elements to exclude. If a property name or
8844 * object is provided it will be used to create a "_.pluck" or "_.where"
8845 * style callback, respectively.
8846 * @param {*} [thisArg] The `this` binding of `callback`.
8847 * @returns {Array} Returns a slice of `array`.
8848 * @example
8849 *
8850 * _.rest([1, 2, 3]);
8851 * // => [2, 3]
8852 *
8853 * _.rest([1, 2, 3], 2);
8854 * // => [3]
8855 *
8856 * _.rest([1, 2, 3], function(num) {
8857 * return num < 3;
8858 * });
8859 * // => [3]
8860 *
8861 * var characters = [
8862 * { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
8863 * { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
8864 * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
8865 * ];
8866 *
8867 * // using "_.pluck" callback shorthand
8868 * _.pluck(_.rest(characters, 'blocked'), 'name');
8869 * // => ['fred', 'pebbles']
8870 *
8871 * // using "_.where" callback shorthand
8872 * _.rest(characters, { 'employer': 'slate' });
8873 * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
8874 */
8875 function rest(array, callback, thisArg) {
8876 if (typeof callback != 'number' && callback != null) {
8877 var n = 0,
8878 index = -1,
8879 length = array ? array.length : 0;
8880
8881 callback = lodash.createCallback(callback, thisArg, 3);
8882 while (++index < length && callback(array[index], index, array)) {
8883 n++;
8884 }
8885 } else {
8886 n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
8887 }
8888 return slice(array, n);
8889 }
8890
8891 /**
8892 * Uses a binary search to determine the smallest index at which a value
8893 * should be inserted into a given sorted array in order to maintain the sort
8894 * order of the array. If a callback is provided it will be executed for
8895 * `value` and each element of `array` to compute their sort ranking. The
8896 * callback is bound to `thisArg` and invoked with one argument; (value).
8897 *
8898 * If a property name is provided for `callback` the created "_.pluck" style
8899 * callback will return the property value of the given element.
8900 *
8901 * If an object is provided for `callback` the created "_.where" style callback
8902 * will return `true` for elements that have the properties of the given object,
8903 * else `false`.
8904 *
8905 * @static
8906 * @memberOf _
8907 * @category Arrays
8908 * @param {Array} array The array to inspect.
8909 * @param {*} value The value to evaluate.
8910 * @param {Function|Object|string} [callback=identity] The function called
8911 * per iteration. If a property name or object is provided it will be used
8912 * to create a "_.pluck" or "_.where" style callback, respectively.
8913 * @param {*} [thisArg] The `this` binding of `callback`.
8914 * @returns {number} Returns the index at which `value` should be inserted
8915 * into `array`.
8916 * @example
8917 *
8918 * _.sortedIndex([20, 30, 50], 40);
8919 * // => 2
8920 *
8921 * // using "_.pluck" callback shorthand
8922 * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
8923 * // => 2
8924 *
8925 * var dict = {
8926 * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
8927 * };
8928 *
8929 * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
8930 * return dict.wordToNumber[word];
8931 * });
8932 * // => 2
8933 *
8934 * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
8935 * return this.wordToNumber[word];
8936 * }, dict);
8937 * // => 2
8938 */
8939 function sortedIndex(array, value, callback, thisArg) {
8940 var low = 0,
8941 high = array ? array.length : low;
8942
8943 // explicitly reference `identity` for better inlining in Firefox
8944 callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
8945 value = callback(value);
8946
8947 while (low < high) {
8948 var mid = (low + high) >>> 1;
8949 (callback(array[mid]) < value)
8950 ? low = mid + 1
8951 : high = mid;
8952 }
8953 return low;
8954 }
8955
8956 /**
8957 * Creates an array of unique values, in order, of the provided arrays using
8958 * strict equality for comparisons, i.e. `===`.
8959 *
8960 * @static
8961 * @memberOf _
8962 * @category Arrays
8963 * @param {...Array} [array] The arrays to inspect.
8964 * @returns {Array} Returns an array of combined values.
8965 * @example
8966 *
8967 * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
8968 * // => [1, 2, 3, 5, 4]
8969 */
8970 function union() {
8971 return baseUniq(baseFlatten(arguments, true, true));
8972 }
8973
8974 /**
8975 * Creates a duplicate-value-free version of an array using strict equality
8976 * for comparisons, i.e. `===`. If the array is sorted, providing
8977 * `true` for `isSorted` will use a faster algorithm. If a callback is provided
8978 * each element of `array` is passed through the callback before uniqueness
8979 * is computed. The callback is bound to `thisArg` and invoked with three
8980 * arguments; (value, index, array).
8981 *
8982 * If a property name is provided for `callback` the created "_.pluck" style
8983 * callback will return the property value of the given element.
8984 *
8985 * If an object is provided for `callback` the created "_.where" style callback
8986 * will return `true` for elements that have the properties of the given object,
8987 * else `false`.
8988 *
8989 * @static
8990 * @memberOf _
8991 * @alias unique
8992 * @category Arrays
8993 * @param {Array} array The array to process.
8994 * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
8995 * @param {Function|Object|string} [callback=identity] The function called
8996 * per iteration. If a property name or object is provided it will be used
8997 * to create a "_.pluck" or "_.where" style callback, respectively.
8998 * @param {*} [thisArg] The `this` binding of `callback`.
8999 * @returns {Array} Returns a duplicate-value-free array.
9000 * @example
9001 *
9002 * _.uniq([1, 2, 1, 3, 1]);
9003 * // => [1, 2, 3]
9004 *
9005 * _.uniq([1, 1, 2, 2, 3], true);
9006 * // => [1, 2, 3]
9007 *
9008 * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
9009 * // => ['A', 'b', 'C']
9010 *
9011 * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
9012 * // => [1, 2.5, 3]
9013 *
9014 * // using "_.pluck" callback shorthand
9015 * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
9016 * // => [{ 'x': 1 }, { 'x': 2 }]
9017 */
9018 function uniq(array, isSorted, callback, thisArg) {
9019 // juggle arguments
9020 if (typeof isSorted != 'boolean' && isSorted != null) {
9021 thisArg = callback;
9022 callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
9023 isSorted = false;
9024 }
9025 if (callback != null) {
9026 callback = lodash.createCallback(callback, thisArg, 3);
9027 }
9028 return baseUniq(array, isSorted, callback);
9029 }
9030
9031 /**
9032 * Creates an array excluding all provided values using strict equality for
9033 * comparisons, i.e. `===`.
9034 *
9035 * @static
9036 * @memberOf _
9037 * @category Arrays
9038 * @param {Array} array The array to filter.
9039 * @param {...*} [value] The values to exclude.
9040 * @returns {Array} Returns a new array of filtered values.
9041 * @example
9042 *
9043 * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
9044 * // => [2, 3, 4]
9045 */
9046 function without(array) {
9047 return baseDifference(array, slice(arguments, 1));
9048 }
9049
9050 /**
9051 * Creates an array that is the symmetric difference of the provided arrays.
9052 * See http://en.wikipedia.org/wiki/Symmetric_difference.
9053 *
9054 * @static
9055 * @memberOf _
9056 * @category Arrays
9057 * @param {...Array} [array] The arrays to inspect.
9058 * @returns {Array} Returns an array of values.
9059 * @example
9060 *
9061 * _.xor([1, 2, 3], [5, 2, 1, 4]);
9062 * // => [3, 5, 4]
9063 *
9064 * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
9065 * // => [1, 4, 5]
9066 */
9067 function xor() {
9068 var index = -1,
9069 length = arguments.length;
9070
9071 while (++index < length) {
9072 var array = arguments[index];
9073 if (isArray(array) || isArguments(array)) {
9074 var result = result
9075 ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
9076 : array;
9077 }
9078 }
9079 return result || [];
9080 }
9081
9082 /**
9083 * Creates an array of grouped elements, the first of which contains the first
9084 * elements of the given arrays, the second of which contains the second
9085 * elements of the given arrays, and so on.
9086 *
9087 * @static
9088 * @memberOf _
9089 * @alias unzip
9090 * @category Arrays
9091 * @param {...Array} [array] Arrays to process.
9092 * @returns {Array} Returns a new array of grouped elements.
9093 * @example
9094 *
9095 * _.zip(['fred', 'barney'], [30, 40], [true, false]);
9096 * // => [['fred', 30, true], ['barney', 40, false]]
9097 */
9098 function zip() {
9099 var array = arguments.length > 1 ? arguments : arguments[0],
9100 index = -1,
9101 length = array ? max(pluck(array, 'length')) : 0,
9102 result = Array(length < 0 ? 0 : length);
9103
9104 while (++index < length) {
9105 result[index] = pluck(array, index);
9106 }
9107 return result;
9108 }
9109
9110 /**
9111 * Creates an object composed from arrays of `keys` and `values`. Provide
9112 * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
9113 * or two arrays, one of `keys` and one of corresponding `values`.
9114 *
9115 * @static
9116 * @memberOf _
9117 * @alias object
9118 * @category Arrays
9119 * @param {Array} keys The array of keys.
9120 * @param {Array} [values=[]] The array of values.
9121 * @returns {Object} Returns an object composed of the given keys and
9122 * corresponding values.
9123 * @example
9124 *
9125 * _.zipObject(['fred', 'barney'], [30, 40]);
9126 * // => { 'fred': 30, 'barney': 40 }
9127 */
9128 function zipObject(keys, values) {
9129 var index = -1,
9130 length = keys ? keys.length : 0,
9131 result = {};
9132
9133 if (!values && length && !isArray(keys[0])) {
9134 values = [];
9135 }
9136 while (++index < length) {
9137 var key = keys[index];
9138 if (values) {
9139 result[key] = values[index];
9140 } else if (key) {
9141 result[key[0]] = key[1];
9142 }
9143 }
9144 return result;
9145 }
9146
9147 /*--------------------------------------------------------------------------*/
9148
9149 /**
9150 * Creates a function that executes `func`, with the `this` binding and
9151 * arguments of the created function, only after being called `n` times.
9152 *
9153 * @static
9154 * @memberOf _
9155 * @category Functions
9156 * @param {number} n The number of times the function must be called before
9157 * `func` is executed.
9158 * @param {Function} func The function to restrict.
9159 * @returns {Function} Returns the new restricted function.
9160 * @example
9161 *
9162 * var saves = ['profile', 'settings'];
9163 *
9164 * var done = _.after(saves.length, function() {
9165 * console.log('Done saving!');
9166 * });
9167 *
9168 * _.forEach(saves, function(type) {
9169 * asyncSave({ 'type': type, 'complete': done });
9170 * });
9171 * // => logs 'Done saving!', after all saves have completed
9172 */
9173 function after(n, func) {
9174 if (!isFunction(func)) {
9175 throw new TypeError;
9176 }
9177 return function() {
9178 if (--n < 1) {
9179 return func.apply(this, arguments);
9180 }
9181 };
9182 }
9183
9184 /**
9185 * Creates a function that, when called, invokes `func` with the `this`
9186 * binding of `thisArg` and prepends any additional `bind` arguments to those
9187 * provided to the bound function.
9188 *
9189 * @static
9190 * @memberOf _
9191 * @category Functions
9192 * @param {Function} func The function to bind.
9193 * @param {*} [thisArg] The `this` binding of `func`.
9194 * @param {...*} [arg] Arguments to be partially applied.
9195 * @returns {Function} Returns the new bound function.
9196 * @example
9197 *
9198 * var func = function(greeting) {
9199 * return greeting + ' ' + this.name;
9200 * };
9201 *
9202 * func = _.bind(func, { 'name': 'fred' }, 'hi');
9203 * func();
9204 * // => 'hi fred'
9205 */
9206 function bind(func, thisArg) {
9207 return arguments.length > 2
9208 ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
9209 : createWrapper(func, 1, null, null, thisArg);
9210 }
9211
9212 /**
9213 * Binds methods of an object to the object itself, overwriting the existing
9214 * method. Method names may be specified as individual arguments or as arrays
9215 * of method names. If no method names are provided all the function properties
9216 * of `object` will be bound.
9217 *
9218 * @static
9219 * @memberOf _
9220 * @category Functions
9221 * @param {Object} object The object to bind and assign the bound methods to.
9222 * @param {...string} [methodName] The object method names to
9223 * bind, specified as individual method names or arrays of method names.
9224 * @returns {Object} Returns `object`.
9225 * @example
9226 *
9227 * var view = {
9228 * 'label': 'docs',
9229 * 'onClick': function() { console.log('clicked ' + this.label); }
9230 * };
9231 *
9232 * _.bindAll(view);
9233 * jQuery('#docs').on('click', view.onClick);
9234 * // => logs 'clicked docs', when the button is clicked
9235 */
9236 function bindAll(object) {
9237 var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
9238 index = -1,
9239 length = funcs.length;
9240
9241 while (++index < length) {
9242 var key = funcs[index];
9243 object[key] = createWrapper(object[key], 1, null, null, object);
9244 }
9245 return object;
9246 }
9247
9248 /**
9249 * Creates a function that, when called, invokes the method at `object[key]`
9250 * and prepends any additional `bindKey` arguments to those provided to the bound
9251 * function. This method differs from `_.bind` by allowing bound functions to
9252 * reference methods that will be redefined or don't yet exist.
9253 * See http://michaux.ca/articles/lazy-function-definition-pattern.
9254 *
9255 * @static
9256 * @memberOf _
9257 * @category Functions
9258 * @param {Object} object The object the method belongs to.
9259 * @param {string} key The key of the method.
9260 * @param {...*} [arg] Arguments to be partially applied.
9261 * @returns {Function} Returns the new bound function.
9262 * @example
9263 *
9264 * var object = {
9265 * 'name': 'fred',
9266 * 'greet': function(greeting) {
9267 * return greeting + ' ' + this.name;
9268 * }
9269 * };
9270 *
9271 * var func = _.bindKey(object, 'greet', 'hi');
9272 * func();
9273 * // => 'hi fred'
9274 *
9275 * object.greet = function(greeting) {
9276 * return greeting + 'ya ' + this.name + '!';
9277 * };
9278 *
9279 * func();
9280 * // => 'hiya fred!'
9281 */
9282 function bindKey(object, key) {
9283 return arguments.length > 2
9284 ? createWrapper(key, 19, slice(arguments, 2), null, object)
9285 : createWrapper(key, 3, null, null, object);
9286 }
9287
9288 /**
9289 * Creates a function that is the composition of the provided functions,
9290 * where each function consumes the return value of the function that follows.
9291 * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
9292 * Each function is executed with the `this` binding of the composed function.
9293 *
9294 * @static
9295 * @memberOf _
9296 * @category Functions
9297 * @param {...Function} [func] Functions to compose.
9298 * @returns {Function} Returns the new composed function.
9299 * @example
9300 *
9301 * var realNameMap = {
9302 * 'pebbles': 'penelope'
9303 * };
9304 *
9305 * var format = function(name) {
9306 * name = realNameMap[name.toLowerCase()] || name;
9307 * return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
9308 * };
9309 *
9310 * var greet = function(formatted) {
9311 * return 'Hiya ' + formatted + '!';
9312 * };
9313 *
9314 * var welcome = _.compose(greet, format);
9315 * welcome('pebbles');
9316 * // => 'Hiya Penelope!'
9317 */
9318 function compose() {
9319 var funcs = arguments,
9320 length = funcs.length;
9321
9322 while (length--) {
9323 if (!isFunction(funcs[length])) {
9324 throw new TypeError;
9325 }
9326 }
9327 return function() {
9328 var args = arguments,
9329 length = funcs.length;
9330
9331 while (length--) {
9332 args = [funcs[length].apply(this, args)];
9333 }
9334 return args[0];
9335 };
9336 }
9337
9338 /**
9339 * Creates a function which accepts one or more arguments of `func` that when
9340 * invoked either executes `func` returning its result, if all `func` arguments
9341 * have been provided, or returns a function that accepts one or more of the
9342 * remaining `func` arguments, and so on. The arity of `func` can be specified
9343 * if `func.length` is not sufficient.
9344 *
9345 * @static
9346 * @memberOf _
9347 * @category Functions
9348 * @param {Function} func The function to curry.
9349 * @param {number} [arity=func.length] The arity of `func`.
9350 * @returns {Function} Returns the new curried function.
9351 * @example
9352 *
9353 * var curried = _.curry(function(a, b, c) {
9354 * console.log(a + b + c);
9355 * });
9356 *
9357 * curried(1)(2)(3);
9358 * // => 6
9359 *
9360 * curried(1, 2)(3);
9361 * // => 6
9362 *
9363 * curried(1, 2, 3);
9364 * // => 6
9365 */
9366 function curry(func, arity) {
9367 arity = typeof arity == 'number' ? arity : (+arity || func.length);
9368 return createWrapper(func, 4, null, null, null, arity);
9369 }
9370
9371 /**
9372 * Creates a function that will delay the execution of `func` until after
9373 * `wait` milliseconds have elapsed since the last time it was invoked.
9374 * Provide an options object to indicate that `func` should be invoked on
9375 * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
9376 * to the debounced function will return the result of the last `func` call.
9377 *
9378 * Note: If `leading` and `trailing` options are `true` `func` will be called
9379 * on the trailing edge of the timeout only if the the debounced function is
9380 * invoked more than once during the `wait` timeout.
9381 *
9382 * @static
9383 * @memberOf _
9384 * @category Functions
9385 * @param {Function} func The function to debounce.
9386 * @param {number} wait The number of milliseconds to delay.
9387 * @param {Object} [options] The options object.
9388 * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
9389 * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
9390 * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
9391 * @returns {Function} Returns the new debounced function.
9392 * @example
9393 *
9394 * // avoid costly calculations while the window size is in flux
9395 * var lazyLayout = _.debounce(calculateLayout, 150);
9396 * jQuery(window).on('resize', lazyLayout);
9397 *
9398 * // execute `sendMail` when the click event is fired, debouncing subsequent calls
9399 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
9400 * 'leading': true,
9401 * 'trailing': false
9402 * });
9403 *
9404 * // ensure `batchLog` is executed once after 1 second of debounced calls
9405 * var source = new EventSource('/stream');
9406 * source.addEventListener('message', _.debounce(batchLog, 250, {
9407 * 'maxWait': 1000
9408 * }, false);
9409 */
9410 function debounce(func, wait, options) {
9411 var args,
9412 maxTimeoutId,
9413 result,
9414 stamp,
9415 thisArg,
9416 timeoutId,
9417 trailingCall,
9418 lastCalled = 0,
9419 maxWait = false,
9420 trailing = true;
9421
9422 if (!isFunction(func)) {
9423 throw new TypeError;
9424 }
9425 wait = nativeMax(0, wait) || 0;
9426 if (options === true) {
9427 var leading = true;
9428 trailing = false;
9429 } else if (isObject(options)) {
9430 leading = options.leading;
9431 maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
9432 trailing = 'trailing' in options ? options.trailing : trailing;
9433 }
9434 var delayed = function() {
9435 var remaining = wait - (now() - stamp);
9436 if (remaining <= 0) {
9437 if (maxTimeoutId) {
9438 clearTimeout(maxTimeoutId);
9439 }
9440 var isCalled = trailingCall;
9441 maxTimeoutId = timeoutId = trailingCall = undefined;
9442 if (isCalled) {
9443 lastCalled = now();
9444 result = func.apply(thisArg, args);
9445 if (!timeoutId && !maxTimeoutId) {
9446 args = thisArg = null;
9447 }
9448 }
9449 } else {
9450 timeoutId = setTimeout(delayed, remaining);
9451 }
9452 };
9453
9454 var maxDelayed = function() {
9455 if (timeoutId) {
9456 clearTimeout(timeoutId);
9457 }
9458 maxTimeoutId = timeoutId = trailingCall = undefined;
9459 if (trailing || (maxWait !== wait)) {
9460 lastCalled = now();
9461 result = func.apply(thisArg, args);
9462 if (!timeoutId && !maxTimeoutId) {
9463 args = thisArg = null;
9464 }
9465 }
9466 };
9467
9468 return function() {
9469 args = arguments;
9470 stamp = now();
9471 thisArg = this;
9472 trailingCall = trailing && (timeoutId || !leading);
9473
9474 if (maxWait === false) {
9475 var leadingCall = leading && !timeoutId;
9476 } else {
9477 if (!maxTimeoutId && !leading) {
9478 lastCalled = stamp;
9479 }
9480 var remaining = maxWait - (stamp - lastCalled),
9481 isCalled = remaining <= 0;
9482
9483 if (isCalled) {
9484 if (maxTimeoutId) {
9485 maxTimeoutId = clearTimeout(maxTimeoutId);
9486 }
9487 lastCalled = stamp;
9488 result = func.apply(thisArg, args);
9489 }
9490 else if (!maxTimeoutId) {
9491 maxTimeoutId = setTimeout(maxDelayed, remaining);
9492 }
9493 }
9494 if (isCalled && timeoutId) {
9495 timeoutId = clearTimeout(timeoutId);
9496 }
9497 else if (!timeoutId && wait !== maxWait) {
9498 timeoutId = setTimeout(delayed, wait);
9499 }
9500 if (leadingCall) {
9501 isCalled = true;
9502 result = func.apply(thisArg, args);
9503 }
9504 if (isCalled && !timeoutId && !maxTimeoutId) {
9505 args = thisArg = null;
9506 }
9507 return result;
9508 };
9509 }
9510
9511 /**
9512 * Defers executing the `func` function until the current call stack has cleared.
9513 * Additional arguments will be provided to `func` when it is invoked.
9514 *
9515 * @static
9516 * @memberOf _
9517 * @category Functions
9518 * @param {Function} func The function to defer.
9519 * @param {...*} [arg] Arguments to invoke the function with.
9520 * @returns {number} Returns the timer id.
9521 * @example
9522 *
9523 * _.defer(function(text) { console.log(text); }, 'deferred');
9524 * // logs 'deferred' after one or more milliseconds
9525 */
9526 function defer(func) {
9527 if (!isFunction(func)) {
9528 throw new TypeError;
9529 }
9530 var args = slice(arguments, 1);
9531 return setTimeout(function() { func.apply(undefined, args); }, 1);
9532 }
9533
9534 /**
9535 * Executes the `func` function after `wait` milliseconds. Additional arguments
9536 * will be provided to `func` when it is invoked.
9537 *
9538 * @static
9539 * @memberOf _
9540 * @category Functions
9541 * @param {Function} func The function to delay.
9542 * @param {number} wait The number of milliseconds to delay execution.
9543 * @param {...*} [arg] Arguments to invoke the function with.
9544 * @returns {number} Returns the timer id.
9545 * @example
9546 *
9547 * _.delay(function(text) { console.log(text); }, 1000, 'later');
9548 * // => logs 'later' after one second
9549 */
9550 function delay(func, wait) {
9551 if (!isFunction(func)) {
9552 throw new TypeError;
9553 }
9554 var args = slice(arguments, 2);
9555 return setTimeout(function() { func.apply(undefined, args); }, wait);
9556 }
9557
9558 /**
9559 * Creates a function that memoizes the result of `func`. If `resolver` is
9560 * provided it will be used to determine the cache key for storing the result
9561 * based on the arguments provided to the memoized function. By default, the
9562 * first argument provided to the memoized function is used as the cache key.
9563 * The `func` is executed with the `this` binding of the memoized function.
9564 * The result cache is exposed as the `cache` property on the memoized function.
9565 *
9566 * @static
9567 * @memberOf _
9568 * @category Functions
9569 * @param {Function} func The function to have its output memoized.
9570 * @param {Function} [resolver] A function used to resolve the cache key.
9571 * @returns {Function} Returns the new memoizing function.
9572 * @example
9573 *
9574 * var fibonacci = _.memoize(function(n) {
9575 * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
9576 * });
9577 *
9578 * fibonacci(9)
9579 * // => 34
9580 *
9581 * var data = {
9582 * 'fred': { 'name': 'fred', 'age': 40 },
9583 * 'pebbles': { 'name': 'pebbles', 'age': 1 }
9584 * };
9585 *
9586 * // modifying the result cache
9587 * var get = _.memoize(function(name) { return data[name]; }, _.identity);
9588 * get('pebbles');
9589 * // => { 'name': 'pebbles', 'age': 1 }
9590 *
9591 * get.cache.pebbles.name = 'penelope';
9592 * get('pebbles');
9593 * // => { 'name': 'penelope', 'age': 1 }
9594 */
9595 function memoize(func, resolver) {
9596 if (!isFunction(func)) {
9597 throw new TypeError;
9598 }
9599 var memoized = function() {
9600 var cache = memoized.cache,
9601 key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
9602
9603 return hasOwnProperty.call(cache, key)
9604 ? cache[key]
9605 : (cache[key] = func.apply(this, arguments));
9606 }
9607 memoized.cache = {};
9608 return memoized;
9609 }
9610
9611 /**
9612 * Creates a function that is restricted to execute `func` once. Repeat calls to
9613 * the function will return the value of the first call. The `func` is executed
9614 * with the `this` binding of the created function.
9615 *
9616 * @static
9617 * @memberOf _
9618 * @category Functions
9619 * @param {Function} func The function to restrict.
9620 * @returns {Function} Returns the new restricted function.
9621 * @example
9622 *
9623 * var initialize = _.once(createApplication);
9624 * initialize();
9625 * initialize();
9626 * // `initialize` executes `createApplication` once
9627 */
9628 function once(func) {
9629 var ran,
9630 result;
9631
9632 if (!isFunction(func)) {
9633 throw new TypeError;
9634 }
9635 return function() {
9636 if (ran) {
9637 return result;
9638 }
9639 ran = true;
9640 result = func.apply(this, arguments);
9641
9642 // clear the `func` variable so the function may be garbage collected
9643 func = null;
9644 return result;
9645 };
9646 }
9647
9648 /**
9649 * Creates a function that, when called, invokes `func` with any additional
9650 * `partial` arguments prepended to those provided to the new function. This
9651 * method is similar to `_.bind` except it does **not** alter the `this` binding.
9652 *
9653 * @static
9654 * @memberOf _
9655 * @category Functions
9656 * @param {Function} func The function to partially apply arguments to.
9657 * @param {...*} [arg] Arguments to be partially applied.
9658 * @returns {Function} Returns the new partially applied function.
9659 * @example
9660 *
9661 * var greet = function(greeting, name) { return greeting + ' ' + name; };
9662 * var hi = _.partial(greet, 'hi');
9663 * hi('fred');
9664 * // => 'hi fred'
9665 */
9666 function partial(func) {
9667 return createWrapper(func, 16, slice(arguments, 1));
9668 }
9669
9670 /**
9671 * This method is like `_.partial` except that `partial` arguments are
9672 * appended to those provided to the new function.
9673 *
9674 * @static
9675 * @memberOf _
9676 * @category Functions
9677 * @param {Function} func The function to partially apply arguments to.
9678 * @param {...*} [arg] Arguments to be partially applied.
9679 * @returns {Function} Returns the new partially applied function.
9680 * @example
9681 *
9682 * var defaultsDeep = _.partialRight(_.merge, _.defaults);
9683 *
9684 * var options = {
9685 * 'variable': 'data',
9686 * 'imports': { 'jq': $ }
9687 * };
9688 *
9689 * defaultsDeep(options, _.templateSettings);
9690 *
9691 * options.variable
9692 * // => 'data'
9693 *
9694 * options.imports
9695 * // => { '_': _, 'jq': $ }
9696 */
9697 function partialRight(func) {
9698 return createWrapper(func, 32, null, slice(arguments, 1));
9699 }
9700
9701 /**
9702 * Creates a function that, when executed, will only call the `func` function
9703 * at most once per every `wait` milliseconds. Provide an options object to
9704 * indicate that `func` should be invoked on the leading and/or trailing edge
9705 * of the `wait` timeout. Subsequent calls to the throttled function will
9706 * return the result of the last `func` call.
9707 *
9708 * Note: If `leading` and `trailing` options are `true` `func` will be called
9709 * on the trailing edge of the timeout only if the the throttled function is
9710 * invoked more than once during the `wait` timeout.
9711 *
9712 * @static
9713 * @memberOf _
9714 * @category Functions
9715 * @param {Function} func The function to throttle.
9716 * @param {number} wait The number of milliseconds to throttle executions to.
9717 * @param {Object} [options] The options object.
9718 * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
9719 * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
9720 * @returns {Function} Returns the new throttled function.
9721 * @example
9722 *
9723 * // avoid excessively updating the position while scrolling
9724 * var throttled = _.throttle(updatePosition, 100);
9725 * jQuery(window).on('scroll', throttled);
9726 *
9727 * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
9728 * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
9729 * 'trailing': false
9730 * }));
9731 */
9732 function throttle(func, wait, options) {
9733 var leading = true,
9734 trailing = true;
9735
9736 if (!isFunction(func)) {
9737 throw new TypeError;
9738 }
9739 if (options === false) {
9740 leading = false;
9741 } else if (isObject(options)) {
9742 leading = 'leading' in options ? options.leading : leading;
9743 trailing = 'trailing' in options ? options.trailing : trailing;
9744 }
9745 debounceOptions.leading = leading;
9746 debounceOptions.maxWait = wait;
9747 debounceOptions.trailing = trailing;
9748
9749 return debounce(func, wait, debounceOptions);
9750 }
9751
9752 /**
9753 * Creates a function that provides `value` to the wrapper function as its
9754 * first argument. Additional arguments provided to the function are appended
9755 * to those provided to the wrapper function. The wrapper is executed with
9756 * the `this` binding of the created function.
9757 *
9758 * @static
9759 * @memberOf _
9760 * @category Functions
9761 * @param {*} value The value to wrap.
9762 * @param {Function} wrapper The wrapper function.
9763 * @returns {Function} Returns the new function.
9764 * @example
9765 *
9766 * var p = _.wrap(_.escape, function(func, text) {
9767 * return '<p>' + func(text) + '</p>';
9768 * });
9769 *
9770 * p('Fred, Wilma, & Pebbles');
9771 * // => '<p>Fred, Wilma, &amp; Pebbles</p>'
9772 */
9773 function wrap(value, wrapper) {
9774 return createWrapper(wrapper, 16, [value]);
9775 }
9776
9777 /*--------------------------------------------------------------------------*/
9778
9779 /**
9780 * Creates a function that returns `value`.
9781 *
9782 * @static
9783 * @memberOf _
9784 * @category Utilities
9785 * @param {*} value The value to return from the new function.
9786 * @returns {Function} Returns the new function.
9787 * @example
9788 *
9789 * var object = { 'name': 'fred' };
9790 * var getter = _.constant(object);
9791 * getter() === object;
9792 * // => true
9793 */
9794 function constant(value) {
9795 return function() {
9796 return value;
9797 };
9798 }
9799
9800 /**
9801 * Produces a callback bound to an optional `thisArg`. If `func` is a property
9802 * name the created callback will return the property value for a given element.
9803 * If `func` is an object the created callback will return `true` for elements
9804 * that contain the equivalent object properties, otherwise it will return `false`.
9805 *
9806 * @static
9807 * @memberOf _
9808 * @category Utilities
9809 * @param {*} [func=identity] The value to convert to a callback.
9810 * @param {*} [thisArg] The `this` binding of the created callback.
9811 * @param {number} [argCount] The number of arguments the callback accepts.
9812 * @returns {Function} Returns a callback function.
9813 * @example
9814 *
9815 * var characters = [
9816 * { 'name': 'barney', 'age': 36 },
9817 * { 'name': 'fred', 'age': 40 }
9818 * ];
9819 *
9820 * // wrap to create custom callback shorthands
9821 * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
9822 * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
9823 * return !match ? func(callback, thisArg) : function(object) {
9824 * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
9825 * };
9826 * });
9827 *
9828 * _.filter(characters, 'age__gt38');
9829 * // => [{ 'name': 'fred', 'age': 40 }]
9830 */
9831 function createCallback(func, thisArg, argCount) {
9832 var type = typeof func;
9833 if (func == null || type == 'function') {
9834 return baseCreateCallback(func, thisArg, argCount);
9835 }
9836 // handle "_.pluck" style callback shorthands
9837 if (type != 'object') {
9838 return property(func);
9839 }
9840 var props = keys(func),
9841 key = props[0],
9842 a = func[key];
9843
9844 // handle "_.where" style callback shorthands
9845 if (props.length == 1 && a === a && !isObject(a)) {
9846 // fast path the common case of providing an object with a single
9847 // property containing a primitive value
9848 return function(object) {
9849 var b = object[key];
9850 return a === b && (a !== 0 || (1 / a == 1 / b));
9851 };
9852 }
9853 return function(object) {
9854 var length = props.length,
9855 result = false;
9856
9857 while (length--) {
9858 if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
9859 break;
9860 }
9861 }
9862 return result;
9863 };
9864 }
9865
9866 /**
9867 * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
9868 * corresponding HTML entities.
9869 *
9870 * @static
9871 * @memberOf _
9872 * @category Utilities
9873 * @param {string} string The string to escape.
9874 * @returns {string} Returns the escaped string.
9875 * @example
9876 *
9877 * _.escape('Fred, Wilma, & Pebbles');
9878 * // => 'Fred, Wilma, &amp; Pebbles'
9879 */
9880 function escape(string) {
9881 return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
9882 }
9883
9884 /**
9885 * This method returns the first argument provided to it.
9886 *
9887 * @static
9888 * @memberOf _
9889 * @category Utilities
9890 * @param {*} value Any value.
9891 * @returns {*} Returns `value`.
9892 * @example
9893 *
9894 * var object = { 'name': 'fred' };
9895 * _.identity(object) === object;
9896 * // => true
9897 */
9898 function identity(value) {
9899 return value;
9900 }
9901
9902 /**
9903 * Adds function properties of a source object to the destination object.
9904 * If `object` is a function methods will be added to its prototype as well.
9905 *
9906 * @static
9907 * @memberOf _
9908 * @category Utilities
9909 * @param {Function|Object} [object=lodash] object The destination object.
9910 * @param {Object} source The object of functions to add.
9911 * @param {Object} [options] The options object.
9912 * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
9913 * @example
9914 *
9915 * function capitalize(string) {
9916 * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
9917 * }
9918 *
9919 * _.mixin({ 'capitalize': capitalize });
9920 * _.capitalize('fred');
9921 * // => 'Fred'
9922 *
9923 * _('fred').capitalize().value();
9924 * // => 'Fred'
9925 *
9926 * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
9927 * _('fred').capitalize();
9928 * // => 'Fred'
9929 */
9930 function mixin(object, source, options) {
9931 var chain = true,
9932 methodNames = source && functions(source);
9933
9934 if (!source || (!options && !methodNames.length)) {
9935 if (options == null) {
9936 options = source;
9937 }
9938 ctor = lodashWrapper;
9939 source = object;
9940 object = lodash;
9941 methodNames = functions(source);
9942 }
9943 if (options === false) {
9944 chain = false;
9945 } else if (isObject(options) && 'chain' in options) {
9946 chain = options.chain;
9947 }
9948 var ctor = object,
9949 isFunc = isFunction(ctor);
9950
9951 forEach(methodNames, function(methodName) {
9952 var func = object[methodName] = source[methodName];
9953 if (isFunc) {
9954 ctor.prototype[methodName] = function() {
9955 var chainAll = this.__chain__,
9956 value = this.__wrapped__,
9957 args = [value];
9958
9959 push.apply(args, arguments);
9960 var result = func.apply(object, args);
9961 if (chain || chainAll) {
9962 if (value === result && isObject(result)) {
9963 return this;
9964 }
9965 result = new ctor(result);
9966 result.__chain__ = chainAll;
9967 }
9968 return result;
9969 };
9970 }
9971 });
9972 }
9973
9974 /**
9975 * Reverts the '_' variable to its previous value and returns a reference to
9976 * the `lodash` function.
9977 *
9978 * @static
9979 * @memberOf _
9980 * @category Utilities
9981 * @returns {Function} Returns the `lodash` function.
9982 * @example
9983 *
9984 * var lodash = _.noConflict();
9985 */
9986 function noConflict() {
9987 context._ = oldDash;
9988 return this;
9989 }
9990
9991 /**
9992 * A no-operation function.
9993 *
9994 * @static
9995 * @memberOf _
9996 * @category Utilities
9997 * @example
9998 *
9999 * var object = { 'name': 'fred' };
10000 * _.noop(object) === undefined;
10001 * // => true
10002 */
10003 function noop() {
10004 // no operation performed
10005 }
10006
10007 /**
10008 * Gets the number of milliseconds that have elapsed since the Unix epoch
10009 * (1 January 1970 00:00:00 UTC).
10010 *
10011 * @static
10012 * @memberOf _
10013 * @category Utilities
10014 * @example
10015 *
10016 * var stamp = _.now();
10017 * _.defer(function() { console.log(_.now() - stamp); });
10018 * // => logs the number of milliseconds it took for the deferred function to be called
10019 */
10020 var now = isNative(now = Date.now) && now || function() {
10021 return new Date().getTime();
10022 };
10023
10024 /**
10025 * Converts the given value into an integer of the specified radix.
10026 * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
10027 * `value` is a hexadecimal, in which case a `radix` of `16` is used.
10028 *
10029 * Note: This method avoids differences in native ES3 and ES5 `parseInt`
10030 * implementations. See http://es5.github.io/#E.
10031 *
10032 * @static
10033 * @memberOf _
10034 * @category Utilities
10035 * @param {string} value The value to parse.
10036 * @param {number} [radix] The radix used to interpret the value to parse.
10037 * @returns {number} Returns the new integer value.
10038 * @example
10039 *
10040 * _.parseInt('08');
10041 * // => 8
10042 */
10043 var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
10044 // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
10045 return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
10046 };
10047
10048 /**
10049 * Creates a "_.pluck" style function, which returns the `key` value of a
10050 * given object.
10051 *
10052 * @static
10053 * @memberOf _
10054 * @category Utilities
10055 * @param {string} key The name of the property to retrieve.
10056 * @returns {Function} Returns the new function.
10057 * @example
10058 *
10059 * var characters = [
10060 * { 'name': 'fred', 'age': 40 },
10061 * { 'name': 'barney', 'age': 36 }
10062 * ];
10063 *
10064 * var getName = _.property('name');
10065 *
10066 * _.map(characters, getName);
10067 * // => ['barney', 'fred']
10068 *
10069 * _.sortBy(characters, getName);
10070 * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }]
10071 */
10072 function property(key) {
10073 return function(object) {
10074 return object[key];
10075 };
10076 }
10077
10078 /**
10079 * Produces a random number between `min` and `max` (inclusive). If only one
10080 * argument is provided a number between `0` and the given number will be
10081 * returned. If `floating` is truey or either `min` or `max` are floats a
10082 * floating-point number will be returned instead of an integer.
10083 *
10084 * @static
10085 * @memberOf _
10086 * @category Utilities
10087 * @param {number} [min=0] The minimum possible value.
10088 * @param {number} [max=1] The maximum possible value.
10089 * @param {boolean} [floating=false] Specify returning a floating-point number.
10090 * @returns {number} Returns a random number.
10091 * @example
10092 *
10093 * _.random(0, 5);
10094 * // => an integer between 0 and 5
10095 *
10096 * _.random(5);
10097 * // => also an integer between 0 and 5
10098 *
10099 * _.random(5, true);
10100 * // => a floating-point number between 0 and 5
10101 *
10102 * _.random(1.2, 5.2);
10103 * // => a floating-point number between 1.2 and 5.2
10104 */
10105 function random(min, max, floating) {
10106 var noMin = min == null,
10107 noMax = max == null;
10108
10109 if (floating == null) {
10110 if (typeof min == 'boolean' && noMax) {
10111 floating = min;
10112 min = 1;
10113 }
10114 else if (!noMax && typeof max == 'boolean') {
10115 floating = max;
10116 noMax = true;
10117 }
10118 }
10119 if (noMin && noMax) {
10120 max = 1;
10121 }
10122 min = +min || 0;
10123 if (noMax) {
10124 max = min;
10125 min = 0;
10126 } else {
10127 max = +max || 0;
10128 }
10129 if (floating || min % 1 || max % 1) {
10130 var rand = nativeRandom();
10131 return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
10132 }
10133 return baseRandom(min, max);
10134 }
10135
10136 /**
10137 * Resolves the value of property `key` on `object`. If `key` is a function
10138 * it will be invoked with the `this` binding of `object` and its result returned,
10139 * else the property value is returned. If `object` is falsey then `undefined`
10140 * is returned.
10141 *
10142 * @static
10143 * @memberOf _
10144 * @category Utilities
10145 * @param {Object} object The object to inspect.
10146 * @param {string} key The name of the property to resolve.
10147 * @returns {*} Returns the resolved value.
10148 * @example
10149 *
10150 * var object = {
10151 * 'cheese': 'crumpets',
10152 * 'stuff': function() {
10153 * return 'nonsense';
10154 * }
10155 * };
10156 *
10157 * _.result(object, 'cheese');
10158 * // => 'crumpets'
10159 *
10160 * _.result(object, 'stuff');
10161 * // => 'nonsense'
10162 */
10163 function result(object, key) {
10164 if (object) {
10165 var value = object[key];
10166 return isFunction(value) ? object[key]() : value;
10167 }
10168 }
10169
10170 /**
10171 * A micro-templating method that handles arbitrary delimiters, preserves
10172 * whitespace, and correctly escapes quotes within interpolated code.
10173 *
10174 * Note: In the development build, `_.template` utilizes sourceURLs for easier
10175 * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
10176 *
10177 * For more information on precompiling templates see:
10178 * http://lodash.com/custom-builds
10179 *
10180 * For more information on Chrome extension sandboxes see:
10181 * http://developer.chrome.com/stable/extensions/sandboxingEval.html
10182 *
10183 * @static
10184 * @memberOf _
10185 * @category Utilities
10186 * @param {string} text The template text.
10187 * @param {Object} data The data object used to populate the text.
10188 * @param {Object} [options] The options object.
10189 * @param {RegExp} [options.escape] The "escape" delimiter.
10190 * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
10191 * @param {Object} [options.imports] An object to import into the template as local variables.
10192 * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
10193 * @param {string} [sourceURL] The sourceURL of the template's compiled source.
10194 * @param {string} [variable] The data object variable name.
10195 * @returns {Function|string} Returns a compiled function when no `data` object
10196 * is given, else it returns the interpolated text.
10197 * @example
10198 *
10199 * // using the "interpolate" delimiter to create a compiled template
10200 * var compiled = _.template('hello <%= name %>');
10201 * compiled({ 'name': 'fred' });
10202 * // => 'hello fred'
10203 *
10204 * // using the "escape" delimiter to escape HTML in data property values
10205 * _.template('<b><%- value %></b>', { 'value': '<script>' });
10206 * // => '<b>&lt;script&gt;</b>'
10207 *
10208 * // using the "evaluate" delimiter to generate HTML
10209 * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
10210 * _.template(list, { 'people': ['fred', 'barney'] });
10211 * // => '<li>fred</li><li>barney</li>'
10212 *
10213 * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
10214 * _.template('hello ${ name }', { 'name': 'pebbles' });
10215 * // => 'hello pebbles'
10216 *
10217 * // using the internal `print` function in "evaluate" delimiters
10218 * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
10219 * // => 'hello barney!'
10220 *
10221 * // using a custom template delimiters
10222 * _.templateSettings = {
10223 * 'interpolate': /{{([\s\S]+?)}}/g
10224 * };
10225 *
10226 * _.template('hello {{ name }}!', { 'name': 'mustache' });
10227 * // => 'hello mustache!'
10228 *
10229 * // using the `imports` option to import jQuery
10230 * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
10231 * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
10232 * // => '<li>fred</li><li>barney</li>'
10233 *
10234 * // using the `sourceURL` option to specify a custom sourceURL for the template
10235 * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
10236 * compiled(data);
10237 * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
10238 *
10239 * // using the `variable` option to ensure a with-statement isn't used in the compiled template
10240 * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
10241 * compiled.source;
10242 * // => function(data) {
10243 * var __t, __p = '', __e = _.escape;
10244 * __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
10245 * return __p;
10246 * }
10247 *
10248 * // using the `source` property to inline compiled templates for meaningful
10249 * // line numbers in error messages and a stack trace
10250 * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
10251 * var JST = {\
10252 * "main": ' + _.template(mainText).source + '\
10253 * };\
10254 * ');
10255 */
10256 function template(text, data, options) {
10257 // based on John Resig's `tmpl` implementation
10258 // http://ejohn.org/blog/javascript-micro-templating/
10259 // and Laura Doktorova's doT.js
10260 // https://github.com/olado/doT
10261 var settings = lodash.templateSettings;
10262 text = String(text || '');
10263
10264 // avoid missing dependencies when `iteratorTemplate` is not defined
10265 options = defaults({}, options, settings);
10266
10267 var imports = defaults({}, options.imports, settings.imports),
10268 importsKeys = keys(imports),
10269 importsValues = values(imports);
10270
10271 var isEvaluating,
10272 index = 0,
10273 interpolate = options.interpolate || reNoMatch,
10274 source = "__p += '";
10275
10276 // compile the regexp to match each delimiter
10277 var reDelimiters = RegExp(
10278 (options.escape || reNoMatch).source + '|' +
10279 interpolate.source + '|' +
10280 (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
10281 (options.evaluate || reNoMatch).source + '|$'
10282 , 'g');
10283
10284 text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
10285 interpolateValue || (interpolateValue = esTemplateValue);
10286
10287 // escape characters that cannot be included in string literals
10288 source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
10289
10290 // replace delimiters with snippets
10291 if (escapeValue) {
10292 source += "' +\n__e(" + escapeValue + ") +\n'";
10293 }
10294 if (evaluateValue) {
10295 isEvaluating = true;
10296 source += "';\n" + evaluateValue + ";\n__p += '";
10297 }
10298 if (interpolateValue) {
10299 source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
10300 }
10301 index = offset + match.length;
10302
10303 // the JS engine embedded in Adobe products requires returning the `match`
10304 // string in order to produce the correct `offset` value
10305 return match;
10306 });
10307
10308 source += "';\n";
10309
10310 // if `variable` is not specified, wrap a with-statement around the generated
10311 // code to add the data object to the top of the scope chain
10312 var variable = options.variable,
10313 hasVariable = variable;
10314
10315 if (!hasVariable) {
10316 variable = 'obj';
10317 source = 'with (' + variable + ') {\n' + source + '\n}\n';
10318 }
10319 // cleanup code by stripping empty strings
10320 source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
10321 .replace(reEmptyStringMiddle, '$1')
10322 .replace(reEmptyStringTrailing, '$1;');
10323
10324 // frame code as the function body
10325 source = 'function(' + variable + ') {\n' +
10326 (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
10327 "var __t, __p = '', __e = _.escape" +
10328 (isEvaluating
10329 ? ', __j = Array.prototype.join;\n' +
10330 "function print() { __p += __j.call(arguments, '') }\n"
10331 : ';\n'
10332 ) +
10333 source +
10334 'return __p\n}';
10335
10336 // Use a sourceURL for easier debugging.
10337 // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
10338 var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
10339
10340 try {
10341 var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
10342 } catch(e) {
10343 e.source = source;
10344 throw e;
10345 }
10346 if (data) {
10347 return result(data);
10348 }
10349 // provide the compiled function's source by its `toString` method, in
10350 // supported environments, or the `source` property as a convenience for
10351 // inlining compiled templates during the build process
10352 result.source = source;
10353 return result;
10354 }
10355
10356 /**
10357 * Executes the callback `n` times, returning an array of the results
10358 * of each callback execution. The callback is bound to `thisArg` and invoked
10359 * with one argument; (index).
10360 *
10361 * @static
10362 * @memberOf _
10363 * @category Utilities
10364 * @param {number} n The number of times to execute the callback.
10365 * @param {Function} callback The function called per iteration.
10366 * @param {*} [thisArg] The `this` binding of `callback`.
10367 * @returns {Array} Returns an array of the results of each `callback` execution.
10368 * @example
10369 *
10370 * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
10371 * // => [3, 6, 4]
10372 *
10373 * _.times(3, function(n) { mage.castSpell(n); });
10374 * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
10375 *
10376 * _.times(3, function(n) { this.cast(n); }, mage);
10377 * // => also calls `mage.castSpell(n)` three times
10378 */
10379 function times(n, callback, thisArg) {
10380 n = (n = +n) > -1 ? n : 0;
10381 var index = -1,
10382 result = Array(n);
10383
10384 callback = baseCreateCallback(callback, thisArg, 1);
10385 while (++index < n) {
10386 result[index] = callback(index);
10387 }
10388 return result;
10389 }
10390
10391 /**
10392 * The inverse of `_.escape` this method converts the HTML entities
10393 * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to their
10394 * corresponding characters.
10395 *
10396 * @static
10397 * @memberOf _
10398 * @category Utilities
10399 * @param {string} string The string to unescape.
10400 * @returns {string} Returns the unescaped string.
10401 * @example
10402 *
10403 * _.unescape('Fred, Barney &amp; Pebbles');
10404 * // => 'Fred, Barney & Pebbles'
10405 */
10406 function unescape(string) {
10407 return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
10408 }
10409
10410 /**
10411 * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
10412 *
10413 * @static
10414 * @memberOf _
10415 * @category Utilities
10416 * @param {string} [prefix] The value to prefix the ID with.
10417 * @returns {string} Returns the unique ID.
10418 * @example
10419 *
10420 * _.uniqueId('contact_');
10421 * // => 'contact_104'
10422 *
10423 * _.uniqueId();
10424 * // => '105'
10425 */
10426 function uniqueId(prefix) {
10427 var id = ++idCounter;
10428 return String(prefix == null ? '' : prefix) + id;
10429 }
10430
10431 /*--------------------------------------------------------------------------*/
10432
10433 /**
10434 * Creates a `lodash` object that wraps the given value with explicit
10435 * method chaining enabled.
10436 *
10437 * @static
10438 * @memberOf _
10439 * @category Chaining
10440 * @param {*} value The value to wrap.
10441 * @returns {Object} Returns the wrapper object.
10442 * @example
10443 *
10444 * var characters = [
10445 * { 'name': 'barney', 'age': 36 },
10446 * { 'name': 'fred', 'age': 40 },
10447 * { 'name': 'pebbles', 'age': 1 }
10448 * ];
10449 *
10450 * var youngest = _.chain(characters)
10451 * .sortBy('age')
10452 * .map(function(chr) { return chr.name + ' is ' + chr.age; })
10453 * .first()
10454 * .value();
10455 * // => 'pebbles is 1'
10456 */
10457 function chain(value) {
10458 value = new lodashWrapper(value);
10459 value.__chain__ = true;
10460 return value;
10461 }
10462
10463 /**
10464 * Invokes `interceptor` with the `value` as the first argument and then
10465 * returns `value`. The purpose of this method is to "tap into" a method
10466 * chain in order to perform operations on intermediate results within
10467 * the chain.
10468 *
10469 * @static
10470 * @memberOf _
10471 * @category Chaining
10472 * @param {*} value The value to provide to `interceptor`.
10473 * @param {Function} interceptor The function to invoke.
10474 * @returns {*} Returns `value`.
10475 * @example
10476 *
10477 * _([1, 2, 3, 4])
10478 * .tap(function(array) { array.pop(); })
10479 * .reverse()
10480 * .value();
10481 * // => [3, 2, 1]
10482 */
10483 function tap(value, interceptor) {
10484 interceptor(value);
10485 return value;
10486 }
10487
10488 /**
10489 * Enables explicit method chaining on the wrapper object.
10490 *
10491 * @name chain
10492 * @memberOf _
10493 * @category Chaining
10494 * @returns {*} Returns the wrapper object.
10495 * @example
10496 *
10497 * var characters = [
10498 * { 'name': 'barney', 'age': 36 },
10499 * { 'name': 'fred', 'age': 40 }
10500 * ];
10501 *
10502 * // without explicit chaining
10503 * _(characters).first();
10504 * // => { 'name': 'barney', 'age': 36 }
10505 *
10506 * // with explicit chaining
10507 * _(characters).chain()
10508 * .first()
10509 * .pick('age')
10510 * .value();
10511 * // => { 'age': 36 }
10512 */
10513 function wrapperChain() {
10514 this.__chain__ = true;
10515 return this;
10516 }
10517
10518 /**
10519 * Produces the `toString` result of the wrapped value.
10520 *
10521 * @name toString
10522 * @memberOf _
10523 * @category Chaining
10524 * @returns {string} Returns the string result.
10525 * @example
10526 *
10527 * _([1, 2, 3]).toString();
10528 * // => '1,2,3'
10529 */
10530 function wrapperToString() {
10531 return String(this.__wrapped__);
10532 }
10533
10534 /**
10535 * Extracts the wrapped value.
10536 *
10537 * @name valueOf
10538 * @memberOf _
10539 * @alias value
10540 * @category Chaining
10541 * @returns {*} Returns the wrapped value.
10542 * @example
10543 *
10544 * _([1, 2, 3]).valueOf();
10545 * // => [1, 2, 3]
10546 */
10547 function wrapperValueOf() {
10548 return this.__wrapped__;
10549 }
10550
10551 /*--------------------------------------------------------------------------*/
10552
10553 // add functions that return wrapped values when chaining
10554 lodash.after = after;
10555 lodash.assign = assign;
10556 lodash.at = at;
10557 lodash.bind = bind;
10558 lodash.bindAll = bindAll;
10559 lodash.bindKey = bindKey;
10560 lodash.chain = chain;
10561 lodash.compact = compact;
10562 lodash.compose = compose;
10563 lodash.constant = constant;
10564 lodash.countBy = countBy;
10565 lodash.create = create;
10566 lodash.createCallback = createCallback;
10567 lodash.curry = curry;
10568 lodash.debounce = debounce;
10569 lodash.defaults = defaults;
10570 lodash.defer = defer;
10571 lodash.delay = delay;
10572 lodash.difference = difference;
10573 lodash.filter = filter;
10574 lodash.flatten = flatten;
10575 lodash.forEach = forEach;
10576 lodash.forEachRight = forEachRight;
10577 lodash.forIn = forIn;
10578 lodash.forInRight = forInRight;
10579 lodash.forOwn = forOwn;
10580 lodash.forOwnRight = forOwnRight;
10581 lodash.functions = functions;
10582 lodash.groupBy = groupBy;
10583 lodash.indexBy = indexBy;
10584 lodash.initial = initial;
10585 lodash.intersection = intersection;
10586 lodash.invert = invert;
10587 lodash.invoke = invoke;
10588 lodash.keys = keys;
10589 lodash.map = map;
10590 lodash.mapValues = mapValues;
10591 lodash.max = max;
10592 lodash.memoize = memoize;
10593 lodash.merge = merge;
10594 lodash.min = min;
10595 lodash.omit = omit;
10596 lodash.once = once;
10597 lodash.pairs = pairs;
10598 lodash.partial = partial;
10599 lodash.partialRight = partialRight;
10600 lodash.pick = pick;
10601 lodash.pluck = pluck;
10602 lodash.property = property;
10603 lodash.pull = pull;
10604 lodash.range = range;
10605 lodash.reject = reject;
10606 lodash.remove = remove;
10607 lodash.rest = rest;
10608 lodash.shuffle = shuffle;
10609 lodash.sortBy = sortBy;
10610 lodash.tap = tap;
10611 lodash.throttle = throttle;
10612 lodash.times = times;
10613 lodash.toArray = toArray;
10614 lodash.transform = transform;
10615 lodash.union = union;
10616 lodash.uniq = uniq;
10617 lodash.values = values;
10618 lodash.where = where;
10619 lodash.without = without;
10620 lodash.wrap = wrap;
10621 lodash.xor = xor;
10622 lodash.zip = zip;
10623 lodash.zipObject = zipObject;
10624
10625 // add aliases
10626 lodash.collect = map;
10627 lodash.drop = rest;
10628 lodash.each = forEach;
10629 lodash.eachRight = forEachRight;
10630 lodash.extend = assign;
10631 lodash.methods = functions;
10632 lodash.object = zipObject;
10633 lodash.select = filter;
10634 lodash.tail = rest;
10635 lodash.unique = uniq;
10636 lodash.unzip = zip;
10637
10638 // add functions to `lodash.prototype`
10639 mixin(lodash);
10640
10641 /*--------------------------------------------------------------------------*/
10642
10643 // add functions that return unwrapped values when chaining
10644 lodash.clone = clone;
10645 lodash.cloneDeep = cloneDeep;
10646 lodash.contains = contains;
10647 lodash.escape = escape;
10648 lodash.every = every;
10649 lodash.find = find;
10650 lodash.findIndex = findIndex;
10651 lodash.findKey = findKey;
10652 lodash.findLast = findLast;
10653 lodash.findLastIndex = findLastIndex;
10654 lodash.findLastKey = findLastKey;
10655 lodash.has = has;
10656 lodash.identity = identity;
10657 lodash.indexOf = indexOf;
10658 lodash.isArguments = isArguments;
10659 lodash.isArray = isArray;
10660 lodash.isBoolean = isBoolean;
10661 lodash.isDate = isDate;
10662 lodash.isElement = isElement;
10663 lodash.isEmpty = isEmpty;
10664 lodash.isEqual = isEqual;
10665 lodash.isFinite = isFinite;
10666 lodash.isFunction = isFunction;
10667 lodash.isNaN = isNaN;
10668 lodash.isNull = isNull;
10669 lodash.isNumber = isNumber;
10670 lodash.isObject = isObject;
10671 lodash.isPlainObject = isPlainObject;
10672 lodash.isRegExp = isRegExp;
10673 lodash.isString = isString;
10674 lodash.isUndefined = isUndefined;
10675 lodash.lastIndexOf = lastIndexOf;
10676 lodash.mixin = mixin;
10677 lodash.noConflict = noConflict;
10678 lodash.noop = noop;
10679 lodash.now = now;
10680 lodash.parseInt = parseInt;
10681 lodash.random = random;
10682 lodash.reduce = reduce;
10683 lodash.reduceRight = reduceRight;
10684 lodash.result = result;
10685 lodash.runInContext = runInContext;
10686 lodash.size = size;
10687 lodash.some = some;
10688 lodash.sortedIndex = sortedIndex;
10689 lodash.template = template;
10690 lodash.unescape = unescape;
10691 lodash.uniqueId = uniqueId;
10692
10693 // add aliases
10694 lodash.all = every;
10695 lodash.any = some;
10696 lodash.detect = find;
10697 lodash.findWhere = find;
10698 lodash.foldl = reduce;
10699 lodash.foldr = reduceRight;
10700 lodash.include = contains;
10701 lodash.inject = reduce;
10702
10703 mixin(function() {
10704 var source = {}
10705 forOwn(lodash, function(func, methodName) {
10706 if (!lodash.prototype[methodName]) {
10707 source[methodName] = func;
10708 }
10709 });
10710 return source;
10711 }(), false);
10712
10713 /*--------------------------------------------------------------------------*/
10714
10715 // add functions capable of returning wrapped and unwrapped values when chaining
10716 lodash.first = first;
10717 lodash.last = last;
10718 lodash.sample = sample;
10719
10720 // add aliases
10721 lodash.take = first;
10722 lodash.head = first;
10723
10724 forOwn(lodash, function(func, methodName) {
10725 var callbackable = methodName !== 'sample';
10726 if (!lodash.prototype[methodName]) {
10727 lodash.prototype[methodName]= function(n, guard) {
10728 var chainAll = this.__chain__,
10729 result = func(this.__wrapped__, n, guard);
10730
10731 return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
10732 ? result
10733 : new lodashWrapper(result, chainAll);
10734 };
10735 }
10736 });
10737
10738 /*--------------------------------------------------------------------------*/
10739
10740 /**
10741 * The semantic version number.
10742 *
10743 * @static
10744 * @memberOf _
10745 * @type string
10746 */
10747 lodash.VERSION = '2.4.1';
10748
10749 // add "Chaining" functions to the wrapper
10750 lodash.prototype.chain = wrapperChain;
10751 lodash.prototype.toString = wrapperToString;
10752 lodash.prototype.value = wrapperValueOf;
10753 lodash.prototype.valueOf = wrapperValueOf;
10754
10755 // add `Array` functions that return unwrapped values
10756 forEach(['join', 'pop', 'shift'], function(methodName) {
10757 var func = arrayRef[methodName];
10758 lodash.prototype[methodName] = function() {
10759 var chainAll = this.__chain__,
10760 result = func.apply(this.__wrapped__, arguments);
10761
10762 return chainAll
10763 ? new lodashWrapper(result, chainAll)
10764 : result;
10765 };
10766 });
10767
10768 // add `Array` functions that return the existing wrapped value
10769 forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
10770 var func = arrayRef[methodName];
10771 lodash.prototype[methodName] = function() {
10772 func.apply(this.__wrapped__, arguments);
10773 return this;
10774 };
10775 });
10776
10777 // add `Array` functions that return new wrapped values
10778 forEach(['concat', 'slice', 'splice'], function(methodName) {
10779 var func = arrayRef[methodName];
10780 lodash.prototype[methodName] = function() {
10781 return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
10782 };
10783 });
10784
10785 return lodash;
10786 }
10787
10788 /*--------------------------------------------------------------------------*/
10789
10790 // expose Lo-Dash
10791 var _ = runInContext();
10792
10793 // some AMD build optimizers like r.js check for condition patterns like the following:
10794 if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
10795 // Expose Lo-Dash to the global object even when an AMD loader is present in
10796 // case Lo-Dash is loaded with a RequireJS shim config.
10797 // See http://requirejs.org/docs/api.html#config-shim
10798 root._ = _;
10799
10800 // define as an anonymous module so, through path mapping, it can be
10801 // referenced as the "underscore" module
10802 define(function() {
10803 return _;
10804 });
10805 }
10806 // check for `exports` after `define` in case a build optimizer adds an `exports` object
10807 else if (freeExports && freeModule) {
10808 // in Node.js or RingoJS
10809 if (moduleExports) {
10810 (freeModule.exports = _)._ = _;
10811 }
10812 // in Narwhal or Rhino -require
10813 else {
10814 freeExports._ = _;
10815 }
10816 }
10817 else {
10818 // in a browser or Rhino
10819 root._ = _;
10820 }
10821}.call(this));
10822
10823}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
10824},{}]},{},[1])(1)
10825});