[Pkg-javascript-commits] [node-lodash] 01/01: Update to 3.0
Valentin ovd
valentinovd-guest at moszumanska.debian.org
Fri Jan 23 18:32:06 UTC 2015
This is an automated email from the git hooks/post-receive script.
valentinovd-guest pushed a commit to branch master
in repository node-lodash.
commit d2318ac9b3e53c4d6d2cbbdd622beb415b0c5c82
Author: vovd <vovd.tanglu at gmail.com>
Date: Fri Jan 23 19:31:24 2015 +0100
Update to 3.0
---
.travis.yml | 79 -
CONTRIBUTING.md | 14 +-
LICENSE.txt | 6 +-
README.md | 165 +-
bower.json | 11 +-
component.json | 12 +-
debian/build/lodash.js | 10784 ++++++++++++++
debian/build/lodash.min.js | 10 +
debian/changelog | 6 +
debian/copyright | 37 +-
debian/files | 2 +
debian/libjs-lodash.debhelper.log | 19 +
debian/libjs-lodash.substvars | 1 +
debian/libjs-lodash/DEBIAN/control | 13 +
debian/libjs-lodash/DEBIAN/md5sums | 4 +
.../usr/share/doc/libjs-lodash/changelog.Debian.gz | Bin 0 -> 307 bytes
.../usr/share/doc/libjs-lodash}/copyright | 37 +-
debian/libjs-lodash/usr/share/javascript/lodash.js | 10784 ++++++++++++++
.../usr/share/javascript/lodash.min.js | 10 +
debian/node-lodash.debhelper.log | 19 +
debian/node-lodash.substvars | 1 +
debian/node-lodash/DEBIAN/control | 14 +
debian/node-lodash/DEBIAN/md5sums | 4 +
debian/node-lodash/usr/lib/nodejs/lodash.js | 10784 ++++++++++++++
.../usr/share/doc/node-lodash/README.md | 16 +
.../usr/share/doc/node-lodash/changelog.Debian.gz | Bin 0 -> 307 bytes
.../usr/share/doc/node-lodash}/copyright | 37 +-
doc/README.md | 6642 +++++----
lodash.js | 13861 +++++++++++-------
lodash.src.js | 11020 +++++++++++++++
package.json | 55 +-
perf/asset/perf-ui.js | 63 +-
perf/index.html | 8 +-
perf/perf.js | 801 +-
perf/run-perf.sh | 4 +-
test/asset/set.js | 146 +
test/asset/test-ui.js | 129 +-
test/asset/weakmap.js | 91 +
test/asset/worker.js | 8 +-
test/backbone.html | 172 +-
test/index.html | 460 +-
test/run-test.sh | 12 +-
test/saucelabs.js | 1216 +-
test/test.js | 14080 +++++++++++++------
test/underscore.html | 181 +-
vendor/backbone/LICENSE | 2 +-
vendor/backbone/backbone.js | 163 +-
vendor/backbone/test/collection.js | 95 +-
vendor/backbone/test/environment.js | 10 +-
vendor/backbone/test/events.js | 2 +-
vendor/backbone/test/model.js | 20 +
vendor/backbone/test/router.js | 105 +-
vendor/backbone/test/view.js | 42 +-
vendor/benchmark.js/LICENSE.txt | 4 +-
vendor/benchmark.js/benchmark.js | 472 +-
vendor/curl/LICENSE.txt | 24 -
vendor/docdown/LICENSE.txt | 20 -
vendor/docdown/docdown.php | 38 -
vendor/docdown/src/DocDown/Alias.php | 226 -
vendor/docdown/src/DocDown/Entry.php | 452 -
vendor/docdown/src/DocDown/MarkdownGenerator.php | 648 -
vendor/dojo/LICENSE | 195 -
vendor/dojo/dojo.js | 1997 ---
vendor/firebug-lite/skin/xp/textEditorBorders.gif | Bin 117 -> 0 bytes
vendor/firebug-lite/skin/xp/textEditorCorners.gif | Bin 1821 -> 0 bytes
vendor/jquery/MIT-LICENSE.txt | 21 -
vendor/jquery/jquery.js | 9440 -------------
vendor/json-js/json2.js | 27 +-
vendor/platform.js/LICENSE.txt | 20 -
vendor/platform.js/platform.js | 1007 --
vendor/qunit-extras/LICENSE.txt | 20 -
vendor/qunit-extras/qunit-extras.js | 570 -
vendor/qunit/MIT-LICENSE.txt | 21 -
vendor/qunit/qunit/qunit.css | 244 -
vendor/qunit/qunit/qunit.js | 2152 ---
vendor/requirejs/LICENSE | 58 -
vendor/requirejs/require.js | 2054 ---
vendor/underscore/LICENSE | 2 +-
vendor/underscore/test/arrays.js | 322 +-
vendor/underscore/test/chaining.js | 39 +-
vendor/underscore/test/collections.js | 478 +-
vendor/underscore/test/functions.js | 342 +-
vendor/underscore/test/objects.js | 619 +-
vendor/underscore/test/utility.js | 205 +-
vendor/underscore/underscore-min.js | 6 +-
vendor/underscore/underscore.js | 1025 +-
86 files changed, 71421 insertions(+), 33584 deletions(-)
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index d47b4bc..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,79 +0,0 @@
-language: node_js
-node_js:
- - "0.6"
- - "0.8"
- - "0.10"
-env:
- global:
- - BIN="node" BUILD=false COMPAT=false MAKE=false OPTION="" SAUCE_LABS=false SAUCE_USERNAME="lodash"
- - secure: "tg1JFsIFnxzLaTboFPOnm+aJCuMm5+JdhLlESlqg9x3fwro++7KCnwHKLNovhchaPe4otC43ZMB/nfWhDnDm11dKbm/V6HlTkED+dadTsaLxVDg6J+7yK41QhokBPJOxLV78iDaNaAQVYEirAgZ0yn8kFubxmNKV+bpCGQNc9yU="
- matrix:
- - BUILD="compat"
- - BUILD="modern"
- - BUILD="legacy"
- - BUILD="mobile"
- - BIN="phantomjs" BUILD="compat"
- - BIN="phantomjs" BUILD="legacy"
- - BIN="phantomjs" BUILD="mobile"
-matrix:
- include:
- - node_js: "0.10"
- env: BIN="istanbul"
- - node_js: "0.10"
- env: BIN="narwhal" BUILD="compat"
- - node_js: "0.10"
- env: BIN="narwhal" BUILD="legacy"
- - node_js: "0.10"
- env: BIN="rhino" BUILD="compat"
- - node_js: "0.10"
- env: BIN="rhino" BUILD="legacy"
- - node_js: "0.10"
- env: BIN="rhino" BUILD="compat" OPTION="-require"
- - node_js: "0.10"
- env: BIN="rhino" BUILD="legacy" OPTION="-require"
- - node_js: "0.10"
- env: BIN="ringo" BUILD="compat"
- - node_js: "0.10"
- env: BIN="ringo" BUILD="legacy"
- - node_js: "0.8"
- env: SAUCE_LABS=true BUILD="compat"
- - node_js: "0.8"
- env: SAUCE_LABS=true BUILD="modern"
- - node_js: "0.8"
- env: SAUCE_LABS=true BUILD="legacy"
- - node_js: "0.8"
- env: SAUCE_LABS=true BUILD="mobile"
- - node_js: "0.8"
- env: SAUCE_LABS=true BUILD="underscore"
-git:
- depth: 10
-branches:
- only:
- - master
-before_install:
- - "([ $BUILD == 'legacy' ] || [ $BUILD == 'mobile' ] || [ $BUILD == 'modern' ]) && MAKE=true || true"
- - "([ $BUILD == 'compat' ] || [ $BUILD == 'legacy' ]) && COMPAT=true || true"
- - "[ $SAUCE_LABS != false ] && npm i ecstatic@\"~0.4.0\" request@\"~2.27.0\" sauce-tunnel@\"~1.1.0\" || true"
- - "[ $BIN == 'istanbul' ] && npm i -g coveralls@\"~2.5.0\" istanbul@\"~0.1.0\" || true"
- - "[ $BIN == 'narwhal' ] && wget https://github.com/280north/narwhal/archive/v0.3.2.zip && sudo unzip v0.3.2 -d /opt/ && rm v0.3.2.zip || true"
- - "[ $BIN == 'narwhal' ] && sudo ln -s /opt/narwhal-0.3.2/bin/narwhal /usr/local/bin/narwhal && sudo chmod +x /usr/local/bin/narwhal || true"
- - "[ $BIN == 'rhino' ] && sudo mkdir /opt/rhino-1.7R5 && sudo wget -O /opt/rhino-1.7R5/js.jar https://oss.sonatype.org/content/repositories/snapshots/org/mozilla/rhino/1.7R5-SNAPSHOT/rhino-1.7R5-20120629.144839-4.jar || true"
- - "[ $BIN == 'rhino' ] && echo -e '#!/bin/sh\\njava -jar /opt/rhino-1.7R5/js.jar $@' | sudo tee /usr/local/bin/rhino && sudo chmod +x /usr/local/bin/rhino || true"
- - "[ $BIN == 'ringo' ] && wget http://ringojs.org/downloads/ringojs-0.9.zip && sudo unzip ringojs-0.9 -d /opt && rm ringojs-0.9.zip || true"
- - "[ $BIN == 'ringo' ] && sudo ln -s /opt/ringojs-0.9/bin/ringo /usr/local/bin/ringo && sudo chmod +x /usr/local/bin/ringo || true"
- - "[ $MAKE != false ] && git clone --depth=10 --branch=master git://github.com/lodash/lodash-cli.git ./node_modules/lodash-cli || true"
- - "[ $MAKE != false ] && mkdir ./node_modules/lodash-cli/node_modules && cd ./node_modules/lodash-cli/node_modules/ && ln -s ../../../ ./lodash && cd ../ && npm i . && cd ../../ || true"
- - "[ $MAKE != false ] && node ./node_modules/lodash-cli/bin/lodash $BUILD -o ./dist/lodash.$BUILD.js || true"
-script:
- - "[ $BIN == 'istanbul' ] && $BIN cover -x \"**/vendor/**\" --report lcovonly ./test/test.js -- ./dist/lodash.js && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage || true"
- - "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || cd ./test"
- - "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || $BIN $OPTION ./test.js ../dist/lodash.$BUILD.js"
- - "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || $BIN $OPTION ./test.js ../dist/lodash.$BUILD.min.js"
- - "([ $SAUCE_LABS == false ] || [ $BUILD == 'underscore' ]) && true || node ./test/saucelabs.js runner=\"test/index.html?build=lodash-$BUILD\" tags=\"$BUILD,production\""
- - "([ $SAUCE_LABS == false ] || [ $COMPAT == false ]) && true || node ./test/saucelabs.js runner=\"test/index.html?build=lodash-$BUILD\" tags=\"$BUILD,production,ie-compat\" compatMode=7"
- - "([ $SAUCE_LABS == false ] || [ $BUILD == 'underscore' ]) && true || node ./test/saucelabs.js runner=\"test/index.html?build=../dist/lodash.$BUILD.js\" tags=\"$BUILD,development\""
- - "([ $SAUCE_LABS == false ] || [ $COMPAT == false ]) && true || node ./test/saucelabs.js runner=\"test/index.html?build=../dist/lodash.$BUILD.js\" tags=\"$BUILD,development,ie-compat\" compatMode=7"
- - "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=lodash-$BUILD\" tags=\"$BUILD,production,backbone\""
- - "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.$BUILD.js\" tags=\"$BUILD,development,backbone\""
- - "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=lodash-$BUILD\" tags=\"$BUILD,production,underscore\""
- - "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../dist/lodash.$BUILD.js\" tags=\"$BUILD,development,underscore\""
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6aee273..17d88b9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,14 +1,16 @@
# Contributing to Lo-Dash
-If you’d like to contribute a feature or bug fix, you can [fork](https://help.github.com/articles/fork-a-repo) Lo-Dash, commit your changes, and [send a pull request](https://help.github.com/articles/using-pull-requests).
+If you’d like to contribute a feature or bug fix, you can [fork](https://help.github.com/articles/fork-a-repo/) Lo-Dash, commit your changes, & [send a pull request](https://help.github.com/articles/using-pull-requests/).
Please make sure to [search the issue tracker](https://github.com/lodash/lodash/issues) first; your issue may have already been discussed or fixed in `master`.
## Tests
Include updated unit tests in the `test` directory as part of your pull request.
+Don’t worry about regenerating the documentation, lodash.js, or lodash.min.js.
+
You can run the tests from the command line via `node test/test`, or open `test/index.html` in a web browser.
-The `test/run-test.sh` script attempts to run the tests in [Rhino](https://developer.mozilla.org/en-US/docs/Rhino), [Narwhal](https://github.com/280north/narwhal), [RingoJS](http://ringojs.org/), [PhantomJS](http://phantomjs.org/), and [Node](http://nodejs.org/), before running them in your default browser.
-The [Backbone](http://backbonejs.org/) and [Underscore](http://http://underscorejs.org/) test suites are included as well.
+The `test/run-test.sh` script attempts to run the tests in [Rhino](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino), [RingoJS](http://ringojs.org/), [PhantomJS](http://phantomjs.org/), & [Node](http://nodejs.org/), before running them in your default browser.
+The [Backbone](http://backbonejs.org/) & [Underscore](http://underscorejs.org/) test suites are included as well.
## Contributor License Agreement
@@ -25,11 +27,11 @@ In addition to the following guidelines, please follow the conventions already e
Use two spaces for indentation. No tabs.
- **Naming**:<br>
- Keep variable and method names concise and descriptive.<br>
- Variable names `index`, `collection`, and `callback` are preferable to `i`, `arr`, and `fn`.
+ Keep variable & method names concise & descriptive.<br>
+ Variable names `index`, `collection`, & `callback` are preferable to `i`, `arr`, & `fn`.
- **Quotes**:<br>
Single-quoted strings are preferred to double-quoted strings; however, please use a double-quoted string if the value contains a single-quote character to avoid unnecessary escaping.
- **Comments**:<br>
- Please use single-line comments to annotate significant additions, and [JSDoc-style](http://www.2ality.com/2011/08/jsdoc-intro.html) comments for new methods.
+ Please use single-line comments to annotate significant additions, & [JSDoc-style](http://www.2ality.com/2011/08/jsdoc-intro.html) comments for new methods.
diff --git a/LICENSE.txt b/LICENSE.txt
index 49869bb..1776432 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,5 +1,5 @@
-Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
-Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas,
+Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+Based on Underscore.js 1.7.0, copyright 2009-2015 Jeremy Ashkenas,
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
Permission is hereby granted, free of charge, to any person obtaining
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 6f9598e..4c74d5d 100644
--- a/README.md
+++ b/README.md
@@ -1,163 +1,16 @@
-# Lo-Dash v2.4.1
-A utility library delivering consistency, [customization](http://lodash.com/custom-builds), [performance](http://lodash.com/benchmarks), & [extras](http://lodash.com/#features).
+# lodash v3.0.0
-## Download
-
-Check out our [wiki]([https://github.com/lodash/lodash/wiki/build-differences]) for details over the differences between builds.
-
-* Modern builds perfect for newer browsers/environments:<br>
-[Development](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.js) &
-[Production](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.min.js)
-
-* Compatibility builds for older environment support too:<br>
-[Development](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.compat.js) &
-[Production](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.compat.min.js)
-
-* Underscore builds to use as a drop-in replacement:<br>
-[Development](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.underscore.js) &
-[Production](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.underscore.min.js)
-
-CDN copies are available on [cdnjs](http://cdnjs.com/libraries/lodash.js/) & [jsDelivr](http://www.jsdelivr.com/#!lodash). For smaller file sizes, create [custom builds](http://lodash.com/custom-builds) with only the features needed.
-
-Love modules? We’ve got you covered with [lodash-amd](https://npmjs.org/package/lodash-amd), [lodash-es6](https://github.com/lodash/lodash-es6), [lodash-node](https://npmjs.org/package/lodash-node), & [npm packages](https://npmjs.org/browse/keyword/lodash-modularized) per method.
-
-## Dive in
-
-There’s plenty of **[documentation](http://lodash.com/docs)**, [unit tests](http://lodash.com/tests), & [benchmarks](http://lodash.com/benchmarks).<br>
-Check out <a href="http://devdocs.io/lodash/">DevDocs</a> as a fast, organized, & searchable interface for our documentation.
-
-The full changelog for this release is available on our [wiki](https://github.com/lodash/lodash/wiki/Changelog).<br>
-A list of upcoming features is available on our [roadmap](https://github.com/lodash/lodash/wiki/Roadmap).
-
-## Features *not* in Underscore
-
- * AMD loader support ([curl](https://github.com/cujojs/curl), [dojo](http://dojotoolkit.org/), [requirejs](http://requirejs.org/), etc.)
- * [_(…)](http://lodash.com/docs#_) supports intuitive chaining
- * [_.at](http://lodash.com/docs#at) for cherry-picking collection values
- * [_.bindKey](http://lodash.com/docs#bindKey) for binding [*“lazy”*](http://michaux.ca/articles/lazy-function-definition-pattern) defined methods
- * [_.clone](http://lodash.com/docs#clone) supports shallow cloning of `Date` & `RegExp` objects
- * [_.cloneDeep](http://lodash.com/docs#cloneDeep) for deep cloning arrays & objects
- * [_.constant](http://lodash.com/docs#constant) & [_.property](http://lodash.com/docs#property) function generators for composing functions
- * [_.contains](http://lodash.com/docs#contains) accepts a `fromIndex`
- * [_.create](http://lodash.com/docs#create) for easier object inheritance
- * [_.createCallback](http://lodash.com/docs#createCallback) for extending callbacks in methods & mixins
- * [_.curry](http://lodash.com/docs#curry) for creating [curried](http://hughfdjackson.com/javascript/2013/07/06/why-curry-helps/) functions
- * [_.debounce](http://lodash.com/docs#debounce) & [_.throttle](http://lodash.com/docs#throttle) accept additional `options` for more control
- * [_.findIndex](http://lodash.com/docs#findIndex) & [_.findKey](http://lodash.com/docs#findKey) for finding indexes & keys
- * [_.forEach](http://lodash.com/docs#forEach) is chainable & supports exiting early
- * [_.forIn](http://lodash.com/docs#forIn) for iterating own & inherited properties
- * [_.forOwn](http://lodash.com/docs#forOwn) for iterating own properties
- * [_.isPlainObject](http://lodash.com/docs#isPlainObject) for checking if values are created by `Object`
- * [_.mapValues](http://lodash.com/docs#mapValues) for [mapping](http://lodash.com/docs#map) values to an object
- * [_.memoize](http://lodash.com/docs#memoize) exposes the `cache` of memoized functions
- * [_.merge](http://lodash.com/docs#merge) for a deep [_.extend](http://lodash.com/docs#extend)
- * [_.noop](http://lodash.com/docs#noop) for function placeholders
- * [_.now](http://lodash.com/docs#now) as a cross-browser `Date.now` alternative
- * [_.parseInt](http://lodash.com/docs#parseInt) for consistent behavior
- * [_.pull](http://lodash.com/docs#pull) & [_.remove](http://lodash.com/docs#remove) for mutating arrays
- * [_.random](http://lodash.com/docs#random) supports returning floating-point numbers
- * [_.runInContext](http://lodash.com/docs#runInContext) for easier mocking
- * [_.sortBy](http://lodash.com/docs#sortBy) supports sorting by multiple properties
- * [_.support](http://lodash.com/docs#support) for flagging environment features
- * [_.template](http://lodash.com/docs#template) supports [*“imports”*](http://lodash.com/docs#templateSettings_imports) options & [ES6 template delimiters](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals)
- * [_.transform](http://lodash.com/docs#transform) as a powerful alternative to [_.reduce](http://lodash.com/docs#reduce) for transforming objects
- * [_.where](http://lodash.com/docs#where) supports deep object comparisons
- * [_.xor](http://lodash.com/docs#xor) as a companion to [_.difference](http://lodash.com/docs#difference), [_.intersection](http://lodash.com/docs#intersection), & [_.union](http://lodash.com/docs#union)
- * [_.zip](http://lodash.com/docs#zip) is capable of unzipping values
- * [_.omit](http://lodash.com/docs#omit), [_.pick](http://lodash.com/docs#pick), &
- [more](http://lodash.com/docs "_.assign, _.clone, _.cloneDeep, _.first, _.initial, _.isEqual, _.last, _.merge, _.rest") accept callbacks
- * [_.contains](http://lodash.com/docs#contains), [_.toArray](http://lodash.com/docs#toArray), &
- [more](http://lodash.com/docs "_.at, _.countBy, _.every, _.filter, _.find, _.forEach, _.forEachRight, _.groupBy, _.invoke, _.map, _.max, _.min, _.pluck, _.reduce, _.reduceRight, _.reject, _.shuffle, _.size, _.some, _.sortBy, _.where") accept strings
- * [_.filter](http://lodash.com/docs#filter), [_.map](http://lodash.com/docs#map), &
- [more](http://lodash.com/docs "_.countBy, _.every, _.find, _.findKey, _.findLast, _.findLastIndex, _.findLastKey, _.first, _.groupBy, _.initial, _.last, _.max, _.min, _.reject, _.rest, _.some, _.sortBy, _.sortedIndex, _.uniq") support *“_.pluck”* & *“_.where”* shorthands
- * [_.findLast](http://lodash.com/docs#findLast), [_.findLastIndex](http://lodash.com/docs#findLastIndex), &
- [more](http://lodash.com/docs "_.findLastKey, _.forEachRight, _.forInRight, _.forOwnRight, _.partialRight") right-associative methods
-
-## Resources
-
- * Podcasts
- - [JavaScript Jabber](http://javascriptjabber.com/079-jsj-lo-dash-with-john-david-dalton/)
-
- * Posts
- - [Say “Hello” to Lo-Dash](http://kitcambridge.be/blog/say-hello-to-lo-dash/)
- - [Custom builds in Lo-Dash 2.0](http://kitcambridge.be/blog/custom-builds-in-lo-dash-2-dot-0/)
-
- * Videos
- - [Introduction](https://vimeo.com/44154599)
- - [Origins](https://vimeo.com/44154600)
- - [Optimizations & builds](https://vimeo.com/44154601)
- - [Native method use](https://vimeo.com/48576012)
- - [Testing](https://vimeo.com/45865290)
- - [CascadiaJS ’12](http://www.youtube.com/watch?v=dpPy4f_SeEk)
-
- A list of other community created podcasts, posts, & videos is available on our [wiki](https://github.com/lodash/lodash/wiki/Resources).
-
-## Support
-
-Tested in Chrome 5~31, Firefox 2~25, IE 6-11, Opera 9.25~17, Safari 3-7, Node.js 0.6.21~0.10.22, Narwhal 0.3.2, PhantomJS 1.9.2, RingoJS 0.9, & Rhino 1.7RC5.<br>
-Automated browser test results [are available](https://saucelabs.com/u/lodash) as well as [Travis CI](https://travis-ci.org/) builds for [lodash](https://travis-ci.org/lodash/lodash/), [lodash-cli](https://travis-ci.org/lodash/lodash-cli/), [lodash-amd](https://travis-ci.org/lodash/lodash-amd/), [lodash-node](https://travis-ci.org/lodash/lodash-node/), & [grunt-lodash](https://travis-ci.org/lodash/grunt-lodash).
-
-Special thanks to [Sauce Labs](https://saucelabs.com/) for providing automated browser testing.<br>
-[![Sauce Labs](http://lodash.com/_img/sauce.png)](https://saucelabs.com/ "Sauce Labs: Selenium Testing & More")
-
-## Installation & usage
-
-In browsers:
-
-```html
-<script src="lodash.js"></script>
-```
-
-Using [`npm`](http://npmjs.org/):
+The [modern build](https://github.com/lodash/lodash/wiki/Build-Differences) of [Lo-Dash](https://lodash.com/) with packages for [Bower](http://bower.io/), [Component](http://component.github.io/), & [Volo](http://volojs.org/).
+Generated using [lodash-cli](https://www.npmjs.com/package/lodash-cli):
```bash
-npm i --save lodash
-
-{sudo} npm i -g lodash
-npm ln lodash
-```
-
-In [Node.js](http://nodejs.org/) & [Ringo](http://ringojs.org/):
-
-```js
-var _ = require('lodash');
-// or as Underscore
-var _ = require('lodash/dist/lodash.underscore');
+$ lodash modern -o ./lodash.js
```
-**Notes:**
- * Don’t assign values to [special variable](http://nodejs.org/api/repl.html#repl_repl_features) `_` when in the REPL
- * If Lo-Dash is installed globally, run [`npm ln lodash`](http://blog.nodejs.org/2011/03/23/npm-1-0-global-vs-local-installation/) in your project’s root directory *before* requiring it
-
-In [Rhino](http://www.mozilla.org/rhino/):
-
-```js
-load('lodash.js');
-```
-
-In an AMD loader:
-
-```js
-require({
- 'packages': [
- { 'name': 'lodash', 'location': 'path/to/lodash', 'main': 'lodash' }
- ]
-},
-['lodash'], function(_) {
- console.log(_.VERSION);
-});
-```
-
-## Author
-
-| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") |
-|---|
-| [John-David Dalton](http://allyoucanleet.com/) |
-
-## Contributors
+## Module formats
-| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
-|---|---|---|
-| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) |
+Lo-Dash is also available in a variety of other builds & module formats.
-[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lodash/lodash/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
+ * npm packages for [modern](https://www.npmjs.com/package/lodash), [compatibility](https://www.npmjs.com/package/lodash-compat), & [per method](https://www.npmjs.com/browse/keyword/lodash-modularized) builds
+ * AMD modules for [modern](https://github.com/lodash/lodash/tree/3.0.0-amd) & [compatibility](https://github.com/lodash/lodash-compat/tree/3.0.0-amd) builds
+ * ES modules for the [modern](https://github.com/lodash/lodash/tree/3.0.0-es) build
diff --git a/bower.json b/bower.json
index a6f139d..4d4c03d 100644
--- a/bower.json
+++ b/bower.json
@@ -1,20 +1,17 @@
{
"name": "lodash",
- "version": "2.4.1",
- "main": "dist/lodash.compat.js",
+ "version": "3.0.0",
+ "main": "lodash.js",
"ignore": [
".*",
"*.custom.*",
- "*.template.*",
+ "*.log",
"*.map",
"*.md",
- "/*.min.*",
- "/lodash.js",
- "index.js",
+ "lodash.src.js",
"component.json",
"package.json",
"doc",
- "modularize",
"node_modules",
"perf",
"test",
diff --git a/component.json b/component.json
index 6cd4698..bd9dc72 100644
--- a/component.json
+++ b/component.json
@@ -1,12 +1,10 @@
{
"name": "lodash",
"repo": "lodash/lodash",
- "version": "2.4.1",
- "description": "A utility library delivering consistency, customization, performance, & extras.",
+ "version": "3.0.0",
+ "description": "The modern build of Lo-Dash.",
"license": "MIT",
- "keywords": ["amd", "browser", "client", "functional", "server", "util"],
- "scripts": [
- "index.js",
- "dist/lodash.compat.js"
- ]
+ "main": "lodash.js",
+ "keywords": ["stdlib", "util"],
+ "scripts": ["lodash.js"]
}
diff --git a/debian/build/lodash.js b/debian/build/lodash.js
new file mode 100644
index 0000000..4ecebb5
--- /dev/null
+++ b/debian/build/lodash.js
@@ -0,0 +1,10784 @@
+/**
+ * @license
+ * Lo-Dash 3.0.0 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern -o ./lodash.js`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+;(function() {
+
+ /** Used as a safe reference for `undefined` in pre ES5 environments. */
+ var undefined;
+
+ /** Used as the semantic version number. */
+ var VERSION = '3.0.0';
+
+ /** Used to compose bitmasks for wrapper metadata. */
+ var BIND_FLAG = 1,
+ BIND_KEY_FLAG = 2,
+ CURRY_BOUND_FLAG = 4,
+ CURRY_FLAG = 8,
+ CURRY_RIGHT_FLAG = 16,
+ PARTIAL_FLAG = 32,
+ PARTIAL_RIGHT_FLAG = 64,
+ REARG_FLAG = 128,
+ ARY_FLAG = 256;
+
+ /** Used as default options for `_.trunc`. */
+ var DEFAULT_TRUNC_LENGTH = 30,
+ DEFAULT_TRUNC_OMISSION = '...';
+
+ /** Used to detect when a function becomes hot. */
+ var HOT_COUNT = 150,
+ HOT_SPAN = 16;
+
+ /** Used to indicate the type of lazy iteratees. */
+ var LAZY_FILTER_FLAG = 0,
+ LAZY_MAP_FLAG = 1,
+ LAZY_WHILE_FLAG = 2;
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used as the internal argument placeholder. */
+ var PLACEHOLDER = '__lodash_placeholder__';
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /** Used to match empty string literals in compiled template source. */
+ var reEmptyStringLeading = /\b__p \+= '';/g,
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+ /** Used to match HTML entities and HTML characters. */
+ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g,
+ reUnescapedHtml = /[&<>"'`]/g,
+ reHasEscapedHtml = RegExp(reEscapedHtml.source),
+ reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
+
+ /** Used to match template delimiters. */
+ var reEscape = /<%-([\s\S]+?)%>/g,
+ reEvaluate = /<%([\s\S]+?)%>/g,
+ reInterpolate = /<%=([\s\S]+?)%>/g;
+
+ /**
+ * Used to match ES6 template delimiters.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literal-lexical-components)
+ * for more details.
+ */
+ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
+
+ /** Used to detect named functions. */
+ var reFuncName = /^\s*function[ \n\r\t]+\w/;
+
+ /** Used to detect hexadecimal string values. */
+ var reHexPrefix = /^0[xX]/;
+
+ /** Used to detect host constructors (Safari > 5). */
+ var reHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to match latin-1 supplementary letters (excluding mathematical operators). */
+ var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g;
+
+ /** Used to ensure capturing order of template delimiters. */
+ var reNoMatch = /($^)/;
+
+ /**
+ * Used to match `RegExp` special characters.
+ * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
+ * for more details.
+ */
+ var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
+ reHasRegExpChars = RegExp(reRegExpChars.source);
+
+ /** Used to detect functions containing a `this` reference. */
+ var reThis = /\bthis\b/;
+
+ /** Used to match unescaped characters in compiled string literals. */
+ var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
+
+ /** Used to match words to create compound words. */
+ var reWords = (function() {
+ var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]',
+ lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+';
+
+ return RegExp(upper + '{2,}(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g');
+ }());
+
+ /** Used to detect and test for whitespace. */
+ var whitespace = (
+ // Basic whitespace characters.
+ ' \t\x0b\f\xa0\ufeff' +
+
+ // Line terminators.
+ '\n\r\u2028\u2029' +
+
+ // Unicode category "Zs" space separators.
+ '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
+ );
+
+ /** Used to assign default `context` object properties. */
+ var contextProps = [
+ 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array',
+ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number',
+ 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document',
+ 'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array',
+ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
+ 'window', 'WinRTError'
+ ];
+
+ /** Used to make template sourceURLs easier to identify. */
+ var templateCounter = -1;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dateTag] = typedArrayTags[errorTag] =
+ typedArrayTags[funcTag] = typedArrayTags[mapTag] =
+ typedArrayTags[numberTag] = typedArrayTags[objectTag] =
+ typedArrayTags[regexpTag] = typedArrayTags[setTag] =
+ typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag] = cloneableTags[arrayTag] =
+ cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
+ cloneableTags[dateTag] = cloneableTags[float32Tag] =
+ cloneableTags[float64Tag] = cloneableTags[int8Tag] =
+ cloneableTags[int16Tag] = cloneableTags[int32Tag] =
+ cloneableTags[numberTag] = cloneableTags[objectTag] =
+ cloneableTags[regexpTag] = cloneableTags[stringTag] =
+ cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+ cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+ cloneableTags[errorTag] = cloneableTags[funcTag] =
+ cloneableTags[mapTag] = cloneableTags[setTag] =
+ cloneableTags[weakMapTag] = false;
+
+ /** Used as an internal `_.debounce` options object by `_.throttle`. */
+ var debounceOptions = {
+ 'leading': false,
+ 'maxWait': 0,
+ 'trailing': false
+ };
+
+ /** Used to map latin-1 supplementary letters to basic latin letters. */
+ var deburredLetters = {
+ '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+ '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+ '\xc7': 'C', '\xe7': 'c',
+ '\xd0': 'D', '\xf0': 'd',
+ '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+ '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+ '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+ '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
+ '\xd1': 'N', '\xf1': 'n',
+ '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+ '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+ '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+ '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
+ '\xc6': 'Ae', '\xe6': 'ae',
+ '\xde': 'Th', '\xfe': 'th',
+ '\xdf': 'ss'
+ };
+
+ /** Used to map characters to HTML entities. */
+ var htmlEscapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
+ };
+
+ /** Used to map HTML entities to characters. */
+ var htmlUnescapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ ''': "'",
+ '`': '`'
+ };
+
+ /** Used to determine if values are of the language type `Object`. */
+ var objectTypes = {
+ 'function': true,
+ 'object': true
+ };
+
+ /** Used to escape characters for inclusion in compiled string literals. */
+ var stringEscapes = {
+ '\\': '\\',
+ "'": "'",
+ '\n': 'n',
+ '\r': 'r',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ /**
+ * Used as a reference to the global object.
+ *
+ * The `this` value is used if it is the global object to avoid Greasemonkey's
+ * restricted `window` object, otherwise the `window` object is used.
+ */
+ var root = (objectTypes[typeof window] && window !== (this && this.window)) ? window : this;
+
+ /** Detect free variable `exports`. */
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
+
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */
+ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
+ root = freeGlobal;
+ }
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The base implementation of `compareAscending` which compares values and
+ * sorts them in ascending order without guaranteeing a stable sort.
+ *
+ * @private
+ * @param {*} value The value to compare to `other`.
+ * @param {*} other The value to compare to `value`.
+ * @returns {number} Returns the sort order indicator for `value`.
+ */
+ function baseCompareAscending(value, other) {
+ if (value !== other) {
+ var valIsReflexive = value === value,
+ othIsReflexive = other === other;
+
+ if (value > other || !valIsReflexive || (typeof value == 'undefined' && othIsReflexive)) {
+ return 1;
+ }
+ if (value < other || !othIsReflexive || (typeof other == 'undefined' && valIsReflexive)) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * The base implementation of `_.indexOf` without support for binary searches.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseIndexOf(array, value, fromIndex) {
+ if (value !== value) {
+ return indexOfNaN(array, fromIndex);
+ }
+ var index = (fromIndex || 0) - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.sortBy` and `_.sortByAll` which uses `comparer`
+ * to define the sort order of `array` and replaces criteria objects with their
+ * corresponding values.
+ *
+ * @private
+ * @param {Array} array The array to sort.
+ * @param {Function} comparer The function to define sort order.
+ * @returns {Array} Returns `array`.
+ */
+ function baseSortBy(array, comparer) {
+ var length = array.length;
+
+ array.sort(comparer);
+ while (length--) {
+ array[length] = array[length].value;
+ }
+ return array;
+ }
+
+ /**
+ * Converts `value` to a string if it is not one. An empty string is returned
+ * for `null` or `undefined` values.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ if (typeof value == 'string') {
+ return value;
+ }
+ return value == null ? '' : (value + '');
+ }
+
+ /**
+ * Used by `_.max` and `_.min` as the default callback for string values.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the code unit of the first character of the string.
+ */
+ function charAtCallback(string) {
+ return string.charCodeAt(0);
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the first character not found in `chars`.
+ */
+ function charsLeftIndex(string, chars) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the last character not found in `chars`.
+ */
+ function charsRightIndex(string, chars) {
+ var index = string.length;
+
+ while (index-- && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.sortBy` to compare transformed elements of a collection and stable
+ * sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareAscending(object, other) {
+ return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index);
+ }
+
+ /**
+ * Used by `_.sortByAll` to compare multiple properties of each element
+ * in a collection and stable sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareMultipleAscending(object, other) {
+ var index = -1,
+ objCriteria = object.criteria,
+ othCriteria = other.criteria,
+ length = objCriteria.length;
+
+ while (++index < length) {
+ var result = baseCompareAscending(objCriteria[index], othCriteria[index]);
+ if (result) {
+ return result;
+ }
+ }
+ // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+ // that causes it, under certain circumstances, to provide the same value
+ // for `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247.
+ //
+ // This also ensures a stable sort in V8 and other engines.
+ // See https://code.google.com/p/v8/issues/detail?id=90.
+ return object.index - other.index;
+ }
+
+ /**
+ * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
+ *
+ * @private
+ * @param {string} letter The matched letter to deburr.
+ * @returns {string} Returns the deburred letter.
+ */
+ function deburrLetter(letter) {
+ return deburredLetters[letter];
+ }
+
+ /**
+ * Used by `_.escape` to convert characters to HTML entities.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeHtmlChar(chr) {
+ return htmlEscapes[chr];
+ }
+
+ /**
+ * Used by `_.template` to escape characters for inclusion in compiled
+ * string literals.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeStringChar(chr) {
+ return '\\' + stringEscapes[chr];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `NaN` is found in `array`.
+ * If `fromRight` is provided elements of `array` are iterated from right to left.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {number} [fromIndex] The index to search from.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched `NaN`, else `-1`.
+ */
+ function indexOfNaN(array, fromIndex, fromRight) {
+ var length = array.length,
+ index = fromRight ? (fromIndex || length) : ((fromIndex || 0) - 1);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var other = array[index];
+ if (other !== other) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if `value` is object-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ */
+ function isObjectLike(value) {
+ return (value && typeof value == 'object') || false;
+ }
+
+ /**
+ * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a
+ * character code is whitespace.
+ *
+ * @private
+ * @param {number} charCode The character code to inspect.
+ * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`.
+ */
+ function isSpace(charCode) {
+ return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 ||
+ (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279)));
+ }
+
+ /**
+ * Replaces all `placeholder` elements in `array` with an internal placeholder
+ * and returns an array of their indexes.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {*} placeholder The placeholder to replace.
+ * @returns {Array} Returns the new array of placeholder indexes.
+ */
+ function replaceHolders(array, placeholder) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ if (array[index] === placeholder) {
+ array[index] = PLACEHOLDER;
+ result[++resIndex] = index;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * An implementation of `_.uniq` optimized for sorted arrays without support
+ * for callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function sortedUniq(array, iteratee) {
+ var seen,
+ index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (!index || seen !== computed) {
+ seen = computed;
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the first non-whitespace character.
+ */
+ function trimmedLeftIndex(string) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the last non-whitespace character.
+ */
+ function trimmedRightIndex(string) {
+ var index = string.length;
+
+ while (index-- && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} chr The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ function unescapeHtmlChar(chr) {
+ return htmlUnescapes[chr];
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Create a new pristine `lodash` function using the given `context` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} [context=root] The context object.
+ * @returns {Function} Returns a new `lodash` function.
+ * @example
+ *
+ * _.mixin({ 'add': function(a, b) { return a + b; } });
+ *
+ * var lodash = _.runInContext();
+ * lodash.mixin({ 'sub': function(a, b) { return a - b; } });
+ *
+ * _.isFunction(_.add);
+ * // => true
+ * _.isFunction(_.sub);
+ * // => false
+ *
+ * lodash.isFunction(lodash.add);
+ * // => false
+ * lodash.isFunction(lodash.sub);
+ * // => true
+ *
+ * // using `context` to mock `Date#getTime` use in `_.now`
+ * var mock = _.runInContext({
+ * 'Date': function() {
+ * return { 'getTime': getTimeMock };
+ * }
+ * });
+ *
+ * // or creating a suped-up `defer` in Node.js
+ * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+ */
+ function runInContext(context) {
+ // Avoid issues with some ES3 environments that attempt to use values, named
+ // after built-in constructors like `Object`, for the creation of literals.
+ // ES5 clears this up by stating that literals must use built-in constructors.
+ // See http://es5.github.io/#x11.1.5.
+ context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
+
+ /** Native constructor references. */
+ var Array = context.Array,
+ Date = context.Date,
+ Error = context.Error,
+ Function = context.Function,
+ Math = context.Math,
+ Number = context.Number,
+ Object = context.Object,
+ RegExp = context.RegExp,
+ String = context.String,
+ TypeError = context.TypeError;
+
+ /** Used for native method references. */
+ var arrayProto = Array.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect DOM support. */
+ var document = (document = context.window) && document.document;
+
+ /** Used to resolve the decompiled source of functions. */
+ var fnToString = Function.prototype.toString;
+
+ /** Used to the length of n-tuples for `_.unzip`. */
+ var getLength = baseProperty('length');
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to generate unique IDs. */
+ var idCounter = 0;
+
+ /**
+ * Used to resolve the `toStringTag` of values.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
+ * for more details.
+ */
+ var objToString = objectProto.toString;
+
+ /** Used to restore the original `_` reference in `_.noConflict`. */
+ var oldDash = context._;
+
+ /** Used to detect if a method is native. */
+ var reNative = RegExp('^' +
+ escapeRegExp(objToString)
+ .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Native method references. */
+ var ArrayBuffer = isNative(ArrayBuffer = context.ArrayBuffer) && ArrayBuffer,
+ bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice,
+ ceil = Math.ceil,
+ clearTimeout = context.clearTimeout,
+ floor = Math.floor,
+ getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
+ push = arrayProto.push,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ Set = isNative(Set = context.Set) && Set,
+ setTimeout = context.setTimeout,
+ splice = arrayProto.splice,
+ Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array,
+ unshift = arrayProto.unshift,
+ WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap;
+
+ /** Used to clone array buffers. */
+ var Float64Array = (function() {
+ // Safari 5 errors when using an array buffer to initialize a typed array
+ // where the array buffer's `byteLength` is not a multiple of the typed
+ // array's `BYTES_PER_ELEMENT`.
+ try {
+ var func = isNative(func = context.Float64Array) && func,
+ result = new func(new ArrayBuffer(10), 0, 1) && func;
+ } catch(e) {}
+ return result;
+ }());
+
+ /* Native method references for those with the same name as other `lodash` methods. */
+ var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
+ nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
+ nativeIsFinite = context.isFinite,
+ nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
+ nativeMax = Math.max,
+ nativeMin = Math.min,
+ nativeNow = isNative(nativeNow = Date.now) && nativeNow,
+ nativeNumIsFinite = isNative(nativeNumIsFinite = Number.isFinite) && nativeNumIsFinite,
+ nativeParseInt = context.parseInt,
+ nativeRandom = Math.random;
+
+ /** Used as references for `-Infinity` and `Infinity`. */
+ var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY,
+ POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
+
+ /** Used as references for the maximum length and index of an array. */
+ var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1,
+ MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+ HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+ /** Used as the size, in bytes, of each `Float64Array` element. */
+ var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;
+
+ /**
+ * Used as the maximum length of an array-like value.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
+ * for more details.
+ */
+ var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
+
+ /** Used to store function metadata. */
+ var metaMap = WeakMap && new WeakMap;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object which wraps `value` to enable intuitive chaining.
+ * Methods that operate on and return arrays, collections, and functions can
+ * be chained together. Methods that return a boolean or single value will
+ * automatically end the chain returning the unwrapped value. Explicit chaining
+ * may be enabled using `_.chain`. The execution of chained methods is lazy,
+ * that is, execution is deferred until `_#value` is implicitly or explicitly
+ * called.
+ *
+ * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
+ * fusion is an optimization that merges iteratees to avoid creating intermediate
+ * arrays and reduce the number of iteratee executions.
+ *
+ * Chaining is supported in custom builds as long as the `_#value` method is
+ * directly or indirectly included in the build.
+ *
+ * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
+ * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
+ * and `unshift`
+ *
+ * The wrapper functions that support shortcut fusion are:
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `first`,
+ * `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, `slice`,
+ * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `where`
+ *
+ * The chainable wrapper functions are:
+ * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
+ * `callback`, `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`,
+ * `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`,
+ * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`,
+ * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`,
+ * `initial`, `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`,
+ * `mapValues`, `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`,
+ * `omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`,
+ * `pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`,
+ * `rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
+ * `sortBy`, `sortByAll`, `splice`, `take`, `takeRight`, `takeRightWhile`,
+ * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
+ * `transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`,
+ * `where`, `without`, `wrap`, `xor`, `zip`, and `zipObject`
+ *
+ * The wrapper functions that are **not** chainable by default are:
+ * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
+ * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`,
+ * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`,
+ * `identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`,
+ * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`,
+ * `isFunction`, `isMatch` , `isNative`, `isNaN`, `isNull`, `isNumber`,
+ * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`,
+ * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`,
+ * `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`,
+ * `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`,
+ * `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`,
+ * `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
+ * `unescape`, `uniqueId`, `value`, and `words`
+ *
+ * The wrapper function `sample` will return a wrapped value when `n` is provided,
+ * otherwise an unwrapped value is returned.
+ *
+ * @name _
+ * @constructor
+ * @category Chain
+ * @param {*} value The value to wrap in a `lodash` instance.
+ * @returns {Object} Returns a `lodash` instance.
+ * @example
+ *
+ * var wrapped = _([1, 2, 3]);
+ *
+ * // returns an unwrapped value
+ * wrapped.reduce(function(sum, n) { return sum + n; });
+ * // => 6
+ *
+ * // returns a wrapped value
+ * var squares = wrapped.map(function(n) { return n * n; });
+ *
+ * _.isArray(squares);
+ * // => false
+ *
+ * _.isArray(squares.value());
+ * // => true
+ */
+ function lodash(value) {
+ if (isObjectLike(value) && !isArray(value)) {
+ if (value instanceof LodashWrapper) {
+ return value;
+ }
+ if (hasOwnProperty.call(value, '__wrapped__')) {
+ return new LodashWrapper(value.__wrapped__, value.__chain__, arrayCopy(value.__actions__));
+ }
+ }
+ return new LodashWrapper(value);
+ }
+
+ /**
+ * The base constructor for creating `lodash` wrapper objects.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
+ * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
+ */
+ function LodashWrapper(value, chainAll, actions) {
+ this.__actions__ = actions || [];
+ this.__chain__ = !!chainAll;
+ this.__wrapped__ = value;
+ }
+
+ /**
+ * An object environment feature flags.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ var support = lodash.support = {};
+
+ (function(x) {
+
+ /**
+ * Detect if functions can be decompiled by `Function#toString`
+ * (all but Firefox OS certified apps, older Opera mobile browsers, and
+ * the PlayStation 3; forced `false` for Windows 8 apps).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
+
+ /**
+ * Detect if `Function#name` is supported (all but IE).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcNames = typeof Function.name == 'string';
+
+ /**
+ * Detect if the DOM is supported.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ try {
+ support.dom = document.createDocumentFragment().nodeType === 11;
+ } catch(e) {
+ support.dom = false;
+ }
+
+ /**
+ * Detect if `arguments` object indexes are non-enumerable.
+ *
+ * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object
+ * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat
+ * `arguments` object indexes as non-enumerable and fail `hasOwnProperty`
+ * checks for indexes that exceed their function's formal parameters with
+ * associated values of `0`.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ try {
+ support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1);
+ } catch(e) {
+ support.nonEnumArgs = true;
+ }
+ }(0, 0));
+
+ /**
+ * By default, the template delimiters used by Lo-Dash are like those in
+ * embedded Ruby (ERB). Change the following template settings to use
+ * alternative delimiters.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ lodash.templateSettings = {
+
+ /**
+ * Used to detect `data` property values to be HTML-escaped.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'escape': reEscape,
+
+ /**
+ * Used to detect code to be evaluated.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'evaluate': reEvaluate,
+
+ /**
+ * Used to detect `data` property values to inject.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'interpolate': reInterpolate,
+
+ /**
+ * Used to reference the data object in the template text.
+ *
+ * @memberOf _.templateSettings
+ * @type string
+ */
+ 'variable': '',
+
+ /**
+ * Used to import variables into the compiled template.
+ *
+ * @memberOf _.templateSettings
+ * @type Object
+ */
+ 'imports': {
+
+ /**
+ * A reference to the `lodash` function.
+ *
+ * @memberOf _.templateSettings.imports
+ * @type Function
+ */
+ '_': lodash
+ }
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ */
+ function LazyWrapper(value) {
+ this.actions = null;
+ this.dir = 1;
+ this.dropCount = 0;
+ this.filtered = false;
+ this.iteratees = null;
+ this.takeCount = POSITIVE_INFINITY;
+ this.views = null;
+ this.wrapped = value;
+ }
+
+ /**
+ * Creates a clone of the lazy wrapper object.
+ *
+ * @private
+ * @name clone
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the cloned `LazyWrapper` object.
+ */
+ function lazyClone() {
+ var actions = this.actions,
+ iteratees = this.iteratees,
+ views = this.views,
+ result = new LazyWrapper(this.wrapped);
+
+ result.actions = actions ? arrayCopy(actions) : null;
+ result.dir = this.dir;
+ result.dropCount = this.dropCount;
+ result.filtered = this.filtered;
+ result.iteratees = iteratees ? arrayCopy(iteratees) : null;
+ result.takeCount = this.takeCount;
+ result.views = views ? arrayCopy(views) : null;
+ return result;
+ }
+
+ /**
+ * Reverses the direction of lazy iteration.
+ *
+ * @private
+ * @name reverse
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the new reversed `LazyWrapper` object.
+ */
+ function lazyReverse() {
+ var filtered = this.filtered,
+ result = filtered ? new LazyWrapper(this) : this.clone();
+
+ result.dir = this.dir * -1;
+ result.filtered = filtered;
+ return result;
+ }
+
+ /**
+ * Extracts the unwrapped value from its lazy wrapper.
+ *
+ * @private
+ * @name value
+ * @memberOf LazyWrapper
+ * @returns {*} Returns the unwrapped value.
+ */
+ function lazyValue() {
+ var array = this.wrapped.value();
+ if (!isArray(array)) {
+ return baseWrapperValue(array, this.actions);
+ }
+ var dir = this.dir,
+ isRight = dir < 0,
+ length = array.length,
+ view = getView(0, length, this.views),
+ start = view.start,
+ end = view.end,
+ dropCount = this.dropCount,
+ takeCount = nativeMin(end - start, this.takeCount - dropCount),
+ index = isRight ? end : start - 1,
+ iteratees = this.iteratees,
+ iterLength = iteratees ? iteratees.length : 0,
+ resIndex = 0,
+ result = [];
+
+ outer:
+ while (length-- && resIndex < takeCount) {
+ index += dir;
+
+ var iterIndex = -1,
+ value = array[index];
+
+ while (++iterIndex < iterLength) {
+ var data = iteratees[iterIndex],
+ iteratee = data.iteratee,
+ computed = iteratee(value, index, array),
+ type = data.type;
+
+ if (type == LAZY_MAP_FLAG) {
+ value = computed;
+ } else if (!computed) {
+ if (type == LAZY_FILTER_FLAG) {
+ continue outer;
+ } else {
+ break outer;
+ }
+ }
+ }
+ if (dropCount) {
+ dropCount--;
+ } else {
+ result[resIndex++] = value;
+ }
+ }
+ return isRight ? result.reverse() : result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a cache object to store key/value pairs.
+ *
+ * @private
+ * @static
+ * @name Cache
+ * @memberOf _.memoize
+ */
+ function MapCache() {
+ this.__data__ = {};
+ }
+
+ /**
+ * Removes `key` and its value from the cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`.
+ */
+ function mapDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the cached value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the cached value.
+ */
+ function mapGet(key) {
+ return key == '__proto__' ? undefined : this.__data__[key];
+ }
+
+ /**
+ * Checks if a cached value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapHas(key) {
+ return key != '__proto__' && hasOwnProperty.call(this.__data__, key);
+ }
+
+ /**
+ * Adds `value` to `key` of the cache.
+ *
+ * @private
+ * @name set
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to cache.
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache object.
+ */
+ function mapSet(key, value) {
+ if (key != '__proto__') {
+ this.__data__[key] = value;
+ }
+ return this;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ *
+ * Creates a cache object to store unique values.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var length = values ? values.length : 0;
+
+ this.data = { 'hash': nativeCreate(null), 'set': new Set };
+ while (length--) {
+ this.push(values[length]);
+ }
+ }
+
+ /**
+ * Checks if `value` is in `cache` mimicking the return signature of
+ * `_.indexOf` by returning `0` if the value is found, else `-1`.
+ *
+ * @private
+ * @param {Object} cache The cache to search.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `0` if `value` is found, else `-1`.
+ */
+ function cacheIndexOf(cache, value) {
+ var data = cache.data,
+ result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
+
+ return result ? 0 : -1;
+ }
+
+ /**
+ * Adds `value` to the cache.
+ *
+ * @private
+ * @name push
+ * @memberOf SetCache
+ * @param {*} value The value to cache.
+ */
+ function cachePush(value) {
+ var data = this.data;
+ if (typeof value == 'string' || isObject(value)) {
+ data.set.add(value);
+ } else {
+ data.hash[value] = true;
+ }
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayCopy(source, array) {
+ var index = -1,
+ length = source.length;
+
+ array || (array = Array(length));
+ while (++index < length) {
+ array[index] = source[index];
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEach` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEachRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEachRight(array, iteratee) {
+ var length = array.length;
+
+ while (length--) {
+ if (iteratee(array[length], length, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.every` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ */
+ function arrayEvery(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (!predicate(array[index], index, array)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A specialized version of `_.filter` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function arrayFilter(array, predicate) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.map` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function arrayMap(array, iteratee) {
+ var index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = iteratee(array[index], index, array);
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.max` for arrays without support for iteratees.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the maximum value.
+ */
+ function arrayMax(array) {
+ var index = -1,
+ length = array.length,
+ result = NEGATIVE_INFINITY;
+
+ while (++index < length) {
+ var value = array[index];
+ if (value > result) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.min` for arrays without support for iteratees.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the minimum value.
+ */
+ function arrayMin(array) {
+ var index = -1,
+ length = array.length,
+ result = POSITIVE_INFINITY;
+
+ while (++index < length) {
+ var value = array[index];
+ if (value < result) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.reduce` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the first element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduce(array, iteratee, accumulator, initFromArray) {
+ var index = -1,
+ length = array.length;
+
+ if (initFromArray && length) {
+ accumulator = array[++index];
+ }
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.reduceRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the last element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduceRight(array, iteratee, accumulator, initFromArray) {
+ var length = array.length;
+ if (initFromArray && length) {
+ accumulator = array[--length];
+ }
+ while (length--) {
+ accumulator = iteratee(accumulator, array[length], length, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.some` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Used by `_.defaults` to customize its `_.assign` use.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignDefaults(objectValue, sourceValue) {
+ return typeof objectValue == 'undefined' ? sourceValue : objectValue;
+ }
+
+ /**
+ * Used by `_.template` to customize its `_.assign` use.
+ *
+ * **Note:** This method is like `assignDefaults` except that it ignores
+ * inherited property values when checking if a property is `undefined`.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @param {string} key The key associated with the object and source values.
+ * @param {Object} object The destination object.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignOwnDefaults(objectValue, sourceValue, key, object) {
+ return (typeof objectValue == 'undefined' || !hasOwnProperty.call(object, key))
+ ? sourceValue
+ : objectValue;
+ }
+
+ /**
+ * The base implementation of `_.assign` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseAssign(object, source, customizer) {
+ var props = keys(source);
+ if (!customizer) {
+ return baseCopy(source, object, props);
+ }
+ var index = -1,
+ length = props.length
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key],
+ result = customizer(value, source[key], key, object, source);
+
+ if ((result === result ? result !== value : value === value) ||
+ (typeof value == 'undefined' && !(key in object))) {
+ object[key] = result;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.at` without support for strings and individual
+ * key arguments.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {number[]|string[]} [props] The property names or indexes of elements to pick.
+ * @returns {Array} Returns the new array of picked elements.
+ */
+ function baseAt(collection, props) {
+ var index = -1,
+ length = collection.length,
+ isArr = isLength(length),
+ propsLength = props.length,
+ result = Array(propsLength);
+
+ while(++index < propsLength) {
+ var key = props[index];
+ if (isArr) {
+ key = parseFloat(key);
+ result[index] = isIndex(key, length) ? collection[key] : undefined;
+ } else {
+ result[index] = collection[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copies the properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Array} props The property names to copy.
+ * @returns {Object} Returns `object`.
+ */
+ function baseCopy(source, object, props) {
+ if (!props) {
+ props = object;
+ object = {};
+ }
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ object[key] = source[key];
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.bindAll` without support for individual
+ * method name arguments.
+ *
+ * @private
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {string[]} methodNames The object method names to bind.
+ * @returns {Object} Returns `object`.
+ */
+ function baseBindAll(object, methodNames) {
+ var index = -1,
+ length = methodNames.length;
+
+ while (++index < length) {
+ var key = methodNames[index];
+ object[key] = createWrapper(object[key], BIND_FLAG, object);
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.callback` which supports specifying the
+ * number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function baseCallback(func, thisArg, argCount) {
+ var type = typeof func;
+ if (type == 'function') {
+ return (typeof thisArg != 'undefined' && isBindable(func))
+ ? bindCallback(func, thisArg, argCount)
+ : func;
+ }
+ if (func == null) {
+ return identity;
+ }
+ // Handle "_.property" and "_.matches" style callback shorthands.
+ return type == 'object'
+ ? baseMatches(func, !argCount)
+ : baseProperty(argCount ? baseToString(func) : func);
+ }
+
+ /**
+ * The base implementation of `_.clone` without support for argument juggling
+ * and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The object `value` belongs to.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates clones with source counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
+ var result;
+ if (customizer) {
+ result = object ? customizer(value, key, object) : customizer(value);
+ }
+ if (typeof result != 'undefined') {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return arrayCopy(value, result);
+ }
+ } else {
+ var tag = objToString.call(value),
+ isFunc = tag == funcTag;
+
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ result = initCloneObject(isFunc ? {} : value);
+ if (!isDeep) {
+ return baseCopy(value, result, keys(value));
+ }
+ } else {
+ return cloneableTags[tag]
+ ? initCloneByTag(value, tag, isDeep)
+ : (object ? value : {});
+ }
+ }
+ // Check for circular references and return corresponding clone.
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == value) {
+ return stackB[length];
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate it with its clone.
+ stackA.push(value);
+ stackB.push(result);
+
+ // Recursively populate clone (susceptible to call stack limits).
+ (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
+ result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+ var baseCreate = (function() {
+ function Object() {}
+ return function(prototype) {
+ if (isObject(prototype)) {
+ Object.prototype = prototype;
+ var result = new Object;
+ Object.prototype = null;
+ }
+ return result || context.Object();
+ };
+ }());
+
+ /**
+ * The base implementation of `_.delay` and `_.defer` which accepts an index
+ * of where to slice the arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {Object} args The `arguments` object to slice and provide to `func`.
+ * @returns {number} Returns the timer id.
+ */
+ function baseDelay(func, wait, args, fromIndex) {
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return setTimeout(function() { func.apply(undefined, baseSlice(args, fromIndex)); }, wait);
+ }
+
+ /**
+ * The base implementation of `_.difference` which accepts a single array
+ * of values to exclude.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Array} values The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ */
+ function baseDifference(array, values) {
+ var length = array ? array.length : 0,
+ result = [];
+
+ if (!length) {
+ return result;
+ }
+ var index = -1,
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf,
+ cache = isCommon && values.length >= 200 && createCache(values),
+ valuesLength = values.length;
+
+ if (cache) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ values = cache;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index];
+
+ if (isCommon && value === value) {
+ var valuesIndex = valuesLength;
+ while (valuesIndex--) {
+ if (values[valuesIndex] === value) {
+ continue outer;
+ }
+ }
+ result.push(value);
+ }
+ else if (indexOf(values, value) < 0) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.forEach` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEach(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwn(collection, iteratee);
+ }
+ var index = -1,
+ iterable = toObject(collection);
+
+ while (++index < length) {
+ if (iteratee(iterable[index], index, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.forEachRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEachRight(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwnRight(collection, iteratee);
+ }
+ var iterable = toObject(collection);
+ while (length--) {
+ if (iteratee(iterable[length], length, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.every` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`
+ */
+ function baseEvery(collection, predicate) {
+ var result = true;
+ baseEach(collection, function(value, index, collection) {
+ result = !!predicate(value, index, collection);
+ return result;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.filter` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function baseFilter(collection, predicate) {
+ var result = [];
+ baseEach(collection, function(value, index, collection) {
+ if (predicate(value, index, collection)) {
+ result.push(value);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
+ * without support for callback shorthands and `this` binding, which iterates
+ * over `collection` using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @param {boolean} [retKey] Specify returning the key of the found element
+ * instead of the element itself.
+ * @returns {*} Returns the found element or its key, else `undefined`.
+ */
+ function baseFind(collection, predicate, eachFunc, retKey) {
+ var result;
+ eachFunc(collection, function(value, key, collection) {
+ if (predicate(value, key, collection)) {
+ result = retKey ? key : value;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.flatten` with added support for restricting
+ * flattening and specifying the start index.
+ *
+ * @private
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param {boolean} [isStrict] Restrict flattening to arrays and `arguments` objects.
+ * @param {number} [fromIndex=0] The index to start from.
+ * @returns {Array} Returns the new flattened array.
+ */
+ function baseFlatten(array, isDeep, isStrict, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+
+ if (isObjectLike(value) && isLength(value.length) && (isArray(value) || isArguments(value))) {
+ if (isDeep) {
+ // Recursively flatten arrays (susceptible to call stack limits).
+ value = baseFlatten(value, isDeep, isStrict);
+ }
+ var valIndex = -1,
+ valLength = value.length;
+
+ result.length += valLength;
+ while (++valIndex < valLength) {
+ result[++resIndex] = value[valIndex];
+ }
+ } else if (!isStrict) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `baseForIn` and `baseForOwn` which iterates
+ * over `object` properties returned by `keysFunc` invoking `iteratee` for
+ * each property. Iterator functions may exit iteration early by explicitly
+ * returning `false`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ function baseFor(object, iteratee, keysFunc) {
+ var index = -1,
+ iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * This function is like `baseFor` except that it iterates over properties
+ * in the opposite order.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForRight(object, iteratee, keysFunc) {
+ var iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (length--) {
+ var key = props[length];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.forIn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForIn(object, iteratee) {
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * The base implementation of `_.forOwn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwn(object, iteratee) {
+ return baseFor(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.forOwnRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwnRight(object, iteratee) {
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.functions` which creates an array of
+ * `object` function property names filtered from those provided.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Array} props The property names to filter.
+ * @returns {Array} Returns the new array of filtered property names.
+ */
+ function baseFunctions(object, props) {
+ var index = -1,
+ length = props.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var key = props[index];
+ if (isFunction(object[key])) {
+ result[++resIndex] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.invoke` which requires additional arguments
+ * to be provided as an array of arguments rather than individually.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {Array} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseInvoke(collection, methodName, args) {
+ var index = -1,
+ isFunc = typeof methodName == 'function',
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value) {
+ var func = isFunc ? methodName : (value != null && value[methodName]);
+ result[++index] = func ? func.apply(value, args) : undefined;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isEqual` without support for `this` binding
+ * `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, customizer, isWhere, stackA, stackB) {
+ // Exit early for identical values.
+ if (value === other) {
+ // Treat `+0` vs. `-0` as not equal.
+ return value !== 0 || (1 / value == 1 / other);
+ }
+ var valType = typeof value,
+ othType = typeof other;
+
+ // Exit early for unlike primitive values.
+ if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') ||
+ value == null || other == null) {
+ // Return `false` unless both values are `NaN`.
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, baseIsEqual, customizer, isWhere, stackA, stackB);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA=[]] Tracks traversed `value` objects.
+ * @param {Array} [stackB=[]] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = arrayTag,
+ othTag = arrayTag;
+
+ if (!objIsArr) {
+ objTag = objToString.call(object);
+ if (objTag == argsTag) {
+ objTag = objectTag;
+ } else if (objTag != objectTag) {
+ objIsArr = isTypedArray(object);
+ }
+ }
+ if (!othIsArr) {
+ othTag = objToString.call(other);
+ if (othTag == argsTag) {
+ othTag = objectTag;
+ } else if (othTag != objectTag) {
+ othIsArr = isTypedArray(other);
+ }
+ }
+ var objIsObj = objTag == objectTag,
+ othIsObj = othTag == objectTag,
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && !(objIsArr || objIsObj)) {
+ return equalByTag(object, other, objTag);
+ }
+ var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (valWrapped || othWrapped) {
+ return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isWhere, stackA, stackB);
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ // Assume cyclic structures are equal.
+ // The algorithm for detecting cyclic structures is adapted from ES 5.1
+ // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3).
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == object) {
+ return stackB[length] == other;
+ }
+ }
+ // Add `object` and `other` to the stack of traversed objects.
+ stackA.push(object);
+ stackB.push(other);
+
+ var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isWhere, stackA, stackB);
+
+ stackA.pop();
+ stackB.pop();
+
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isMatch` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Object} source The object to inspect.
+ * @param {Array} props The source property names to match.
+ * @param {Array} values The source values to match.
+ * @param {Array} strictCompareFlags Strict comparison flags for source values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ */
+ function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
+ var length = props.length;
+ if (object == null) {
+ return !length;
+ }
+ var index = -1,
+ noCustomizer = !customizer;
+
+ while (++index < length) {
+ if ((noCustomizer && strictCompareFlags[index])
+ ? values[index] !== object[props[index]]
+ : !hasOwnProperty.call(object, props[index])
+ ) {
+ return false;
+ }
+ }
+ index = -1;
+ while (++index < length) {
+ var key = props[index];
+ if (noCustomizer && strictCompareFlags[index]) {
+ var result = hasOwnProperty.call(object, key);
+ } else {
+ var objValue = object[key],
+ srcValue = values[index];
+
+ result = customizer ? customizer(objValue, srcValue, key) : undefined;
+ if (typeof result == 'undefined') {
+ result = baseIsEqual(srcValue, objValue, customizer, true);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.map` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function baseMap(collection, iteratee) {
+ var result = [];
+ baseEach(collection, function(value, key, collection) {
+ result.push(iteratee(value, key, collection));
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.matches` which supports specifying whether
+ * `source` should be cloned.
+ *
+ * @private
+ * @param {Object} source The object of property values to match.
+ * @param {boolean} [isCloned] Specify cloning the source object.
+ * @returns {Function} Returns the new function.
+ */
+ function baseMatches(source, isCloned) {
+ var props = keys(source),
+ length = props.length;
+
+ if (length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return function(object) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ };
+ }
+ }
+ if (isCloned) {
+ source = baseClone(source, true);
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = source[props[length]];
+ values[length] = value;
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return function(object) {
+ return baseIsMatch(object, props, values, strictCompareFlags);
+ };
+ }
+
+ /**
+ * The base implementation of `_.merge` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseMerge(object, source, customizer, stackA, stackB) {
+ var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
+
+ (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
+ if (isObjectLike(srcValue)) {
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+ return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ }
+ if ((isSrcArr || typeof result != 'undefined') &&
+ (isCommon || (result === result ? result !== value : value === value))) {
+ object[key] = result;
+ }
+ });
+ return object;
+ }
+
+ /**
+ * A specialized version of `baseMerge` for arrays and objects which performs
+ * deep merges and tracks traversed objects enabling objects with circular
+ * references to be merged.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {string} key The key of the value to merge.
+ * @param {Function} mergeFunc The function to merge values.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
+ var length = stackA.length,
+ srcValue = source[key];
+
+ while (length--) {
+ if (stackA[length] == srcValue) {
+ object[key] = stackB[length];
+ return;
+ }
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) {
+ result = isArray(value)
+ ? value
+ : (value ? arrayCopy(value) : []);
+ }
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+ result = isArguments(value)
+ ? toPlainObject(value)
+ : (isPlainObject(value) ? value : {});
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate
+ // it with its merged value.
+ stackA.push(srcValue);
+ stackB.push(result);
+
+ if (isCommon) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
+ } else if (result === result ? result !== value : value === value) {
+ object[key] = result;
+ }
+ }
+
+ /**
+ * The base implementation of `_.property` which does not coerce `key` to a string.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * The base implementation of `_.pullAt` without support for individual
+ * index arguments.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {number[]} indexes The indexes of elements to remove.
+ * @returns {Array} Returns the new array of removed elements.
+ */
+ function basePullAt(array, indexes) {
+ var length = indexes.length,
+ result = baseAt(array, indexes);
+
+ indexes.sort(baseCompareAscending);
+ while (length--) {
+ var index = parseFloat(indexes[length]);
+ if (index != previous && isIndex(index)) {
+ var previous = index;
+ splice.call(array, index, 1);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.random` without support for argument juggling
+ * and returning floating-point numbers.
+ *
+ * @private
+ * @param {number} min The minimum possible value.
+ * @param {number} max The maximum possible value.
+ * @returns {number} Returns the random number.
+ */
+ function baseRandom(min, max) {
+ return min + floor(nativeRandom() * (max - min + 1));
+ }
+
+ /**
+ * The base implementation of `_.reduce` and `_.reduceRight` without support
+ * for callback shorthands or `this` binding, which iterates over `collection`
+ * using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} accumulator The initial value.
+ * @param {boolean} initFromCollection Specify using the first or last element
+ * of `collection` as the initial value.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @returns {*} Returns the accumulated value.
+ */
+ function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
+ eachFunc(collection, function(value, index, collection) {
+ accumulator = initFromCollection
+ ? (initFromCollection = false, value)
+ : iteratee(accumulator, value, index, collection)
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `setData` without support for hot loop detection.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var baseSetData = !metaMap ? identity : function(func, data) {
+ metaMap.set(func, data);
+ return func;
+ };
+
+ /**
+ * The base implementation of `_.slice` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseSlice(array, start, end) {
+ var index = -1,
+ length = array.length;
+
+ start = start == null ? 0 : (+start || 0);
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = (typeof end == 'undefined' || end > length) ? length : (+end || 0);
+ if (end < 0) {
+ end += length;
+ }
+ length = start > end ? 0 : (end - start);
+
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = array[index + start];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.some` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function baseSome(collection, predicate) {
+ var result;
+
+ baseEach(collection, function(value, index, collection) {
+ result = predicate(value, index, collection);
+ return !result;
+ });
+ return !!result;
+ }
+
+ /**
+ * The base implementation of `_.uniq` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function baseUniq(array, iteratee) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = array.length,
+ isCommon = indexOf == baseIndexOf,
+ isLarge = isCommon && length >= 200,
+ seen = isLarge && createCache(),
+ result = [];
+
+ if (seen) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ } else {
+ isLarge = false;
+ seen = iteratee ? [] : result;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (isCommon && value === value) {
+ var seenIndex = seen.length;
+ while (seenIndex--) {
+ if (seen[seenIndex] === computed) {
+ continue outer;
+ }
+ }
+ if (iteratee) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ else if (indexOf(seen, computed) < 0) {
+ if (iteratee || isLarge) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.values` and `_.valuesIn` which creates an
+ * array of `object` property values corresponding to the property names
+ * returned by `keysFunc`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} props The property names to get values for.
+ * @returns {Object} Returns the array of property values.
+ */
+ function baseValues(object, props) {
+ var index = -1,
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = object[props[index]];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `wrapperValue` which returns the result of
+ * performing a sequence of actions on the unwrapped `value`, where each
+ * successive action is supplied the return value of the previous.
+ *
+ * @private
+ * @param {*} value The unwrapped value.
+ * @param {Array} actions Actions to peform to resolve the unwrapped value.
+ * @returns {*} Returns the resolved unwrapped value.
+ */
+ function baseWrapperValue(value, actions) {
+ var result = value;
+ if (result instanceof LazyWrapper) {
+ result = result.value();
+ }
+ var index = -1,
+ length = actions.length;
+
+ while (++index < length) {
+ var args = [result],
+ action = actions[index];
+
+ push.apply(args, action.args);
+ result = action.func.apply(action.thisArg, args);
+ }
+ return result;
+ }
+
+ /**
+ * Performs a binary search of `array` to determine the index at which `value`
+ * should be inserted into `array` in order to maintain its sort order.
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndex(array, value, retHighest) {
+ var low = 0,
+ high = array ? array.length : low;
+
+ if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+ while (low < high) {
+ var mid = (low + high) >>> 1,
+ computed = array[mid];
+
+ if (retHighest ? (computed <= value) : (computed < value)) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return high;
+ }
+ return binaryIndexBy(array, value, identity, retHighest);
+ }
+
+ /**
+ * This function is like `binaryIndex` except that it invokes `iteratee` for
+ * `value` and each element of `array` to compute their sort ranking. The
+ * iteratee is invoked with one argument; (value).
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndexBy(array, value, iteratee, retHighest) {
+ value = iteratee(value);
+
+ var low = 0,
+ high = array ? array.length : 0,
+ valIsNaN = value !== value,
+ valIsUndef = typeof value == 'undefined';
+
+ while (low < high) {
+ var mid = floor((low + high) / 2),
+ computed = iteratee(array[mid]),
+ isReflexive = computed === computed;
+
+ if (valIsNaN) {
+ var setLow = isReflexive || retHighest;
+ } else if (valIsUndef) {
+ setLow = isReflexive && (retHighest || typeof computed != 'undefined');
+ } else {
+ setLow = retHighest ? (computed <= value) : (computed < value);
+ }
+ if (setLow) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return nativeMin(high, MAX_ARRAY_INDEX);
+ }
+
+ /**
+ * A specialized version of `baseCallback` which only supports `this` binding
+ * and specifying the number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function bindCallback(func, thisArg, argCount) {
+ if (typeof func != 'function') {
+ return identity;
+ }
+ if (typeof thisArg == 'undefined') {
+ return func;
+ }
+ switch (argCount) {
+ case 1: return function(value) {
+ return func.call(thisArg, value);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ case 5: return function(value, other, key, object, source) {
+ return func.call(thisArg, value, other, key, object, source);
+ };
+ }
+ return function() {
+ return func.apply(thisArg, arguments);
+ };
+ }
+
+ /**
+ * Creates a clone of the given array buffer.
+ *
+ * @private
+ * @param {ArrayBuffer} buffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+ function bufferClone(buffer) {
+ return bufferSlice.call(buffer, 0);
+ }
+ if (!bufferSlice) {
+ // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`.
+ bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) {
+ var byteLength = buffer.byteLength,
+ floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
+ offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
+ result = new ArrayBuffer(byteLength);
+
+ if (floatLength) {
+ var view = new Float64Array(result, 0, floatLength);
+ view.set(new Float64Array(buffer, 0, floatLength));
+ }
+ if (byteLength != offset) {
+ view = new Uint8Array(result, offset);
+ view.set(new Uint8Array(buffer, offset));
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates an array that is the composition of partially applied arguments,
+ * placeholders, and provided arguments into a single array of arguments.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to prepend to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgs(args, partials, holders) {
+ var holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ leftIndex = -1,
+ leftLength = partials.length,
+ result = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ result[leftIndex] = partials[leftIndex];
+ }
+ while (++argsIndex < holdersLength) {
+ result[holders[argsIndex]] = args[argsIndex];
+ }
+ while (argsLength--) {
+ result[leftIndex++] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * This function is like `composeArgs` except that the arguments composition
+ * is tailored for `_.partialRight`.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to append to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgsRight(args, partials, holders) {
+ var holdersIndex = -1,
+ holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ rightIndex = -1,
+ rightLength = partials.length,
+ result = Array(argsLength + rightLength);
+
+ while (++argsIndex < argsLength) {
+ result[argsIndex] = args[argsIndex];
+ }
+ var pad = argsIndex;
+ while (++rightIndex < rightLength) {
+ result[pad + rightIndex] = partials[rightIndex];
+ }
+ while (++holdersIndex < holdersLength) {
+ result[pad + holders[holdersIndex]] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * Creates a function that aggregates a collection, creating an accumulator
+ * object composed from the results of running each element in the collection
+ * through an iteratee. The `setter` sets the keys and values of the accumulator
+ * object. If `initializer` is provided initializes the accumulator object.
+ *
+ * @private
+ * @param {Function} setter The function to set keys and values of the accumulator object.
+ * @param {Function} [initializer] The function to initialize the accumulator object.
+ * @returns {Function} Returns the new aggregator function.
+ */
+ function createAggregator(setter, initializer) {
+ return function(collection, iteratee, thisArg) {
+ var result = initializer ? initializer() : {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ setter(result, value, iteratee(value, index, collection), collection);
+ }
+ } else {
+ baseEach(collection, function(value, key, collection) {
+ setter(result, value, iteratee(value, key, collection), collection);
+ });
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that assigns properties of source object(s) to a given
+ * destination object.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return function() {
+ var length = arguments.length,
+ object = arguments[0];
+
+ if (length < 2 || object == null) {
+ return object;
+ }
+ if (length > 3 && isIterateeCall(arguments[1], arguments[2], arguments[3])) {
+ length = 2;
+ }
+ // Juggle arguments.
+ if (length > 3 && typeof arguments[length - 2] == 'function') {
+ var customizer = bindCallback(arguments[--length - 1], arguments[length--], 5);
+ } else if (length > 2 && typeof arguments[length - 1] == 'function') {
+ customizer = arguments[--length];
+ }
+ var index = 0;
+ while (++index < length) {
+ var source = arguments[index];
+ if (source) {
+ assigner(object, source, customizer);
+ }
+ }
+ return object;
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the `this`
+ * binding of `thisArg`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createBindWrapper(func, thisArg) {
+ var Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ return (this instanceof wrapper ? Ctor : func).apply(thisArg, arguments);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `Set` cache object to optimize linear searches of large arrays.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
+ */
+ var createCache = !(nativeCreate && Set) ? constant(null) : function(values) {
+ return new SetCache(values);
+ };
+
+ /**
+ * Creates a function that produces compound words out of the words in a
+ * given string.
+ *
+ * @private
+ * @param {Function} callback The function to combine each word.
+ * @returns {Function} Returns the new compounder function.
+ */
+ function createCompounder(callback) {
+ return function(string) {
+ var index = -1,
+ array = words(deburr(string)),
+ length = array.length,
+ result = '';
+
+ while (++index < length) {
+ result = callback(result, array[index], index);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that produces an instance of `Ctor` regardless of
+ * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+ *
+ * @private
+ * @param {Function} Ctor The constructor to wrap.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createCtorWrapper(Ctor) {
+ return function() {
+ var thisBinding = baseCreate(Ctor.prototype),
+ result = Ctor.apply(thisBinding, arguments);
+
+ // Mimic the constructor's `return` behavior.
+ // See http://es5.github.io/#x13.2.2.
+ return isObject(result) ? result : thisBinding;
+ };
+ }
+
+ /**
+ * Creates a function that gets the extremum value of a collection.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to get the extremum value from an array.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the maximum,
+ * extremum value.
+ * @returns {Function} Returns the new extremum function.
+ */
+ function createExtremum(arrayFunc, isMin) {
+ return function(collection, iteratee, thisArg) {
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ var func = getCallback(),
+ noIteratee = iteratee == null;
+
+ if (!(func === baseCallback && noIteratee)) {
+ noIteratee = false;
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ if (noIteratee) {
+ var isArr = isArray(collection);
+ if (!isArr && isString(collection)) {
+ iteratee = charAtCallback;
+ } else {
+ return arrayFunc(isArr ? collection : toIterable(collection));
+ }
+ }
+ return extremumBy(collection, iteratee, isMin);
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with optional `this`
+ * binding of, partial application, and currying.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
+ * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+ var isAry = bitmask & ARY_FLAG,
+ isBind = bitmask & BIND_FLAG,
+ isBindKey = bitmask & BIND_KEY_FLAG,
+ isCurry = bitmask & CURRY_FLAG,
+ isCurryBound = bitmask & CURRY_BOUND_FLAG,
+ isCurryRight = bitmask & CURRY_RIGHT_FLAG;
+
+ var Ctor = !isBindKey && createCtorWrapper(func),
+ key = func;
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it to other functions.
+ var length = arguments.length,
+ index = length,
+ args = Array(length);
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ if (partials) {
+ args = composeArgs(args, partials, holders);
+ }
+ if (partialsRight) {
+ args = composeArgsRight(args, partialsRight, holdersRight);
+ }
+ if (isCurry || isCurryRight) {
+ var placeholder = wrapper.placeholder,
+ argsHolders = replaceHolders(args, placeholder);
+
+ length -= argsHolders.length;
+ if (length < arity) {
+ var newArgPos = argPos ? arrayCopy(argPos) : null,
+ newArity = nativeMax(arity - length, 0),
+ newsHolders = isCurry ? argsHolders : null,
+ newHoldersRight = isCurry ? null : argsHolders,
+ newPartials = isCurry ? args : null,
+ newPartialsRight = isCurry ? null : args;
+
+ bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
+ bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
+
+ if (!isCurryBound) {
+ bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
+ }
+ var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity);
+ result.placeholder = placeholder;
+ return result;
+ }
+ }
+ var thisBinding = isBind ? thisArg : this;
+ if (isBindKey) {
+ func = thisBinding[key];
+ }
+ if (argPos) {
+ args = reorder(args, argPos);
+ }
+ if (isAry && ary < args.length) {
+ args.length = ary;
+ }
+ return (this instanceof wrapper ? (Ctor || createCtorWrapper(func)) : func).apply(thisBinding, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates the pad required for `string` based on the given padding length.
+ * The `chars` string may be truncated if the number of padding characters
+ * exceeds the padding length.
+ *
+ * @private
+ * @param {string} string The string to create padding for.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the pad for `string`.
+ */
+ function createPad(string, length, chars) {
+ var strLength = string.length;
+ length = +length;
+
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return '';
+ }
+ var padLength = length - strLength;
+ chars = chars == null ? ' ' : baseToString(chars);
+ return repeat(chars, ceil(padLength / chars.length)).slice(0, padLength);
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the optional `this`
+ * binding of `thisArg` and the `partials` prepended to those provided to
+ * the wrapper.
+ *
+ * @private
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} partials The arguments to prepend to those provided to the new function.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createPartialWrapper(func, bitmask, thisArg, partials) {
+ var isBind = bitmask & BIND_FLAG,
+ Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it `func`.
+ var argsIndex = -1,
+ argsLength = arguments.length,
+ leftIndex = -1,
+ leftLength = partials.length,
+ args = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ args[leftIndex] = partials[leftIndex];
+ }
+ while (argsLength--) {
+ args[leftIndex++] = arguments[++argsIndex];
+ }
+ return (this instanceof wrapper ? Ctor : func).apply(isBind ? thisArg : this, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a function that either curries or invokes `func` with optional
+ * `this` binding and partially applied arguments.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags.
+ * The bitmask may be composed of the following flags:
+ * 1 - `_.bind`
+ * 2 - `_.bindKey`
+ * 4 - `_.curry` or `_.curryRight` of a bound function
+ * 8 - `_.curry`
+ * 16 - `_.curryRight`
+ * 32 - `_.partial`
+ * 64 - `_.partialRight`
+ * 128 - `_.rearg`
+ * 256 - `_.ary`
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to be partially applied.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
+ var isBindKey = bitmask & BIND_KEY_FLAG;
+ if (!isBindKey && !isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var length = partials ? partials.length : 0;
+ if (!length) {
+ bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
+ partials = holders = null;
+ }
+ length -= (holders ? holders.length : 0);
+ if (bitmask & PARTIAL_RIGHT_FLAG) {
+ var partialsRight = partials,
+ holdersRight = holders;
+
+ partials = holders = null;
+ }
+ var data = !isBindKey && getData(func),
+ newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
+
+ if (data && data !== true) {
+ mergeData(newData, data);
+ bitmask = newData[1];
+ arity = newData[9];
+ }
+ newData[9] = arity == null
+ ? (isBindKey ? 0 : func.length)
+ : (nativeMax(arity - length, 0) || 0);
+
+ if (bitmask == BIND_FLAG) {
+ var result = createBindWrapper(newData[0], newData[2]);
+ } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
+ result = createPartialWrapper.apply(null, newData);
+ } else {
+ result = createHybridWrapper.apply(null, newData);
+ }
+ var setter = data ? baseSetData : setData;
+ return setter(result, newData);
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing arrays.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var index = -1,
+ arrLength = array.length,
+ othLength = other.length,
+ result = true;
+
+ if (arrLength != othLength && !(isWhere && othLength > arrLength)) {
+ return false;
+ }
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (result && ++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, arrValue, index)
+ : customizer(arrValue, othValue, index);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (isWhere) {
+ var othIndex = othLength;
+ while (othIndex--) {
+ othValue = other[othIndex];
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ if (result) {
+ break;
+ }
+ }
+ } else {
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ }
+ return !!result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} value The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag) {
+ switch (tag) {
+ case boolTag:
+ case dateTag:
+ // Coerce dates and booleans to numbers, dates to milliseconds and booleans
+ // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
+ return +object == +other;
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case numberTag:
+ // Treat `NaN` vs. `NaN` as equal.
+ return (object != +object)
+ ? other != +other
+ // But, treat `-0` vs. `+0` as not equal.
+ : (object == 0 ? ((1 / object) == (1 / other)) : object == +other);
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings (http://es5.github.io/#x15.10.6.4) and
+ // treat strings primitives and string objects as equal.
+ return object == baseToString(other);
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objProps = keys(object),
+ objLength = objProps.length,
+ othProps = keys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isWhere) {
+ return false;
+ }
+ var hasCtor,
+ index = -1;
+
+ while (++index < objLength) {
+ var key = objProps[index],
+ result = hasOwnProperty.call(other, key);
+
+ if (result) {
+ var objValue = object[key],
+ othValue = other[key];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, objValue, key)
+ : customizer(objValue, othValue, key);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare objects (susceptible to call stack limits).
+ result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ hasCtor || (hasCtor = key == 'constructor');
+ }
+ if (!hasCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Gets the extremum value of `collection` invoking `iteratee` for each value
+ * in `collection` to generate the criterion by which the value is ranked.
+ * The `iteratee` is invoked with three arguments; (value, index, collection).
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the
+ * maximum, extremum value.
+ * @returns {*} Returns the extremum value.
+ */
+ function extremumBy(collection, iteratee, isMin) {
+ var exValue = isMin ? POSITIVE_INFINITY : NEGATIVE_INFINITY,
+ computed = exValue,
+ result = computed;
+
+ baseEach(collection, function(value, index, collection) {
+ var current = iteratee(value, index, collection);
+ if ((isMin ? current < computed : current > computed) || (current === exValue && current === result)) {
+ computed = current;
+ result = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Gets the appropriate "callback" function. If the `_.callback` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseCallback` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function} Returns the chosen function or its result.
+ */
+ function getCallback(func, thisArg, argCount) {
+ var result = lodash.callback || callback;
+ result = result === callback ? baseCallback : result;
+ return argCount ? result(func, thisArg, argCount) : result;
+ }
+
+ /**
+ * Gets metadata for `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {*} Returns the metadata for `func`.
+ */
+ var getData = !metaMap ? noop : function(func) {
+ return metaMap.get(func);
+ };
+
+ /**
+ * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseIndexOf` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function|number} Returns the chosen function or its result.
+ */
+ function getIndexOf(collection, target, fromIndex) {
+ var result = lodash.indexOf || indexOf;
+ result = result === indexOf ? baseIndexOf : result;
+ return collection ? result(collection, target, fromIndex) : result;
+ }
+
+ /**
+ * Gets the view, applying any `transforms` to the `start` and `end` positions.
+ *
+ * @private
+ * @param {number} start The start of the view.
+ * @param {number} end The end of the view.
+ * @param {Array} [transforms] The transformations to apply to the view.
+ * @returns {Object} Returns an object containing the `start` and `end`
+ * positions of the view.
+ */
+ function getView(start, end, transforms) {
+ var index = -1,
+ length = transforms ? transforms.length : 0;
+
+ while (++index < length) {
+ var data = transforms[index],
+ size = data.size;
+
+ switch (data.type) {
+ case 'drop': start += size; break;
+ case 'dropRight': end -= size; break;
+ case 'take': end = nativeMin(end, start + size); break;
+ case 'takeRight': start = nativeMax(start, end - size); break;
+ }
+ }
+ return { 'start': start, 'end': end };
+ }
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = new array.constructor(length);
+
+ // Add array properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ /**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneObject(object) {
+ var Ctor = object.constructor;
+ if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
+ Ctor = Object;
+ }
+ return new Ctor;
+ }
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return bufferClone(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ var buffer = object.buffer;
+ return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ var result = new Ctor(object.source, reFlags.exec(object));
+ result.lastIndex = object.lastIndex;
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `func` is eligible for `this` binding.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is eligible, else `false`.
+ */
+ function isBindable(func) {
+ var support = lodash.support,
+ result = !(support.funcNames ? func.name : support.funcDecomp);
+
+ if (!result) {
+ var source = fnToString.call(func);
+ if (!support.funcNames) {
+ result = !reFuncName.test(source);
+ }
+ if (!result) {
+ // Check if `func` references the `this` keyword and store the result.
+ result = reThis.test(source) || isNative(func);
+ baseSetData(func, result);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ value = +value;
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return value > -1 && value % 1 == 0 && value < length;
+ }
+
+ /**
+ * Checks if the provided arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number') {
+ var length = object.length,
+ prereq = isLength(length) && isIndex(index, length);
+ } else {
+ prereq = type == 'string' && index in value;
+ }
+ return prereq && object[index] === value;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+ function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` if suitable for strict
+ * equality comparisons, else `false`.
+ */
+ function isStrictComparable(value) {
+ return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value));
+ }
+
+ /**
+ * Merges the function metadata of `source` into `data`.
+ *
+ * Merging metadata reduces the number of wrappers required to invoke a function.
+ * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+ * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
+ * augment function arguments, making the order in which they are executed important,
+ * preventing the merging of metadata. However, we make an exception for a safe
+ * common case where curried functions have `_.ary` and or `_.rearg` applied.
+ *
+ * @private
+ * @param {Array} data The destination metadata.
+ * @param {Array} source The source metadata.
+ * @returns {Array} Returns `data`.
+ */
+ function mergeData(data, source) {
+ var bitmask = data[1],
+ srcBitmask = source[1],
+ newBitmask = bitmask | srcBitmask;
+
+ var arityFlags = ARY_FLAG | REARG_FLAG,
+ bindFlags = BIND_FLAG | BIND_KEY_FLAG,
+ comboFlags = arityFlags | bindFlags | CURRY_BOUND_FLAG | CURRY_RIGHT_FLAG;
+
+ var isAry = bitmask & ARY_FLAG && !(srcBitmask & ARY_FLAG),
+ isRearg = bitmask & REARG_FLAG && !(srcBitmask & REARG_FLAG),
+ argPos = (isRearg ? data : source)[7],
+ ary = (isAry ? data : source)[8];
+
+ var isCommon = !(bitmask >= REARG_FLAG && srcBitmask > bindFlags) &&
+ !(bitmask > bindFlags && srcBitmask >= REARG_FLAG);
+
+ var isCombo = (newBitmask >= arityFlags && newBitmask <= comboFlags) &&
+ (bitmask < REARG_FLAG || ((isRearg || isAry) && argPos.length <= ary));
+
+ // Exit early if metadata can't be merged.
+ if (!(isCommon || isCombo)) {
+ return data;
+ }
+ // Use source `thisArg` if available.
+ if (srcBitmask & BIND_FLAG) {
+ data[2] = source[2];
+ // Set when currying a bound function.
+ newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
+ }
+ // Compose partial arguments.
+ var value = source[3];
+ if (value) {
+ var partials = data[3];
+ data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
+ data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
+ }
+ // Compose partial right arguments.
+ value = source[5];
+ if (value) {
+ partials = data[5];
+ data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
+ data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
+ }
+ // Use source `argPos` if available.
+ value = source[7];
+ if (value) {
+ data[7] = arrayCopy(value);
+ }
+ // Use source `ary` if it's smaller.
+ if (srcBitmask & ARY_FLAG) {
+ data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
+ }
+ // Use source `arity` if one is not provided.
+ if (data[9] == null) {
+ data[9] = source[9];
+ }
+ // Use source `func` and merge bitmasks.
+ data[0] = source[0];
+ data[1] = newBitmask;
+
+ return data;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties specified
+ * by the `props` array.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {string[]} props The property names to pick.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByArray(object, props) {
+ object = toObject(object);
+
+ var index = -1,
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index];
+ if (key in object) {
+ result[key] = object[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties `predicate`
+ * returns truthy for.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByCallback(object, predicate) {
+ var result = {};
+ baseForIn(object, function(value, key, object) {
+ if (predicate(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Reorder `array` according to the specified indexes where the element at
+ * the first index is assigned as the first element, the element at
+ * the second index is assigned as the second element, and so on.
+ *
+ * @private
+ * @param {Array} array The array to reorder.
+ * @param {Array} indexes The arranged array indexes.
+ * @returns {Array} Returns `array`.
+ */
+ function reorder(array, indexes) {
+ var arrLength = array.length,
+ length = nativeMin(indexes.length, arrLength),
+ oldArray = arrayCopy(array);
+
+ while (length--) {
+ var index = indexes[length];
+ array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
+ }
+ return array;
+ }
+
+ /**
+ * Sets metadata for `func`.
+ *
+ * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+ * period of time, it will trip its breaker and transition to an identity function
+ * to avoid garbage collection pauses in V8. See https://code.google.com/p/v8/issues/detail?id=2070.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var setData = (function() {
+ var count = 0,
+ lastCalled = 0;
+
+ return function(key, value) {
+ var stamp = now(),
+ remaining = HOT_SPAN - (stamp - lastCalled);
+
+ lastCalled = stamp;
+ if (remaining > 0) {
+ if (++count >= HOT_COUNT) {
+ return key;
+ }
+ } else {
+ count = 0;
+ }
+ return baseSetData(key, value);
+ };
+ }());
+
+ /**
+ * A fallback implementation of `_.isPlainObject` which checks if `value`
+ * is an object created by the `Object` constructor or has a `[[Prototype]]`
+ * of `null`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ */
+ function shimIsPlainObject(value) {
+ var Ctor,
+ support = lodash.support;
+
+ // Exit early for non `Object` objects.
+ if (!(isObjectLike(value) && objToString.call(value) == objectTag) ||
+ (!hasOwnProperty.call(value, 'constructor') &&
+ (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
+ return false;
+ }
+ // IE < 9 iterates inherited properties before own properties. If the first
+ // iterated property is an object's own property then there are no inherited
+ // enumerable properties.
+ var result;
+ // In most environments an object's own properties are iterated before
+ // its inherited properties. If the last iterated property is an object's
+ // own property then there are no inherited enumerable properties.
+ baseForIn(value, function(subValue, key) {
+ result = key;
+ });
+ return typeof result == 'undefined' || hasOwnProperty.call(value, result);
+ }
+
+ /**
+ * A fallback implementation of `Object.keys` which creates an array of the
+ * own enumerable property names of `object`.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ */
+ function shimKeys(object) {
+ var props = keysIn(object),
+ propsLength = props.length,
+ length = propsLength && object.length,
+ support = lodash.support;
+
+ var allowIndexes = length && isLength(length) &&
+ (isArray(object) || (support.nonEnumArgs && isArguments(object)));
+
+ var index = -1,
+ result = [];
+
+ while (++index < propsLength) {
+ var key = props[index];
+ if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `value` to an array-like object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Array|Object} Returns the array-like object.
+ */
+ function toIterable(value) {
+ if (value == null) {
+ return [];
+ }
+ if (!isLength(value.length)) {
+ return values(value);
+ }
+ return isObject(value) ? value : Object(value);
+ }
+
+ /**
+ * Converts `value` to an object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Object} Returns the object.
+ */
+ function toObject(value) {
+ return isObject(value) ? value : Object(value);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements split into groups the length of `size`.
+ * If `collection` can't be split evenly, the final chunk will be the remaining
+ * elements.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to process.
+ * @param {numer} [size=1] The length of each chunk.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new array containing chunks.
+ * @example
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 2);
+ * // => [['a', 'b'], ['c', 'd']]
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 3);
+ * // => [['a', 'b', 'c'], ['d']]
+ */
+ function chunk(array, size, guard) {
+ if (guard ? isIterateeCall(array, size, guard) : size == null) {
+ size = 1;
+ } else {
+ size = nativeMax(+size || 1, 1);
+ }
+ var index = 0,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = Array(ceil(length / size));
+
+ while (index < length) {
+ result[++resIndex] = baseSlice(array, index, (index += size));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array with all falsey values removed. The values `false`, `null`,
+ * `0`, `""`, `undefined`, and `NaN` are falsey.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to compact.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.compact([0, 1, false, 2, '', 3]);
+ * // => [1, 2, 3]
+ */
+ function compact(array) {
+ var index = -1,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all values of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The arrays of values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.difference([1, 2, 3], [5, 2, 10]);
+ * // => [1, 3]
+ */
+ function difference() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var value = arguments[index];
+ if (isArray(value) || isArguments(value)) {
+ break;
+ }
+ }
+ return baseDifference(value, baseFlatten(arguments, false, true, ++index));
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.drop([1, 2, 3]);
+ * // => [2, 3]
+ *
+ * _.drop([1, 2, 3], 2);
+ * // => [3]
+ *
+ * _.drop([1, 2, 3], 5);
+ * // => []
+ *
+ * _.drop([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function drop(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRight([1, 2, 3]);
+ * // => [1, 2]
+ *
+ * _.dropRight([1, 2, 3], 2);
+ * // => [1]
+ *
+ * _.dropRight([1, 2, 3], 5);
+ * // => []
+ *
+ * _.dropRight([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function dropRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the end.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [1]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropRightWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function dropRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, 0, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the beginning.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['pebbles']
+ */
+ function dropWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, index);
+ }
+
+ /**
+ * This method is like `_.find` except that it returns the index of the first
+ * element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findIndex(users, function(chr) { return chr.age < 40; });
+ * // => 0
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findIndex(users, { 'age': 1 });
+ * // => 2
+ *
+ * // using the "_.property" callback shorthand
+ * _.findIndex(users, 'active');
+ * // => 1
+ */
+ function findIndex(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it iterates over elements
+ * of `collection` from right to left.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findLastIndex(users, function(chr) { return chr.age < 40; });
+ * // => 2
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastIndex(users, { 'age': 40 });
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastIndex(users, 'active');
+ * // => 0
+ */
+ function findLastIndex(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length--) {
+ if (predicate(array[length], length, array)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Gets the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias head
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the first element of `array`.
+ * @example
+ *
+ * _.first([1, 2, 3]);
+ * // => 1
+ *
+ * _.first([]);
+ * // => undefined
+ */
+ function first(array) {
+ return array ? array[0] : undefined;
+ }
+
+ /**
+ * Flattens a nested array. If `isDeep` is `true` the array is recursively
+ * flattened, otherwise it is only flattened a single level.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flatten([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, [[4]]];
+ *
+ * // using `isDeep`
+ * _.flatten([1, [2], [3, [[4]]]], true);
+ * // => [1, 2, 3, 4];
+ */
+ function flatten(array, isDeep, guard) {
+ var length = array ? array.length : 0;
+ if (guard && isIterateeCall(array, isDeep, guard)) {
+ isDeep = false;
+ }
+ return length ? baseFlatten(array, isDeep) : [];
+ }
+
+ /**
+ * Recursively flattens a nested array.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to recursively flatten.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flattenDeep([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, 4];
+ */
+ function flattenDeep(array) {
+ var length = array ? array.length : 0;
+ return length ? baseFlatten(array, true) : [];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found in `array`
+ * using `SameValueZero` for equality comparisons. If `fromIndex` is negative,
+ * it is used as the offset from the end of `array`. If `array` is sorted
+ * providing `true` for `fromIndex` performs a faster binary search.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=0] The index to search from or `true`
+ * to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 1
+ *
+ * // using `fromIndex`
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 4
+ *
+ * // performing a binary search
+ * _.indexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 2
+ */
+ function indexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else if (fromIndex) {
+ var index = binaryIndex(array, value),
+ other = array[index];
+
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ return baseIndexOf(array, value, fromIndex);
+ }
+
+ /**
+ * Gets all but the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.initial([1, 2, 3]);
+ * // => [1, 2]
+ */
+ function initial(array) {
+ return dropRight(array, 1);
+ }
+
+ /**
+ * Creates an array of unique values in all provided arrays using `SameValueZero`
+ * for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of shared values.
+ * @example
+ *
+ * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2]
+ */
+ function intersection() {
+ var args = [],
+ argsIndex = -1,
+ argsLength = arguments.length,
+ caches = [],
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf;
+
+ while (++argsIndex < argsLength) {
+ var value = arguments[argsIndex];
+ if (isArray(value) || isArguments(value)) {
+ args.push(value);
+ caches.push(isCommon && value.length >= 120 && createCache(argsIndex && value));
+ }
+ }
+ argsLength = args.length;
+ var array = args[0],
+ index = -1,
+ length = array ? array.length : 0,
+ result = [],
+ seen = caches[0];
+
+ outer:
+ while (++index < length) {
+ value = array[index];
+ if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value)) < 0) {
+ argsIndex = argsLength;
+ while (--argsIndex) {
+ var cache = caches[argsIndex];
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
+ continue outer;
+ }
+ }
+ if (seen) {
+ seen.push(value);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the last element of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ */
+ function last(array) {
+ var length = array ? array.length : 0;
+ return length ? array[length - 1] : undefined;
+ }
+
+ /**
+ * This method is like `_.indexOf` except that it iterates over elements of
+ * `array` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=array.length-1] The index to search from
+ * or `true` to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 4
+ *
+ * // using `fromIndex`
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 1
+ *
+ * // performing a binary search
+ * _.lastIndexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 3
+ */
+ function lastIndexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ var index = length;
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1;
+ } else if (fromIndex) {
+ index = binaryIndex(array, value, true) - 1;
+ var other = array[index];
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ if (value !== value) {
+ return indexOfNaN(array, index, true);
+ }
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all provided values from `array` using `SameValueZero` for equality
+ * comparisons.
+ *
+ * **Notes:**
+ * - Unlike `_.without`, this method mutates `array`.
+ * - `SameValueZero` comparisons are like strict equality comparisons, e.g. `===`,
+ * except that `NaN` matches `NaN`. See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...*} [values] The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3, 1, 2, 3];
+ * _.pull(array, 2, 3);
+ * console.log(array);
+ * // => [1, 1]
+ */
+ function pull() {
+ var array = arguments[0];
+ if (!(array && array.length)) {
+ return array;
+ }
+ var index = 0,
+ indexOf = getIndexOf(),
+ length = arguments.length;
+
+ while (++index < length) {
+ var fromIndex = 0,
+ value = arguments[index];
+
+ while ((fromIndex = indexOf(array, value, fromIndex)) > -1) {
+ splice.call(array, fromIndex, 1);
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Removes elements from `array` corresponding to the given indexes and returns
+ * an array of the removed elements. Indexes may be specified as an array of
+ * indexes or as individual arguments.
+ *
+ * **Note:** Unlike `_.at`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...(number|number[])} [indexes] The indexes of elements to remove,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [5, 10, 15, 20];
+ * var evens = _.pullAt(array, [1, 3]);
+ *
+ * console.log(array);
+ * // => [5, 15]
+ *
+ * console.log(evens);
+ * // => [10, 20]
+ */
+ function pullAt(array) {
+ return basePullAt(array || [], baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Removes all elements from `array` that `predicate` returns truthy for
+ * and returns an array of the removed elements. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** Unlike `_.filter`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [1, 2, 3, 4];
+ * var evens = _.remove(array, function(n) { return n % 2 == 0; });
+ *
+ * console.log(array);
+ * // => [1, 3]
+ *
+ * console.log(evens);
+ * // => [2, 4]
+ */
+ function remove(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0,
+ result = [];
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result.push(value);
+ splice.call(array, index--, 1);
+ length--;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets all but the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias tail
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.rest([1, 2, 3]);
+ * // => [2, 3]
+ */
+ function rest(array) {
+ return drop(array, 1);
+ }
+
+ /**
+ * Creates a slice of `array` from `start` up to, but not including, `end`.
+ *
+ * **Note:** This function is used instead of `Array#slice` to support node
+ * lists in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function slice(array, start, end) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
+ start = 0;
+ end = length;
+ }
+ return baseSlice(array, start, end);
+ }
+
+ /**
+ * Uses a binary search to determine the lowest index at which `value` should
+ * be inserted into `array` in order to maintain its sort order. If an iteratee
+ * function is provided it is invoked for `value` and each element of `array`
+ * to compute their sort ranking. The iteratee is bound to `thisArg` and
+ * invoked with one argument; (value).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([30, 50], 40);
+ * // => 1
+ *
+ * _.sortedIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 2
+ *
+ * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } };
+ *
+ * // using an iteratee function
+ * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) {
+ * return this.data[word];
+ * }, dict);
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
+ * // => 1
+ */
+ function sortedIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1));
+ }
+
+ /**
+ * This method is like `_.sortedIndex` except that it returns the highest
+ * index at which `value` should be inserted into `array` in order to
+ * maintain its sort order.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedLastIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 4
+ */
+ function sortedLastIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value, true)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1), true);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.take([1, 2, 3]);
+ * // => [1]
+ *
+ * _.take([1, 2, 3], 2);
+ * // => [1, 2]
+ *
+ * _.take([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.take([1, 2, 3], 0);
+ * // => []
+ */
+ function take(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRight([1, 2, 3]);
+ * // => [3]
+ *
+ * _.takeRight([1, 2, 3], 2);
+ * // => [2, 3]
+ *
+ * _.takeRight([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.takeRight([1, 2, 3], 0);
+ * // => []
+ */
+ function takeRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the end. Elements are
+ * taken until `predicate` returns falsey. The predicate is bound to `thisArg`
+ * and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [2, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeRightWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['pebbles']
+ */
+ function takeRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the beginning. Elements
+ * are taken until `predicate` returns falsey. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [1, 2]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function takeWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, 0, index);
+ }
+
+ /**
+ * Creates an array of unique values, in order, of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2, 3, 5, 4]
+ */
+ function union() {
+ return baseUniq(baseFlatten(arguments, false, true));
+ }
+
+ /**
+ * Creates a duplicate-value-free version of an array using `SameValueZero`
+ * for equality comparisons. Providing `true` for `isSorted` performs a faster
+ * search algorithm for sorted arrays. If an iteratee function is provided it
+ * is invoked for each value in the array to generate the criterion by which
+ * uniqueness is computed. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias unique
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {boolean} [isSorted] Specify the array is sorted.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ * @example
+ *
+ * _.uniq([1, 2, 1]);
+ * // => [1, 2]
+ *
+ * // using `isSorted`
+ * _.uniq([1, 1, 2], true);
+ * // => [1, 2]
+ *
+ * // using an iteratee function
+ * _.uniq([1, 2.5, 1.5, 2], function(n) { return this.floor(n); }, Math);
+ * // => [1, 2.5]
+ *
+ * // using the "_.property" callback shorthand
+ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniq(array, isSorted, iteratee, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ // Juggle arguments.
+ if (typeof isSorted != 'boolean' && isSorted != null) {
+ thisArg = iteratee;
+ iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted;
+ isSorted = false;
+ }
+ var func = getCallback();
+ if (!(func === baseCallback && iteratee == null)) {
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ return (isSorted && getIndexOf() == baseIndexOf)
+ ? sortedUniq(array, iteratee)
+ : baseUniq(array, iteratee);
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts an array of grouped
+ * elements and creates an array regrouping the elements to their pre `_.zip`
+ * configuration.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ *
+ * _.unzip(zipped);
+ * // => [['fred', 'barney'], [30, 40], [true, false]]
+ */
+ function unzip(array) {
+ var index = -1,
+ length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = arrayMap(array, baseProperty(index));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all provided values using `SameValueZero` for
+ * equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to filter.
+ * @param {...*} [values] The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+ * // => [2, 3, 4]
+ */
+ function without(array) {
+ return baseDifference(array, baseSlice(arguments, 1));
+ }
+
+ /**
+ * Creates an array that is the symmetric difference of the provided arrays.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Symmetric_difference) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of values.
+ * @example
+ *
+ * _.xor([1, 2, 3], [5, 2, 1, 4]);
+ * // => [3, 5, 4]
+ *
+ * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+ * // => [1, 4, 5]
+ */
+ function xor() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var array = arguments[index];
+ if (isArray(array) || isArguments(array)) {
+ var result = result
+ ? baseDifference(result, array).concat(baseDifference(array, result))
+ : array;
+ }
+ }
+ return result ? baseUniq(result) : [];
+ }
+
+ /**
+ * Creates an array of grouped elements, the first of which contains the first
+ * elements of the given arrays, the second of which contains the second elements
+ * of the given arrays, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ */
+ function zip() {
+ var length = arguments.length,
+ array = Array(length);
+
+ while (length--) {
+ array[length] = arguments[length];
+ }
+ return unzip(array);
+ }
+
+ /**
+ * Creates an object composed from arrays of property names and values. Provide
+ * either a single two dimensional array, e.g. `[[key1, value1], [key2, value2]]`
+ * or two arrays, one of property names and one of corresponding values.
+ *
+ * @static
+ * @memberOf _
+ * @alias object
+ * @category Array
+ * @param {Array} props The property names.
+ * @param {Array} [values=[]] The property values.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.zipObject(['fred', 'barney'], [30, 40]);
+ * // => { 'fred': 30, 'barney': 40 }
+ */
+ function zipObject(props, values) {
+ var index = -1,
+ length = props ? props.length : 0,
+ result = {};
+
+ if (length && !values && !isArray(props[0])) {
+ values = [];
+ }
+ while (++index < length) {
+ var key = props[index];
+ if (values) {
+ result[key] = values[index];
+ } else if (key) {
+ result[key[0]] = key[1];
+ }
+ }
+ return result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object that wraps `value` with explicit method
+ * chaining enabled.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to wrap.
+ * @returns {Object} Returns the new `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'pebbles', 'age': 1 }
+ * ];
+ *
+ * var youngest = _.chain(users)
+ * .sortBy('age')
+ * .map(function(chr) { return chr.user + ' is ' + chr.age; })
+ * .first()
+ * .value();
+ * // => 'pebbles is 1'
+ */
+ function chain(value) {
+ var result = lodash(value);
+ result.__chain__ = true;
+ return result;
+ }
+
+ /**
+ * This method invokes `interceptor` and returns `value`. The interceptor is
+ * bound to `thisArg` and invoked with one argument; (value). The purpose of
+ * this method is to "tap into" a method chain in order to perform operations
+ * on intermediate results within the chain.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .tap(function(array) { array.pop(); })
+ * .reverse()
+ * .value();
+ * // => [2, 1]
+ */
+ function tap(value, interceptor, thisArg) {
+ interceptor.call(thisArg, value);
+ return value;
+ }
+
+ /**
+ * This method is like `_.tap` except that it returns the result of `interceptor`.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns the result of `interceptor`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .last()
+ * .thru(function(value) { return [value]; })
+ * .value();
+ * // => [3]
+ */
+ function thru(value, interceptor, thisArg) {
+ return interceptor.call(thisArg, value);
+ }
+
+ /**
+ * Enables explicit method chaining on the wrapper object.
+ *
+ * @name chain
+ * @memberOf _
+ * @category Chain
+ * @returns {*} Returns the `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // without explicit chaining
+ * _(users).first();
+ * // => { 'user': 'barney', 'age': 36 }
+ *
+ * // with explicit chaining
+ * _(users).chain()
+ * .first()
+ * .pick('user')
+ * .value();
+ * // => { 'user': 'barney' }
+ */
+ function wrapperChain() {
+ return chain(this);
+ }
+
+ /**
+ * Reverses the wrapped array so the first element becomes the last, the
+ * second element becomes the second to last, and so on.
+ *
+ * **Note:** This method mutates the wrapped array.
+ *
+ * @name reverse
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new reversed `lodash` object.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _(array).reverse().value()
+ * // => [3, 2, 1]
+ *
+ * console.log(array);
+ * // => [3, 2, 1]
+ */
+ function wrapperReverse() {
+ var value = this.__wrapped__;
+ if (value instanceof LazyWrapper) {
+ return new LodashWrapper(value.reverse());
+ }
+ return this.thru(function(value) {
+ return value.reverse();
+ });
+ }
+
+ /**
+ * Produces the result of coercing the unwrapped value to a string.
+ *
+ * @name toString
+ * @memberOf _
+ * @category Chain
+ * @returns {string} Returns the coerced string value.
+ * @example
+ *
+ * _([1, 2, 3]).toString();
+ * // => '1,2,3'
+ */
+ function wrapperToString() {
+ return (this.value() + '');
+ }
+
+ /**
+ * Executes the chained sequence to extract the unwrapped value.
+ *
+ * @name value
+ * @memberOf _
+ * @alias toJSON, valueOf
+ * @category Chain
+ * @returns {*} Returns the resolved unwrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperValue() {
+ return baseWrapperValue(this.__wrapped__, this.__actions__);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements corresponding to the given keys, or indexes,
+ * of `collection`. Keys may be specified as individual arguments or as arrays
+ * of keys.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(number|number[]|string|string[])} [props] The property names
+ * or indexes of elements to pick, specified individually or in arrays.
+ * @returns {Array} Returns the new array of picked elements.
+ * @example
+ *
+ * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
+ * // => ['a', 'c', 'e']
+ *
+ * _.at(['fred', 'barney', 'pebbles'], 0, 2);
+ * // => ['fred', 'pebbles']
+ */
+ function at(collection) {
+ var length = collection ? collection.length : 0;
+ if (isLength(length)) {
+ collection = toIterable(collection);
+ }
+ return baseAt(collection, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Checks if `value` is in `collection` using `SameValueZero` for equality
+ * comparisons. If `fromIndex` is negative, it is used as the offset from
+ * the end of `collection`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias contains, include
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {*} target The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {boolean} Returns `true` if a matching element is found, else `false`.
+ * @example
+ *
+ * _.includes([1, 2, 3], 1);
+ * // => true
+ *
+ * _.includes([1, 2, 3], 1, 2);
+ * // => false
+ *
+ * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
+ * // => true
+ *
+ * _.includes('pebbles', 'eb');
+ * // => true
+ */
+ function includes(collection, target, fromIndex) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ collection = values(collection);
+ length = collection.length;
+ }
+ if (!length) {
+ return false;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else {
+ fromIndex = 0;
+ }
+ return (typeof collection == 'string' || !isArray(collection) && isString(collection))
+ ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
+ : (getIndexOf(collection, target, fromIndex) > -1);
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the number of times the key was returned by `iteratee`.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy(['one', 'two', 'three'], 'length');
+ * // => { '3': 2, '5': 1 }
+ */
+ var countBy = createAggregator(function(result, value, key) {
+ hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1);
+ });
+
+ /**
+ * Checks if `predicate` returns truthy for **all** elements of `collection`.
+ * The predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias all
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes']);
+ * // => false
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.every(users, 'age');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.every(users, { 'age': 36 });
+ * // => false
+ */
+ function every(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayEvery : baseEvery;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning an array of all elements
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias select
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var evens = _.filter([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [2, 4]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.filter(users, 'active'), 'user');
+ * // => ['fred']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.filter(users, { 'age': 36 }), 'user');
+ * // => ['barney']
+ */
+ function filter(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning the first element
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias detect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.result(_.find(users, function(chr) { return chr.age < 40; }), 'user');
+ * // => 'barney'
+ *
+ * // using the "_.matches" callback shorthand
+ * _.result(_.find(users, { 'age': 1 }), 'user');
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.result(_.find(users, 'active'), 'user');
+ * // => 'fred'
+ */
+ function find(collection, predicate, thisArg) {
+ if (isArray(collection)) {
+ var index = findIndex(collection, predicate, thisArg);
+ return index > -1 ? collection[index] : undefined;
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEach);
+ }
+
+ /**
+ * This method is like `_.find` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * _.findLast([1, 2, 3, 4], function(n) { return n % 2 == 1; });
+ * // => 3
+ */
+ function findLast(collection, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEachRight);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning the first element that has equivalent property
+ * values.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy' },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy' }
+ * ];
+ *
+ * _.result(_.findWhere(users, { 'status': 'busy' }), 'user');
+ * // => 'barney'
+ *
+ * _.result(_.findWhere(users, { 'age': 40 }), 'user');
+ * // => 'fred'
+ */
+ function findWhere(collection, source) {
+ return find(collection, matches(source));
+ }
+
+ /**
+ * Iterates over elements of `collection` invoking `iteratee` for each element.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection). Iterator functions may exit iteration early
+ * by explicitly returning `false`.
+ *
+ * **Note:** As with other "Collections" methods, objects with a `length` property
+ * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+ * may be used for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEach(function(n) { console.log(n); });
+ * // => logs each value from left to right and returns the array
+ *
+ * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(n, key) { console.log(n, key); });
+ * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
+ */
+ function forEach(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEach(collection, iteratee)
+ : baseEach(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * This method is like `_.forEach` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias eachRight
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEachRight(function(n) { console.log(n); }).join(',');
+ * // => logs each value from right to left and returns the array
+ */
+ function forEachRight(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEachRight(collection, iteratee)
+ : baseEachRight(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is an array of the elements responsible for generating the key.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * // using the "_.property" callback shorthand
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
+ */
+ var groupBy = createAggregator(function(result, value, key) {
+ if (hasOwnProperty.call(result, key)) {
+ result[key].push(value);
+ } else {
+ result[key] = [value];
+ }
+ });
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the last element responsible for generating the key. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * var keyData = [
+ * { 'dir': 'left', 'code': 97 },
+ * { 'dir': 'right', 'code': 100 }
+ * ];
+ *
+ * _.indexBy(keyData, 'dir');
+ * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) { return String.fromCharCode(object.code); });
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) { return this.fromCharCode(object.code); }, String);
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ */
+ var indexBy = createAggregator(function(result, value, key) {
+ result[key] = value;
+ });
+
+ /**
+ * Invokes the method named by `methodName` on each element in `collection`,
+ * returning an array of the results of each invoked method. Any additional
+ * arguments are provided to each invoked method. If `methodName` is a function
+ * it is invoked for, and `this` bound to, each element in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {...*} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+ * // => [[1, 5, 7], [1, 2, 3]]
+ *
+ * _.invoke([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
+ */
+ function invoke(collection, methodName) {
+ return baseInvoke(collection, methodName, baseSlice(arguments, 2));
+ }
+
+ /**
+ * Creates an array of values by running each element in `collection` through
+ * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias collect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new mapped array.
+ * @example
+ *
+ * _.map([1, 2, 3], function(n) { return n * 3; });
+ * // => [3, 6, 9]
+ *
+ * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(n) { return n * 3; });
+ * // => [3, 6, 9] (iteration order is not guaranteed)
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(users, 'user');
+ * // => ['barney', 'fred']
+ */
+ function map(collection, iteratee, thisArg) {
+ var func = isArray(collection) ? arrayMap : baseMap;
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return func(collection, iteratee);
+ }
+
+ /**
+ * Gets the maximum value of `collection`. If `collection` is empty or falsey
+ * `-Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the maximum value.
+ * @example
+ *
+ * _.max([4, 2, 8, 6]);
+ * // => 8
+ *
+ * _.max([]);
+ * // => -Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.max(users, function(chr) { return chr.age; });
+ * // => { 'user': 'fred', 'age': 40 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.max(users, 'age');
+ * // => { 'user': 'fred', 'age': 40 };
+ */
+ var max = createExtremum(arrayMax);
+
+ /**
+ * Gets the minimum value of `collection`. If `collection` is empty or falsey
+ * `Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the minimum value.
+ * @example
+ *
+ * _.min([4, 2, 8, 6]);
+ * // => 2
+ *
+ * _.min([]);
+ * // => Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.min(users, function(chr) { return chr.age; });
+ * // => { 'user': 'barney', 'age': 36 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.min(users, 'age');
+ * // => { 'user': 'barney', 'age': 36 };
+ */
+ var min = createExtremum(arrayMin, true);
+
+ /**
+ * Creates an array of elements split into two groups, the first of which
+ * contains elements `predicate` returns truthy for, while the second of which
+ * contains elements `predicate` returns falsey for. The predicate is bound
+ * to `thisArg` and invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the array of grouped elements.
+ * @example
+ *
+ * _.partition([1, 2, 3], function(n) { return n % 2; });
+ * // => [[1, 3], [2]]
+ *
+ * _.partition([1.2, 2.3, 3.4], function(n) { return this.floor(n) % 2; }, Math);
+ * // => [[1, 3], [2]]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * // using the "_.matches" callback shorthand
+ * _.map(_.partition(users, { 'age': 1 }), function(array) { return _.pluck(array, 'user'); });
+ * // => [['pebbles'], ['barney', 'fred']]
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(_.partition(users, 'active'), function(array) { return _.pluck(array, 'user'); });
+ * // => [['fred'], ['barney', 'pebbles']]
+ */
+ var partition = createAggregator(function(result, value, key) {
+ result[key ? 0 : 1].push(value);
+ }, function() { return [[], []]; });
+
+ /**
+ * Gets the value of `key` from all elements in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {string} key The key of the property to pluck.
+ * @returns {Array} Returns the property values.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.pluck(users, 'user');
+ * // => ['barney', 'fred']
+ *
+ * var userIndex = _.indexBy(users, 'user');
+ * _.pluck(userIndex, 'age');
+ * // => [36, 40] (iteration order is not guaranteed)
+ */
+ function pluck(collection, key) {
+ return map(collection, property(key));
+ }
+
+ /**
+ * Reduces `collection` to a value which is the accumulated result of running
+ * each element in `collection` through `iteratee`, where each successive
+ * invocation is supplied the return value of the previous. If `accumulator`
+ * is not provided the first element of `collection` is used as the initial
+ * value. The `iteratee` is bound to `thisArg`and invoked with four arguments;
+ * (accumulator, value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @alias foldl, inject
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var sum = _.reduce([1, 2, 3], function(sum, n) { return sum + n; });
+ * // => 6
+ *
+ * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * return result;
+ * }, {});
+ * // => { 'a': 3, 'b': 6, 'c': 9 } (iteration order is not guaranteed)
+ */
+ function reduce(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduce : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEach);
+ }
+
+ /**
+ * This method is like `_.reduce` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias foldr
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var array = [[0, 1], [2, 3], [4, 5]];
+ * _.reduceRight(array, function(flattened, other) { return flattened.concat(other); }, []);
+ * // => [4, 5, 2, 3, 0, 1]
+ */
+ function reduceRight(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduceRight : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEachRight);
+ }
+
+ /**
+ * The opposite of `_.filter`; this method returns the elements of `collection`
+ * that `predicate` does **not** return truthy for.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var odds = _.reject([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [1, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.reject(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.reject(users, { 'age': 36 }), 'user');
+ * // => ['fred']
+ */
+ function reject(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, function(value, index, collection) {
+ return !predicate(value, index, collection);
+ });
+ }
+
+ /**
+ * Gets a random element or `n` random elements from a collection.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to sample.
+ * @param {number} [n] The number of elements to sample.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {*} Returns the random sample(s).
+ * @example
+ *
+ * _.sample([1, 2, 3, 4]);
+ * // => 2
+ *
+ * _.sample([1, 2, 3, 4], 2);
+ * // => [3, 1]
+ */
+ function sample(collection, n, guard) {
+ if (guard ? isIterateeCall(collection, n, guard) : n == null) {
+ collection = toIterable(collection);
+ var length = collection.length;
+ return length > 0 ? collection[baseRandom(0, length - 1)] : undefined;
+ }
+ var result = shuffle(collection);
+ result.length = nativeMin(n < 0 ? 0 : (+n || 0), result.length);
+ return result;
+ }
+
+ /**
+ * Creates an array of shuffled values, using a version of the Fisher-Yates
+ * shuffle. See [Wikipedia](http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to shuffle.
+ * @returns {Array} Returns the new shuffled array.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4]);
+ * // => [4, 1, 3, 2]
+ */
+ function shuffle(collection) {
+ collection = toIterable(collection);
+
+ var index = -1,
+ length = collection.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var rand = baseRandom(0, index);
+ if (index != rand) {
+ result[index] = result[rand];
+ }
+ result[rand] = collection[index];
+ }
+ return result;
+ }
+
+ /**
+ * Gets the size of `collection` by returning `collection.length` for
+ * array-like values or the number of own enumerable properties for objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @returns {number} Returns the size of `collection`.
+ * @example
+ *
+ * _.size([1, 2]);
+ * // => 2
+ *
+ * _.size({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => 3
+ *
+ * _.size('pebbles');
+ * // => 7
+ */
+ function size(collection) {
+ var length = collection ? collection.length : 0;
+ return isLength(length) ? length : keys(collection).length;
+ }
+
+ /**
+ * Checks if `predicate` returns truthy for **any** element of `collection`.
+ * The function returns as soon as it finds a passing value and does not iterate
+ * over the entire collection. The predicate is bound to `thisArg` and invoked
+ * with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias any
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.some([null, 0, 'yes', false], Boolean);
+ * // => true
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.some(users, 'active');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.some(users, { 'age': 1 });
+ * // => false
+ */
+ function some(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arraySome : baseSome;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Creates an array of elements, sorted in ascending order by the results of
+ * running each element in a collection through `iteratee`. This method performs
+ * a stable sort, that is, it preserves the original sort order of equal elements.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Array|Function|Object|string} [iteratee=_.identity] The function
+ * invoked per iteration. If a property name or an object is provided it is
+ * used to create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * _.sortBy([1, 2, 3], function(n) { return Math.sin(n); });
+ * // => [3, 1, 2]
+ *
+ * _.sortBy([1, 2, 3], function(n) { return this.sin(n); }, Math);
+ * // => [3, 1, 2]
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'pebbles' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.sortBy(users, 'user'), 'user');
+ * // => ['barney', 'fred', 'pebbles']
+ */
+ function sortBy(collection, iteratee, thisArg) {
+ var index = -1,
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ iteratee = getCallback(iteratee, thisArg, 3);
+ baseEach(collection, function(value, key, collection) {
+ result[++index] = { 'criteria': iteratee(value, key, collection), 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareAscending);
+ }
+
+ /**
+ * This method is like `_.sortBy` except that it sorts by property names
+ * instead of an iteratee function.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(string|string[])} props The property names to sort by,
+ * specified as individual property names or arrays of property names.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 26 },
+ * { 'user': 'fred', 'age': 30 }
+ * ];
+ *
+ * _.map(_.sortByAll(users, ['user', 'age']), _.values);
+ * // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
+ */
+ function sortByAll(collection) {
+ var args = arguments;
+ if (args.length > 3 && isIterateeCall(args[1], args[2], args[3])) {
+ args = [collection, args[1]];
+ }
+ var index = -1,
+ length = collection ? collection.length : 0,
+ props = baseFlatten(args, false, false, 1),
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value, key, collection) {
+ var length = props.length,
+ criteria = Array(length);
+
+ while (length--) {
+ criteria[length] = value == null ? undefined : value[props[length]];
+ }
+ result[++index] = { 'criteria': criteria, 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareMultipleAscending);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning an array of all elements that have equivalent
+ * property values.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy', 'pets': ['hoppy'] },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy', 'pets': ['baby puss', 'dino'] }
+ * ];
+ *
+ * _.pluck(_.where(users, { 'age': 36 }), 'user');
+ * // => ['barney']
+ *
+ * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user');
+ * // => ['fred']
+ *
+ * _.pluck(_.where(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function where(collection, source) {
+ return filter(collection, matches(source));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Gets the number of milliseconds that have elapsed since the Unix epoch
+ * (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @category Date
+ * @example
+ *
+ * _.defer(function(stamp) { console.log(_.now() - stamp); }, _.now());
+ * // => logs the number of milliseconds it took for the deferred function to be invoked
+ */
+ var now = nativeNow || function() {
+ return new Date().getTime();
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The opposite of `_.before`; this method creates a function that invokes
+ * `func` once it is called `n` or more times.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls before `func` is invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var saves = ['profile', 'settings'];
+ *
+ * var done = _.after(saves.length, function() {
+ * console.log('done saving!');
+ * });
+ *
+ * _.forEach(saves, function(type) {
+ * asyncSave({ 'type': type, 'complete': done });
+ * });
+ * // => logs 'done saving!' after the two async saves have completed
+ */
+ function after(n, func) {
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ n = nativeIsFinite(n = +n) ? n : 0;
+ return function() {
+ if (--n < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ }
+
+ /**
+ * Creates a function that accepts up to `n` arguments ignoring any
+ * additional arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to cap arguments for.
+ * @param {number} [n=func.length] The arity cap.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+ * // => [6, 8, 10]
+ */
+ function ary(func, n, guard) {
+ if (guard && isIterateeCall(func, n, guard)) {
+ n = null;
+ }
+ n = n == null ? func.length : (+n || 0);
+ return createWrapper(func, ARY_FLAG, null, null, null, null, n);
+ }
+
+ /**
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it is called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * jQuery('#add').on('click', _.before(5, addContactToList));
+ * // => allows adding up to 4 contacts to the list
+ */
+ function before(n, func) {
+ var result;
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ return function() {
+ if (--n > 0) {
+ result = func.apply(this, arguments);
+ } else {
+ func = null;
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of `thisArg`
+ * and prepends any additional `_.bind` arguments to those provided to the
+ * bound function.
+ *
+ * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** Unlike native `Function#bind` this method does not set the `length`
+ * property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var greet = function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * };
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * var bound = _.bind(greet, object, 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * // using placeholders
+ * var bound = _.bind(greet, object, _, '!');
+ * bound('hi');
+ * // => 'hi fred!'
+ */
+ function bind(func, thisArg) {
+ var bitmask = BIND_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bind.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(func, bitmask, thisArg, partials, holders);
+ }
+
+ /**
+ * Binds methods of an object to the object itself, overwriting the existing
+ * method. Method names may be specified as individual arguments or as arrays
+ * of method names. If no method names are provided all enumerable function
+ * properties, own and inherited, of `object` are bound.
+ *
+ * **Note:** This method does not set the `length` property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {...(string|string[])} [methodNames] The object method names to bind,
+ * specified as individual method names or arrays of method names.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var view = {
+ * 'label': 'docs',
+ * 'onClick': function() { console.log('clicked ' + this.label); }
+ * };
+ *
+ * _.bindAll(view);
+ * jQuery('#docs').on('click', view.onClick);
+ * // => logs 'clicked docs' when the element is clicked
+ */
+ function bindAll(object) {
+ return baseBindAll(object,
+ arguments.length > 1
+ ? baseFlatten(arguments, false, false, 1)
+ : functions(object)
+ );
+ }
+
+ /**
+ * Creates a function that invokes the method at `object[key]` and prepends
+ * any additional `_.bindKey` arguments to those provided to the bound function.
+ *
+ * This method differs from `_.bind` by allowing bound functions to reference
+ * methods that may be redefined or don't yet exist.
+ * See [Peter Michaux's article](http://michaux.ca/articles/lazy-function-definition-pattern)
+ * for more details.
+ *
+ * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object the method belongs to.
+ * @param {string} key The key of the method.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var object = {
+ * 'user': 'fred',
+ * 'greet': function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * }
+ * };
+ *
+ * var bound = _.bindKey(object, 'greet', 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * object.greet = function(greeting, punctuation) {
+ * return greeting + 'ya ' + this.user + punctuation;
+ * };
+ *
+ * bound('!');
+ * // => 'hiya fred!'
+ *
+ * // using placeholders
+ * var bound = _.bindKey(object, 'greet', _, '!');
+ * bound('hi');
+ * // => 'hiya fred!'
+ */
+ function bindKey(object, key) {
+ var bitmask = BIND_FLAG | BIND_KEY_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bindKey.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(key, bitmask, object, partials, holders);
+ }
+
+ /**
+ * Creates a function that accepts one or more arguments of `func` that when
+ * called either invokes `func` returning its result, if all `func` arguments
+ * have been provided, or returns a function that accepts one or more of the
+ * remaining `func` arguments, and so on. The arity of `func` may be specified
+ * if `func.length` is not sufficient.
+ *
+ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curry(abc);
+ *
+ * curried(1)(2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(1)(_, 3)(2);
+ * // => [1, 2, 3]
+ */
+ function curry(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curry.placeholder;
+ return result;
+ }
+
+ /**
+ * This method is like `_.curry` except that arguments are applied to `func`
+ * in the manner of `_.partialRight` instead of `_.partial`.
+ *
+ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curryRight(abc);
+ *
+ * curried(3)(2)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(2, 3)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(3)(1, _)(2);
+ * // => [1, 2, 3]
+ */
+ function curryRight(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_RIGHT_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curryRight.placeholder;
+ return result;
+ }
+
+ /**
+ * Creates a function that delays invoking `func` until after `wait` milliseconds
+ * have elapsed since the last time it was invoked. The created function comes
+ * with a `cancel` method to cancel delayed invocations. Provide an options
+ * object to indicate that `func` should be invoked on the leading and/or
+ * trailing edge of the `wait` timeout. Subsequent calls to the debounced
+ * function return the result of the last `func` invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the debounced function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.debounce` and `_.throttle`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} wait The number of milliseconds to delay.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=false] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {number} [options.maxWait] The maximum time `func` is allowed to be
+ * delayed before it is invoked.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // avoid costly calculations while the window size is in flux
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+ *
+ * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
+ * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
+ *
+ * // ensure `batchLog` is invoked once after 1 second of debounced calls
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', _.debounce(batchLog, 250, {
+ * 'maxWait': 1000
+ * }));
+ *
+ * // cancel a debounced call
+ * var todoChanges = _.debounce(batchLog, 1000);
+ * Object.observe(models.todo, todoChanges);
+ *
+ * Object.observe(models, function(changes) {
+ * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
+ * todoChanges.cancel();
+ * }
+ * }, ['delete']);
+ *
+ * // ...at some point `models.todo` is changed
+ * models.todo.completed = true;
+ *
+ * // ...before 1 second has passed `models.todo` is deleted
+ * // which cancels the debounced `todoChanges` call
+ * delete models.todo;
+ */
+ function debounce(func, wait, options) {
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = wait < 0 ? 0 : wait;
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (isObject(options)) {
+ leading = options.leading;
+ maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+
+ function cancel() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ }
+
+ function delayed() {
+ var remaining = wait - (now() - stamp);
+ if (remaining <= 0 || remaining > wait) {
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ var isCalled = trailingCall;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
+ }
+ }
+
+ function maxDelayed() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ }
+
+ function debounced() {
+ args = arguments;
+ stamp = now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0 || remaining > maxWait;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ return debounced;
+ }
+
+ /**
+ * Defers invoking the `func` until the current call stack has cleared. Any
+ * additional arguments are provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to defer.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.defer(function(text) { console.log(text); }, 'deferred');
+ * // logs 'deferred' after one or more milliseconds
+ */
+ function defer(func) {
+ return baseDelay(func, 1, arguments, 1);
+ }
+
+ /**
+ * Invokes `func` after `wait` milliseconds. Any additional arguments are
+ * provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.delay(function(text) { console.log(text); }, 1000, 'later');
+ * // => logs 'later' after one second
+ */
+ function delay(func, wait) {
+ return baseDelay(func, wait, arguments, 2);
+ }
+
+ /**
+ * Creates a function that returns the result of invoking the provided
+ * functions with the `this` binding of the created function, where each
+ * successive invocation is supplied the return value of the previous.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function add(x, y) {
+ * return x + y;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flow(add, square);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ function flow() {
+ var funcs = arguments,
+ length = funcs.length;
+
+ if (!length) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = 0,
+ result = funcs[index].apply(this, arguments);
+
+ while (++index < length) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * This method is like `_.flow` except that it creates a function that
+ * invokes the provided functions from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias backflow, compose
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function add(x, y) {
+ * return x + y;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flowRight(square, add);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ function flowRight() {
+ var funcs = arguments,
+ fromIndex = funcs.length - 1;
+
+ if (fromIndex < 0) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = fromIndex,
+ result = funcs[index].apply(this, arguments);
+
+ while (index--) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is coerced to a string and used as the
+ * cache key. The `func` is invoked with the `this` binding of the memoized
+ * function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the ES6 `Map` method interface
+ * of `get`, `has`, and `set`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoizing function.
+ * @example
+ *
+ * var upperCase = _.memoize(function(string) {
+ * return string.toUpperCase();
+ * });
+ *
+ * upperCase('fred');
+ * // => 'FRED'
+ *
+ * // modifying the result cache
+ * upperCase.cache.set('fred, 'BARNEY');
+ * upperCase('fred');
+ * // => 'BARNEY'
+ *
+ * // replacing `_.memoize.Cache`
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'barney' };
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'fred' }
+ *
+ * _.memoize.Cache = WeakMap;
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'barney' }
+ */
+ function memoize(func, resolver) {
+ if (!isFunction(func) || (resolver && !isFunction(resolver))) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var cache = memoized.cache,
+ key = resolver ? resolver.apply(this, arguments) : arguments[0];
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, arguments);
+ cache.set(key, result);
+ return result;
+ };
+ memoized.cache = new memoize.Cache;
+ return memoized;
+ }
+
+ /**
+ * Creates a function that negates the result of the predicate `func`. The
+ * `func` predicate is invoked with the `this` binding and arguments of the
+ * created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} predicate The predicate to negate.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function isEven(n) {
+ * return n % 2 == 0;
+ * }
+ *
+ * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+ * // => [1, 3, 5]
+ */
+ function negate(predicate) {
+ if (!isFunction(predicate)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
+ }
+
+ /**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first call. The `func` is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // `initialize` invokes `createApplication` once
+ */
+ function once(func) {
+ return before(func, 2);
+ }
+
+ /**
+ * Creates a function that invokes `func` with `partial` arguments prepended
+ * to those provided to the new function. This method is like `_.bind` except
+ * it does **not** alter the `this` binding.
+ *
+ * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var sayHelloTo = _.partial(greet, 'hello');
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ *
+ * // using placeholders
+ * var greetFred = _.partial(greet, _, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ */
+ function partial(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partial.placeholder);
+
+ return createWrapper(func, PARTIAL_FLAG, null, partials, holders);
+ }
+
+ /**
+ * This method is like `_.partial` except that partially applied arguments
+ * are appended to those provided to the new function.
+ *
+ * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var greetFred = _.partialRight(greet, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ *
+ * // using placeholders
+ * var sayHelloTo = _.partialRight(greet, 'hello', _);
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ */
+ function partialRight(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partialRight.placeholder);
+
+ return createWrapper(func, PARTIAL_RIGHT_FLAG, null, partials, holders);
+ }
+
+ /**
+ * Creates a function that invokes `func` with arguments arranged according
+ * to the specified indexes where the argument value at the first index is
+ * provided as the first argument, the argument value at the second index is
+ * provided as the second argument, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to rearrange arguments for.
+ * @param {...(number|number[])} indexes The arranged argument indexes,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var rearged = _.rearg(function(a, b, c) {
+ * return [a, b, c];
+ * }, 2, 0, 1);
+ *
+ * rearged('b', 'c', 'a')
+ * // => ['a', 'b', 'c']
+ *
+ * var map = _.rearg(_.map, [1, 0]);
+ * map(function(n) { return n * 3; }, [1, 2, 3]);
+ * // => [3, 6, 9]
+ */
+ function rearg(func) {
+ var indexes = baseFlatten(arguments, false, false, 1);
+ return createWrapper(func, REARG_FLAG, null, null, null, indexes);
+ }
+
+ /**
+ * Creates a function that only invokes `func` at most once per every `wait`
+ * milliseconds. The created function comes with a `cancel` method to cancel
+ * delayed invocations. Provide an options object to indicate that `func`
+ * should be invoked on the leading and/or trailing edge of the `wait` timeout.
+ * Subsequent calls to the throttled function return the result of the last
+ * `func` call.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the throttled function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.throttle` and `_.debounce`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} wait The number of milliseconds to throttle invocations to.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=true] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // avoid excessively updating the position while scrolling
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+ *
+ * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false })
+ * jQuery('.interactive').on('click', throttled);
+ *
+ * // cancel a trailing throttled call
+ * jQuery(window).on('popstate', throttled.cancel);
+ */
+ function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ if (options === false) {
+ leading = false;
+ } else if (isObject(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+ debounceOptions.leading = leading;
+ debounceOptions.maxWait = +wait;
+ debounceOptions.trailing = trailing;
+ return debounce(func, wait, debounceOptions);
+ }
+
+ /**
+ * Creates a function that provides `value` to the wrapper function as its
+ * first argument. Any additional arguments provided to the function are
+ * appended to those provided to the wrapper function. The wrapper is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {*} value The value to wrap.
+ * @param {Function} wrapper The wrapper function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var p = _.wrap(_.escape, function(func, text) {
+ * return '<p>' + func(text) + '</p>';
+ * });
+ *
+ * p('fred, barney, & pebbles');
+ * // => '<p>fred, barney, & pebbles</p>'
+ */
+ function wrap(value, wrapper) {
+ wrapper = wrapper == null ? identity : wrapper;
+ return createWrapper(wrapper, PARTIAL_FLAG, null, [value], []);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
+ * otherwise they are assigned by reference. If `customizer` is provided it is
+ * invoked to produce the cloned values. If `customizer` returns `undefined`
+ * cloning is handled by the method instead. The `customizer` is bound to
+ * `thisArg` and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var shallow = _.clone(users);
+ * shallow[0] === users[0];
+ * // => true
+ *
+ * var deep = _.clone(users, true);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var body = _.clone(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(false) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 0
+ */
+ function clone(value, isDeep, customizer, thisArg) {
+ // Juggle arguments.
+ if (typeof isDeep != 'boolean' && isDeep != null) {
+ thisArg = customizer;
+ customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep;
+ isDeep = false;
+ }
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, isDeep, customizer);
+ }
+
+ /**
+ * Creates a deep clone of `value`. If `customizer` is provided it is invoked
+ * to produce the cloned values. If `customizer` returns `undefined` cloning
+ * is handled by the method instead. The `customizer` is bound to `thisArg`
+ * and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the deep cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var deep = _.cloneDeep(users);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var el = _.cloneDeep(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(true) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 20
+ */
+ function cloneDeep(value, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, true, customizer);
+ }
+
+ /**
+ * Checks if `value` is classified as an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * (function() { return _.isArguments(arguments); })();
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ var length = isObjectLike(value) ? value.length : undefined;
+ return (isLength(length) && objToString.call(value) == argsTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * (function() { return _.isArray(arguments); })();
+ * // => false
+ */
+ var isArray = nativeIsArray || function(value) {
+ return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false;
+ };
+
+ /**
+ * Checks if `value` is classified as a boolean primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isBoolean(false);
+ * // => true
+ *
+ * _.isBoolean(null);
+ * // => false
+ */
+ function isBoolean(value) {
+ return (value === true || value === false || isObjectLike(value) && objToString.call(value) == boolTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Date` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isDate(new Date);
+ * // => true
+ *
+ * _.isDate('Mon April 23 2012');
+ * // => false
+ */
+ function isDate(value) {
+ return (isObjectLike(value) && objToString.call(value) == dateTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a DOM element.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
+ * @example
+ *
+ * _.isElement(document.body);
+ * // => true
+ *
+ * _.isElement('<body>');
+ * // => false
+ */
+ function isElement(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) &&
+ objToString.call(value).indexOf('Element') > -1) || false;
+ }
+ // Fallback for environments without DOM support.
+ if (!support.dom) {
+ isElement = function(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value)) || false;
+ };
+ }
+
+ /**
+ * Checks if a value is empty. A value is considered empty unless it is an
+ * `arguments` object, array, string, or jQuery-like collection with a length
+ * greater than `0` or an object with own enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Array|Object|string} value The value to inspect.
+ * @returns {boolean} Returns `true` if `value` is empty, else `false`.
+ * @example
+ *
+ * _.isEmpty(null);
+ * // => true
+ *
+ * _.isEmpty(true);
+ * // => true
+ *
+ * _.isEmpty(1);
+ * // => true
+ *
+ * _.isEmpty([1, 2, 3]);
+ * // => false
+ *
+ * _.isEmpty({ 'a': 1 });
+ * // => false
+ */
+ function isEmpty(value) {
+ if (value == null) {
+ return true;
+ }
+ var length = value.length;
+ if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) ||
+ (isObjectLike(value) && isFunction(value.splice)))) {
+ return !length;
+ }
+ return !keys(value).length;
+ }
+
+ /**
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent. If `customizer` is provided it is invoked to compare values.
+ * If `customizer` returns `undefined` comparisons are handled by the method
+ * instead. The `customizer` is bound to `thisArg` and invoked with three
+ * arguments; (value, other [, index|key]).
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Functions and DOM nodes
+ * are **not** supported. Provide a customizer function to extend support
+ * for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'fred' };
+ *
+ * object == other;
+ * // => false
+ *
+ * _.isEqual(object, other);
+ * // => true
+ *
+ * // using a customizer callback
+ * var array = ['hello', 'goodbye'];
+ * var other = ['hi', 'goodbye'];
+ *
+ * _.isEqual(array, other, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isEqual(value, other, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && isStrictComparable(value) && isStrictComparable(other)) {
+ return value === other;
+ }
+ var result = customizer ? customizer(value, other) : undefined;
+ return typeof result == 'undefined' ? baseIsEqual(value, other, customizer) : !!result;
+ }
+
+ /**
+ * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+ * `SyntaxError`, `TypeError`, or `URIError` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
+ * @example
+ *
+ * _.isError(new Error);
+ * // => true
+ *
+ * _.isError(Error);
+ * // => false
+ */
+ function isError(value) {
+ return (isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a finite primitive number.
+ *
+ * **Note:** This method is based on ES6 `Number.isFinite`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
+ * @example
+ *
+ * _.isFinite(10);
+ * // => true
+ *
+ * _.isFinite('10');
+ * // => false
+ *
+ * _.isFinite(true);
+ * // => false
+ *
+ * _.isFinite(Object(10));
+ * // => false
+ *
+ * _.isFinite(Infinity);
+ * // => false
+ */
+ var isFinite = nativeNumIsFinite || function(value) {
+ return typeof value == 'number' && nativeIsFinite(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // Avoid a Chakra JIT bug in compatibility modes of IE 11.
+ // See https://github.com/jashkenas/underscore/issues/1621.
+ return typeof value == 'function' || false;
+ }
+ // Fallback for environments that return incorrect `typeof` operator results.
+ if (isFunction(/x/) || (Uint8Array && !isFunction(Uint8Array))) {
+ isFunction = function(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in older versions of Chrome and Safari which return 'function' for regexes
+ // and Safari 8 equivalents which return 'object' for typed array constructors.
+ return objToString.call(value) == funcTag;
+ };
+ }
+
+ /**
+ * Checks if `value` is the language type of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * **Note:** See the [ES5 spec](http://es5.github.io/#x8) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+ function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291.
+ var type = typeof value;
+ return type == 'function' || (value && type == 'object') || false;
+ }
+
+ /**
+ * Performs a deep comparison between `object` and `source` to determine if
+ * `object` contains equivalent property values. If `customizer` is provided
+ * it is invoked to compare values. If `customizer` returns `undefined`
+ * comparisons are handled by the method instead. The `customizer` is bound
+ * to `thisArg` and invoked with three arguments; (value, other, index|key).
+ *
+ * **Note:** This method supports comparing properties of arrays, booleans,
+ * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions
+ * and DOM nodes are **not** supported. Provide a customizer function to extend
+ * support for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Object} source The object to inspect.
+ * @param {Object} source The object of property values to match.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.isMatch(object, { 'age': 40 });
+ * // => true
+ *
+ * _.isMatch(object, { 'age': 36 });
+ * // => false
+ *
+ * // using a customizer callback
+ * var object = { 'greeting': 'hello' };
+ * var source = { 'greeting': 'hi' };
+ *
+ * _.isMatch(object, source, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isMatch(object, source, customizer, thisArg) {
+ var props = keys(source),
+ length = props.length;
+
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ }
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = values[length] = source[props[length]];
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return baseIsMatch(object, props, values, strictCompareFlags, customizer);
+ }
+
+ /**
+ * Checks if `value` is `NaN`.
+ *
+ * **Note:** This method is not the same as native `isNaN` which returns `true`
+ * for `undefined` and other non-numeric values. See the [ES5 spec](http://es5.github.io/#x15.1.2.4)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+ * @example
+ *
+ * _.isNaN(NaN);
+ * // => true
+ *
+ * _.isNaN(new Number(NaN));
+ * // => true
+ *
+ * isNaN(undefined);
+ * // => true
+ *
+ * _.isNaN(undefined);
+ * // => false
+ */
+ function isNaN(value) {
+ // An `NaN` primitive is the only value that is not equal to itself.
+ // Perform the `toStringTag` check first to avoid errors with some host objects in IE.
+ return isNumber(value) && value != +value;
+ }
+
+ /**
+ * Checks if `value` is a native function.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
+ * @example
+ *
+ * _.isNative(Array.prototype.push);
+ * // => true
+ *
+ * _.isNative(_);
+ * // => false
+ */
+ function isNative(value) {
+ if (value == null) {
+ return false;
+ }
+ if (objToString.call(value) == funcTag) {
+ return reNative.test(fnToString.call(value));
+ }
+ return (isObjectLike(value) && reHostCtor.test(value)) || false;
+ }
+
+ /**
+ * Checks if `value` is `null`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
+ * @example
+ *
+ * _.isNull(null);
+ * // => true
+ *
+ * _.isNull(void 0);
+ * // => false
+ */
+ function isNull(value) {
+ return value === null;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Number` primitive or object.
+ *
+ * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified
+ * as numbers, use the `_.isFinite` method.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isNumber(8.4);
+ * // => true
+ *
+ * _.isNumber(NaN);
+ * // => true
+ *
+ * _.isNumber('8.4');
+ * // => false
+ */
+ function isNumber(value) {
+ return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
+ *
+ * **Note:** This method assumes objects created by the `Object` constructor
+ * have no inherited enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * }
+ *
+ * _.isPlainObject(new Foo);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ *
+ * _.isPlainObject(Object.create(null));
+ * // => true
+ */
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
+ if (!(value && objToString.call(value) == objectTag)) {
+ return false;
+ }
+ var valueOf = value.valueOf,
+ objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
+
+ return objProto
+ ? (value == objProto || getPrototypeOf(value) == objProto)
+ : shimIsPlainObject(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `RegExp` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isRegExp(/abc/);
+ * // => true
+ *
+ * _.isRegExp('/abc/');
+ * // => false
+ */
+ function isRegExp(value) {
+ return (isObjectLike(value) && objToString.call(value) == regexpTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a `String` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isString('abc');
+ * // => true
+ *
+ * _.isString(1);
+ * // => false
+ */
+ function isString(value) {
+ return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+ function isTypedArray(value) {
+ return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false;
+ }
+
+ /**
+ * Checks if `value` is `undefined`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+ * @example
+ *
+ * _.isUndefined(void 0);
+ * // => true
+ *
+ * _.isUndefined(null);
+ * // => false
+ */
+ function isUndefined(value) {
+ return typeof value == 'undefined';
+ }
+
+ /**
+ * Converts `value` to an array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Array} Returns the converted array.
+ * @example
+ *
+ * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3);
+ * // => [2, 3]
+ */
+ function toArray(value) {
+ var length = value ? value.length : 0;
+ if (!isLength(length)) {
+ return values(value);
+ }
+ if (!length) {
+ return [];
+ }
+ return arrayCopy(value);
+ }
+
+ /**
+ * Converts `value` to a plain object flattening inherited enumerable
+ * properties of `value` to own properties of the plain object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Object} Returns the converted plain object.
+ * @example
+ *
+ * function Foo() {
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.assign({ 'a': 1 }, new Foo);
+ * // => { 'a': 1, 'b': 2 }
+ *
+ * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+ * // => { 'a': 1, 'b': 2, 'c': 3 }
+ */
+ function toPlainObject(value) {
+ return baseCopy(value, keysIn(value));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources overwrite property assignments of previous sources.
+ * If `customizer` is provided it is invoked to produce the assigned values.
+ * The `customizer` is bound to `thisArg` and invoked with five arguments;
+ * (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @alias extend
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+ * // => { 'user': 'fred', 'age': 40 }
+ *
+ * // using a customizer callback
+ * var defaults = _.partialRight(_.assign, function(value, other) {
+ * return typeof value == 'undefined' ? other : value;
+ * });
+ *
+ * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ var assign = createAssigner(baseAssign);
+
+ /**
+ * Creates an object that inherits from the given `prototype` object. If a
+ * `properties` object is provided its own enumerable properties are assigned
+ * to the created object.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} prototype The object to inherit from.
+ * @param {Object} [properties] The properties to assign to the object.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * function Circle() {
+ * Shape.call(this);
+ * }
+ *
+ * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
+ *
+ * var circle = new Circle;
+ * circle instanceof Circle;
+ * // => true
+ *
+ * circle instanceof Shape;
+ * // => true
+ */
+ function create(prototype, properties, guard) {
+ var result = baseCreate(prototype);
+ if (guard && isIterateeCall(prototype, properties, guard)) {
+ properties = null;
+ }
+ return properties ? baseCopy(properties, result, keys(properties)) : result;
+ }
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object for all destination properties that resolve to `undefined`. Once a
+ * property is set, additional defaults of the same property are ignored.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function defaults(object) {
+ if (object == null) {
+ return object;
+ }
+ var args = arrayCopy(arguments);
+ args.push(assignDefaults);
+ return assign.apply(undefined, args);
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it returns the key of the
+ * first element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findKey(users, function(chr) { return chr.age < 40; });
+ * // => 'barney' (iteration order is not guaranteed)
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findKey(users, { 'age': 1 });
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findKey(users, 'active');
+ * // => 'barney'
+ */
+ function findKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwn, true);
+ }
+
+ /**
+ * This method is like `_.findKey` except that it iterates over elements of
+ * a collection in the opposite order.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findLastKey(users, function(chr) { return chr.age < 40; });
+ * // => returns `pebbles` assuming `_.findKey` returns `barney`
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastKey(users, { 'age': 36 });
+ * // => 'barney'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastKey(users, 'active');
+ * // => 'pebbles'
+ */
+ function findLastKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwnRight, true);
+ }
+
+ /**
+ * Iterates over own and inherited enumerable properties of an object invoking
+ * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, key, object). Iterator functions may exit
+ * iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forIn(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed)
+ */
+ function forIn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * This method is like `_.forIn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forInRight(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c'
+ */
+ function forInRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keysIn);
+ }
+
+ /**
+ * Iterates over own enumerable properties of an object invoking `iteratee`
+ * for each property. The `iteratee` is bound to `thisArg` and invoked with
+ * three arguments; (value, key, object). Iterator functions may exit iteration
+ * early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs '0', '1', and 'length' (iteration order is not guaranteed)
+ */
+ function forOwn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return baseForOwn(object, iteratee);
+ }
+
+ /**
+ * This method is like `_.forOwn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
+ */
+ function forOwnRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * Creates an array of function property names from all enumerable properties,
+ * own and inherited, of `object`.
+ *
+ * @static
+ * @memberOf _
+ * @alias methods
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of property names.
+ * @example
+ *
+ * _.functions(_);
+ * // => ['all', 'any', 'bind', ...]
+ */
+ function functions(object) {
+ return baseFunctions(object, keysIn(object));
+ }
+
+ /**
+ * Checks if `key` exists as a direct property of `object` instead of an
+ * inherited property.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @param {string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` is a direct property, else `false`.
+ * @example
+ *
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+ * // => true
+ */
+ function has(object, key) {
+ return object ? hasOwnProperty.call(object, key) : false;
+ }
+
+ /**
+ * Creates an object composed of the inverted keys and values of `object`.
+ * If `object` contains duplicate values, subsequent values overwrite property
+ * assignments of previous values unless `multiValue` is `true`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to invert.
+ * @param {boolean} [multiValue] Allow multiple values per key.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new inverted object.
+ * @example
+ *
+ * _.invert({ 'first': 'fred', 'second': 'barney' });
+ * // => { 'fred': 'first', 'barney': 'second' }
+ *
+ * // without `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' });
+ * // => { 'fred': 'third', 'barney': 'second' }
+ *
+ * // with `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }, true);
+ * // => { 'fred': ['first', 'third'], 'barney': ['second'] }
+ */
+ function invert(object, multiValue, guard) {
+ if (guard && isIterateeCall(object, multiValue, guard)) {
+ multiValue = null;
+ }
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key];
+
+ if (multiValue) {
+ if (hasOwnProperty.call(result, value)) {
+ result[value].push(key);
+ } else {
+ result[value] = [key];
+ }
+ }
+ else {
+ result[value] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ var keys = !nativeKeys ? shimKeys : function(object) {
+ if (object) {
+ var Ctor = object.constructor,
+ length = object.length;
+ }
+ if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
+ (typeof object != 'function' && (length && isLength(length)))) {
+ return shimKeys(object);
+ }
+ return isObject(object) ? nativeKeys(object) : [];
+ };
+
+ /**
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+ */
+ function keysIn(object) {
+ if (object == null) {
+ return [];
+ }
+ if (!isObject(object)) {
+ object = Object(object);
+ }
+ var length = object.length;
+ length = (length && isLength(length) &&
+ (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0;
+
+ var Ctor = object.constructor,
+ index = -1,
+ isProto = typeof Ctor == 'function' && Ctor.prototype == object,
+ result = Array(length),
+ skipIndexes = length > 0;
+
+ while (++index < length) {
+ result[index] = (index + '');
+ }
+ for (var key in object) {
+ if (!(skipIndexes && isIndex(key, length)) &&
+ !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object with the same keys as `object` and values generated by
+ * running each own enumerable property of `object` through `iteratee`. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * If a property name is provided for `iteratee` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `iteratee` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the new mapped object.
+ * @example
+ *
+ * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(n) { return n * 3; });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ *
+ * var users = {
+ * 'fred': { 'user': 'fred', 'age': 40 },
+ * 'pebbles': { 'user': 'pebbles', 'age': 1 }
+ * };
+ *
+ * // using the "_.property" callback shorthand
+ * _.mapValues(users, 'age');
+ * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+ */
+ function mapValues(object, iteratee, thisArg) {
+ var result = {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ baseForOwn(object, function(value, key, object) {
+ result[key] = iteratee(value, key, object);
+ });
+ return result;
+ }
+
+ /**
+ * Recursively merges own enumerable properties of the source object(s), that
+ * don't resolve to `undefined` into the destination object. Subsequent sources
+ * overwrite property assignments of previous sources. If `customizer` is
+ * provided it is invoked to produce the merged values of the destination and
+ * source properties. If `customizer` returns `undefined` merging is handled
+ * by the method instead. The `customizer` is bound to `thisArg` and invoked
+ * with five arguments; (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var users = {
+ * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
+ * };
+ *
+ * var ages = {
+ * 'data': [{ 'age': 36 }, { 'age': 40 }]
+ * };
+ *
+ * _.merge(users, ages);
+ * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
+ *
+ * // using a customizer callback
+ * var object = {
+ * 'fruits': ['apple'],
+ * 'vegetables': ['beet']
+ * };
+ *
+ * var other = {
+ * 'fruits': ['banana'],
+ * 'vegetables': ['carrot']
+ * };
+ *
+ * _.merge(object, other, function(a, b) {
+ * return _.isArray(a) ? a.concat(b) : undefined;
+ * });
+ * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
+ */
+ var merge = createAssigner(baseMerge);
+
+ /**
+ * The opposite of `_.pick`; this method creates an object composed of the
+ * own and inherited enumerable properties of `object` that are not omitted.
+ * Property names may be specified as individual arguments or as arrays of
+ * property names. If `predicate` is provided it is invoked for each property
+ * of `object` omitting the properties `predicate` returns truthy for. The
+ * predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to omit, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.omit(object, 'age');
+ * // => { 'user': 'fred' }
+ *
+ * _.omit(object, _.isNumber);
+ * // => { 'user': 'fred' }
+ */
+ function omit(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ if (typeof predicate != 'function') {
+ var props = arrayMap(baseFlatten(arguments, false, false, 1), String);
+ return pickByArray(object, baseDifference(keysIn(object), props));
+ }
+ predicate = bindCallback(predicate, thisArg, 3);
+ return pickByCallback(object, function(value, key, object) {
+ return !predicate(value, key, object);
+ });
+ }
+
+ /**
+ * Creates a two dimensional array of the key-value pairs for `object`,
+ * e.g. `[[key1, value1], [key2, value2]]`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of key-value pairs.
+ * @example
+ *
+ * _.pairs({ 'barney': 36, 'fred': 40 });
+ * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
+ */
+ function pairs(object) {
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var key = props[index];
+ result[index] = [key, object[key]];
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object composed of the picked `object` properties. Property
+ * names may be specified as individual arguments or as arrays of property
+ * names. If `predicate` is provided it is invoked for each property of `object`
+ * picking the properties `predicate` returns truthy for. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to pick, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.pick(object, 'user');
+ * // => { 'user': 'fred' }
+ *
+ * _.pick(object, _.isString);
+ * // => { 'user': 'fred' }
+ */
+ function pick(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ return typeof predicate == 'function'
+ ? pickByCallback(object, bindCallback(predicate, thisArg, 3))
+ : pickByArray(object, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Resolves the value of property `key` on `object`. If the value of `key` is
+ * a function it is invoked with the `this` binding of `object` and its result
+ * is returned, else the property value is returned. If the property value is
+ * `undefined` the `defaultValue` is used in its place.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the property to resolve.
+ * @param {*} [defaultValue] The value returned if the property value
+ * resolves to `undefined`.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': _.constant(40) };
+ *
+ * _.result(object, 'user');
+ * // => 'fred'
+ *
+ * _.result(object, 'age');
+ * // => 40
+ *
+ * _.result(object, 'status', 'busy');
+ * // => 'busy'
+ *
+ * _.result(object, 'status', _.constant('busy'));
+ * // => 'busy'
+ */
+ function result(object, key, defaultValue) {
+ var value = object == null ? undefined : object[key];
+ if (typeof value == 'undefined') {
+ value = defaultValue;
+ }
+ return isFunction(value) ? value.call(object) : value;
+ }
+
+ /**
+ * An alternative to `_.reduce`; this method transforms `object` to a new
+ * `accumulator` object which is the result of running each of its own enumerable
+ * properties through `iteratee`, with each invocation potentially mutating
+ * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked
+ * with four arguments; (accumulator, value, key, object). Iterator functions
+ * may exit iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Array|Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The custom accumulator value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var squares = _.transform([1, 2, 3, 4, 5, 6], function(result, n) {
+ * n *= n;
+ * if (n % 2) {
+ * return result.push(n) < 3;
+ * }
+ * });
+ * // => [1, 9, 25]
+ *
+ * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ */
+ function transform(object, iteratee, accumulator, thisArg) {
+ var isArr = isArray(object) || isTypedArray(object);
+ iteratee = getCallback(iteratee, thisArg, 4);
+
+ if (accumulator == null) {
+ if (isArr || isObject(object)) {
+ var Ctor = object.constructor;
+ if (isArr) {
+ accumulator = isArray(object) ? new Ctor : [];
+ } else {
+ accumulator = baseCreate(typeof Ctor == 'function' && Ctor.prototype);
+ }
+ } else {
+ accumulator = {};
+ }
+ }
+ (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) {
+ return iteratee(accumulator, value, index, object);
+ });
+ return accumulator;
+ }
+
+ /**
+ * Creates an array of the own enumerable property values of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.values(new Foo);
+ * // => [1, 2] (iteration order is not guaranteed)
+ *
+ * _.values('hi');
+ * // => ['h', 'i']
+ */
+ function values(object) {
+ return baseValues(object, keys(object));
+ }
+
+ /**
+ * Creates an array of the own and inherited enumerable property values
+ * of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.valuesIn(new Foo);
+ * // => [1, 2, 3] (iteration order is not guaranteed)
+ */
+ function valuesIn(object) {
+ return baseValues(object, keysIn(object));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Produces a random number between `min` and `max` (inclusive). If only one
+ * argument is provided a number between `0` and the given number is returned.
+ * If `floating` is `true`, or either `min` or `max` are floats, a floating-point
+ * number is returned instead of an integer.
+ *
+ * @static
+ * @memberOf _
+ * @category Number
+ * @param {number} [min=0] The minimum possible value.
+ * @param {number} [max=1] The maximum possible value.
+ * @param {boolean} [floating] Specify returning a floating-point number.
+ * @returns {number} Returns the random number.
+ * @example
+ *
+ * _.random(0, 5);
+ * // => an integer between 0 and 5
+ *
+ * _.random(5);
+ * // => also an integer between 0 and 5
+ *
+ * _.random(5, true);
+ * // => a floating-point number between 0 and 5
+ *
+ * _.random(1.2, 5.2);
+ * // => a floating-point number between 1.2 and 5.2
+ */
+ function random(min, max, floating) {
+ if (floating && isIterateeCall(min, max, floating)) {
+ max = floating = null;
+ }
+ var noMin = min == null,
+ noMax = max == null;
+
+ if (floating == null) {
+ if (noMax && typeof min == 'boolean') {
+ floating = min;
+ min = 1;
+ }
+ else if (typeof max == 'boolean') {
+ floating = max;
+ noMax = true;
+ }
+ }
+ if (noMin && noMax) {
+ max = 1;
+ noMax = false;
+ }
+ min = +min || 0;
+ if (noMax) {
+ max = min;
+ min = 0;
+ } else {
+ max = +max || 0;
+ }
+ if (floating || min % 1 || max % 1) {
+ var rand = nativeRandom();
+ return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max);
+ }
+ return baseRandom(min, max);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Converts `string` to camel case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/CamelCase) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the camel cased string.
+ * @example
+ *
+ * _.camelCase('Foo Bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('--foo-bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('__foo_bar__');
+ * // => 'fooBar'
+ */
+ var camelCase = createCompounder(function(result, word, index) {
+ word = word.toLowerCase();
+ return index ? (result + word.charAt(0).toUpperCase() + word.slice(1)) : word;
+ });
+
+ /**
+ * Capitalizes the first character of `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to capitalize.
+ * @returns {string} Returns the capitalized string.
+ * @example
+ *
+ * _.capitalize('fred');
+ * // => 'Fred'
+ */
+ function capitalize(string) {
+ string = baseToString(string);
+ return string && (string.charAt(0).toUpperCase() + string.slice(1));
+ }
+
+ /**
+ * Deburrs `string` by converting latin-1 supplementary letters to basic latin letters.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to deburr.
+ * @returns {string} Returns the deburred string.
+ * @example
+ *
+ * _.deburr('déjà vu');
+ * // => 'deja vu'
+ */
+ function deburr(string) {
+ string = baseToString(string);
+ return string && string.replace(reLatin1, deburrLetter);
+ }
+
+ /**
+ * Checks if `string` ends with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=string.length] The position to search from.
+ * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`.
+ * @example
+ *
+ * _.endsWith('abc', 'c');
+ * // => true
+ *
+ * _.endsWith('abc', 'b');
+ * // => false
+ *
+ * _.endsWith('abc', 'b', 2);
+ * // => true
+ */
+ function endsWith(string, target, position) {
+ string = baseToString(string);
+ target = (target + '');
+
+ var length = string.length;
+ position = (typeof position == 'undefined' ? length : nativeMin(position < 0 ? 0 : (+position || 0), length)) - target.length;
+ return position >= 0 && string.indexOf(target, position) == position;
+ }
+
+ /**
+ * Converts the characters "&", "<", ">", '"', "'", and '`', in `string` to
+ * their corresponding HTML entities.
+ *
+ * **Note:** No other characters are escaped. To escape additional characters
+ * use a third-party library like [_he_](http://mths.be/he).
+ *
+ * Though the ">" character is escaped for symmetry, characters like
+ * ">" and "/" don't require escaping in HTML and have no special meaning
+ * unless they're part of a tag or unquoted attribute value.
+ * See [Mathias Bynens's article](http://mathiasbynens.be/notes/ambiguous-ampersands)
+ * (under "semi-related fun fact") for more details.
+ *
+ * Backticks are escaped because in Internet Explorer < 9, they can break out
+ * of attribute values or HTML comments. See [#102](http://html5sec.org/#102),
+ * [#108](http://html5sec.org/#108), and [#133](http://html5sec.org/#133) of
+ * the [HTML5 Security Cheatsheet](http://html5sec.org/) for more details.
+ *
+ * When working with HTML you should always quote attribute values to reduce
+ * XSS vectors. See [Ryan Grove's article](http://wonko.com/post/html-escaping)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function escape(string) {
+ // Reset `lastIndex` because in IE < 9 `String#replace` does not.
+ string = baseToString(string);
+ return (string && reHasUnescapedHtml.test(string))
+ ? string.replace(reUnescapedHtml, escapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*",
+ * "+", "(", ")", "[", "]", "{" and "}" in `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escapeRegExp('[lodash](https://lodash.com/)');
+ * // => '\[lodash\]\(https://lodash\.com/\)'
+ */
+ function escapeRegExp(string) {
+ string = baseToString(string);
+ return (string && reHasRegExpChars.test(string))
+ ? string.replace(reRegExpChars, '\\$&')
+ : string;
+ }
+
+ /**
+ * Converts `string` to kebab case (a.k.a. spinal case).
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Letter_case#Computers) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the kebab cased string.
+ * @example
+ *
+ * _.kebabCase('Foo Bar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('fooBar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('__foo_bar__');
+ * // => 'foo-bar'
+ */
+ var kebabCase = createCompounder(function(result, word, index) {
+ return result + (index ? '-' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Pads `string` on the left and right sides if it is shorter then the given
+ * padding length. The `chars` string may be truncated if the number of padding
+ * characters can't be evenly divided by the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.pad('abc', 8);
+ * // => ' abc '
+ *
+ * _.pad('abc', 8, '_-');
+ * // => '_-abc_-_'
+ *
+ * _.pad('abc', 3);
+ * // => 'abc'
+ */
+ function pad(string, length, chars) {
+ string = baseToString(string);
+ length = +length;
+
+ var strLength = string.length;
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return string;
+ }
+ var mid = (length - strLength) / 2,
+ leftLength = floor(mid),
+ rightLength = ceil(mid);
+
+ chars = createPad('', rightLength, chars);
+ return chars.slice(0, leftLength) + string + chars;
+ }
+
+ /**
+ * Pads `string` on the left side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padLeft('abc', 6);
+ * // => ' abc'
+ *
+ * _.padLeft('abc', 6, '_-');
+ * // => '_-_abc'
+ *
+ * _.padLeft('abc', 3);
+ * // => 'abc'
+ */
+ function padLeft(string, length, chars) {
+ string = baseToString(string);
+ return string && (createPad(string, length, chars) + string);
+ }
+
+ /**
+ * Pads `string` on the right side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padRight('abc', 6);
+ * // => 'abc '
+ *
+ * _.padRight('abc', 6, '_-');
+ * // => 'abc_-_'
+ *
+ * _.padRight('abc', 3);
+ * // => 'abc'
+ */
+ function padRight(string, length, chars) {
+ string = baseToString(string);
+ return string && (string + createPad(string, length, chars));
+ }
+
+ /**
+ * Converts `string` to an integer of the specified radix. If `radix` is
+ * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal,
+ * in which case a `radix` of `16` is used.
+ *
+ * **Note:** This method aligns with the ES5 implementation of `parseInt`.
+ * See the [ES5 spec](http://es5.github.io/#E) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} string The string to convert.
+ * @param {number} [radix] The radix to interpret `value` by.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {number} Returns the converted integer.
+ * @example
+ *
+ * _.parseInt('08');
+ * // => 8
+ *
+ * _.map(['6', '08', '10'], _.parseInt);
+ * // => [6, 8, 10]
+ */
+ function parseInt(string, radix, guard) {
+ if (guard && isIterateeCall(string, radix, guard)) {
+ radix = 0;
+ }
+ return nativeParseInt(string, radix);
+ }
+ // Fallback for environments with pre-ES5 implementations.
+ if (nativeParseInt(whitespace + '08') != 8) {
+ parseInt = function(string, radix, guard) {
+ // Firefox < 21 and Opera < 15 follow ES3 for `parseInt` and
+ // Chrome fails to trim leading <BOM> whitespace characters.
+ // See https://code.google.com/p/v8/issues/detail?id=3109.
+ if (guard ? isIterateeCall(string, radix, guard) : radix == null) {
+ radix = 0;
+ } else if (radix) {
+ radix = +radix;
+ }
+ string = trim(string);
+ return nativeParseInt(string, radix || (reHexPrefix.test(string) ? 16 : 10));
+ };
+ }
+
+ /**
+ * Repeats the given string `n` times.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to repeat.
+ * @param {number} [n=0] The number of times to repeat the string.
+ * @returns {string} Returns the repeated string.
+ * @example
+ *
+ * _.repeat('*', 3);
+ * // => '***'
+ *
+ * _.repeat('abc', 2);
+ * // => 'abcabc'
+ *
+ * _.repeat('abc', 0);
+ * // => ''
+ */
+ function repeat(string, n) {
+ var result = '';
+ string = baseToString(string);
+ n = +n;
+ if (n < 1 || !string || !nativeIsFinite(n)) {
+ return result;
+ }
+ // Leverage the exponentiation by squaring algorithm for a faster repeat.
+ // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring.
+ do {
+ if (n % 2) {
+ result += string;
+ }
+ n = floor(n / 2);
+ string += string;
+ } while (n);
+
+ return result;
+ }
+
+ /**
+ * Converts `string` to snake case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Snake_case) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the snake cased string.
+ * @example
+ *
+ * _.snakeCase('Foo Bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('--foo-bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('fooBar');
+ * // => 'foo_bar'
+ */
+ var snakeCase = createCompounder(function(result, word, index) {
+ return result + (index ? '_' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Checks if `string` starts with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=0] The position to search from.
+ * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`.
+ * @example
+ *
+ * _.startsWith('abc', 'a');
+ * // => true
+ *
+ * _.startsWith('abc', 'b');
+ * // => false
+ *
+ * _.startsWith('abc', 'b', 1);
+ * // => true
+ */
+ function startsWith(string, target, position) {
+ string = baseToString(string);
+ position = position == null ? 0 : nativeMin(position < 0 ? 0 : (+position || 0), string.length);
+ return string.lastIndexOf(target, position) == position;
+ }
+
+ /**
+ * Creates a compiled template function that can interpolate data properties
+ * in "interpolate" delimiters, HTML-escape interpolated data properties in
+ * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+ * properties may be accessed as free variables in the template. If a setting
+ * object is provided it takes precedence over `_.templateSettings` values.
+ *
+ * **Note:** In the development build `_.template` utilizes sourceURLs for easier debugging.
+ * See the [HTML5 Rocks article on sourcemaps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+ * for more details.
+ *
+ * For more information on precompiling templates see
+ * [Lo-Dash's custom builds documentation](https://lodash.com/custom-builds).
+ *
+ * For more information on Chrome extension sandboxes see
+ * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The template string.
+ * @param {Object} [options] The options object.
+ * @param {RegExp} [options.escape] The HTML "escape" delimiter.
+ * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
+ * @param {Object} [options.imports] An object to import into the template as free variables.
+ * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
+ * @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
+ * @param {string} [options.variable] The data object variable name.
+ * @param- {Object} [otherOptions] Enables the legacy `options` param signature.
+ * @returns {Function} Returns the compiled template function.
+ * @example
+ *
+ * // using the "interpolate" delimiter to create a compiled template
+ * var compiled = _.template('hello <%= user %>!');
+ * compiled({ 'user': 'fred' });
+ * // => 'hello fred!'
+ *
+ * // using the HTML "escape" delimiter to escape data property values
+ * var compiled = _.template('<b><%- value %></b>');
+ * compiled({ 'value': '<script>' });
+ * // => '<b><script></b>'
+ *
+ * // using the "evaluate" delimiter to execute JavaScript and generate HTML
+ * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the internal `print` function in "evaluate" delimiters
+ * var compiled = _.template('<% print("hello " + user); %>!');
+ * compiled({ 'user': 'barney' });
+ * // => 'hello barney!'
+ *
+ * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
+ * var compiled = _.template('hello ${ user }!');
+ * compiled({ 'user': 'pebbles' });
+ * // => 'hello pebbles!'
+ *
+ * // using custom template delimiters
+ * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+ * var compiled = _.template('hello {{ user }}!');
+ * compiled({ 'user': 'mustache' });
+ * // => 'hello mustache!'
+ *
+ * // using backslashes to treat delimiters as plain text
+ * var compiled = _.template('<%= "\\<%- value %\\>" %>');
+ * compiled({ 'value': 'ignored' });
+ * // => '<%- value %>'
+ *
+ * // using the `imports` option to import `jQuery` as `jq`
+ * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
+ * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
+ * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
+ * compiled(data);
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
+ *
+ * // using the `variable` option to ensure a with-statement isn't used in the compiled template
+ * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
+ * compiled.source;
+ * // => function(data) {
+ * var __t, __p = '';
+ * __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
+ * return __p;
+ * }
+ *
+ * // using the `source` property to inline compiled templates for meaningful
+ * // line numbers in error messages and a stack trace
+ * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
+ * var JST = {\
+ * "main": ' + _.template(mainText).source + '\
+ * };\
+ * ');
+ */
+ function template(string, options, otherOptions) {
+ // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/)
+ // and Laura Doktorova's doT.js (https://github.com/olado/doT).
+ var settings = lodash.templateSettings;
+
+ if (otherOptions && isIterateeCall(string, options, otherOptions)) {
+ options = otherOptions = null;
+ }
+ string = baseToString(string);
+ options = baseAssign(baseAssign({}, otherOptions || options), settings, assignOwnDefaults);
+
+ var imports = baseAssign(baseAssign({}, options.imports), settings.imports, assignOwnDefaults),
+ importsKeys = keys(imports),
+ importsValues = baseValues(imports, importsKeys);
+
+ var isEscaping,
+ isEvaluating,
+ index = 0,
+ interpolate = options.interpolate || reNoMatch,
+ source = "__p += '";
+
+ // Compile the regexp to match each delimiter.
+ var reDelimiters = RegExp(
+ (options.escape || reNoMatch).source + '|' +
+ interpolate.source + '|' +
+ (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
+ (options.evaluate || reNoMatch).source + '|$'
+ , 'g');
+
+ // Use a sourceURL for easier debugging.
+ // See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl.
+ var sourceURL = '//# sourceURL=' +
+ ('sourceURL' in options
+ ? options.sourceURL
+ : ('lodash.templateSources[' + (++templateCounter) + ']')
+ ) + '\n';
+
+ string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
+ interpolateValue || (interpolateValue = esTemplateValue);
+
+ // Escape characters that can't be included in string literals.
+ source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
+
+ // Replace delimiters with snippets.
+ if (escapeValue) {
+ isEscaping = true;
+ source += "' +\n__e(" + escapeValue + ") +\n'";
+ }
+ if (evaluateValue) {
+ isEvaluating = true;
+ source += "';\n" + evaluateValue + ";\n__p += '";
+ }
+ if (interpolateValue) {
+ source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
+ }
+ index = offset + match.length;
+
+ // The JS engine embedded in Adobe products requires returning the `match`
+ // string in order to produce the correct `offset` value.
+ return match;
+ });
+
+ source += "';\n";
+
+ // If `variable` is not specified wrap a with-statement around the generated
+ // code to add the data object to the top of the scope chain.
+ var variable = options.variable;
+ if (!variable) {
+ source = 'with (obj) {\n' + source + '\n}\n';
+ }
+ // Cleanup code by stripping empty strings.
+ source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
+ .replace(reEmptyStringMiddle, '$1')
+ .replace(reEmptyStringTrailing, '$1;');
+
+ // Frame code as the function body.
+ source = 'function(' + (variable || 'obj') + ') {\n' +
+ (variable
+ ? ''
+ : 'obj || (obj = {});\n'
+ ) +
+ "var __t, __p = ''" +
+ (isEscaping
+ ? ', __e = _.escape'
+ : ''
+ ) +
+ (isEvaluating
+ ? ', __j = Array.prototype.join;\n' +
+ "function print() { __p += __j.call(arguments, '') }\n"
+ : ';\n'
+ ) +
+ source +
+ 'return __p\n}';
+
+ var result = attempt(function() {
+ return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues);
+ });
+
+ // Provide the compiled function's source by its `toString` method or
+ // the `source` property as a convenience for inlining compiled templates.
+ result.source = source;
+ if (isError(result)) {
+ throw result;
+ }
+ return result;
+ }
+
+ /**
+ * Removes leading and trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trim(' abc ');
+ * // => 'abc'
+ *
+ * _.trim('-_-abc-_-', '_-');
+ * // => 'abc'
+ *
+ * _.map([' foo ', ' bar '], _.trim);
+ * // => ['foo', 'bar]
+ */
+ function trim(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string), trimmedRightIndex(string) + 1);
+ }
+ chars = baseToString(chars);
+ return string.slice(charsLeftIndex(string, chars), charsRightIndex(string, chars) + 1);
+ }
+
+ /**
+ * Removes leading whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimLeft(' abc ');
+ * // => 'abc '
+ *
+ * _.trimLeft('-_-abc-_-', '_-');
+ * // => 'abc-_-'
+ */
+ function trimLeft(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string))
+ }
+ return string.slice(charsLeftIndex(string, baseToString(chars)));
+ }
+
+ /**
+ * Removes trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimRight(' abc ');
+ * // => ' abc'
+ *
+ * _.trimRight('-_-abc-_-', '_-');
+ * // => '-_-abc'
+ */
+ function trimRight(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(0, trimmedRightIndex(string) + 1)
+ }
+ return string.slice(0, charsRightIndex(string, baseToString(chars)) + 1);
+ }
+
+ /**
+ * Truncates `string` if it is longer than the given maximum string length.
+ * The last characters of the truncated string are replaced with the omission
+ * string which defaults to "...".
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to truncate.
+ * @param {Object|number} [options] The options object or maximum string length.
+ * @param {number} [options.length=30] The maximum string length.
+ * @param {string} [options.omission='...'] The string to indicate text is omitted.
+ * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the truncated string.
+ * @example
+ *
+ * _.trunc('hi-diddly-ho there, neighborino');
+ * // => 'hi-diddly-ho there, neighbo...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', 24);
+ * // => 'hi-diddly-ho there, n...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': ' ' });
+ * // => 'hi-diddly-ho there,...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': /,? +/ });
+ * //=> 'hi-diddly-ho there...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'omission': ' [...]' });
+ * // => 'hi-diddly-ho there, neig [...]'
+ */
+ function trunc(string, options, guard) {
+ if (guard && isIterateeCall(string, options, guard)) {
+ options = null;
+ }
+ var length = DEFAULT_TRUNC_LENGTH,
+ omission = DEFAULT_TRUNC_OMISSION;
+
+ if (options != null) {
+ if (isObject(options)) {
+ var separator = 'separator' in options ? options.separator : separator;
+ length = 'length' in options ? +options.length || 0 : length;
+ omission = 'omission' in options ? baseToString(options.omission) : omission;
+ } else {
+ length = +options || 0;
+ }
+ }
+ string = baseToString(string);
+ if (length >= string.length) {
+ return string;
+ }
+ var end = length - omission.length;
+ if (end < 1) {
+ return omission;
+ }
+ var result = string.slice(0, end);
+ if (separator == null) {
+ return result + omission;
+ }
+ if (isRegExp(separator)) {
+ if (string.slice(end).search(separator)) {
+ var match,
+ newEnd,
+ substring = string.slice(0, end);
+
+ if (!separator.global) {
+ separator = RegExp(separator.source, (reFlags.exec(separator) || '') + 'g');
+ }
+ separator.lastIndex = 0;
+ while ((match = separator.exec(substring))) {
+ newEnd = match.index;
+ }
+ result = result.slice(0, newEnd == null ? end : newEnd);
+ }
+ } else if (string.indexOf(separator, end) != end) {
+ var index = result.lastIndexOf(separator);
+ if (index > -1) {
+ result = result.slice(0, index);
+ }
+ }
+ return result + omission;
+ }
+
+ /**
+ * The inverse of `_.escape`; this method converts the HTML entities
+ * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to their
+ * corresponding characters.
+ *
+ * **Note:** No other HTML entities are unescaped. To unescape additional HTML
+ * entities use a third-party library like [_he_](http://mths.be/he).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to unescape.
+ * @returns {string} Returns the unescaped string.
+ * @example
+ *
+ * _.unescape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function unescape(string) {
+ string = baseToString(string);
+ return (string && reHasEscapedHtml.test(string))
+ ? string.replace(reEscapedHtml, unescapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Splits `string` into an array of its words.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to inspect.
+ * @param {RegExp|string} [pattern] The pattern to match words.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the words of `string`.
+ * @example
+ *
+ * _.words('fred, barney, & pebbles');
+ * // => ['fred', 'barney', 'pebbles']
+ *
+ * _.words('fred, barney, & pebbles', /[^, ]+/g);
+ * // => ['fred', 'barney', '&', 'pebbles']
+ */
+ function words(string, pattern, guard) {
+ if (guard && isIterateeCall(string, pattern, guard)) {
+ pattern = null;
+ }
+ string = baseToString(string);
+ return string.match(pattern || reWords) || [];
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Attempts to invoke `func`, returning either the result or the caught
+ * error object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} func The function to attempt.
+ * @returns {*} Returns the `func` result or error object.
+ * @example
+ *
+ * // avoid throwing errors for invalid selectors
+ * var elements = _.attempt(function() {
+ * return document.querySelectorAll(selector);
+ * });
+ *
+ * if (_.isError(elements)) {
+ * elements = [];
+ * }
+ */
+ function attempt(func) {
+ try {
+ return func();
+ } catch(e) {
+ return isError(e) ? e : Error(e);
+ }
+ }
+
+ /**
+ * Creates a function bound to an optional `thisArg`. If `func` is a property
+ * name the created callback returns the property value for a given element.
+ * If `func` is an object the created callback returns `true` for elements
+ * that contain the equivalent object properties, otherwise it returns `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias iteratee
+ * @category Utility
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the callback.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // wrap to create custom callback shorthands
+ * _.callback = _.wrap(_.callback, function(callback, func, thisArg) {
+ * var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
+ * if (!match) {
+ * return callback(func, thisArg);
+ * }
+ * return function(object) {
+ * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
+ * };
+ * });
+ *
+ * _.filter(users, 'age__gt36');
+ * // => [{ 'user': 'fred', 'age': 40 }]
+ */
+ function callback(func, thisArg, guard) {
+ if (guard && isIterateeCall(func, thisArg, guard)) {
+ thisArg = null;
+ }
+ return baseCallback(func, thisArg);
+ }
+
+ /**
+ * Creates a function that returns `value`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value The value to return from the new function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var getter = _.constant(object);
+ * getter() === object;
+ * // => true
+ */
+ function constant(value) {
+ return function() {
+ return value;
+ };
+ }
+
+ /**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.identity(object) === object;
+ * // => true
+ */
+ function identity(value) {
+ return value;
+ }
+
+ /**
+ * Creates a function which performs a deep comparison between a given object
+ * and `source`, returning `true` if the given object has equivalent property
+ * values, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 36 }
+ * ];
+ *
+ * var matchesAge = _.matches({ 'age': 36 });
+ *
+ * _.filter(users, matchesAge);
+ * // => [{ 'user': 'barney', 'age': 36 }]
+ *
+ * _.find(users, matchesAge);
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function matches(source) {
+ return baseMatches(source, true);
+ }
+
+ /**
+ * Adds all own enumerable function properties of a source object to the
+ * destination object. If `object` is a function then methods are added to
+ * its prototype as well.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Function|Object} [object=this] object The destination object.
+ * @param {Object} source The object of functions to add.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.chain=true] Specify whether the functions added
+ * are chainable.
+ * @returns {Function|Object} Returns `object`.
+ * @example
+ *
+ * function vowels(string) {
+ * return _.filter(string, function(v) {
+ * return /[aeiou]/i.test(v);
+ * });
+ * }
+ *
+ * _.mixin({ 'vowels': vowels });
+ * _.vowels('fred');
+ * // => ['e']
+ *
+ * _('fred').vowels().value();
+ * // => ['e']
+ *
+ * _.mixin({ 'vowels': vowels }, { 'chain': false });
+ * _('fred').vowels();
+ * // => ['e']
+ */
+ function mixin(object, source, options) {
+ if (options == null) {
+ var isObj = isObject(source),
+ props = isObj && keys(source),
+ methodNames = props && props.length && baseFunctions(source, props);
+
+ if (!(methodNames ? methodNames.length : isObj)) {
+ methodNames = false;
+ options = source;
+ source = object;
+ object = this;
+ }
+ }
+ if (!methodNames) {
+ methodNames = baseFunctions(source, keys(source));
+ }
+ var chain = true,
+ index = -1,
+ isFunc = isFunction(object),
+ length = methodNames.length;
+
+ if (options === false) {
+ chain = false;
+ } else if (isObject(options) && 'chain' in options) {
+ chain = options.chain;
+ }
+ while (++index < length) {
+ var methodName = methodNames[index],
+ func = source[methodName];
+
+ object[methodName] = func;
+ if (isFunc) {
+ object.prototype[methodName] = (function(func) {
+ return function() {
+ var chainAll = this.__chain__;
+ if (chain || chainAll) {
+ var result = object(this.__wrapped__);
+ (result.__actions__ = arrayCopy(this.__actions__)).push({ 'func': func, 'args': arguments, 'thisArg': object });
+ result.__chain__ = chainAll;
+ return result;
+ }
+ var args = [this.value()];
+ push.apply(args, arguments);
+ return func.apply(object, args);
+ };
+ }(func));
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Reverts the `_` variable to its previous value and returns a reference to
+ * the `lodash` function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @returns {Function} Returns the `lodash` function.
+ * @example
+ *
+ * var lodash = _.noConflict();
+ */
+ function noConflict() {
+ context._ = oldDash;
+ return this;
+ }
+
+ /**
+ * A no-operation function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.noop(object) === undefined;
+ * // => true
+ */
+ function noop() {
+ // No operation performed.
+ }
+
+ /**
+ * Creates a function which returns the property value of `key` on a given object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * var getName = _.property('user');
+ *
+ * _.map(users, getName);
+ * // => ['fred', barney']
+ *
+ * _.pluck(_.sortBy(users, getName), 'user');
+ * // => ['barney', 'fred']
+ */
+ function property(key) {
+ return baseProperty(key + '');
+ }
+
+ /**
+ * The inverse of `_.property`; this method creates a function which returns
+ * the property value of a given key on `object`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} object The object to inspect.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40, 'active': true };
+ * _.map(['active', 'user'], _.propertyOf(object));
+ * // => [true, 'fred']
+ *
+ * var object = { 'a': 3, 'b': 1, 'c': 2 };
+ * _.sortBy(['a', 'b', 'c'], _.propertyOf(object));
+ * // => ['b', 'c', 'a']
+ */
+ function propertyOf(object) {
+ return function(key) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * Creates an array of numbers (positive and/or negative) progressing from
+ * `start` up to, but not including, `end`. If `start` is less than `end` a
+ * zero-length range is created unless a negative `step` is specified.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} [start=0] The start of the range.
+ * @param {number} end The end of the range.
+ * @param {number} [step=1] The value to increment or decrement by.
+ * @returns {Array} Returns the new array of numbers.
+ * @example
+ *
+ * _.range(4);
+ * // => [0, 1, 2, 3]
+ *
+ * _.range(1, 5);
+ * // => [1, 2, 3, 4]
+ *
+ * _.range(0, 20, 5);
+ * // => [0, 5, 10, 15]
+ *
+ * _.range(0, -4, -1);
+ * // => [0, -1, -2, -3]
+ *
+ * _.range(1, 4, 0);
+ * // => [1, 1, 1]
+ *
+ * _.range(0);
+ * // => []
+ */
+ function range(start, end, step) {
+ if (step && isIterateeCall(start, end, step)) {
+ end = step = null;
+ }
+ start = +start || 0;
+ step = step == null ? 1 : (+step || 0);
+
+ if (end == null) {
+ end = start;
+ start = 0;
+ } else {
+ end = +end || 0;
+ }
+ // Use `Array(length)` so engines like Chakra and V8 avoid slower modes.
+ // See http://youtu.be/XAqIpGU8ZZk#t=17m25s.
+ var index = -1,
+ length = nativeMax(ceil((end - start) / (step || 1)), 0),
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = start;
+ start += step;
+ }
+ return result;
+ }
+
+ /**
+ * Invokes the iteratee function `n` times, returning an array of the results
+ * of each invocation. The `iteratee` is bound to `thisArg` and invoked with
+ * one argument; (index).
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * var diceRolls = _.times(3, _.partial(_.random, 1, 6, false));
+ * // => [3, 6, 4]
+ *
+ * _.times(3, function(n) { mage.castSpell(n); });
+ * // => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2` respectively
+ *
+ * _.times(3, function(n) { this.cast(n); }, mage);
+ * // => also invokes `mage.castSpell(n)` three times
+ */
+ function times(n, iteratee, thisArg) {
+ n = +n;
+
+ // Exit early to avoid a JSC JIT bug in Safari 8
+ // where `Array(0)` is treated as `Array(1)`.
+ if (n < 1 || !nativeIsFinite(n)) {
+ return [];
+ }
+ var index = -1,
+ result = Array(nativeMin(n, MAX_ARRAY_LENGTH));
+
+ iteratee = bindCallback(iteratee, thisArg, 1);
+ while (++index < n) {
+ if (index < MAX_ARRAY_LENGTH) {
+ result[index] = iteratee(index);
+ } else {
+ iteratee(index);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Generates a unique ID. If `prefix` is provided the ID is appended to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} [prefix] The value to prefix the ID with.
+ * @returns {string} Returns the unique ID.
+ * @example
+ *
+ * _.uniqueId('contact_');
+ * // => 'contact_104'
+ *
+ * _.uniqueId();
+ * // => '105'
+ */
+ function uniqueId(prefix) {
+ var id = ++idCounter;
+ return baseToString(prefix) + id;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ // Ensure `new LodashWrapper` is an instance of `lodash`.
+ LodashWrapper.prototype = lodash.prototype;
+
+ // Add functions to the `Map` cache.
+ MapCache.prototype['delete'] = mapDelete;
+ MapCache.prototype.get = mapGet;
+ MapCache.prototype.has = mapHas;
+ MapCache.prototype.set = mapSet;
+
+ // Add functions to the `Set` cache.
+ SetCache.prototype.push = cachePush;
+
+ // Assign cache to `_.memoize`.
+ memoize.Cache = MapCache;
+
+ // Add functions that return wrapped values when chaining.
+ lodash.after = after;
+ lodash.ary = ary;
+ lodash.assign = assign;
+ lodash.at = at;
+ lodash.before = before;
+ lodash.bind = bind;
+ lodash.bindAll = bindAll;
+ lodash.bindKey = bindKey;
+ lodash.callback = callback;
+ lodash.chain = chain;
+ lodash.chunk = chunk;
+ lodash.compact = compact;
+ lodash.constant = constant;
+ lodash.countBy = countBy;
+ lodash.create = create;
+ lodash.curry = curry;
+ lodash.curryRight = curryRight;
+ lodash.debounce = debounce;
+ lodash.defaults = defaults;
+ lodash.defer = defer;
+ lodash.delay = delay;
+ lodash.difference = difference;
+ lodash.drop = drop;
+ lodash.dropRight = dropRight;
+ lodash.dropRightWhile = dropRightWhile;
+ lodash.dropWhile = dropWhile;
+ lodash.filter = filter;
+ lodash.flatten = flatten;
+ lodash.flattenDeep = flattenDeep;
+ lodash.flow = flow;
+ lodash.flowRight = flowRight;
+ lodash.forEach = forEach;
+ lodash.forEachRight = forEachRight;
+ lodash.forIn = forIn;
+ lodash.forInRight = forInRight;
+ lodash.forOwn = forOwn;
+ lodash.forOwnRight = forOwnRight;
+ lodash.functions = functions;
+ lodash.groupBy = groupBy;
+ lodash.indexBy = indexBy;
+ lodash.initial = initial;
+ lodash.intersection = intersection;
+ lodash.invert = invert;
+ lodash.invoke = invoke;
+ lodash.keys = keys;
+ lodash.keysIn = keysIn;
+ lodash.map = map;
+ lodash.mapValues = mapValues;
+ lodash.matches = matches;
+ lodash.memoize = memoize;
+ lodash.merge = merge;
+ lodash.mixin = mixin;
+ lodash.negate = negate;
+ lodash.omit = omit;
+ lodash.once = once;
+ lodash.pairs = pairs;
+ lodash.partial = partial;
+ lodash.partialRight = partialRight;
+ lodash.partition = partition;
+ lodash.pick = pick;
+ lodash.pluck = pluck;
+ lodash.property = property;
+ lodash.propertyOf = propertyOf;
+ lodash.pull = pull;
+ lodash.pullAt = pullAt;
+ lodash.range = range;
+ lodash.rearg = rearg;
+ lodash.reject = reject;
+ lodash.remove = remove;
+ lodash.rest = rest;
+ lodash.shuffle = shuffle;
+ lodash.slice = slice;
+ lodash.sortBy = sortBy;
+ lodash.sortByAll = sortByAll;
+ lodash.take = take;
+ lodash.takeRight = takeRight;
+ lodash.takeRightWhile = takeRightWhile;
+ lodash.takeWhile = takeWhile;
+ lodash.tap = tap;
+ lodash.throttle = throttle;
+ lodash.thru = thru;
+ lodash.times = times;
+ lodash.toArray = toArray;
+ lodash.toPlainObject = toPlainObject;
+ lodash.transform = transform;
+ lodash.union = union;
+ lodash.uniq = uniq;
+ lodash.unzip = unzip;
+ lodash.values = values;
+ lodash.valuesIn = valuesIn;
+ lodash.where = where;
+ lodash.without = without;
+ lodash.wrap = wrap;
+ lodash.xor = xor;
+ lodash.zip = zip;
+ lodash.zipObject = zipObject;
+
+ // Add aliases.
+ lodash.backflow = flowRight;
+ lodash.collect = map;
+ lodash.compose = flowRight;
+ lodash.each = forEach;
+ lodash.eachRight = forEachRight;
+ lodash.extend = assign;
+ lodash.iteratee = callback;
+ lodash.methods = functions;
+ lodash.object = zipObject;
+ lodash.select = filter;
+ lodash.tail = rest;
+ lodash.unique = uniq;
+
+ // Add functions to `lodash.prototype`.
+ mixin(lodash, lodash);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions that return unwrapped values when chaining.
+ lodash.attempt = attempt;
+ lodash.camelCase = camelCase;
+ lodash.capitalize = capitalize;
+ lodash.clone = clone;
+ lodash.cloneDeep = cloneDeep;
+ lodash.deburr = deburr;
+ lodash.endsWith = endsWith;
+ lodash.escape = escape;
+ lodash.escapeRegExp = escapeRegExp;
+ lodash.every = every;
+ lodash.find = find;
+ lodash.findIndex = findIndex;
+ lodash.findKey = findKey;
+ lodash.findLast = findLast;
+ lodash.findLastIndex = findLastIndex;
+ lodash.findLastKey = findLastKey;
+ lodash.findWhere = findWhere;
+ lodash.first = first;
+ lodash.has = has;
+ lodash.identity = identity;
+ lodash.includes = includes;
+ lodash.indexOf = indexOf;
+ lodash.isArguments = isArguments;
+ lodash.isArray = isArray;
+ lodash.isBoolean = isBoolean;
+ lodash.isDate = isDate;
+ lodash.isElement = isElement;
+ lodash.isEmpty = isEmpty;
+ lodash.isEqual = isEqual;
+ lodash.isError = isError;
+ lodash.isFinite = isFinite;
+ lodash.isFunction = isFunction;
+ lodash.isMatch = isMatch;
+ lodash.isNaN = isNaN;
+ lodash.isNative = isNative;
+ lodash.isNull = isNull;
+ lodash.isNumber = isNumber;
+ lodash.isObject = isObject;
+ lodash.isPlainObject = isPlainObject;
+ lodash.isRegExp = isRegExp;
+ lodash.isString = isString;
+ lodash.isTypedArray = isTypedArray;
+ lodash.isUndefined = isUndefined;
+ lodash.kebabCase = kebabCase;
+ lodash.last = last;
+ lodash.lastIndexOf = lastIndexOf;
+ lodash.max = max;
+ lodash.min = min;
+ lodash.noConflict = noConflict;
+ lodash.noop = noop;
+ lodash.now = now;
+ lodash.pad = pad;
+ lodash.padLeft = padLeft;
+ lodash.padRight = padRight;
+ lodash.parseInt = parseInt;
+ lodash.random = random;
+ lodash.reduce = reduce;
+ lodash.reduceRight = reduceRight;
+ lodash.repeat = repeat;
+ lodash.result = result;
+ lodash.runInContext = runInContext;
+ lodash.size = size;
+ lodash.snakeCase = snakeCase;
+ lodash.some = some;
+ lodash.sortedIndex = sortedIndex;
+ lodash.sortedLastIndex = sortedLastIndex;
+ lodash.startsWith = startsWith;
+ lodash.template = template;
+ lodash.trim = trim;
+ lodash.trimLeft = trimLeft;
+ lodash.trimRight = trimRight;
+ lodash.trunc = trunc;
+ lodash.unescape = unescape;
+ lodash.uniqueId = uniqueId;
+ lodash.words = words;
+
+ // Add aliases.
+ lodash.all = every;
+ lodash.any = some;
+ lodash.contains = includes;
+ lodash.detect = find;
+ lodash.foldl = reduce;
+ lodash.foldr = reduceRight;
+ lodash.head = first;
+ lodash.include = includes;
+ lodash.inject = reduce;
+
+ mixin(lodash, (function() {
+ var source = {};
+ baseForOwn(lodash, function(func, methodName) {
+ if (!lodash.prototype[methodName]) {
+ source[methodName] = func;
+ }
+ });
+ return source;
+ }()), false);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions capable of returning wrapped and unwrapped values when chaining.
+ lodash.sample = sample;
+
+ lodash.prototype.sample = function(n) {
+ if (!this.__chain__ && n == null) {
+ return sample(this.value());
+ }
+ return this.thru(function(value) {
+ return sample(value, n);
+ });
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The semantic version number.
+ *
+ * @static
+ * @memberOf _
+ * @type string
+ */
+ lodash.VERSION = VERSION;
+
+ // Assign default placeholders.
+ arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
+ lodash[methodName].placeholder = lodash;
+ });
+
+ // Add `LazyWrapper` methods that accept an `iteratee` value.
+ arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
+ var isFilter = index == LAZY_FILTER_FLAG;
+
+ LazyWrapper.prototype[methodName] = function(iteratee, thisArg) {
+ var result = this.clone(),
+ filtered = result.filtered,
+ iteratees = result.iteratees || (result.iteratees = []);
+
+ result.filtered = filtered || isFilter || (index == LAZY_WHILE_FLAG && result.dir < 0);
+ iteratees.push({ 'iteratee': getCallback(iteratee, thisArg, 3), 'type': index });
+ return result;
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
+ arrayEach(['drop', 'take'], function(methodName, index) {
+ var countName = methodName + 'Count',
+ whileName = methodName + 'While';
+
+ LazyWrapper.prototype[methodName] = function(n) {
+ n = n == null ? 1 : nativeMax(+n || 0, 0);
+
+ var result = this.clone();
+ if (result.filtered) {
+ var value = result[countName];
+ result[countName] = index ? nativeMin(value, n) : (value + n);
+ } else {
+ var views = result.views || (result.views = []);
+ views.push({ 'size': n, 'type': methodName + (result.dir < 0 ? 'Right' : '') });
+ }
+ return result;
+ };
+
+ LazyWrapper.prototype[methodName + 'Right'] = function(n) {
+ return this.reverse()[methodName](n).reverse();
+ };
+
+ LazyWrapper.prototype[methodName + 'RightWhile'] = function(predicate, thisArg) {
+ return this.reverse()[whileName](predicate, thisArg).reverse();
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.first` and `_.last`.
+ arrayEach(['first', 'last'], function(methodName, index) {
+ var takeName = 'take' + (index ? 'Right': '');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[takeName](1).value()[0];
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.initial` and `_.rest`.
+ arrayEach(['initial', 'rest'], function(methodName, index) {
+ var dropName = 'drop' + (index ? '' : 'Right');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[dropName](1);
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.pluck` and `_.where`.
+ arrayEach(['pluck', 'where'], function(methodName, index) {
+ var operationName = index ? 'filter' : 'map',
+ createCallback = index ? matches : property;
+
+ LazyWrapper.prototype[methodName] = function(value) {
+ return this[operationName](createCallback(value));
+ };
+ });
+
+ LazyWrapper.prototype.dropWhile = function(iteratee, thisArg) {
+ var done,
+ lastIndex,
+ isRight = this.dir < 0;
+
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ done = done && (isRight ? index < lastIndex : index > lastIndex);
+ lastIndex = index;
+ return done || (done = !iteratee(value, index, array));
+ });
+ };
+
+ LazyWrapper.prototype.reject = function(iteratee, thisArg) {
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ return !iteratee(value, index, array);
+ });
+ };
+
+ LazyWrapper.prototype.slice = function(start, end) {
+ start = start == null ? 0 : (+start || 0);
+ var result = start < 0 ? this.takeRight(-start) : this.drop(start);
+
+ if (typeof end != 'undefined') {
+ end = (+end || 0);
+ result = end < 0 ? result.dropRight(-end) : result.take(end - start);
+ }
+ return result;
+ };
+
+ // Add `LazyWrapper` methods to `lodash.prototype`.
+ baseForOwn(LazyWrapper.prototype, function(func, methodName) {
+ var retUnwrapped = /^(?:first|last)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var value = this.__wrapped__,
+ args = arguments,
+ chainAll = this.__chain__,
+ isHybrid = !!this.__actions__.length,
+ isLazy = value instanceof LazyWrapper,
+ onlyLazy = isLazy && !isHybrid;
+
+ if (retUnwrapped && !chainAll) {
+ return onlyLazy
+ ? func.call(value)
+ : lodash[methodName](this.value());
+ }
+ var interceptor = function(value) {
+ var otherArgs = [value];
+ push.apply(otherArgs, args);
+ return lodash[methodName].apply(lodash, otherArgs);
+ };
+ if (isLazy || isArray(value)) {
+ var wrapper = onlyLazy ? value : new LazyWrapper(this),
+ result = func.apply(wrapper, args);
+
+ if (!retUnwrapped && (isHybrid || result.actions)) {
+ var actions = result.actions || (result.actions = []);
+ actions.push({ 'func': thru, 'args': [interceptor], 'thisArg': lodash });
+ }
+ return new LodashWrapper(result, chainAll);
+ }
+ return this.thru(interceptor);
+ };
+ });
+
+ // Add `Array.prototype` functions to `lodash.prototype`.
+ arrayEach(['concat', 'join', 'pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
+ var func = arrayProto[methodName],
+ chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
+ retUnwrapped = /^(?:join|pop|shift)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var args = arguments;
+ if (retUnwrapped && !this.__chain__) {
+ return func.apply(this.value(), args);
+ }
+ return this[chainName](function(value) {
+ return func.apply(value, args);
+ });
+ };
+ });
+
+ // Add functions to the lazy wrapper.
+ LazyWrapper.prototype.clone = lazyClone;
+ LazyWrapper.prototype.reverse = lazyReverse;
+ LazyWrapper.prototype.value = lazyValue;
+
+ // Add chaining functions to the lodash wrapper.
+ lodash.prototype.chain = wrapperChain;
+ lodash.prototype.reverse = wrapperReverse;
+ lodash.prototype.toString = wrapperToString;
+ lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
+
+ // Add function aliases to the lodash wrapper.
+ lodash.prototype.collect = lodash.prototype.map;
+ lodash.prototype.head = lodash.prototype.first;
+ lodash.prototype.select = lodash.prototype.filter;
+ lodash.prototype.tail = lodash.prototype.rest;
+
+ return lodash;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // Export Lo-Dash.
+ var _ = runInContext();
+
+ // Some AMD build optimizers like r.js check for condition patterns like the following:
+ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ // Expose Lo-Dash to the global object when an AMD loader is present to avoid
+ // errors in cases where Lo-Dash is loaded by a script tag and not intended
+ // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch.
+ root._ = _;
+
+ // Define as an anonymous module so, through path mapping, it can be
+ // referenced as the "underscore" module.
+ define(function() {
+ return _;
+ });
+ }
+ // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
+ else if (freeExports && freeModule) {
+ // Export for Node.js or RingoJS.
+ if (moduleExports) {
+ (freeModule.exports = _)._ = _;
+ }
+ // Export for Narwhal or Rhino -require.
+ else {
+ freeExports._ = _;
+ }
+ }
+ else {
+ // Export for a browser or Rhino.
+ root._ = _;
+ }
+}.call(this));
diff --git a/debian/build/lodash.min.js b/debian/build/lodash.min.js
new file mode 100644
index 0000000..3e889fe
--- /dev/null
+++ b/debian/build/lodash.min.js
@@ -0,0 +1,10 @@
+/**
+ * @license
+ * Lo-Dash 3.0.0 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern -o ./lodash.js`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */(function(){function kt(e,t){if(e!==t){var n=e===e,r=t===t;if(e>t||!n||typeof e=="undefined"&&r)return 1;if(e<t||!r||typeof t=="undefined"&&n)return-1}return 0}function Lt(e,t,n){if(t!==t)return It(e,n);var r=(n||0)-1,i=e.length;while(++r<i)if(e[r]===t)return r;return-1}function At(e,t){var n=e.length;e.sort(t);while(n--)e[n]=e[n].value;return e}function Ot(e){return typeof e=="string"?e:e==null?"":e+""}function Mt(e){return e.charCodeAt(0)}function _t(e,t){var n=-1,r=e.length;while(+ [...]
+),h=(f?h.replace(z,""):h).replace(W,"$1").replace(X,"$1;"),h="function("+(v||"obj")+") {\n"+(v?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(a?", __e = _.escape":"")+(f?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+h+"return __p\n}";var m=Iu(function(){return yt(o,d+"return "+h).apply(e,u)});m.source=h;if(_o(m))throw m;return m}function Du(e,t,n){var r=e;return e=Ot(e),e?(n?Ci(r,t,n):t==null)?e.slice(Wt(e),Xt(e)+1):(t=Ot(t),e.slice(_t(e,t [...]
\ No newline at end of file
diff --git a/debian/changelog b/debian/changelog
index 8da1685..f7d8627 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+node-lodash (3.0+dfsg-1) unstable; urgency=low
+
+ * Update Node-Lodash to 3.0
+
+ -- Valentin OVD <valentin.ovd at live.fr> Fri, 23 Jan 2015 17:08:03 +0100
+
node-lodash (2.4.1+dfsg-3) unstable; urgency=low
* Add the missing licence (Closes: #751583)
diff --git a/debian/copyright b/debian/copyright
index 7bbb0c3..5ec2eda 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -6,55 +6,28 @@ Source: https://github.com/lodash/lodash
vendor/firebug-lite/skin/xp/textEditorBorders.png
vendor/curl/dist/curl-kitchen-sink/curl.js
+
Files: *
-Copyright: 2013 John-David Dalton
+Copyright: 2012-2015 John-David Dalton
License: Expat
Files: vendor/backbone/*
-Copyright: 2010-2011 Jeremy Ashkenas, DocumentCloud
- 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+Copyright: 2010-2014 Jeremy Ashkenas, DocumentCloud
License: Expat
Files: vendor/benchmark.js/*
-Copyright: 2010-2013 Mathias Bynens
- 2012-2014 John-David Dalton
-License: Expat
-
-Files: vendor/curl/*
-Copyright: 2010-2013 Brian Cavalier and John Hann
+Copyright: 2010-2015 Mathias Bynens
License: Expat
-Files: vendor/dojo/*
-Copyright: 2005-2013, The Dojo Foundation
-License: BSD-3-clause-Dojo or AFL-2.1-clause-Dojo
-
Files: vendor/firebug-lite/*
Copyright: 2007, Parakey Inc.
License: BSD-3-clause-Parakey
-Files: vendor/jquery/*
- vendor/qunit/*
-Copyright: 2012 jQuery Foundation and other contributors
-License: Expat
-
Files: vendor/json-js/*
-Copyright: 2010 Douglas Crockford
License: public-domain
-Files: vendor/platform.js
-Copyright: 2010-2013 John-David Dalton
-License: Expat
-
-Files: vendor/qunit-extras/*
-Copyright: 2011-2012 John-David Dalton
-License: Expat
-
-Files: vendor/requirejs/*
-Copyright: 2010-2011, The Dojo Foundation
-License: BSD-3-clause-Dojo or Expat
-
Files: vendor/underscore/*
-Copyright: 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+Copyright: 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
License: Expat
License: AFL-2.1-clause-Dojo
diff --git a/debian/files b/debian/files
new file mode 100644
index 0000000..1588786
--- /dev/null
+++ b/debian/files
@@ -0,0 +1,2 @@
+node-lodash_3.0+dfsg-1_all.deb web optional
+libjs-lodash_3.0+dfsg-1_all.deb web optional
diff --git a/debian/libjs-lodash.debhelper.log b/debian/libjs-lodash.debhelper.log
new file mode 100644
index 0000000..4c7ea2f
--- /dev/null
+++ b/debian/libjs-lodash.debhelper.log
@@ -0,0 +1,19 @@
+dh_auto_configure
+override_dh_auto_build dh_auto_build
+dh_auto_build
+dh_auto_test
+dh_prep
+dh_auto_install
+dh_install
+dh_installdocs
+dh_installchangelogs
+dh_perl
+dh_link
+dh_compress
+dh_fixperms
+dh_installdeb
+dh_gencontrol
+dh_md5sums
+dh_builddeb
+dh_builddeb
+dh_builddeb
diff --git a/debian/libjs-lodash.substvars b/debian/libjs-lodash.substvars
new file mode 100644
index 0000000..abd3ebe
--- /dev/null
+++ b/debian/libjs-lodash.substvars
@@ -0,0 +1 @@
+misc:Depends=
diff --git a/debian/libjs-lodash/DEBIAN/control b/debian/libjs-lodash/DEBIAN/control
new file mode 100644
index 0000000..dbc9ebd
--- /dev/null
+++ b/debian/libjs-lodash/DEBIAN/control
@@ -0,0 +1,13 @@
+Package: libjs-lodash
+Source: node-lodash
+Version: 3.0+dfsg-1
+Architecture: all
+Maintainer: Debian Javascript Maintainers <pkg-javascript-devel at lists.alioth.debian.org>
+Installed-Size: 448
+Depends: javascript-common
+Section: web
+Priority: optional
+Homepage: http://lodash.com/
+Description: Lo-dash is a Javascript utility library
+ Lo-dash is a Javascript utility library delivering
+ consistency, customization, performance, & extras for Web Application.
diff --git a/debian/libjs-lodash/DEBIAN/md5sums b/debian/libjs-lodash/DEBIAN/md5sums
new file mode 100644
index 0000000..db4ddb9
--- /dev/null
+++ b/debian/libjs-lodash/DEBIAN/md5sums
@@ -0,0 +1,4 @@
+e22bea7778f243fadfd1647c48477f11 usr/share/doc/libjs-lodash/changelog.Debian.gz
+b366291265b4bbb8290c20e3bbf1beff usr/share/doc/libjs-lodash/copyright
+df9e34edcc0e8a40bc98651f84b18016 usr/share/javascript/lodash.js
+c7b3be5dcfee332bc1b738ed12e662a4 usr/share/javascript/lodash.min.js
diff --git a/debian/libjs-lodash/usr/share/doc/libjs-lodash/changelog.Debian.gz b/debian/libjs-lodash/usr/share/doc/libjs-lodash/changelog.Debian.gz
new file mode 100644
index 0000000..687c87b
Binary files /dev/null and b/debian/libjs-lodash/usr/share/doc/libjs-lodash/changelog.Debian.gz differ
diff --git a/debian/copyright b/debian/libjs-lodash/usr/share/doc/libjs-lodash/copyright
similarity index 94%
copy from debian/copyright
copy to debian/libjs-lodash/usr/share/doc/libjs-lodash/copyright
index 7bbb0c3..5ec2eda 100644
--- a/debian/copyright
+++ b/debian/libjs-lodash/usr/share/doc/libjs-lodash/copyright
@@ -6,55 +6,28 @@ Source: https://github.com/lodash/lodash
vendor/firebug-lite/skin/xp/textEditorBorders.png
vendor/curl/dist/curl-kitchen-sink/curl.js
+
Files: *
-Copyright: 2013 John-David Dalton
+Copyright: 2012-2015 John-David Dalton
License: Expat
Files: vendor/backbone/*
-Copyright: 2010-2011 Jeremy Ashkenas, DocumentCloud
- 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+Copyright: 2010-2014 Jeremy Ashkenas, DocumentCloud
License: Expat
Files: vendor/benchmark.js/*
-Copyright: 2010-2013 Mathias Bynens
- 2012-2014 John-David Dalton
-License: Expat
-
-Files: vendor/curl/*
-Copyright: 2010-2013 Brian Cavalier and John Hann
+Copyright: 2010-2015 Mathias Bynens
License: Expat
-Files: vendor/dojo/*
-Copyright: 2005-2013, The Dojo Foundation
-License: BSD-3-clause-Dojo or AFL-2.1-clause-Dojo
-
Files: vendor/firebug-lite/*
Copyright: 2007, Parakey Inc.
License: BSD-3-clause-Parakey
-Files: vendor/jquery/*
- vendor/qunit/*
-Copyright: 2012 jQuery Foundation and other contributors
-License: Expat
-
Files: vendor/json-js/*
-Copyright: 2010 Douglas Crockford
License: public-domain
-Files: vendor/platform.js
-Copyright: 2010-2013 John-David Dalton
-License: Expat
-
-Files: vendor/qunit-extras/*
-Copyright: 2011-2012 John-David Dalton
-License: Expat
-
-Files: vendor/requirejs/*
-Copyright: 2010-2011, The Dojo Foundation
-License: BSD-3-clause-Dojo or Expat
-
Files: vendor/underscore/*
-Copyright: 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+Copyright: 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
License: Expat
License: AFL-2.1-clause-Dojo
diff --git a/debian/libjs-lodash/usr/share/javascript/lodash.js b/debian/libjs-lodash/usr/share/javascript/lodash.js
new file mode 100644
index 0000000..4ecebb5
--- /dev/null
+++ b/debian/libjs-lodash/usr/share/javascript/lodash.js
@@ -0,0 +1,10784 @@
+/**
+ * @license
+ * Lo-Dash 3.0.0 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern -o ./lodash.js`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+;(function() {
+
+ /** Used as a safe reference for `undefined` in pre ES5 environments. */
+ var undefined;
+
+ /** Used as the semantic version number. */
+ var VERSION = '3.0.0';
+
+ /** Used to compose bitmasks for wrapper metadata. */
+ var BIND_FLAG = 1,
+ BIND_KEY_FLAG = 2,
+ CURRY_BOUND_FLAG = 4,
+ CURRY_FLAG = 8,
+ CURRY_RIGHT_FLAG = 16,
+ PARTIAL_FLAG = 32,
+ PARTIAL_RIGHT_FLAG = 64,
+ REARG_FLAG = 128,
+ ARY_FLAG = 256;
+
+ /** Used as default options for `_.trunc`. */
+ var DEFAULT_TRUNC_LENGTH = 30,
+ DEFAULT_TRUNC_OMISSION = '...';
+
+ /** Used to detect when a function becomes hot. */
+ var HOT_COUNT = 150,
+ HOT_SPAN = 16;
+
+ /** Used to indicate the type of lazy iteratees. */
+ var LAZY_FILTER_FLAG = 0,
+ LAZY_MAP_FLAG = 1,
+ LAZY_WHILE_FLAG = 2;
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used as the internal argument placeholder. */
+ var PLACEHOLDER = '__lodash_placeholder__';
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /** Used to match empty string literals in compiled template source. */
+ var reEmptyStringLeading = /\b__p \+= '';/g,
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+ /** Used to match HTML entities and HTML characters. */
+ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g,
+ reUnescapedHtml = /[&<>"'`]/g,
+ reHasEscapedHtml = RegExp(reEscapedHtml.source),
+ reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
+
+ /** Used to match template delimiters. */
+ var reEscape = /<%-([\s\S]+?)%>/g,
+ reEvaluate = /<%([\s\S]+?)%>/g,
+ reInterpolate = /<%=([\s\S]+?)%>/g;
+
+ /**
+ * Used to match ES6 template delimiters.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literal-lexical-components)
+ * for more details.
+ */
+ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
+
+ /** Used to detect named functions. */
+ var reFuncName = /^\s*function[ \n\r\t]+\w/;
+
+ /** Used to detect hexadecimal string values. */
+ var reHexPrefix = /^0[xX]/;
+
+ /** Used to detect host constructors (Safari > 5). */
+ var reHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to match latin-1 supplementary letters (excluding mathematical operators). */
+ var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g;
+
+ /** Used to ensure capturing order of template delimiters. */
+ var reNoMatch = /($^)/;
+
+ /**
+ * Used to match `RegExp` special characters.
+ * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
+ * for more details.
+ */
+ var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
+ reHasRegExpChars = RegExp(reRegExpChars.source);
+
+ /** Used to detect functions containing a `this` reference. */
+ var reThis = /\bthis\b/;
+
+ /** Used to match unescaped characters in compiled string literals. */
+ var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
+
+ /** Used to match words to create compound words. */
+ var reWords = (function() {
+ var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]',
+ lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+';
+
+ return RegExp(upper + '{2,}(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g');
+ }());
+
+ /** Used to detect and test for whitespace. */
+ var whitespace = (
+ // Basic whitespace characters.
+ ' \t\x0b\f\xa0\ufeff' +
+
+ // Line terminators.
+ '\n\r\u2028\u2029' +
+
+ // Unicode category "Zs" space separators.
+ '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
+ );
+
+ /** Used to assign default `context` object properties. */
+ var contextProps = [
+ 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array',
+ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number',
+ 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document',
+ 'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array',
+ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
+ 'window', 'WinRTError'
+ ];
+
+ /** Used to make template sourceURLs easier to identify. */
+ var templateCounter = -1;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dateTag] = typedArrayTags[errorTag] =
+ typedArrayTags[funcTag] = typedArrayTags[mapTag] =
+ typedArrayTags[numberTag] = typedArrayTags[objectTag] =
+ typedArrayTags[regexpTag] = typedArrayTags[setTag] =
+ typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag] = cloneableTags[arrayTag] =
+ cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
+ cloneableTags[dateTag] = cloneableTags[float32Tag] =
+ cloneableTags[float64Tag] = cloneableTags[int8Tag] =
+ cloneableTags[int16Tag] = cloneableTags[int32Tag] =
+ cloneableTags[numberTag] = cloneableTags[objectTag] =
+ cloneableTags[regexpTag] = cloneableTags[stringTag] =
+ cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+ cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+ cloneableTags[errorTag] = cloneableTags[funcTag] =
+ cloneableTags[mapTag] = cloneableTags[setTag] =
+ cloneableTags[weakMapTag] = false;
+
+ /** Used as an internal `_.debounce` options object by `_.throttle`. */
+ var debounceOptions = {
+ 'leading': false,
+ 'maxWait': 0,
+ 'trailing': false
+ };
+
+ /** Used to map latin-1 supplementary letters to basic latin letters. */
+ var deburredLetters = {
+ '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+ '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+ '\xc7': 'C', '\xe7': 'c',
+ '\xd0': 'D', '\xf0': 'd',
+ '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+ '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+ '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+ '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
+ '\xd1': 'N', '\xf1': 'n',
+ '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+ '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+ '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+ '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
+ '\xc6': 'Ae', '\xe6': 'ae',
+ '\xde': 'Th', '\xfe': 'th',
+ '\xdf': 'ss'
+ };
+
+ /** Used to map characters to HTML entities. */
+ var htmlEscapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
+ };
+
+ /** Used to map HTML entities to characters. */
+ var htmlUnescapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ ''': "'",
+ '`': '`'
+ };
+
+ /** Used to determine if values are of the language type `Object`. */
+ var objectTypes = {
+ 'function': true,
+ 'object': true
+ };
+
+ /** Used to escape characters for inclusion in compiled string literals. */
+ var stringEscapes = {
+ '\\': '\\',
+ "'": "'",
+ '\n': 'n',
+ '\r': 'r',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ /**
+ * Used as a reference to the global object.
+ *
+ * The `this` value is used if it is the global object to avoid Greasemonkey's
+ * restricted `window` object, otherwise the `window` object is used.
+ */
+ var root = (objectTypes[typeof window] && window !== (this && this.window)) ? window : this;
+
+ /** Detect free variable `exports`. */
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
+
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */
+ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
+ root = freeGlobal;
+ }
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The base implementation of `compareAscending` which compares values and
+ * sorts them in ascending order without guaranteeing a stable sort.
+ *
+ * @private
+ * @param {*} value The value to compare to `other`.
+ * @param {*} other The value to compare to `value`.
+ * @returns {number} Returns the sort order indicator for `value`.
+ */
+ function baseCompareAscending(value, other) {
+ if (value !== other) {
+ var valIsReflexive = value === value,
+ othIsReflexive = other === other;
+
+ if (value > other || !valIsReflexive || (typeof value == 'undefined' && othIsReflexive)) {
+ return 1;
+ }
+ if (value < other || !othIsReflexive || (typeof other == 'undefined' && valIsReflexive)) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * The base implementation of `_.indexOf` without support for binary searches.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseIndexOf(array, value, fromIndex) {
+ if (value !== value) {
+ return indexOfNaN(array, fromIndex);
+ }
+ var index = (fromIndex || 0) - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.sortBy` and `_.sortByAll` which uses `comparer`
+ * to define the sort order of `array` and replaces criteria objects with their
+ * corresponding values.
+ *
+ * @private
+ * @param {Array} array The array to sort.
+ * @param {Function} comparer The function to define sort order.
+ * @returns {Array} Returns `array`.
+ */
+ function baseSortBy(array, comparer) {
+ var length = array.length;
+
+ array.sort(comparer);
+ while (length--) {
+ array[length] = array[length].value;
+ }
+ return array;
+ }
+
+ /**
+ * Converts `value` to a string if it is not one. An empty string is returned
+ * for `null` or `undefined` values.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ if (typeof value == 'string') {
+ return value;
+ }
+ return value == null ? '' : (value + '');
+ }
+
+ /**
+ * Used by `_.max` and `_.min` as the default callback for string values.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the code unit of the first character of the string.
+ */
+ function charAtCallback(string) {
+ return string.charCodeAt(0);
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the first character not found in `chars`.
+ */
+ function charsLeftIndex(string, chars) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the last character not found in `chars`.
+ */
+ function charsRightIndex(string, chars) {
+ var index = string.length;
+
+ while (index-- && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.sortBy` to compare transformed elements of a collection and stable
+ * sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareAscending(object, other) {
+ return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index);
+ }
+
+ /**
+ * Used by `_.sortByAll` to compare multiple properties of each element
+ * in a collection and stable sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareMultipleAscending(object, other) {
+ var index = -1,
+ objCriteria = object.criteria,
+ othCriteria = other.criteria,
+ length = objCriteria.length;
+
+ while (++index < length) {
+ var result = baseCompareAscending(objCriteria[index], othCriteria[index]);
+ if (result) {
+ return result;
+ }
+ }
+ // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+ // that causes it, under certain circumstances, to provide the same value
+ // for `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247.
+ //
+ // This also ensures a stable sort in V8 and other engines.
+ // See https://code.google.com/p/v8/issues/detail?id=90.
+ return object.index - other.index;
+ }
+
+ /**
+ * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
+ *
+ * @private
+ * @param {string} letter The matched letter to deburr.
+ * @returns {string} Returns the deburred letter.
+ */
+ function deburrLetter(letter) {
+ return deburredLetters[letter];
+ }
+
+ /**
+ * Used by `_.escape` to convert characters to HTML entities.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeHtmlChar(chr) {
+ return htmlEscapes[chr];
+ }
+
+ /**
+ * Used by `_.template` to escape characters for inclusion in compiled
+ * string literals.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeStringChar(chr) {
+ return '\\' + stringEscapes[chr];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `NaN` is found in `array`.
+ * If `fromRight` is provided elements of `array` are iterated from right to left.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {number} [fromIndex] The index to search from.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched `NaN`, else `-1`.
+ */
+ function indexOfNaN(array, fromIndex, fromRight) {
+ var length = array.length,
+ index = fromRight ? (fromIndex || length) : ((fromIndex || 0) - 1);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var other = array[index];
+ if (other !== other) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if `value` is object-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ */
+ function isObjectLike(value) {
+ return (value && typeof value == 'object') || false;
+ }
+
+ /**
+ * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a
+ * character code is whitespace.
+ *
+ * @private
+ * @param {number} charCode The character code to inspect.
+ * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`.
+ */
+ function isSpace(charCode) {
+ return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 ||
+ (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279)));
+ }
+
+ /**
+ * Replaces all `placeholder` elements in `array` with an internal placeholder
+ * and returns an array of their indexes.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {*} placeholder The placeholder to replace.
+ * @returns {Array} Returns the new array of placeholder indexes.
+ */
+ function replaceHolders(array, placeholder) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ if (array[index] === placeholder) {
+ array[index] = PLACEHOLDER;
+ result[++resIndex] = index;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * An implementation of `_.uniq` optimized for sorted arrays without support
+ * for callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function sortedUniq(array, iteratee) {
+ var seen,
+ index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (!index || seen !== computed) {
+ seen = computed;
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the first non-whitespace character.
+ */
+ function trimmedLeftIndex(string) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the last non-whitespace character.
+ */
+ function trimmedRightIndex(string) {
+ var index = string.length;
+
+ while (index-- && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} chr The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ function unescapeHtmlChar(chr) {
+ return htmlUnescapes[chr];
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Create a new pristine `lodash` function using the given `context` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} [context=root] The context object.
+ * @returns {Function} Returns a new `lodash` function.
+ * @example
+ *
+ * _.mixin({ 'add': function(a, b) { return a + b; } });
+ *
+ * var lodash = _.runInContext();
+ * lodash.mixin({ 'sub': function(a, b) { return a - b; } });
+ *
+ * _.isFunction(_.add);
+ * // => true
+ * _.isFunction(_.sub);
+ * // => false
+ *
+ * lodash.isFunction(lodash.add);
+ * // => false
+ * lodash.isFunction(lodash.sub);
+ * // => true
+ *
+ * // using `context` to mock `Date#getTime` use in `_.now`
+ * var mock = _.runInContext({
+ * 'Date': function() {
+ * return { 'getTime': getTimeMock };
+ * }
+ * });
+ *
+ * // or creating a suped-up `defer` in Node.js
+ * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+ */
+ function runInContext(context) {
+ // Avoid issues with some ES3 environments that attempt to use values, named
+ // after built-in constructors like `Object`, for the creation of literals.
+ // ES5 clears this up by stating that literals must use built-in constructors.
+ // See http://es5.github.io/#x11.1.5.
+ context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
+
+ /** Native constructor references. */
+ var Array = context.Array,
+ Date = context.Date,
+ Error = context.Error,
+ Function = context.Function,
+ Math = context.Math,
+ Number = context.Number,
+ Object = context.Object,
+ RegExp = context.RegExp,
+ String = context.String,
+ TypeError = context.TypeError;
+
+ /** Used for native method references. */
+ var arrayProto = Array.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect DOM support. */
+ var document = (document = context.window) && document.document;
+
+ /** Used to resolve the decompiled source of functions. */
+ var fnToString = Function.prototype.toString;
+
+ /** Used to the length of n-tuples for `_.unzip`. */
+ var getLength = baseProperty('length');
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to generate unique IDs. */
+ var idCounter = 0;
+
+ /**
+ * Used to resolve the `toStringTag` of values.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
+ * for more details.
+ */
+ var objToString = objectProto.toString;
+
+ /** Used to restore the original `_` reference in `_.noConflict`. */
+ var oldDash = context._;
+
+ /** Used to detect if a method is native. */
+ var reNative = RegExp('^' +
+ escapeRegExp(objToString)
+ .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Native method references. */
+ var ArrayBuffer = isNative(ArrayBuffer = context.ArrayBuffer) && ArrayBuffer,
+ bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice,
+ ceil = Math.ceil,
+ clearTimeout = context.clearTimeout,
+ floor = Math.floor,
+ getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
+ push = arrayProto.push,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ Set = isNative(Set = context.Set) && Set,
+ setTimeout = context.setTimeout,
+ splice = arrayProto.splice,
+ Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array,
+ unshift = arrayProto.unshift,
+ WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap;
+
+ /** Used to clone array buffers. */
+ var Float64Array = (function() {
+ // Safari 5 errors when using an array buffer to initialize a typed array
+ // where the array buffer's `byteLength` is not a multiple of the typed
+ // array's `BYTES_PER_ELEMENT`.
+ try {
+ var func = isNative(func = context.Float64Array) && func,
+ result = new func(new ArrayBuffer(10), 0, 1) && func;
+ } catch(e) {}
+ return result;
+ }());
+
+ /* Native method references for those with the same name as other `lodash` methods. */
+ var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
+ nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
+ nativeIsFinite = context.isFinite,
+ nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
+ nativeMax = Math.max,
+ nativeMin = Math.min,
+ nativeNow = isNative(nativeNow = Date.now) && nativeNow,
+ nativeNumIsFinite = isNative(nativeNumIsFinite = Number.isFinite) && nativeNumIsFinite,
+ nativeParseInt = context.parseInt,
+ nativeRandom = Math.random;
+
+ /** Used as references for `-Infinity` and `Infinity`. */
+ var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY,
+ POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
+
+ /** Used as references for the maximum length and index of an array. */
+ var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1,
+ MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+ HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+ /** Used as the size, in bytes, of each `Float64Array` element. */
+ var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;
+
+ /**
+ * Used as the maximum length of an array-like value.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
+ * for more details.
+ */
+ var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
+
+ /** Used to store function metadata. */
+ var metaMap = WeakMap && new WeakMap;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object which wraps `value` to enable intuitive chaining.
+ * Methods that operate on and return arrays, collections, and functions can
+ * be chained together. Methods that return a boolean or single value will
+ * automatically end the chain returning the unwrapped value. Explicit chaining
+ * may be enabled using `_.chain`. The execution of chained methods is lazy,
+ * that is, execution is deferred until `_#value` is implicitly or explicitly
+ * called.
+ *
+ * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
+ * fusion is an optimization that merges iteratees to avoid creating intermediate
+ * arrays and reduce the number of iteratee executions.
+ *
+ * Chaining is supported in custom builds as long as the `_#value` method is
+ * directly or indirectly included in the build.
+ *
+ * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
+ * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
+ * and `unshift`
+ *
+ * The wrapper functions that support shortcut fusion are:
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `first`,
+ * `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, `slice`,
+ * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `where`
+ *
+ * The chainable wrapper functions are:
+ * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
+ * `callback`, `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`,
+ * `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`,
+ * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`,
+ * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`,
+ * `initial`, `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`,
+ * `mapValues`, `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`,
+ * `omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`,
+ * `pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`,
+ * `rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
+ * `sortBy`, `sortByAll`, `splice`, `take`, `takeRight`, `takeRightWhile`,
+ * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
+ * `transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`,
+ * `where`, `without`, `wrap`, `xor`, `zip`, and `zipObject`
+ *
+ * The wrapper functions that are **not** chainable by default are:
+ * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
+ * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`,
+ * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`,
+ * `identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`,
+ * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`,
+ * `isFunction`, `isMatch` , `isNative`, `isNaN`, `isNull`, `isNumber`,
+ * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`,
+ * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`,
+ * `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`,
+ * `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`,
+ * `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`,
+ * `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
+ * `unescape`, `uniqueId`, `value`, and `words`
+ *
+ * The wrapper function `sample` will return a wrapped value when `n` is provided,
+ * otherwise an unwrapped value is returned.
+ *
+ * @name _
+ * @constructor
+ * @category Chain
+ * @param {*} value The value to wrap in a `lodash` instance.
+ * @returns {Object} Returns a `lodash` instance.
+ * @example
+ *
+ * var wrapped = _([1, 2, 3]);
+ *
+ * // returns an unwrapped value
+ * wrapped.reduce(function(sum, n) { return sum + n; });
+ * // => 6
+ *
+ * // returns a wrapped value
+ * var squares = wrapped.map(function(n) { return n * n; });
+ *
+ * _.isArray(squares);
+ * // => false
+ *
+ * _.isArray(squares.value());
+ * // => true
+ */
+ function lodash(value) {
+ if (isObjectLike(value) && !isArray(value)) {
+ if (value instanceof LodashWrapper) {
+ return value;
+ }
+ if (hasOwnProperty.call(value, '__wrapped__')) {
+ return new LodashWrapper(value.__wrapped__, value.__chain__, arrayCopy(value.__actions__));
+ }
+ }
+ return new LodashWrapper(value);
+ }
+
+ /**
+ * The base constructor for creating `lodash` wrapper objects.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
+ * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
+ */
+ function LodashWrapper(value, chainAll, actions) {
+ this.__actions__ = actions || [];
+ this.__chain__ = !!chainAll;
+ this.__wrapped__ = value;
+ }
+
+ /**
+ * An object environment feature flags.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ var support = lodash.support = {};
+
+ (function(x) {
+
+ /**
+ * Detect if functions can be decompiled by `Function#toString`
+ * (all but Firefox OS certified apps, older Opera mobile browsers, and
+ * the PlayStation 3; forced `false` for Windows 8 apps).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
+
+ /**
+ * Detect if `Function#name` is supported (all but IE).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcNames = typeof Function.name == 'string';
+
+ /**
+ * Detect if the DOM is supported.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ try {
+ support.dom = document.createDocumentFragment().nodeType === 11;
+ } catch(e) {
+ support.dom = false;
+ }
+
+ /**
+ * Detect if `arguments` object indexes are non-enumerable.
+ *
+ * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object
+ * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat
+ * `arguments` object indexes as non-enumerable and fail `hasOwnProperty`
+ * checks for indexes that exceed their function's formal parameters with
+ * associated values of `0`.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ try {
+ support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1);
+ } catch(e) {
+ support.nonEnumArgs = true;
+ }
+ }(0, 0));
+
+ /**
+ * By default, the template delimiters used by Lo-Dash are like those in
+ * embedded Ruby (ERB). Change the following template settings to use
+ * alternative delimiters.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ lodash.templateSettings = {
+
+ /**
+ * Used to detect `data` property values to be HTML-escaped.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'escape': reEscape,
+
+ /**
+ * Used to detect code to be evaluated.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'evaluate': reEvaluate,
+
+ /**
+ * Used to detect `data` property values to inject.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'interpolate': reInterpolate,
+
+ /**
+ * Used to reference the data object in the template text.
+ *
+ * @memberOf _.templateSettings
+ * @type string
+ */
+ 'variable': '',
+
+ /**
+ * Used to import variables into the compiled template.
+ *
+ * @memberOf _.templateSettings
+ * @type Object
+ */
+ 'imports': {
+
+ /**
+ * A reference to the `lodash` function.
+ *
+ * @memberOf _.templateSettings.imports
+ * @type Function
+ */
+ '_': lodash
+ }
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ */
+ function LazyWrapper(value) {
+ this.actions = null;
+ this.dir = 1;
+ this.dropCount = 0;
+ this.filtered = false;
+ this.iteratees = null;
+ this.takeCount = POSITIVE_INFINITY;
+ this.views = null;
+ this.wrapped = value;
+ }
+
+ /**
+ * Creates a clone of the lazy wrapper object.
+ *
+ * @private
+ * @name clone
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the cloned `LazyWrapper` object.
+ */
+ function lazyClone() {
+ var actions = this.actions,
+ iteratees = this.iteratees,
+ views = this.views,
+ result = new LazyWrapper(this.wrapped);
+
+ result.actions = actions ? arrayCopy(actions) : null;
+ result.dir = this.dir;
+ result.dropCount = this.dropCount;
+ result.filtered = this.filtered;
+ result.iteratees = iteratees ? arrayCopy(iteratees) : null;
+ result.takeCount = this.takeCount;
+ result.views = views ? arrayCopy(views) : null;
+ return result;
+ }
+
+ /**
+ * Reverses the direction of lazy iteration.
+ *
+ * @private
+ * @name reverse
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the new reversed `LazyWrapper` object.
+ */
+ function lazyReverse() {
+ var filtered = this.filtered,
+ result = filtered ? new LazyWrapper(this) : this.clone();
+
+ result.dir = this.dir * -1;
+ result.filtered = filtered;
+ return result;
+ }
+
+ /**
+ * Extracts the unwrapped value from its lazy wrapper.
+ *
+ * @private
+ * @name value
+ * @memberOf LazyWrapper
+ * @returns {*} Returns the unwrapped value.
+ */
+ function lazyValue() {
+ var array = this.wrapped.value();
+ if (!isArray(array)) {
+ return baseWrapperValue(array, this.actions);
+ }
+ var dir = this.dir,
+ isRight = dir < 0,
+ length = array.length,
+ view = getView(0, length, this.views),
+ start = view.start,
+ end = view.end,
+ dropCount = this.dropCount,
+ takeCount = nativeMin(end - start, this.takeCount - dropCount),
+ index = isRight ? end : start - 1,
+ iteratees = this.iteratees,
+ iterLength = iteratees ? iteratees.length : 0,
+ resIndex = 0,
+ result = [];
+
+ outer:
+ while (length-- && resIndex < takeCount) {
+ index += dir;
+
+ var iterIndex = -1,
+ value = array[index];
+
+ while (++iterIndex < iterLength) {
+ var data = iteratees[iterIndex],
+ iteratee = data.iteratee,
+ computed = iteratee(value, index, array),
+ type = data.type;
+
+ if (type == LAZY_MAP_FLAG) {
+ value = computed;
+ } else if (!computed) {
+ if (type == LAZY_FILTER_FLAG) {
+ continue outer;
+ } else {
+ break outer;
+ }
+ }
+ }
+ if (dropCount) {
+ dropCount--;
+ } else {
+ result[resIndex++] = value;
+ }
+ }
+ return isRight ? result.reverse() : result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a cache object to store key/value pairs.
+ *
+ * @private
+ * @static
+ * @name Cache
+ * @memberOf _.memoize
+ */
+ function MapCache() {
+ this.__data__ = {};
+ }
+
+ /**
+ * Removes `key` and its value from the cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`.
+ */
+ function mapDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the cached value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the cached value.
+ */
+ function mapGet(key) {
+ return key == '__proto__' ? undefined : this.__data__[key];
+ }
+
+ /**
+ * Checks if a cached value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapHas(key) {
+ return key != '__proto__' && hasOwnProperty.call(this.__data__, key);
+ }
+
+ /**
+ * Adds `value` to `key` of the cache.
+ *
+ * @private
+ * @name set
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to cache.
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache object.
+ */
+ function mapSet(key, value) {
+ if (key != '__proto__') {
+ this.__data__[key] = value;
+ }
+ return this;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ *
+ * Creates a cache object to store unique values.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var length = values ? values.length : 0;
+
+ this.data = { 'hash': nativeCreate(null), 'set': new Set };
+ while (length--) {
+ this.push(values[length]);
+ }
+ }
+
+ /**
+ * Checks if `value` is in `cache` mimicking the return signature of
+ * `_.indexOf` by returning `0` if the value is found, else `-1`.
+ *
+ * @private
+ * @param {Object} cache The cache to search.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `0` if `value` is found, else `-1`.
+ */
+ function cacheIndexOf(cache, value) {
+ var data = cache.data,
+ result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
+
+ return result ? 0 : -1;
+ }
+
+ /**
+ * Adds `value` to the cache.
+ *
+ * @private
+ * @name push
+ * @memberOf SetCache
+ * @param {*} value The value to cache.
+ */
+ function cachePush(value) {
+ var data = this.data;
+ if (typeof value == 'string' || isObject(value)) {
+ data.set.add(value);
+ } else {
+ data.hash[value] = true;
+ }
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayCopy(source, array) {
+ var index = -1,
+ length = source.length;
+
+ array || (array = Array(length));
+ while (++index < length) {
+ array[index] = source[index];
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEach` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEachRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEachRight(array, iteratee) {
+ var length = array.length;
+
+ while (length--) {
+ if (iteratee(array[length], length, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.every` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ */
+ function arrayEvery(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (!predicate(array[index], index, array)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A specialized version of `_.filter` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function arrayFilter(array, predicate) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.map` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function arrayMap(array, iteratee) {
+ var index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = iteratee(array[index], index, array);
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.max` for arrays without support for iteratees.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the maximum value.
+ */
+ function arrayMax(array) {
+ var index = -1,
+ length = array.length,
+ result = NEGATIVE_INFINITY;
+
+ while (++index < length) {
+ var value = array[index];
+ if (value > result) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.min` for arrays without support for iteratees.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the minimum value.
+ */
+ function arrayMin(array) {
+ var index = -1,
+ length = array.length,
+ result = POSITIVE_INFINITY;
+
+ while (++index < length) {
+ var value = array[index];
+ if (value < result) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.reduce` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the first element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduce(array, iteratee, accumulator, initFromArray) {
+ var index = -1,
+ length = array.length;
+
+ if (initFromArray && length) {
+ accumulator = array[++index];
+ }
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.reduceRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the last element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduceRight(array, iteratee, accumulator, initFromArray) {
+ var length = array.length;
+ if (initFromArray && length) {
+ accumulator = array[--length];
+ }
+ while (length--) {
+ accumulator = iteratee(accumulator, array[length], length, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.some` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Used by `_.defaults` to customize its `_.assign` use.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignDefaults(objectValue, sourceValue) {
+ return typeof objectValue == 'undefined' ? sourceValue : objectValue;
+ }
+
+ /**
+ * Used by `_.template` to customize its `_.assign` use.
+ *
+ * **Note:** This method is like `assignDefaults` except that it ignores
+ * inherited property values when checking if a property is `undefined`.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @param {string} key The key associated with the object and source values.
+ * @param {Object} object The destination object.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignOwnDefaults(objectValue, sourceValue, key, object) {
+ return (typeof objectValue == 'undefined' || !hasOwnProperty.call(object, key))
+ ? sourceValue
+ : objectValue;
+ }
+
+ /**
+ * The base implementation of `_.assign` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseAssign(object, source, customizer) {
+ var props = keys(source);
+ if (!customizer) {
+ return baseCopy(source, object, props);
+ }
+ var index = -1,
+ length = props.length
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key],
+ result = customizer(value, source[key], key, object, source);
+
+ if ((result === result ? result !== value : value === value) ||
+ (typeof value == 'undefined' && !(key in object))) {
+ object[key] = result;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.at` without support for strings and individual
+ * key arguments.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {number[]|string[]} [props] The property names or indexes of elements to pick.
+ * @returns {Array} Returns the new array of picked elements.
+ */
+ function baseAt(collection, props) {
+ var index = -1,
+ length = collection.length,
+ isArr = isLength(length),
+ propsLength = props.length,
+ result = Array(propsLength);
+
+ while(++index < propsLength) {
+ var key = props[index];
+ if (isArr) {
+ key = parseFloat(key);
+ result[index] = isIndex(key, length) ? collection[key] : undefined;
+ } else {
+ result[index] = collection[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copies the properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Array} props The property names to copy.
+ * @returns {Object} Returns `object`.
+ */
+ function baseCopy(source, object, props) {
+ if (!props) {
+ props = object;
+ object = {};
+ }
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ object[key] = source[key];
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.bindAll` without support for individual
+ * method name arguments.
+ *
+ * @private
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {string[]} methodNames The object method names to bind.
+ * @returns {Object} Returns `object`.
+ */
+ function baseBindAll(object, methodNames) {
+ var index = -1,
+ length = methodNames.length;
+
+ while (++index < length) {
+ var key = methodNames[index];
+ object[key] = createWrapper(object[key], BIND_FLAG, object);
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.callback` which supports specifying the
+ * number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function baseCallback(func, thisArg, argCount) {
+ var type = typeof func;
+ if (type == 'function') {
+ return (typeof thisArg != 'undefined' && isBindable(func))
+ ? bindCallback(func, thisArg, argCount)
+ : func;
+ }
+ if (func == null) {
+ return identity;
+ }
+ // Handle "_.property" and "_.matches" style callback shorthands.
+ return type == 'object'
+ ? baseMatches(func, !argCount)
+ : baseProperty(argCount ? baseToString(func) : func);
+ }
+
+ /**
+ * The base implementation of `_.clone` without support for argument juggling
+ * and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The object `value` belongs to.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates clones with source counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
+ var result;
+ if (customizer) {
+ result = object ? customizer(value, key, object) : customizer(value);
+ }
+ if (typeof result != 'undefined') {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return arrayCopy(value, result);
+ }
+ } else {
+ var tag = objToString.call(value),
+ isFunc = tag == funcTag;
+
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ result = initCloneObject(isFunc ? {} : value);
+ if (!isDeep) {
+ return baseCopy(value, result, keys(value));
+ }
+ } else {
+ return cloneableTags[tag]
+ ? initCloneByTag(value, tag, isDeep)
+ : (object ? value : {});
+ }
+ }
+ // Check for circular references and return corresponding clone.
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == value) {
+ return stackB[length];
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate it with its clone.
+ stackA.push(value);
+ stackB.push(result);
+
+ // Recursively populate clone (susceptible to call stack limits).
+ (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
+ result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+ var baseCreate = (function() {
+ function Object() {}
+ return function(prototype) {
+ if (isObject(prototype)) {
+ Object.prototype = prototype;
+ var result = new Object;
+ Object.prototype = null;
+ }
+ return result || context.Object();
+ };
+ }());
+
+ /**
+ * The base implementation of `_.delay` and `_.defer` which accepts an index
+ * of where to slice the arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {Object} args The `arguments` object to slice and provide to `func`.
+ * @returns {number} Returns the timer id.
+ */
+ function baseDelay(func, wait, args, fromIndex) {
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return setTimeout(function() { func.apply(undefined, baseSlice(args, fromIndex)); }, wait);
+ }
+
+ /**
+ * The base implementation of `_.difference` which accepts a single array
+ * of values to exclude.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Array} values The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ */
+ function baseDifference(array, values) {
+ var length = array ? array.length : 0,
+ result = [];
+
+ if (!length) {
+ return result;
+ }
+ var index = -1,
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf,
+ cache = isCommon && values.length >= 200 && createCache(values),
+ valuesLength = values.length;
+
+ if (cache) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ values = cache;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index];
+
+ if (isCommon && value === value) {
+ var valuesIndex = valuesLength;
+ while (valuesIndex--) {
+ if (values[valuesIndex] === value) {
+ continue outer;
+ }
+ }
+ result.push(value);
+ }
+ else if (indexOf(values, value) < 0) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.forEach` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEach(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwn(collection, iteratee);
+ }
+ var index = -1,
+ iterable = toObject(collection);
+
+ while (++index < length) {
+ if (iteratee(iterable[index], index, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.forEachRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEachRight(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwnRight(collection, iteratee);
+ }
+ var iterable = toObject(collection);
+ while (length--) {
+ if (iteratee(iterable[length], length, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.every` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`
+ */
+ function baseEvery(collection, predicate) {
+ var result = true;
+ baseEach(collection, function(value, index, collection) {
+ result = !!predicate(value, index, collection);
+ return result;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.filter` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function baseFilter(collection, predicate) {
+ var result = [];
+ baseEach(collection, function(value, index, collection) {
+ if (predicate(value, index, collection)) {
+ result.push(value);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
+ * without support for callback shorthands and `this` binding, which iterates
+ * over `collection` using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @param {boolean} [retKey] Specify returning the key of the found element
+ * instead of the element itself.
+ * @returns {*} Returns the found element or its key, else `undefined`.
+ */
+ function baseFind(collection, predicate, eachFunc, retKey) {
+ var result;
+ eachFunc(collection, function(value, key, collection) {
+ if (predicate(value, key, collection)) {
+ result = retKey ? key : value;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.flatten` with added support for restricting
+ * flattening and specifying the start index.
+ *
+ * @private
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param {boolean} [isStrict] Restrict flattening to arrays and `arguments` objects.
+ * @param {number} [fromIndex=0] The index to start from.
+ * @returns {Array} Returns the new flattened array.
+ */
+ function baseFlatten(array, isDeep, isStrict, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+
+ if (isObjectLike(value) && isLength(value.length) && (isArray(value) || isArguments(value))) {
+ if (isDeep) {
+ // Recursively flatten arrays (susceptible to call stack limits).
+ value = baseFlatten(value, isDeep, isStrict);
+ }
+ var valIndex = -1,
+ valLength = value.length;
+
+ result.length += valLength;
+ while (++valIndex < valLength) {
+ result[++resIndex] = value[valIndex];
+ }
+ } else if (!isStrict) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `baseForIn` and `baseForOwn` which iterates
+ * over `object` properties returned by `keysFunc` invoking `iteratee` for
+ * each property. Iterator functions may exit iteration early by explicitly
+ * returning `false`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ function baseFor(object, iteratee, keysFunc) {
+ var index = -1,
+ iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * This function is like `baseFor` except that it iterates over properties
+ * in the opposite order.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForRight(object, iteratee, keysFunc) {
+ var iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (length--) {
+ var key = props[length];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.forIn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForIn(object, iteratee) {
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * The base implementation of `_.forOwn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwn(object, iteratee) {
+ return baseFor(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.forOwnRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwnRight(object, iteratee) {
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.functions` which creates an array of
+ * `object` function property names filtered from those provided.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Array} props The property names to filter.
+ * @returns {Array} Returns the new array of filtered property names.
+ */
+ function baseFunctions(object, props) {
+ var index = -1,
+ length = props.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var key = props[index];
+ if (isFunction(object[key])) {
+ result[++resIndex] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.invoke` which requires additional arguments
+ * to be provided as an array of arguments rather than individually.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {Array} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseInvoke(collection, methodName, args) {
+ var index = -1,
+ isFunc = typeof methodName == 'function',
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value) {
+ var func = isFunc ? methodName : (value != null && value[methodName]);
+ result[++index] = func ? func.apply(value, args) : undefined;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isEqual` without support for `this` binding
+ * `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, customizer, isWhere, stackA, stackB) {
+ // Exit early for identical values.
+ if (value === other) {
+ // Treat `+0` vs. `-0` as not equal.
+ return value !== 0 || (1 / value == 1 / other);
+ }
+ var valType = typeof value,
+ othType = typeof other;
+
+ // Exit early for unlike primitive values.
+ if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') ||
+ value == null || other == null) {
+ // Return `false` unless both values are `NaN`.
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, baseIsEqual, customizer, isWhere, stackA, stackB);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA=[]] Tracks traversed `value` objects.
+ * @param {Array} [stackB=[]] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = arrayTag,
+ othTag = arrayTag;
+
+ if (!objIsArr) {
+ objTag = objToString.call(object);
+ if (objTag == argsTag) {
+ objTag = objectTag;
+ } else if (objTag != objectTag) {
+ objIsArr = isTypedArray(object);
+ }
+ }
+ if (!othIsArr) {
+ othTag = objToString.call(other);
+ if (othTag == argsTag) {
+ othTag = objectTag;
+ } else if (othTag != objectTag) {
+ othIsArr = isTypedArray(other);
+ }
+ }
+ var objIsObj = objTag == objectTag,
+ othIsObj = othTag == objectTag,
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && !(objIsArr || objIsObj)) {
+ return equalByTag(object, other, objTag);
+ }
+ var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (valWrapped || othWrapped) {
+ return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isWhere, stackA, stackB);
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ // Assume cyclic structures are equal.
+ // The algorithm for detecting cyclic structures is adapted from ES 5.1
+ // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3).
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == object) {
+ return stackB[length] == other;
+ }
+ }
+ // Add `object` and `other` to the stack of traversed objects.
+ stackA.push(object);
+ stackB.push(other);
+
+ var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isWhere, stackA, stackB);
+
+ stackA.pop();
+ stackB.pop();
+
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isMatch` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Object} source The object to inspect.
+ * @param {Array} props The source property names to match.
+ * @param {Array} values The source values to match.
+ * @param {Array} strictCompareFlags Strict comparison flags for source values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ */
+ function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
+ var length = props.length;
+ if (object == null) {
+ return !length;
+ }
+ var index = -1,
+ noCustomizer = !customizer;
+
+ while (++index < length) {
+ if ((noCustomizer && strictCompareFlags[index])
+ ? values[index] !== object[props[index]]
+ : !hasOwnProperty.call(object, props[index])
+ ) {
+ return false;
+ }
+ }
+ index = -1;
+ while (++index < length) {
+ var key = props[index];
+ if (noCustomizer && strictCompareFlags[index]) {
+ var result = hasOwnProperty.call(object, key);
+ } else {
+ var objValue = object[key],
+ srcValue = values[index];
+
+ result = customizer ? customizer(objValue, srcValue, key) : undefined;
+ if (typeof result == 'undefined') {
+ result = baseIsEqual(srcValue, objValue, customizer, true);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.map` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function baseMap(collection, iteratee) {
+ var result = [];
+ baseEach(collection, function(value, key, collection) {
+ result.push(iteratee(value, key, collection));
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.matches` which supports specifying whether
+ * `source` should be cloned.
+ *
+ * @private
+ * @param {Object} source The object of property values to match.
+ * @param {boolean} [isCloned] Specify cloning the source object.
+ * @returns {Function} Returns the new function.
+ */
+ function baseMatches(source, isCloned) {
+ var props = keys(source),
+ length = props.length;
+
+ if (length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return function(object) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ };
+ }
+ }
+ if (isCloned) {
+ source = baseClone(source, true);
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = source[props[length]];
+ values[length] = value;
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return function(object) {
+ return baseIsMatch(object, props, values, strictCompareFlags);
+ };
+ }
+
+ /**
+ * The base implementation of `_.merge` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseMerge(object, source, customizer, stackA, stackB) {
+ var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
+
+ (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
+ if (isObjectLike(srcValue)) {
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+ return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ }
+ if ((isSrcArr || typeof result != 'undefined') &&
+ (isCommon || (result === result ? result !== value : value === value))) {
+ object[key] = result;
+ }
+ });
+ return object;
+ }
+
+ /**
+ * A specialized version of `baseMerge` for arrays and objects which performs
+ * deep merges and tracks traversed objects enabling objects with circular
+ * references to be merged.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {string} key The key of the value to merge.
+ * @param {Function} mergeFunc The function to merge values.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
+ var length = stackA.length,
+ srcValue = source[key];
+
+ while (length--) {
+ if (stackA[length] == srcValue) {
+ object[key] = stackB[length];
+ return;
+ }
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) {
+ result = isArray(value)
+ ? value
+ : (value ? arrayCopy(value) : []);
+ }
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+ result = isArguments(value)
+ ? toPlainObject(value)
+ : (isPlainObject(value) ? value : {});
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate
+ // it with its merged value.
+ stackA.push(srcValue);
+ stackB.push(result);
+
+ if (isCommon) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
+ } else if (result === result ? result !== value : value === value) {
+ object[key] = result;
+ }
+ }
+
+ /**
+ * The base implementation of `_.property` which does not coerce `key` to a string.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * The base implementation of `_.pullAt` without support for individual
+ * index arguments.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {number[]} indexes The indexes of elements to remove.
+ * @returns {Array} Returns the new array of removed elements.
+ */
+ function basePullAt(array, indexes) {
+ var length = indexes.length,
+ result = baseAt(array, indexes);
+
+ indexes.sort(baseCompareAscending);
+ while (length--) {
+ var index = parseFloat(indexes[length]);
+ if (index != previous && isIndex(index)) {
+ var previous = index;
+ splice.call(array, index, 1);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.random` without support for argument juggling
+ * and returning floating-point numbers.
+ *
+ * @private
+ * @param {number} min The minimum possible value.
+ * @param {number} max The maximum possible value.
+ * @returns {number} Returns the random number.
+ */
+ function baseRandom(min, max) {
+ return min + floor(nativeRandom() * (max - min + 1));
+ }
+
+ /**
+ * The base implementation of `_.reduce` and `_.reduceRight` without support
+ * for callback shorthands or `this` binding, which iterates over `collection`
+ * using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} accumulator The initial value.
+ * @param {boolean} initFromCollection Specify using the first or last element
+ * of `collection` as the initial value.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @returns {*} Returns the accumulated value.
+ */
+ function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
+ eachFunc(collection, function(value, index, collection) {
+ accumulator = initFromCollection
+ ? (initFromCollection = false, value)
+ : iteratee(accumulator, value, index, collection)
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `setData` without support for hot loop detection.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var baseSetData = !metaMap ? identity : function(func, data) {
+ metaMap.set(func, data);
+ return func;
+ };
+
+ /**
+ * The base implementation of `_.slice` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseSlice(array, start, end) {
+ var index = -1,
+ length = array.length;
+
+ start = start == null ? 0 : (+start || 0);
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = (typeof end == 'undefined' || end > length) ? length : (+end || 0);
+ if (end < 0) {
+ end += length;
+ }
+ length = start > end ? 0 : (end - start);
+
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = array[index + start];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.some` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function baseSome(collection, predicate) {
+ var result;
+
+ baseEach(collection, function(value, index, collection) {
+ result = predicate(value, index, collection);
+ return !result;
+ });
+ return !!result;
+ }
+
+ /**
+ * The base implementation of `_.uniq` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function baseUniq(array, iteratee) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = array.length,
+ isCommon = indexOf == baseIndexOf,
+ isLarge = isCommon && length >= 200,
+ seen = isLarge && createCache(),
+ result = [];
+
+ if (seen) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ } else {
+ isLarge = false;
+ seen = iteratee ? [] : result;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (isCommon && value === value) {
+ var seenIndex = seen.length;
+ while (seenIndex--) {
+ if (seen[seenIndex] === computed) {
+ continue outer;
+ }
+ }
+ if (iteratee) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ else if (indexOf(seen, computed) < 0) {
+ if (iteratee || isLarge) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.values` and `_.valuesIn` which creates an
+ * array of `object` property values corresponding to the property names
+ * returned by `keysFunc`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} props The property names to get values for.
+ * @returns {Object} Returns the array of property values.
+ */
+ function baseValues(object, props) {
+ var index = -1,
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = object[props[index]];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `wrapperValue` which returns the result of
+ * performing a sequence of actions on the unwrapped `value`, where each
+ * successive action is supplied the return value of the previous.
+ *
+ * @private
+ * @param {*} value The unwrapped value.
+ * @param {Array} actions Actions to peform to resolve the unwrapped value.
+ * @returns {*} Returns the resolved unwrapped value.
+ */
+ function baseWrapperValue(value, actions) {
+ var result = value;
+ if (result instanceof LazyWrapper) {
+ result = result.value();
+ }
+ var index = -1,
+ length = actions.length;
+
+ while (++index < length) {
+ var args = [result],
+ action = actions[index];
+
+ push.apply(args, action.args);
+ result = action.func.apply(action.thisArg, args);
+ }
+ return result;
+ }
+
+ /**
+ * Performs a binary search of `array` to determine the index at which `value`
+ * should be inserted into `array` in order to maintain its sort order.
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndex(array, value, retHighest) {
+ var low = 0,
+ high = array ? array.length : low;
+
+ if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+ while (low < high) {
+ var mid = (low + high) >>> 1,
+ computed = array[mid];
+
+ if (retHighest ? (computed <= value) : (computed < value)) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return high;
+ }
+ return binaryIndexBy(array, value, identity, retHighest);
+ }
+
+ /**
+ * This function is like `binaryIndex` except that it invokes `iteratee` for
+ * `value` and each element of `array` to compute their sort ranking. The
+ * iteratee is invoked with one argument; (value).
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndexBy(array, value, iteratee, retHighest) {
+ value = iteratee(value);
+
+ var low = 0,
+ high = array ? array.length : 0,
+ valIsNaN = value !== value,
+ valIsUndef = typeof value == 'undefined';
+
+ while (low < high) {
+ var mid = floor((low + high) / 2),
+ computed = iteratee(array[mid]),
+ isReflexive = computed === computed;
+
+ if (valIsNaN) {
+ var setLow = isReflexive || retHighest;
+ } else if (valIsUndef) {
+ setLow = isReflexive && (retHighest || typeof computed != 'undefined');
+ } else {
+ setLow = retHighest ? (computed <= value) : (computed < value);
+ }
+ if (setLow) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return nativeMin(high, MAX_ARRAY_INDEX);
+ }
+
+ /**
+ * A specialized version of `baseCallback` which only supports `this` binding
+ * and specifying the number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function bindCallback(func, thisArg, argCount) {
+ if (typeof func != 'function') {
+ return identity;
+ }
+ if (typeof thisArg == 'undefined') {
+ return func;
+ }
+ switch (argCount) {
+ case 1: return function(value) {
+ return func.call(thisArg, value);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ case 5: return function(value, other, key, object, source) {
+ return func.call(thisArg, value, other, key, object, source);
+ };
+ }
+ return function() {
+ return func.apply(thisArg, arguments);
+ };
+ }
+
+ /**
+ * Creates a clone of the given array buffer.
+ *
+ * @private
+ * @param {ArrayBuffer} buffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+ function bufferClone(buffer) {
+ return bufferSlice.call(buffer, 0);
+ }
+ if (!bufferSlice) {
+ // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`.
+ bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) {
+ var byteLength = buffer.byteLength,
+ floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
+ offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
+ result = new ArrayBuffer(byteLength);
+
+ if (floatLength) {
+ var view = new Float64Array(result, 0, floatLength);
+ view.set(new Float64Array(buffer, 0, floatLength));
+ }
+ if (byteLength != offset) {
+ view = new Uint8Array(result, offset);
+ view.set(new Uint8Array(buffer, offset));
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates an array that is the composition of partially applied arguments,
+ * placeholders, and provided arguments into a single array of arguments.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to prepend to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgs(args, partials, holders) {
+ var holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ leftIndex = -1,
+ leftLength = partials.length,
+ result = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ result[leftIndex] = partials[leftIndex];
+ }
+ while (++argsIndex < holdersLength) {
+ result[holders[argsIndex]] = args[argsIndex];
+ }
+ while (argsLength--) {
+ result[leftIndex++] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * This function is like `composeArgs` except that the arguments composition
+ * is tailored for `_.partialRight`.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to append to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgsRight(args, partials, holders) {
+ var holdersIndex = -1,
+ holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ rightIndex = -1,
+ rightLength = partials.length,
+ result = Array(argsLength + rightLength);
+
+ while (++argsIndex < argsLength) {
+ result[argsIndex] = args[argsIndex];
+ }
+ var pad = argsIndex;
+ while (++rightIndex < rightLength) {
+ result[pad + rightIndex] = partials[rightIndex];
+ }
+ while (++holdersIndex < holdersLength) {
+ result[pad + holders[holdersIndex]] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * Creates a function that aggregates a collection, creating an accumulator
+ * object composed from the results of running each element in the collection
+ * through an iteratee. The `setter` sets the keys and values of the accumulator
+ * object. If `initializer` is provided initializes the accumulator object.
+ *
+ * @private
+ * @param {Function} setter The function to set keys and values of the accumulator object.
+ * @param {Function} [initializer] The function to initialize the accumulator object.
+ * @returns {Function} Returns the new aggregator function.
+ */
+ function createAggregator(setter, initializer) {
+ return function(collection, iteratee, thisArg) {
+ var result = initializer ? initializer() : {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ setter(result, value, iteratee(value, index, collection), collection);
+ }
+ } else {
+ baseEach(collection, function(value, key, collection) {
+ setter(result, value, iteratee(value, key, collection), collection);
+ });
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that assigns properties of source object(s) to a given
+ * destination object.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return function() {
+ var length = arguments.length,
+ object = arguments[0];
+
+ if (length < 2 || object == null) {
+ return object;
+ }
+ if (length > 3 && isIterateeCall(arguments[1], arguments[2], arguments[3])) {
+ length = 2;
+ }
+ // Juggle arguments.
+ if (length > 3 && typeof arguments[length - 2] == 'function') {
+ var customizer = bindCallback(arguments[--length - 1], arguments[length--], 5);
+ } else if (length > 2 && typeof arguments[length - 1] == 'function') {
+ customizer = arguments[--length];
+ }
+ var index = 0;
+ while (++index < length) {
+ var source = arguments[index];
+ if (source) {
+ assigner(object, source, customizer);
+ }
+ }
+ return object;
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the `this`
+ * binding of `thisArg`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createBindWrapper(func, thisArg) {
+ var Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ return (this instanceof wrapper ? Ctor : func).apply(thisArg, arguments);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `Set` cache object to optimize linear searches of large arrays.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
+ */
+ var createCache = !(nativeCreate && Set) ? constant(null) : function(values) {
+ return new SetCache(values);
+ };
+
+ /**
+ * Creates a function that produces compound words out of the words in a
+ * given string.
+ *
+ * @private
+ * @param {Function} callback The function to combine each word.
+ * @returns {Function} Returns the new compounder function.
+ */
+ function createCompounder(callback) {
+ return function(string) {
+ var index = -1,
+ array = words(deburr(string)),
+ length = array.length,
+ result = '';
+
+ while (++index < length) {
+ result = callback(result, array[index], index);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that produces an instance of `Ctor` regardless of
+ * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+ *
+ * @private
+ * @param {Function} Ctor The constructor to wrap.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createCtorWrapper(Ctor) {
+ return function() {
+ var thisBinding = baseCreate(Ctor.prototype),
+ result = Ctor.apply(thisBinding, arguments);
+
+ // Mimic the constructor's `return` behavior.
+ // See http://es5.github.io/#x13.2.2.
+ return isObject(result) ? result : thisBinding;
+ };
+ }
+
+ /**
+ * Creates a function that gets the extremum value of a collection.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to get the extremum value from an array.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the maximum,
+ * extremum value.
+ * @returns {Function} Returns the new extremum function.
+ */
+ function createExtremum(arrayFunc, isMin) {
+ return function(collection, iteratee, thisArg) {
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ var func = getCallback(),
+ noIteratee = iteratee == null;
+
+ if (!(func === baseCallback && noIteratee)) {
+ noIteratee = false;
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ if (noIteratee) {
+ var isArr = isArray(collection);
+ if (!isArr && isString(collection)) {
+ iteratee = charAtCallback;
+ } else {
+ return arrayFunc(isArr ? collection : toIterable(collection));
+ }
+ }
+ return extremumBy(collection, iteratee, isMin);
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with optional `this`
+ * binding of, partial application, and currying.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
+ * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+ var isAry = bitmask & ARY_FLAG,
+ isBind = bitmask & BIND_FLAG,
+ isBindKey = bitmask & BIND_KEY_FLAG,
+ isCurry = bitmask & CURRY_FLAG,
+ isCurryBound = bitmask & CURRY_BOUND_FLAG,
+ isCurryRight = bitmask & CURRY_RIGHT_FLAG;
+
+ var Ctor = !isBindKey && createCtorWrapper(func),
+ key = func;
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it to other functions.
+ var length = arguments.length,
+ index = length,
+ args = Array(length);
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ if (partials) {
+ args = composeArgs(args, partials, holders);
+ }
+ if (partialsRight) {
+ args = composeArgsRight(args, partialsRight, holdersRight);
+ }
+ if (isCurry || isCurryRight) {
+ var placeholder = wrapper.placeholder,
+ argsHolders = replaceHolders(args, placeholder);
+
+ length -= argsHolders.length;
+ if (length < arity) {
+ var newArgPos = argPos ? arrayCopy(argPos) : null,
+ newArity = nativeMax(arity - length, 0),
+ newsHolders = isCurry ? argsHolders : null,
+ newHoldersRight = isCurry ? null : argsHolders,
+ newPartials = isCurry ? args : null,
+ newPartialsRight = isCurry ? null : args;
+
+ bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
+ bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
+
+ if (!isCurryBound) {
+ bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
+ }
+ var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity);
+ result.placeholder = placeholder;
+ return result;
+ }
+ }
+ var thisBinding = isBind ? thisArg : this;
+ if (isBindKey) {
+ func = thisBinding[key];
+ }
+ if (argPos) {
+ args = reorder(args, argPos);
+ }
+ if (isAry && ary < args.length) {
+ args.length = ary;
+ }
+ return (this instanceof wrapper ? (Ctor || createCtorWrapper(func)) : func).apply(thisBinding, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates the pad required for `string` based on the given padding length.
+ * The `chars` string may be truncated if the number of padding characters
+ * exceeds the padding length.
+ *
+ * @private
+ * @param {string} string The string to create padding for.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the pad for `string`.
+ */
+ function createPad(string, length, chars) {
+ var strLength = string.length;
+ length = +length;
+
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return '';
+ }
+ var padLength = length - strLength;
+ chars = chars == null ? ' ' : baseToString(chars);
+ return repeat(chars, ceil(padLength / chars.length)).slice(0, padLength);
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the optional `this`
+ * binding of `thisArg` and the `partials` prepended to those provided to
+ * the wrapper.
+ *
+ * @private
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} partials The arguments to prepend to those provided to the new function.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createPartialWrapper(func, bitmask, thisArg, partials) {
+ var isBind = bitmask & BIND_FLAG,
+ Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it `func`.
+ var argsIndex = -1,
+ argsLength = arguments.length,
+ leftIndex = -1,
+ leftLength = partials.length,
+ args = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ args[leftIndex] = partials[leftIndex];
+ }
+ while (argsLength--) {
+ args[leftIndex++] = arguments[++argsIndex];
+ }
+ return (this instanceof wrapper ? Ctor : func).apply(isBind ? thisArg : this, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a function that either curries or invokes `func` with optional
+ * `this` binding and partially applied arguments.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags.
+ * The bitmask may be composed of the following flags:
+ * 1 - `_.bind`
+ * 2 - `_.bindKey`
+ * 4 - `_.curry` or `_.curryRight` of a bound function
+ * 8 - `_.curry`
+ * 16 - `_.curryRight`
+ * 32 - `_.partial`
+ * 64 - `_.partialRight`
+ * 128 - `_.rearg`
+ * 256 - `_.ary`
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to be partially applied.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
+ var isBindKey = bitmask & BIND_KEY_FLAG;
+ if (!isBindKey && !isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var length = partials ? partials.length : 0;
+ if (!length) {
+ bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
+ partials = holders = null;
+ }
+ length -= (holders ? holders.length : 0);
+ if (bitmask & PARTIAL_RIGHT_FLAG) {
+ var partialsRight = partials,
+ holdersRight = holders;
+
+ partials = holders = null;
+ }
+ var data = !isBindKey && getData(func),
+ newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
+
+ if (data && data !== true) {
+ mergeData(newData, data);
+ bitmask = newData[1];
+ arity = newData[9];
+ }
+ newData[9] = arity == null
+ ? (isBindKey ? 0 : func.length)
+ : (nativeMax(arity - length, 0) || 0);
+
+ if (bitmask == BIND_FLAG) {
+ var result = createBindWrapper(newData[0], newData[2]);
+ } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
+ result = createPartialWrapper.apply(null, newData);
+ } else {
+ result = createHybridWrapper.apply(null, newData);
+ }
+ var setter = data ? baseSetData : setData;
+ return setter(result, newData);
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing arrays.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var index = -1,
+ arrLength = array.length,
+ othLength = other.length,
+ result = true;
+
+ if (arrLength != othLength && !(isWhere && othLength > arrLength)) {
+ return false;
+ }
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (result && ++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, arrValue, index)
+ : customizer(arrValue, othValue, index);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (isWhere) {
+ var othIndex = othLength;
+ while (othIndex--) {
+ othValue = other[othIndex];
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ if (result) {
+ break;
+ }
+ }
+ } else {
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ }
+ return !!result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} value The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag) {
+ switch (tag) {
+ case boolTag:
+ case dateTag:
+ // Coerce dates and booleans to numbers, dates to milliseconds and booleans
+ // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
+ return +object == +other;
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case numberTag:
+ // Treat `NaN` vs. `NaN` as equal.
+ return (object != +object)
+ ? other != +other
+ // But, treat `-0` vs. `+0` as not equal.
+ : (object == 0 ? ((1 / object) == (1 / other)) : object == +other);
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings (http://es5.github.io/#x15.10.6.4) and
+ // treat strings primitives and string objects as equal.
+ return object == baseToString(other);
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objProps = keys(object),
+ objLength = objProps.length,
+ othProps = keys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isWhere) {
+ return false;
+ }
+ var hasCtor,
+ index = -1;
+
+ while (++index < objLength) {
+ var key = objProps[index],
+ result = hasOwnProperty.call(other, key);
+
+ if (result) {
+ var objValue = object[key],
+ othValue = other[key];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, objValue, key)
+ : customizer(objValue, othValue, key);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare objects (susceptible to call stack limits).
+ result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ hasCtor || (hasCtor = key == 'constructor');
+ }
+ if (!hasCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Gets the extremum value of `collection` invoking `iteratee` for each value
+ * in `collection` to generate the criterion by which the value is ranked.
+ * The `iteratee` is invoked with three arguments; (value, index, collection).
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the
+ * maximum, extremum value.
+ * @returns {*} Returns the extremum value.
+ */
+ function extremumBy(collection, iteratee, isMin) {
+ var exValue = isMin ? POSITIVE_INFINITY : NEGATIVE_INFINITY,
+ computed = exValue,
+ result = computed;
+
+ baseEach(collection, function(value, index, collection) {
+ var current = iteratee(value, index, collection);
+ if ((isMin ? current < computed : current > computed) || (current === exValue && current === result)) {
+ computed = current;
+ result = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Gets the appropriate "callback" function. If the `_.callback` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseCallback` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function} Returns the chosen function or its result.
+ */
+ function getCallback(func, thisArg, argCount) {
+ var result = lodash.callback || callback;
+ result = result === callback ? baseCallback : result;
+ return argCount ? result(func, thisArg, argCount) : result;
+ }
+
+ /**
+ * Gets metadata for `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {*} Returns the metadata for `func`.
+ */
+ var getData = !metaMap ? noop : function(func) {
+ return metaMap.get(func);
+ };
+
+ /**
+ * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseIndexOf` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function|number} Returns the chosen function or its result.
+ */
+ function getIndexOf(collection, target, fromIndex) {
+ var result = lodash.indexOf || indexOf;
+ result = result === indexOf ? baseIndexOf : result;
+ return collection ? result(collection, target, fromIndex) : result;
+ }
+
+ /**
+ * Gets the view, applying any `transforms` to the `start` and `end` positions.
+ *
+ * @private
+ * @param {number} start The start of the view.
+ * @param {number} end The end of the view.
+ * @param {Array} [transforms] The transformations to apply to the view.
+ * @returns {Object} Returns an object containing the `start` and `end`
+ * positions of the view.
+ */
+ function getView(start, end, transforms) {
+ var index = -1,
+ length = transforms ? transforms.length : 0;
+
+ while (++index < length) {
+ var data = transforms[index],
+ size = data.size;
+
+ switch (data.type) {
+ case 'drop': start += size; break;
+ case 'dropRight': end -= size; break;
+ case 'take': end = nativeMin(end, start + size); break;
+ case 'takeRight': start = nativeMax(start, end - size); break;
+ }
+ }
+ return { 'start': start, 'end': end };
+ }
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = new array.constructor(length);
+
+ // Add array properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ /**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneObject(object) {
+ var Ctor = object.constructor;
+ if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
+ Ctor = Object;
+ }
+ return new Ctor;
+ }
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return bufferClone(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ var buffer = object.buffer;
+ return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ var result = new Ctor(object.source, reFlags.exec(object));
+ result.lastIndex = object.lastIndex;
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `func` is eligible for `this` binding.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is eligible, else `false`.
+ */
+ function isBindable(func) {
+ var support = lodash.support,
+ result = !(support.funcNames ? func.name : support.funcDecomp);
+
+ if (!result) {
+ var source = fnToString.call(func);
+ if (!support.funcNames) {
+ result = !reFuncName.test(source);
+ }
+ if (!result) {
+ // Check if `func` references the `this` keyword and store the result.
+ result = reThis.test(source) || isNative(func);
+ baseSetData(func, result);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ value = +value;
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return value > -1 && value % 1 == 0 && value < length;
+ }
+
+ /**
+ * Checks if the provided arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number') {
+ var length = object.length,
+ prereq = isLength(length) && isIndex(index, length);
+ } else {
+ prereq = type == 'string' && index in value;
+ }
+ return prereq && object[index] === value;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+ function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` if suitable for strict
+ * equality comparisons, else `false`.
+ */
+ function isStrictComparable(value) {
+ return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value));
+ }
+
+ /**
+ * Merges the function metadata of `source` into `data`.
+ *
+ * Merging metadata reduces the number of wrappers required to invoke a function.
+ * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+ * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
+ * augment function arguments, making the order in which they are executed important,
+ * preventing the merging of metadata. However, we make an exception for a safe
+ * common case where curried functions have `_.ary` and or `_.rearg` applied.
+ *
+ * @private
+ * @param {Array} data The destination metadata.
+ * @param {Array} source The source metadata.
+ * @returns {Array} Returns `data`.
+ */
+ function mergeData(data, source) {
+ var bitmask = data[1],
+ srcBitmask = source[1],
+ newBitmask = bitmask | srcBitmask;
+
+ var arityFlags = ARY_FLAG | REARG_FLAG,
+ bindFlags = BIND_FLAG | BIND_KEY_FLAG,
+ comboFlags = arityFlags | bindFlags | CURRY_BOUND_FLAG | CURRY_RIGHT_FLAG;
+
+ var isAry = bitmask & ARY_FLAG && !(srcBitmask & ARY_FLAG),
+ isRearg = bitmask & REARG_FLAG && !(srcBitmask & REARG_FLAG),
+ argPos = (isRearg ? data : source)[7],
+ ary = (isAry ? data : source)[8];
+
+ var isCommon = !(bitmask >= REARG_FLAG && srcBitmask > bindFlags) &&
+ !(bitmask > bindFlags && srcBitmask >= REARG_FLAG);
+
+ var isCombo = (newBitmask >= arityFlags && newBitmask <= comboFlags) &&
+ (bitmask < REARG_FLAG || ((isRearg || isAry) && argPos.length <= ary));
+
+ // Exit early if metadata can't be merged.
+ if (!(isCommon || isCombo)) {
+ return data;
+ }
+ // Use source `thisArg` if available.
+ if (srcBitmask & BIND_FLAG) {
+ data[2] = source[2];
+ // Set when currying a bound function.
+ newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
+ }
+ // Compose partial arguments.
+ var value = source[3];
+ if (value) {
+ var partials = data[3];
+ data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
+ data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
+ }
+ // Compose partial right arguments.
+ value = source[5];
+ if (value) {
+ partials = data[5];
+ data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
+ data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
+ }
+ // Use source `argPos` if available.
+ value = source[7];
+ if (value) {
+ data[7] = arrayCopy(value);
+ }
+ // Use source `ary` if it's smaller.
+ if (srcBitmask & ARY_FLAG) {
+ data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
+ }
+ // Use source `arity` if one is not provided.
+ if (data[9] == null) {
+ data[9] = source[9];
+ }
+ // Use source `func` and merge bitmasks.
+ data[0] = source[0];
+ data[1] = newBitmask;
+
+ return data;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties specified
+ * by the `props` array.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {string[]} props The property names to pick.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByArray(object, props) {
+ object = toObject(object);
+
+ var index = -1,
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index];
+ if (key in object) {
+ result[key] = object[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties `predicate`
+ * returns truthy for.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByCallback(object, predicate) {
+ var result = {};
+ baseForIn(object, function(value, key, object) {
+ if (predicate(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Reorder `array` according to the specified indexes where the element at
+ * the first index is assigned as the first element, the element at
+ * the second index is assigned as the second element, and so on.
+ *
+ * @private
+ * @param {Array} array The array to reorder.
+ * @param {Array} indexes The arranged array indexes.
+ * @returns {Array} Returns `array`.
+ */
+ function reorder(array, indexes) {
+ var arrLength = array.length,
+ length = nativeMin(indexes.length, arrLength),
+ oldArray = arrayCopy(array);
+
+ while (length--) {
+ var index = indexes[length];
+ array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
+ }
+ return array;
+ }
+
+ /**
+ * Sets metadata for `func`.
+ *
+ * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+ * period of time, it will trip its breaker and transition to an identity function
+ * to avoid garbage collection pauses in V8. See https://code.google.com/p/v8/issues/detail?id=2070.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var setData = (function() {
+ var count = 0,
+ lastCalled = 0;
+
+ return function(key, value) {
+ var stamp = now(),
+ remaining = HOT_SPAN - (stamp - lastCalled);
+
+ lastCalled = stamp;
+ if (remaining > 0) {
+ if (++count >= HOT_COUNT) {
+ return key;
+ }
+ } else {
+ count = 0;
+ }
+ return baseSetData(key, value);
+ };
+ }());
+
+ /**
+ * A fallback implementation of `_.isPlainObject` which checks if `value`
+ * is an object created by the `Object` constructor or has a `[[Prototype]]`
+ * of `null`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ */
+ function shimIsPlainObject(value) {
+ var Ctor,
+ support = lodash.support;
+
+ // Exit early for non `Object` objects.
+ if (!(isObjectLike(value) && objToString.call(value) == objectTag) ||
+ (!hasOwnProperty.call(value, 'constructor') &&
+ (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
+ return false;
+ }
+ // IE < 9 iterates inherited properties before own properties. If the first
+ // iterated property is an object's own property then there are no inherited
+ // enumerable properties.
+ var result;
+ // In most environments an object's own properties are iterated before
+ // its inherited properties. If the last iterated property is an object's
+ // own property then there are no inherited enumerable properties.
+ baseForIn(value, function(subValue, key) {
+ result = key;
+ });
+ return typeof result == 'undefined' || hasOwnProperty.call(value, result);
+ }
+
+ /**
+ * A fallback implementation of `Object.keys` which creates an array of the
+ * own enumerable property names of `object`.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ */
+ function shimKeys(object) {
+ var props = keysIn(object),
+ propsLength = props.length,
+ length = propsLength && object.length,
+ support = lodash.support;
+
+ var allowIndexes = length && isLength(length) &&
+ (isArray(object) || (support.nonEnumArgs && isArguments(object)));
+
+ var index = -1,
+ result = [];
+
+ while (++index < propsLength) {
+ var key = props[index];
+ if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `value` to an array-like object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Array|Object} Returns the array-like object.
+ */
+ function toIterable(value) {
+ if (value == null) {
+ return [];
+ }
+ if (!isLength(value.length)) {
+ return values(value);
+ }
+ return isObject(value) ? value : Object(value);
+ }
+
+ /**
+ * Converts `value` to an object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Object} Returns the object.
+ */
+ function toObject(value) {
+ return isObject(value) ? value : Object(value);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements split into groups the length of `size`.
+ * If `collection` can't be split evenly, the final chunk will be the remaining
+ * elements.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to process.
+ * @param {numer} [size=1] The length of each chunk.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new array containing chunks.
+ * @example
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 2);
+ * // => [['a', 'b'], ['c', 'd']]
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 3);
+ * // => [['a', 'b', 'c'], ['d']]
+ */
+ function chunk(array, size, guard) {
+ if (guard ? isIterateeCall(array, size, guard) : size == null) {
+ size = 1;
+ } else {
+ size = nativeMax(+size || 1, 1);
+ }
+ var index = 0,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = Array(ceil(length / size));
+
+ while (index < length) {
+ result[++resIndex] = baseSlice(array, index, (index += size));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array with all falsey values removed. The values `false`, `null`,
+ * `0`, `""`, `undefined`, and `NaN` are falsey.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to compact.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.compact([0, 1, false, 2, '', 3]);
+ * // => [1, 2, 3]
+ */
+ function compact(array) {
+ var index = -1,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all values of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The arrays of values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.difference([1, 2, 3], [5, 2, 10]);
+ * // => [1, 3]
+ */
+ function difference() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var value = arguments[index];
+ if (isArray(value) || isArguments(value)) {
+ break;
+ }
+ }
+ return baseDifference(value, baseFlatten(arguments, false, true, ++index));
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.drop([1, 2, 3]);
+ * // => [2, 3]
+ *
+ * _.drop([1, 2, 3], 2);
+ * // => [3]
+ *
+ * _.drop([1, 2, 3], 5);
+ * // => []
+ *
+ * _.drop([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function drop(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRight([1, 2, 3]);
+ * // => [1, 2]
+ *
+ * _.dropRight([1, 2, 3], 2);
+ * // => [1]
+ *
+ * _.dropRight([1, 2, 3], 5);
+ * // => []
+ *
+ * _.dropRight([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function dropRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the end.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [1]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropRightWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function dropRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, 0, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the beginning.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['pebbles']
+ */
+ function dropWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, index);
+ }
+
+ /**
+ * This method is like `_.find` except that it returns the index of the first
+ * element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findIndex(users, function(chr) { return chr.age < 40; });
+ * // => 0
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findIndex(users, { 'age': 1 });
+ * // => 2
+ *
+ * // using the "_.property" callback shorthand
+ * _.findIndex(users, 'active');
+ * // => 1
+ */
+ function findIndex(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it iterates over elements
+ * of `collection` from right to left.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findLastIndex(users, function(chr) { return chr.age < 40; });
+ * // => 2
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastIndex(users, { 'age': 40 });
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastIndex(users, 'active');
+ * // => 0
+ */
+ function findLastIndex(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length--) {
+ if (predicate(array[length], length, array)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Gets the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias head
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the first element of `array`.
+ * @example
+ *
+ * _.first([1, 2, 3]);
+ * // => 1
+ *
+ * _.first([]);
+ * // => undefined
+ */
+ function first(array) {
+ return array ? array[0] : undefined;
+ }
+
+ /**
+ * Flattens a nested array. If `isDeep` is `true` the array is recursively
+ * flattened, otherwise it is only flattened a single level.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flatten([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, [[4]]];
+ *
+ * // using `isDeep`
+ * _.flatten([1, [2], [3, [[4]]]], true);
+ * // => [1, 2, 3, 4];
+ */
+ function flatten(array, isDeep, guard) {
+ var length = array ? array.length : 0;
+ if (guard && isIterateeCall(array, isDeep, guard)) {
+ isDeep = false;
+ }
+ return length ? baseFlatten(array, isDeep) : [];
+ }
+
+ /**
+ * Recursively flattens a nested array.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to recursively flatten.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flattenDeep([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, 4];
+ */
+ function flattenDeep(array) {
+ var length = array ? array.length : 0;
+ return length ? baseFlatten(array, true) : [];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found in `array`
+ * using `SameValueZero` for equality comparisons. If `fromIndex` is negative,
+ * it is used as the offset from the end of `array`. If `array` is sorted
+ * providing `true` for `fromIndex` performs a faster binary search.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=0] The index to search from or `true`
+ * to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 1
+ *
+ * // using `fromIndex`
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 4
+ *
+ * // performing a binary search
+ * _.indexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 2
+ */
+ function indexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else if (fromIndex) {
+ var index = binaryIndex(array, value),
+ other = array[index];
+
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ return baseIndexOf(array, value, fromIndex);
+ }
+
+ /**
+ * Gets all but the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.initial([1, 2, 3]);
+ * // => [1, 2]
+ */
+ function initial(array) {
+ return dropRight(array, 1);
+ }
+
+ /**
+ * Creates an array of unique values in all provided arrays using `SameValueZero`
+ * for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of shared values.
+ * @example
+ *
+ * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2]
+ */
+ function intersection() {
+ var args = [],
+ argsIndex = -1,
+ argsLength = arguments.length,
+ caches = [],
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf;
+
+ while (++argsIndex < argsLength) {
+ var value = arguments[argsIndex];
+ if (isArray(value) || isArguments(value)) {
+ args.push(value);
+ caches.push(isCommon && value.length >= 120 && createCache(argsIndex && value));
+ }
+ }
+ argsLength = args.length;
+ var array = args[0],
+ index = -1,
+ length = array ? array.length : 0,
+ result = [],
+ seen = caches[0];
+
+ outer:
+ while (++index < length) {
+ value = array[index];
+ if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value)) < 0) {
+ argsIndex = argsLength;
+ while (--argsIndex) {
+ var cache = caches[argsIndex];
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
+ continue outer;
+ }
+ }
+ if (seen) {
+ seen.push(value);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the last element of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ */
+ function last(array) {
+ var length = array ? array.length : 0;
+ return length ? array[length - 1] : undefined;
+ }
+
+ /**
+ * This method is like `_.indexOf` except that it iterates over elements of
+ * `array` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=array.length-1] The index to search from
+ * or `true` to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 4
+ *
+ * // using `fromIndex`
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 1
+ *
+ * // performing a binary search
+ * _.lastIndexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 3
+ */
+ function lastIndexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ var index = length;
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1;
+ } else if (fromIndex) {
+ index = binaryIndex(array, value, true) - 1;
+ var other = array[index];
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ if (value !== value) {
+ return indexOfNaN(array, index, true);
+ }
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all provided values from `array` using `SameValueZero` for equality
+ * comparisons.
+ *
+ * **Notes:**
+ * - Unlike `_.without`, this method mutates `array`.
+ * - `SameValueZero` comparisons are like strict equality comparisons, e.g. `===`,
+ * except that `NaN` matches `NaN`. See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...*} [values] The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3, 1, 2, 3];
+ * _.pull(array, 2, 3);
+ * console.log(array);
+ * // => [1, 1]
+ */
+ function pull() {
+ var array = arguments[0];
+ if (!(array && array.length)) {
+ return array;
+ }
+ var index = 0,
+ indexOf = getIndexOf(),
+ length = arguments.length;
+
+ while (++index < length) {
+ var fromIndex = 0,
+ value = arguments[index];
+
+ while ((fromIndex = indexOf(array, value, fromIndex)) > -1) {
+ splice.call(array, fromIndex, 1);
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Removes elements from `array` corresponding to the given indexes and returns
+ * an array of the removed elements. Indexes may be specified as an array of
+ * indexes or as individual arguments.
+ *
+ * **Note:** Unlike `_.at`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...(number|number[])} [indexes] The indexes of elements to remove,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [5, 10, 15, 20];
+ * var evens = _.pullAt(array, [1, 3]);
+ *
+ * console.log(array);
+ * // => [5, 15]
+ *
+ * console.log(evens);
+ * // => [10, 20]
+ */
+ function pullAt(array) {
+ return basePullAt(array || [], baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Removes all elements from `array` that `predicate` returns truthy for
+ * and returns an array of the removed elements. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** Unlike `_.filter`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [1, 2, 3, 4];
+ * var evens = _.remove(array, function(n) { return n % 2 == 0; });
+ *
+ * console.log(array);
+ * // => [1, 3]
+ *
+ * console.log(evens);
+ * // => [2, 4]
+ */
+ function remove(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0,
+ result = [];
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result.push(value);
+ splice.call(array, index--, 1);
+ length--;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets all but the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias tail
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.rest([1, 2, 3]);
+ * // => [2, 3]
+ */
+ function rest(array) {
+ return drop(array, 1);
+ }
+
+ /**
+ * Creates a slice of `array` from `start` up to, but not including, `end`.
+ *
+ * **Note:** This function is used instead of `Array#slice` to support node
+ * lists in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function slice(array, start, end) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
+ start = 0;
+ end = length;
+ }
+ return baseSlice(array, start, end);
+ }
+
+ /**
+ * Uses a binary search to determine the lowest index at which `value` should
+ * be inserted into `array` in order to maintain its sort order. If an iteratee
+ * function is provided it is invoked for `value` and each element of `array`
+ * to compute their sort ranking. The iteratee is bound to `thisArg` and
+ * invoked with one argument; (value).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([30, 50], 40);
+ * // => 1
+ *
+ * _.sortedIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 2
+ *
+ * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } };
+ *
+ * // using an iteratee function
+ * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) {
+ * return this.data[word];
+ * }, dict);
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
+ * // => 1
+ */
+ function sortedIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1));
+ }
+
+ /**
+ * This method is like `_.sortedIndex` except that it returns the highest
+ * index at which `value` should be inserted into `array` in order to
+ * maintain its sort order.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedLastIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 4
+ */
+ function sortedLastIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value, true)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1), true);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.take([1, 2, 3]);
+ * // => [1]
+ *
+ * _.take([1, 2, 3], 2);
+ * // => [1, 2]
+ *
+ * _.take([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.take([1, 2, 3], 0);
+ * // => []
+ */
+ function take(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRight([1, 2, 3]);
+ * // => [3]
+ *
+ * _.takeRight([1, 2, 3], 2);
+ * // => [2, 3]
+ *
+ * _.takeRight([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.takeRight([1, 2, 3], 0);
+ * // => []
+ */
+ function takeRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the end. Elements are
+ * taken until `predicate` returns falsey. The predicate is bound to `thisArg`
+ * and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [2, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeRightWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['pebbles']
+ */
+ function takeRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the beginning. Elements
+ * are taken until `predicate` returns falsey. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [1, 2]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function takeWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, 0, index);
+ }
+
+ /**
+ * Creates an array of unique values, in order, of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2, 3, 5, 4]
+ */
+ function union() {
+ return baseUniq(baseFlatten(arguments, false, true));
+ }
+
+ /**
+ * Creates a duplicate-value-free version of an array using `SameValueZero`
+ * for equality comparisons. Providing `true` for `isSorted` performs a faster
+ * search algorithm for sorted arrays. If an iteratee function is provided it
+ * is invoked for each value in the array to generate the criterion by which
+ * uniqueness is computed. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias unique
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {boolean} [isSorted] Specify the array is sorted.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ * @example
+ *
+ * _.uniq([1, 2, 1]);
+ * // => [1, 2]
+ *
+ * // using `isSorted`
+ * _.uniq([1, 1, 2], true);
+ * // => [1, 2]
+ *
+ * // using an iteratee function
+ * _.uniq([1, 2.5, 1.5, 2], function(n) { return this.floor(n); }, Math);
+ * // => [1, 2.5]
+ *
+ * // using the "_.property" callback shorthand
+ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniq(array, isSorted, iteratee, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ // Juggle arguments.
+ if (typeof isSorted != 'boolean' && isSorted != null) {
+ thisArg = iteratee;
+ iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted;
+ isSorted = false;
+ }
+ var func = getCallback();
+ if (!(func === baseCallback && iteratee == null)) {
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ return (isSorted && getIndexOf() == baseIndexOf)
+ ? sortedUniq(array, iteratee)
+ : baseUniq(array, iteratee);
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts an array of grouped
+ * elements and creates an array regrouping the elements to their pre `_.zip`
+ * configuration.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ *
+ * _.unzip(zipped);
+ * // => [['fred', 'barney'], [30, 40], [true, false]]
+ */
+ function unzip(array) {
+ var index = -1,
+ length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = arrayMap(array, baseProperty(index));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all provided values using `SameValueZero` for
+ * equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to filter.
+ * @param {...*} [values] The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+ * // => [2, 3, 4]
+ */
+ function without(array) {
+ return baseDifference(array, baseSlice(arguments, 1));
+ }
+
+ /**
+ * Creates an array that is the symmetric difference of the provided arrays.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Symmetric_difference) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of values.
+ * @example
+ *
+ * _.xor([1, 2, 3], [5, 2, 1, 4]);
+ * // => [3, 5, 4]
+ *
+ * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+ * // => [1, 4, 5]
+ */
+ function xor() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var array = arguments[index];
+ if (isArray(array) || isArguments(array)) {
+ var result = result
+ ? baseDifference(result, array).concat(baseDifference(array, result))
+ : array;
+ }
+ }
+ return result ? baseUniq(result) : [];
+ }
+
+ /**
+ * Creates an array of grouped elements, the first of which contains the first
+ * elements of the given arrays, the second of which contains the second elements
+ * of the given arrays, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ */
+ function zip() {
+ var length = arguments.length,
+ array = Array(length);
+
+ while (length--) {
+ array[length] = arguments[length];
+ }
+ return unzip(array);
+ }
+
+ /**
+ * Creates an object composed from arrays of property names and values. Provide
+ * either a single two dimensional array, e.g. `[[key1, value1], [key2, value2]]`
+ * or two arrays, one of property names and one of corresponding values.
+ *
+ * @static
+ * @memberOf _
+ * @alias object
+ * @category Array
+ * @param {Array} props The property names.
+ * @param {Array} [values=[]] The property values.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.zipObject(['fred', 'barney'], [30, 40]);
+ * // => { 'fred': 30, 'barney': 40 }
+ */
+ function zipObject(props, values) {
+ var index = -1,
+ length = props ? props.length : 0,
+ result = {};
+
+ if (length && !values && !isArray(props[0])) {
+ values = [];
+ }
+ while (++index < length) {
+ var key = props[index];
+ if (values) {
+ result[key] = values[index];
+ } else if (key) {
+ result[key[0]] = key[1];
+ }
+ }
+ return result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object that wraps `value` with explicit method
+ * chaining enabled.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to wrap.
+ * @returns {Object} Returns the new `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'pebbles', 'age': 1 }
+ * ];
+ *
+ * var youngest = _.chain(users)
+ * .sortBy('age')
+ * .map(function(chr) { return chr.user + ' is ' + chr.age; })
+ * .first()
+ * .value();
+ * // => 'pebbles is 1'
+ */
+ function chain(value) {
+ var result = lodash(value);
+ result.__chain__ = true;
+ return result;
+ }
+
+ /**
+ * This method invokes `interceptor` and returns `value`. The interceptor is
+ * bound to `thisArg` and invoked with one argument; (value). The purpose of
+ * this method is to "tap into" a method chain in order to perform operations
+ * on intermediate results within the chain.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .tap(function(array) { array.pop(); })
+ * .reverse()
+ * .value();
+ * // => [2, 1]
+ */
+ function tap(value, interceptor, thisArg) {
+ interceptor.call(thisArg, value);
+ return value;
+ }
+
+ /**
+ * This method is like `_.tap` except that it returns the result of `interceptor`.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns the result of `interceptor`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .last()
+ * .thru(function(value) { return [value]; })
+ * .value();
+ * // => [3]
+ */
+ function thru(value, interceptor, thisArg) {
+ return interceptor.call(thisArg, value);
+ }
+
+ /**
+ * Enables explicit method chaining on the wrapper object.
+ *
+ * @name chain
+ * @memberOf _
+ * @category Chain
+ * @returns {*} Returns the `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // without explicit chaining
+ * _(users).first();
+ * // => { 'user': 'barney', 'age': 36 }
+ *
+ * // with explicit chaining
+ * _(users).chain()
+ * .first()
+ * .pick('user')
+ * .value();
+ * // => { 'user': 'barney' }
+ */
+ function wrapperChain() {
+ return chain(this);
+ }
+
+ /**
+ * Reverses the wrapped array so the first element becomes the last, the
+ * second element becomes the second to last, and so on.
+ *
+ * **Note:** This method mutates the wrapped array.
+ *
+ * @name reverse
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new reversed `lodash` object.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _(array).reverse().value()
+ * // => [3, 2, 1]
+ *
+ * console.log(array);
+ * // => [3, 2, 1]
+ */
+ function wrapperReverse() {
+ var value = this.__wrapped__;
+ if (value instanceof LazyWrapper) {
+ return new LodashWrapper(value.reverse());
+ }
+ return this.thru(function(value) {
+ return value.reverse();
+ });
+ }
+
+ /**
+ * Produces the result of coercing the unwrapped value to a string.
+ *
+ * @name toString
+ * @memberOf _
+ * @category Chain
+ * @returns {string} Returns the coerced string value.
+ * @example
+ *
+ * _([1, 2, 3]).toString();
+ * // => '1,2,3'
+ */
+ function wrapperToString() {
+ return (this.value() + '');
+ }
+
+ /**
+ * Executes the chained sequence to extract the unwrapped value.
+ *
+ * @name value
+ * @memberOf _
+ * @alias toJSON, valueOf
+ * @category Chain
+ * @returns {*} Returns the resolved unwrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperValue() {
+ return baseWrapperValue(this.__wrapped__, this.__actions__);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements corresponding to the given keys, or indexes,
+ * of `collection`. Keys may be specified as individual arguments or as arrays
+ * of keys.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(number|number[]|string|string[])} [props] The property names
+ * or indexes of elements to pick, specified individually or in arrays.
+ * @returns {Array} Returns the new array of picked elements.
+ * @example
+ *
+ * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
+ * // => ['a', 'c', 'e']
+ *
+ * _.at(['fred', 'barney', 'pebbles'], 0, 2);
+ * // => ['fred', 'pebbles']
+ */
+ function at(collection) {
+ var length = collection ? collection.length : 0;
+ if (isLength(length)) {
+ collection = toIterable(collection);
+ }
+ return baseAt(collection, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Checks if `value` is in `collection` using `SameValueZero` for equality
+ * comparisons. If `fromIndex` is negative, it is used as the offset from
+ * the end of `collection`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias contains, include
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {*} target The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {boolean} Returns `true` if a matching element is found, else `false`.
+ * @example
+ *
+ * _.includes([1, 2, 3], 1);
+ * // => true
+ *
+ * _.includes([1, 2, 3], 1, 2);
+ * // => false
+ *
+ * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
+ * // => true
+ *
+ * _.includes('pebbles', 'eb');
+ * // => true
+ */
+ function includes(collection, target, fromIndex) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ collection = values(collection);
+ length = collection.length;
+ }
+ if (!length) {
+ return false;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else {
+ fromIndex = 0;
+ }
+ return (typeof collection == 'string' || !isArray(collection) && isString(collection))
+ ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
+ : (getIndexOf(collection, target, fromIndex) > -1);
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the number of times the key was returned by `iteratee`.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy(['one', 'two', 'three'], 'length');
+ * // => { '3': 2, '5': 1 }
+ */
+ var countBy = createAggregator(function(result, value, key) {
+ hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1);
+ });
+
+ /**
+ * Checks if `predicate` returns truthy for **all** elements of `collection`.
+ * The predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias all
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes']);
+ * // => false
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.every(users, 'age');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.every(users, { 'age': 36 });
+ * // => false
+ */
+ function every(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayEvery : baseEvery;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning an array of all elements
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias select
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var evens = _.filter([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [2, 4]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.filter(users, 'active'), 'user');
+ * // => ['fred']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.filter(users, { 'age': 36 }), 'user');
+ * // => ['barney']
+ */
+ function filter(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning the first element
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias detect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.result(_.find(users, function(chr) { return chr.age < 40; }), 'user');
+ * // => 'barney'
+ *
+ * // using the "_.matches" callback shorthand
+ * _.result(_.find(users, { 'age': 1 }), 'user');
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.result(_.find(users, 'active'), 'user');
+ * // => 'fred'
+ */
+ function find(collection, predicate, thisArg) {
+ if (isArray(collection)) {
+ var index = findIndex(collection, predicate, thisArg);
+ return index > -1 ? collection[index] : undefined;
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEach);
+ }
+
+ /**
+ * This method is like `_.find` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * _.findLast([1, 2, 3, 4], function(n) { return n % 2 == 1; });
+ * // => 3
+ */
+ function findLast(collection, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEachRight);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning the first element that has equivalent property
+ * values.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy' },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy' }
+ * ];
+ *
+ * _.result(_.findWhere(users, { 'status': 'busy' }), 'user');
+ * // => 'barney'
+ *
+ * _.result(_.findWhere(users, { 'age': 40 }), 'user');
+ * // => 'fred'
+ */
+ function findWhere(collection, source) {
+ return find(collection, matches(source));
+ }
+
+ /**
+ * Iterates over elements of `collection` invoking `iteratee` for each element.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection). Iterator functions may exit iteration early
+ * by explicitly returning `false`.
+ *
+ * **Note:** As with other "Collections" methods, objects with a `length` property
+ * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+ * may be used for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEach(function(n) { console.log(n); });
+ * // => logs each value from left to right and returns the array
+ *
+ * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(n, key) { console.log(n, key); });
+ * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
+ */
+ function forEach(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEach(collection, iteratee)
+ : baseEach(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * This method is like `_.forEach` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias eachRight
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEachRight(function(n) { console.log(n); }).join(',');
+ * // => logs each value from right to left and returns the array
+ */
+ function forEachRight(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEachRight(collection, iteratee)
+ : baseEachRight(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is an array of the elements responsible for generating the key.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * // using the "_.property" callback shorthand
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
+ */
+ var groupBy = createAggregator(function(result, value, key) {
+ if (hasOwnProperty.call(result, key)) {
+ result[key].push(value);
+ } else {
+ result[key] = [value];
+ }
+ });
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the last element responsible for generating the key. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * var keyData = [
+ * { 'dir': 'left', 'code': 97 },
+ * { 'dir': 'right', 'code': 100 }
+ * ];
+ *
+ * _.indexBy(keyData, 'dir');
+ * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) { return String.fromCharCode(object.code); });
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) { return this.fromCharCode(object.code); }, String);
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ */
+ var indexBy = createAggregator(function(result, value, key) {
+ result[key] = value;
+ });
+
+ /**
+ * Invokes the method named by `methodName` on each element in `collection`,
+ * returning an array of the results of each invoked method. Any additional
+ * arguments are provided to each invoked method. If `methodName` is a function
+ * it is invoked for, and `this` bound to, each element in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {...*} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+ * // => [[1, 5, 7], [1, 2, 3]]
+ *
+ * _.invoke([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
+ */
+ function invoke(collection, methodName) {
+ return baseInvoke(collection, methodName, baseSlice(arguments, 2));
+ }
+
+ /**
+ * Creates an array of values by running each element in `collection` through
+ * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias collect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new mapped array.
+ * @example
+ *
+ * _.map([1, 2, 3], function(n) { return n * 3; });
+ * // => [3, 6, 9]
+ *
+ * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(n) { return n * 3; });
+ * // => [3, 6, 9] (iteration order is not guaranteed)
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(users, 'user');
+ * // => ['barney', 'fred']
+ */
+ function map(collection, iteratee, thisArg) {
+ var func = isArray(collection) ? arrayMap : baseMap;
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return func(collection, iteratee);
+ }
+
+ /**
+ * Gets the maximum value of `collection`. If `collection` is empty or falsey
+ * `-Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the maximum value.
+ * @example
+ *
+ * _.max([4, 2, 8, 6]);
+ * // => 8
+ *
+ * _.max([]);
+ * // => -Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.max(users, function(chr) { return chr.age; });
+ * // => { 'user': 'fred', 'age': 40 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.max(users, 'age');
+ * // => { 'user': 'fred', 'age': 40 };
+ */
+ var max = createExtremum(arrayMax);
+
+ /**
+ * Gets the minimum value of `collection`. If `collection` is empty or falsey
+ * `Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the minimum value.
+ * @example
+ *
+ * _.min([4, 2, 8, 6]);
+ * // => 2
+ *
+ * _.min([]);
+ * // => Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.min(users, function(chr) { return chr.age; });
+ * // => { 'user': 'barney', 'age': 36 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.min(users, 'age');
+ * // => { 'user': 'barney', 'age': 36 };
+ */
+ var min = createExtremum(arrayMin, true);
+
+ /**
+ * Creates an array of elements split into two groups, the first of which
+ * contains elements `predicate` returns truthy for, while the second of which
+ * contains elements `predicate` returns falsey for. The predicate is bound
+ * to `thisArg` and invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the array of grouped elements.
+ * @example
+ *
+ * _.partition([1, 2, 3], function(n) { return n % 2; });
+ * // => [[1, 3], [2]]
+ *
+ * _.partition([1.2, 2.3, 3.4], function(n) { return this.floor(n) % 2; }, Math);
+ * // => [[1, 3], [2]]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * // using the "_.matches" callback shorthand
+ * _.map(_.partition(users, { 'age': 1 }), function(array) { return _.pluck(array, 'user'); });
+ * // => [['pebbles'], ['barney', 'fred']]
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(_.partition(users, 'active'), function(array) { return _.pluck(array, 'user'); });
+ * // => [['fred'], ['barney', 'pebbles']]
+ */
+ var partition = createAggregator(function(result, value, key) {
+ result[key ? 0 : 1].push(value);
+ }, function() { return [[], []]; });
+
+ /**
+ * Gets the value of `key` from all elements in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {string} key The key of the property to pluck.
+ * @returns {Array} Returns the property values.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.pluck(users, 'user');
+ * // => ['barney', 'fred']
+ *
+ * var userIndex = _.indexBy(users, 'user');
+ * _.pluck(userIndex, 'age');
+ * // => [36, 40] (iteration order is not guaranteed)
+ */
+ function pluck(collection, key) {
+ return map(collection, property(key));
+ }
+
+ /**
+ * Reduces `collection` to a value which is the accumulated result of running
+ * each element in `collection` through `iteratee`, where each successive
+ * invocation is supplied the return value of the previous. If `accumulator`
+ * is not provided the first element of `collection` is used as the initial
+ * value. The `iteratee` is bound to `thisArg`and invoked with four arguments;
+ * (accumulator, value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @alias foldl, inject
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var sum = _.reduce([1, 2, 3], function(sum, n) { return sum + n; });
+ * // => 6
+ *
+ * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * return result;
+ * }, {});
+ * // => { 'a': 3, 'b': 6, 'c': 9 } (iteration order is not guaranteed)
+ */
+ function reduce(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduce : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEach);
+ }
+
+ /**
+ * This method is like `_.reduce` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias foldr
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var array = [[0, 1], [2, 3], [4, 5]];
+ * _.reduceRight(array, function(flattened, other) { return flattened.concat(other); }, []);
+ * // => [4, 5, 2, 3, 0, 1]
+ */
+ function reduceRight(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduceRight : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEachRight);
+ }
+
+ /**
+ * The opposite of `_.filter`; this method returns the elements of `collection`
+ * that `predicate` does **not** return truthy for.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var odds = _.reject([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [1, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.reject(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.reject(users, { 'age': 36 }), 'user');
+ * // => ['fred']
+ */
+ function reject(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, function(value, index, collection) {
+ return !predicate(value, index, collection);
+ });
+ }
+
+ /**
+ * Gets a random element or `n` random elements from a collection.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to sample.
+ * @param {number} [n] The number of elements to sample.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {*} Returns the random sample(s).
+ * @example
+ *
+ * _.sample([1, 2, 3, 4]);
+ * // => 2
+ *
+ * _.sample([1, 2, 3, 4], 2);
+ * // => [3, 1]
+ */
+ function sample(collection, n, guard) {
+ if (guard ? isIterateeCall(collection, n, guard) : n == null) {
+ collection = toIterable(collection);
+ var length = collection.length;
+ return length > 0 ? collection[baseRandom(0, length - 1)] : undefined;
+ }
+ var result = shuffle(collection);
+ result.length = nativeMin(n < 0 ? 0 : (+n || 0), result.length);
+ return result;
+ }
+
+ /**
+ * Creates an array of shuffled values, using a version of the Fisher-Yates
+ * shuffle. See [Wikipedia](http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to shuffle.
+ * @returns {Array} Returns the new shuffled array.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4]);
+ * // => [4, 1, 3, 2]
+ */
+ function shuffle(collection) {
+ collection = toIterable(collection);
+
+ var index = -1,
+ length = collection.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var rand = baseRandom(0, index);
+ if (index != rand) {
+ result[index] = result[rand];
+ }
+ result[rand] = collection[index];
+ }
+ return result;
+ }
+
+ /**
+ * Gets the size of `collection` by returning `collection.length` for
+ * array-like values or the number of own enumerable properties for objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @returns {number} Returns the size of `collection`.
+ * @example
+ *
+ * _.size([1, 2]);
+ * // => 2
+ *
+ * _.size({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => 3
+ *
+ * _.size('pebbles');
+ * // => 7
+ */
+ function size(collection) {
+ var length = collection ? collection.length : 0;
+ return isLength(length) ? length : keys(collection).length;
+ }
+
+ /**
+ * Checks if `predicate` returns truthy for **any** element of `collection`.
+ * The function returns as soon as it finds a passing value and does not iterate
+ * over the entire collection. The predicate is bound to `thisArg` and invoked
+ * with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias any
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.some([null, 0, 'yes', false], Boolean);
+ * // => true
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.some(users, 'active');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.some(users, { 'age': 1 });
+ * // => false
+ */
+ function some(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arraySome : baseSome;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Creates an array of elements, sorted in ascending order by the results of
+ * running each element in a collection through `iteratee`. This method performs
+ * a stable sort, that is, it preserves the original sort order of equal elements.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Array|Function|Object|string} [iteratee=_.identity] The function
+ * invoked per iteration. If a property name or an object is provided it is
+ * used to create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * _.sortBy([1, 2, 3], function(n) { return Math.sin(n); });
+ * // => [3, 1, 2]
+ *
+ * _.sortBy([1, 2, 3], function(n) { return this.sin(n); }, Math);
+ * // => [3, 1, 2]
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'pebbles' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.sortBy(users, 'user'), 'user');
+ * // => ['barney', 'fred', 'pebbles']
+ */
+ function sortBy(collection, iteratee, thisArg) {
+ var index = -1,
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ iteratee = getCallback(iteratee, thisArg, 3);
+ baseEach(collection, function(value, key, collection) {
+ result[++index] = { 'criteria': iteratee(value, key, collection), 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareAscending);
+ }
+
+ /**
+ * This method is like `_.sortBy` except that it sorts by property names
+ * instead of an iteratee function.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(string|string[])} props The property names to sort by,
+ * specified as individual property names or arrays of property names.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 26 },
+ * { 'user': 'fred', 'age': 30 }
+ * ];
+ *
+ * _.map(_.sortByAll(users, ['user', 'age']), _.values);
+ * // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
+ */
+ function sortByAll(collection) {
+ var args = arguments;
+ if (args.length > 3 && isIterateeCall(args[1], args[2], args[3])) {
+ args = [collection, args[1]];
+ }
+ var index = -1,
+ length = collection ? collection.length : 0,
+ props = baseFlatten(args, false, false, 1),
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value, key, collection) {
+ var length = props.length,
+ criteria = Array(length);
+
+ while (length--) {
+ criteria[length] = value == null ? undefined : value[props[length]];
+ }
+ result[++index] = { 'criteria': criteria, 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareMultipleAscending);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning an array of all elements that have equivalent
+ * property values.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy', 'pets': ['hoppy'] },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy', 'pets': ['baby puss', 'dino'] }
+ * ];
+ *
+ * _.pluck(_.where(users, { 'age': 36 }), 'user');
+ * // => ['barney']
+ *
+ * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user');
+ * // => ['fred']
+ *
+ * _.pluck(_.where(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function where(collection, source) {
+ return filter(collection, matches(source));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Gets the number of milliseconds that have elapsed since the Unix epoch
+ * (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @category Date
+ * @example
+ *
+ * _.defer(function(stamp) { console.log(_.now() - stamp); }, _.now());
+ * // => logs the number of milliseconds it took for the deferred function to be invoked
+ */
+ var now = nativeNow || function() {
+ return new Date().getTime();
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The opposite of `_.before`; this method creates a function that invokes
+ * `func` once it is called `n` or more times.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls before `func` is invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var saves = ['profile', 'settings'];
+ *
+ * var done = _.after(saves.length, function() {
+ * console.log('done saving!');
+ * });
+ *
+ * _.forEach(saves, function(type) {
+ * asyncSave({ 'type': type, 'complete': done });
+ * });
+ * // => logs 'done saving!' after the two async saves have completed
+ */
+ function after(n, func) {
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ n = nativeIsFinite(n = +n) ? n : 0;
+ return function() {
+ if (--n < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ }
+
+ /**
+ * Creates a function that accepts up to `n` arguments ignoring any
+ * additional arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to cap arguments for.
+ * @param {number} [n=func.length] The arity cap.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+ * // => [6, 8, 10]
+ */
+ function ary(func, n, guard) {
+ if (guard && isIterateeCall(func, n, guard)) {
+ n = null;
+ }
+ n = n == null ? func.length : (+n || 0);
+ return createWrapper(func, ARY_FLAG, null, null, null, null, n);
+ }
+
+ /**
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it is called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * jQuery('#add').on('click', _.before(5, addContactToList));
+ * // => allows adding up to 4 contacts to the list
+ */
+ function before(n, func) {
+ var result;
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ return function() {
+ if (--n > 0) {
+ result = func.apply(this, arguments);
+ } else {
+ func = null;
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of `thisArg`
+ * and prepends any additional `_.bind` arguments to those provided to the
+ * bound function.
+ *
+ * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** Unlike native `Function#bind` this method does not set the `length`
+ * property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var greet = function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * };
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * var bound = _.bind(greet, object, 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * // using placeholders
+ * var bound = _.bind(greet, object, _, '!');
+ * bound('hi');
+ * // => 'hi fred!'
+ */
+ function bind(func, thisArg) {
+ var bitmask = BIND_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bind.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(func, bitmask, thisArg, partials, holders);
+ }
+
+ /**
+ * Binds methods of an object to the object itself, overwriting the existing
+ * method. Method names may be specified as individual arguments or as arrays
+ * of method names. If no method names are provided all enumerable function
+ * properties, own and inherited, of `object` are bound.
+ *
+ * **Note:** This method does not set the `length` property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {...(string|string[])} [methodNames] The object method names to bind,
+ * specified as individual method names or arrays of method names.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var view = {
+ * 'label': 'docs',
+ * 'onClick': function() { console.log('clicked ' + this.label); }
+ * };
+ *
+ * _.bindAll(view);
+ * jQuery('#docs').on('click', view.onClick);
+ * // => logs 'clicked docs' when the element is clicked
+ */
+ function bindAll(object) {
+ return baseBindAll(object,
+ arguments.length > 1
+ ? baseFlatten(arguments, false, false, 1)
+ : functions(object)
+ );
+ }
+
+ /**
+ * Creates a function that invokes the method at `object[key]` and prepends
+ * any additional `_.bindKey` arguments to those provided to the bound function.
+ *
+ * This method differs from `_.bind` by allowing bound functions to reference
+ * methods that may be redefined or don't yet exist.
+ * See [Peter Michaux's article](http://michaux.ca/articles/lazy-function-definition-pattern)
+ * for more details.
+ *
+ * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object the method belongs to.
+ * @param {string} key The key of the method.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var object = {
+ * 'user': 'fred',
+ * 'greet': function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * }
+ * };
+ *
+ * var bound = _.bindKey(object, 'greet', 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * object.greet = function(greeting, punctuation) {
+ * return greeting + 'ya ' + this.user + punctuation;
+ * };
+ *
+ * bound('!');
+ * // => 'hiya fred!'
+ *
+ * // using placeholders
+ * var bound = _.bindKey(object, 'greet', _, '!');
+ * bound('hi');
+ * // => 'hiya fred!'
+ */
+ function bindKey(object, key) {
+ var bitmask = BIND_FLAG | BIND_KEY_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bindKey.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(key, bitmask, object, partials, holders);
+ }
+
+ /**
+ * Creates a function that accepts one or more arguments of `func` that when
+ * called either invokes `func` returning its result, if all `func` arguments
+ * have been provided, or returns a function that accepts one or more of the
+ * remaining `func` arguments, and so on. The arity of `func` may be specified
+ * if `func.length` is not sufficient.
+ *
+ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curry(abc);
+ *
+ * curried(1)(2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(1)(_, 3)(2);
+ * // => [1, 2, 3]
+ */
+ function curry(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curry.placeholder;
+ return result;
+ }
+
+ /**
+ * This method is like `_.curry` except that arguments are applied to `func`
+ * in the manner of `_.partialRight` instead of `_.partial`.
+ *
+ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curryRight(abc);
+ *
+ * curried(3)(2)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(2, 3)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(3)(1, _)(2);
+ * // => [1, 2, 3]
+ */
+ function curryRight(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_RIGHT_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curryRight.placeholder;
+ return result;
+ }
+
+ /**
+ * Creates a function that delays invoking `func` until after `wait` milliseconds
+ * have elapsed since the last time it was invoked. The created function comes
+ * with a `cancel` method to cancel delayed invocations. Provide an options
+ * object to indicate that `func` should be invoked on the leading and/or
+ * trailing edge of the `wait` timeout. Subsequent calls to the debounced
+ * function return the result of the last `func` invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the debounced function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.debounce` and `_.throttle`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} wait The number of milliseconds to delay.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=false] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {number} [options.maxWait] The maximum time `func` is allowed to be
+ * delayed before it is invoked.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // avoid costly calculations while the window size is in flux
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+ *
+ * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
+ * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
+ *
+ * // ensure `batchLog` is invoked once after 1 second of debounced calls
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', _.debounce(batchLog, 250, {
+ * 'maxWait': 1000
+ * }));
+ *
+ * // cancel a debounced call
+ * var todoChanges = _.debounce(batchLog, 1000);
+ * Object.observe(models.todo, todoChanges);
+ *
+ * Object.observe(models, function(changes) {
+ * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
+ * todoChanges.cancel();
+ * }
+ * }, ['delete']);
+ *
+ * // ...at some point `models.todo` is changed
+ * models.todo.completed = true;
+ *
+ * // ...before 1 second has passed `models.todo` is deleted
+ * // which cancels the debounced `todoChanges` call
+ * delete models.todo;
+ */
+ function debounce(func, wait, options) {
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = wait < 0 ? 0 : wait;
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (isObject(options)) {
+ leading = options.leading;
+ maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+
+ function cancel() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ }
+
+ function delayed() {
+ var remaining = wait - (now() - stamp);
+ if (remaining <= 0 || remaining > wait) {
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ var isCalled = trailingCall;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
+ }
+ }
+
+ function maxDelayed() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ }
+
+ function debounced() {
+ args = arguments;
+ stamp = now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0 || remaining > maxWait;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ return debounced;
+ }
+
+ /**
+ * Defers invoking the `func` until the current call stack has cleared. Any
+ * additional arguments are provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to defer.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.defer(function(text) { console.log(text); }, 'deferred');
+ * // logs 'deferred' after one or more milliseconds
+ */
+ function defer(func) {
+ return baseDelay(func, 1, arguments, 1);
+ }
+
+ /**
+ * Invokes `func` after `wait` milliseconds. Any additional arguments are
+ * provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.delay(function(text) { console.log(text); }, 1000, 'later');
+ * // => logs 'later' after one second
+ */
+ function delay(func, wait) {
+ return baseDelay(func, wait, arguments, 2);
+ }
+
+ /**
+ * Creates a function that returns the result of invoking the provided
+ * functions with the `this` binding of the created function, where each
+ * successive invocation is supplied the return value of the previous.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function add(x, y) {
+ * return x + y;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flow(add, square);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ function flow() {
+ var funcs = arguments,
+ length = funcs.length;
+
+ if (!length) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = 0,
+ result = funcs[index].apply(this, arguments);
+
+ while (++index < length) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * This method is like `_.flow` except that it creates a function that
+ * invokes the provided functions from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias backflow, compose
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function add(x, y) {
+ * return x + y;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flowRight(square, add);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ function flowRight() {
+ var funcs = arguments,
+ fromIndex = funcs.length - 1;
+
+ if (fromIndex < 0) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = fromIndex,
+ result = funcs[index].apply(this, arguments);
+
+ while (index--) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is coerced to a string and used as the
+ * cache key. The `func` is invoked with the `this` binding of the memoized
+ * function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the ES6 `Map` method interface
+ * of `get`, `has`, and `set`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoizing function.
+ * @example
+ *
+ * var upperCase = _.memoize(function(string) {
+ * return string.toUpperCase();
+ * });
+ *
+ * upperCase('fred');
+ * // => 'FRED'
+ *
+ * // modifying the result cache
+ * upperCase.cache.set('fred, 'BARNEY');
+ * upperCase('fred');
+ * // => 'BARNEY'
+ *
+ * // replacing `_.memoize.Cache`
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'barney' };
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'fred' }
+ *
+ * _.memoize.Cache = WeakMap;
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'barney' }
+ */
+ function memoize(func, resolver) {
+ if (!isFunction(func) || (resolver && !isFunction(resolver))) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var cache = memoized.cache,
+ key = resolver ? resolver.apply(this, arguments) : arguments[0];
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, arguments);
+ cache.set(key, result);
+ return result;
+ };
+ memoized.cache = new memoize.Cache;
+ return memoized;
+ }
+
+ /**
+ * Creates a function that negates the result of the predicate `func`. The
+ * `func` predicate is invoked with the `this` binding and arguments of the
+ * created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} predicate The predicate to negate.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function isEven(n) {
+ * return n % 2 == 0;
+ * }
+ *
+ * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+ * // => [1, 3, 5]
+ */
+ function negate(predicate) {
+ if (!isFunction(predicate)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
+ }
+
+ /**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first call. The `func` is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // `initialize` invokes `createApplication` once
+ */
+ function once(func) {
+ return before(func, 2);
+ }
+
+ /**
+ * Creates a function that invokes `func` with `partial` arguments prepended
+ * to those provided to the new function. This method is like `_.bind` except
+ * it does **not** alter the `this` binding.
+ *
+ * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var sayHelloTo = _.partial(greet, 'hello');
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ *
+ * // using placeholders
+ * var greetFred = _.partial(greet, _, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ */
+ function partial(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partial.placeholder);
+
+ return createWrapper(func, PARTIAL_FLAG, null, partials, holders);
+ }
+
+ /**
+ * This method is like `_.partial` except that partially applied arguments
+ * are appended to those provided to the new function.
+ *
+ * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var greetFred = _.partialRight(greet, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ *
+ * // using placeholders
+ * var sayHelloTo = _.partialRight(greet, 'hello', _);
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ */
+ function partialRight(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partialRight.placeholder);
+
+ return createWrapper(func, PARTIAL_RIGHT_FLAG, null, partials, holders);
+ }
+
+ /**
+ * Creates a function that invokes `func` with arguments arranged according
+ * to the specified indexes where the argument value at the first index is
+ * provided as the first argument, the argument value at the second index is
+ * provided as the second argument, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to rearrange arguments for.
+ * @param {...(number|number[])} indexes The arranged argument indexes,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var rearged = _.rearg(function(a, b, c) {
+ * return [a, b, c];
+ * }, 2, 0, 1);
+ *
+ * rearged('b', 'c', 'a')
+ * // => ['a', 'b', 'c']
+ *
+ * var map = _.rearg(_.map, [1, 0]);
+ * map(function(n) { return n * 3; }, [1, 2, 3]);
+ * // => [3, 6, 9]
+ */
+ function rearg(func) {
+ var indexes = baseFlatten(arguments, false, false, 1);
+ return createWrapper(func, REARG_FLAG, null, null, null, indexes);
+ }
+
+ /**
+ * Creates a function that only invokes `func` at most once per every `wait`
+ * milliseconds. The created function comes with a `cancel` method to cancel
+ * delayed invocations. Provide an options object to indicate that `func`
+ * should be invoked on the leading and/or trailing edge of the `wait` timeout.
+ * Subsequent calls to the throttled function return the result of the last
+ * `func` call.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the throttled function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.throttle` and `_.debounce`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} wait The number of milliseconds to throttle invocations to.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=true] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // avoid excessively updating the position while scrolling
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+ *
+ * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false })
+ * jQuery('.interactive').on('click', throttled);
+ *
+ * // cancel a trailing throttled call
+ * jQuery(window).on('popstate', throttled.cancel);
+ */
+ function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ if (options === false) {
+ leading = false;
+ } else if (isObject(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+ debounceOptions.leading = leading;
+ debounceOptions.maxWait = +wait;
+ debounceOptions.trailing = trailing;
+ return debounce(func, wait, debounceOptions);
+ }
+
+ /**
+ * Creates a function that provides `value` to the wrapper function as its
+ * first argument. Any additional arguments provided to the function are
+ * appended to those provided to the wrapper function. The wrapper is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {*} value The value to wrap.
+ * @param {Function} wrapper The wrapper function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var p = _.wrap(_.escape, function(func, text) {
+ * return '<p>' + func(text) + '</p>';
+ * });
+ *
+ * p('fred, barney, & pebbles');
+ * // => '<p>fred, barney, & pebbles</p>'
+ */
+ function wrap(value, wrapper) {
+ wrapper = wrapper == null ? identity : wrapper;
+ return createWrapper(wrapper, PARTIAL_FLAG, null, [value], []);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
+ * otherwise they are assigned by reference. If `customizer` is provided it is
+ * invoked to produce the cloned values. If `customizer` returns `undefined`
+ * cloning is handled by the method instead. The `customizer` is bound to
+ * `thisArg` and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var shallow = _.clone(users);
+ * shallow[0] === users[0];
+ * // => true
+ *
+ * var deep = _.clone(users, true);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var body = _.clone(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(false) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 0
+ */
+ function clone(value, isDeep, customizer, thisArg) {
+ // Juggle arguments.
+ if (typeof isDeep != 'boolean' && isDeep != null) {
+ thisArg = customizer;
+ customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep;
+ isDeep = false;
+ }
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, isDeep, customizer);
+ }
+
+ /**
+ * Creates a deep clone of `value`. If `customizer` is provided it is invoked
+ * to produce the cloned values. If `customizer` returns `undefined` cloning
+ * is handled by the method instead. The `customizer` is bound to `thisArg`
+ * and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the deep cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var deep = _.cloneDeep(users);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var el = _.cloneDeep(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(true) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 20
+ */
+ function cloneDeep(value, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, true, customizer);
+ }
+
+ /**
+ * Checks if `value` is classified as an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * (function() { return _.isArguments(arguments); })();
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ var length = isObjectLike(value) ? value.length : undefined;
+ return (isLength(length) && objToString.call(value) == argsTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * (function() { return _.isArray(arguments); })();
+ * // => false
+ */
+ var isArray = nativeIsArray || function(value) {
+ return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false;
+ };
+
+ /**
+ * Checks if `value` is classified as a boolean primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isBoolean(false);
+ * // => true
+ *
+ * _.isBoolean(null);
+ * // => false
+ */
+ function isBoolean(value) {
+ return (value === true || value === false || isObjectLike(value) && objToString.call(value) == boolTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Date` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isDate(new Date);
+ * // => true
+ *
+ * _.isDate('Mon April 23 2012');
+ * // => false
+ */
+ function isDate(value) {
+ return (isObjectLike(value) && objToString.call(value) == dateTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a DOM element.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
+ * @example
+ *
+ * _.isElement(document.body);
+ * // => true
+ *
+ * _.isElement('<body>');
+ * // => false
+ */
+ function isElement(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) &&
+ objToString.call(value).indexOf('Element') > -1) || false;
+ }
+ // Fallback for environments without DOM support.
+ if (!support.dom) {
+ isElement = function(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value)) || false;
+ };
+ }
+
+ /**
+ * Checks if a value is empty. A value is considered empty unless it is an
+ * `arguments` object, array, string, or jQuery-like collection with a length
+ * greater than `0` or an object with own enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Array|Object|string} value The value to inspect.
+ * @returns {boolean} Returns `true` if `value` is empty, else `false`.
+ * @example
+ *
+ * _.isEmpty(null);
+ * // => true
+ *
+ * _.isEmpty(true);
+ * // => true
+ *
+ * _.isEmpty(1);
+ * // => true
+ *
+ * _.isEmpty([1, 2, 3]);
+ * // => false
+ *
+ * _.isEmpty({ 'a': 1 });
+ * // => false
+ */
+ function isEmpty(value) {
+ if (value == null) {
+ return true;
+ }
+ var length = value.length;
+ if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) ||
+ (isObjectLike(value) && isFunction(value.splice)))) {
+ return !length;
+ }
+ return !keys(value).length;
+ }
+
+ /**
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent. If `customizer` is provided it is invoked to compare values.
+ * If `customizer` returns `undefined` comparisons are handled by the method
+ * instead. The `customizer` is bound to `thisArg` and invoked with three
+ * arguments; (value, other [, index|key]).
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Functions and DOM nodes
+ * are **not** supported. Provide a customizer function to extend support
+ * for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'fred' };
+ *
+ * object == other;
+ * // => false
+ *
+ * _.isEqual(object, other);
+ * // => true
+ *
+ * // using a customizer callback
+ * var array = ['hello', 'goodbye'];
+ * var other = ['hi', 'goodbye'];
+ *
+ * _.isEqual(array, other, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isEqual(value, other, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && isStrictComparable(value) && isStrictComparable(other)) {
+ return value === other;
+ }
+ var result = customizer ? customizer(value, other) : undefined;
+ return typeof result == 'undefined' ? baseIsEqual(value, other, customizer) : !!result;
+ }
+
+ /**
+ * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+ * `SyntaxError`, `TypeError`, or `URIError` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
+ * @example
+ *
+ * _.isError(new Error);
+ * // => true
+ *
+ * _.isError(Error);
+ * // => false
+ */
+ function isError(value) {
+ return (isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a finite primitive number.
+ *
+ * **Note:** This method is based on ES6 `Number.isFinite`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
+ * @example
+ *
+ * _.isFinite(10);
+ * // => true
+ *
+ * _.isFinite('10');
+ * // => false
+ *
+ * _.isFinite(true);
+ * // => false
+ *
+ * _.isFinite(Object(10));
+ * // => false
+ *
+ * _.isFinite(Infinity);
+ * // => false
+ */
+ var isFinite = nativeNumIsFinite || function(value) {
+ return typeof value == 'number' && nativeIsFinite(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // Avoid a Chakra JIT bug in compatibility modes of IE 11.
+ // See https://github.com/jashkenas/underscore/issues/1621.
+ return typeof value == 'function' || false;
+ }
+ // Fallback for environments that return incorrect `typeof` operator results.
+ if (isFunction(/x/) || (Uint8Array && !isFunction(Uint8Array))) {
+ isFunction = function(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in older versions of Chrome and Safari which return 'function' for regexes
+ // and Safari 8 equivalents which return 'object' for typed array constructors.
+ return objToString.call(value) == funcTag;
+ };
+ }
+
+ /**
+ * Checks if `value` is the language type of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * **Note:** See the [ES5 spec](http://es5.github.io/#x8) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+ function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291.
+ var type = typeof value;
+ return type == 'function' || (value && type == 'object') || false;
+ }
+
+ /**
+ * Performs a deep comparison between `object` and `source` to determine if
+ * `object` contains equivalent property values. If `customizer` is provided
+ * it is invoked to compare values. If `customizer` returns `undefined`
+ * comparisons are handled by the method instead. The `customizer` is bound
+ * to `thisArg` and invoked with three arguments; (value, other, index|key).
+ *
+ * **Note:** This method supports comparing properties of arrays, booleans,
+ * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions
+ * and DOM nodes are **not** supported. Provide a customizer function to extend
+ * support for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Object} source The object to inspect.
+ * @param {Object} source The object of property values to match.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.isMatch(object, { 'age': 40 });
+ * // => true
+ *
+ * _.isMatch(object, { 'age': 36 });
+ * // => false
+ *
+ * // using a customizer callback
+ * var object = { 'greeting': 'hello' };
+ * var source = { 'greeting': 'hi' };
+ *
+ * _.isMatch(object, source, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isMatch(object, source, customizer, thisArg) {
+ var props = keys(source),
+ length = props.length;
+
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ }
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = values[length] = source[props[length]];
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return baseIsMatch(object, props, values, strictCompareFlags, customizer);
+ }
+
+ /**
+ * Checks if `value` is `NaN`.
+ *
+ * **Note:** This method is not the same as native `isNaN` which returns `true`
+ * for `undefined` and other non-numeric values. See the [ES5 spec](http://es5.github.io/#x15.1.2.4)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+ * @example
+ *
+ * _.isNaN(NaN);
+ * // => true
+ *
+ * _.isNaN(new Number(NaN));
+ * // => true
+ *
+ * isNaN(undefined);
+ * // => true
+ *
+ * _.isNaN(undefined);
+ * // => false
+ */
+ function isNaN(value) {
+ // An `NaN` primitive is the only value that is not equal to itself.
+ // Perform the `toStringTag` check first to avoid errors with some host objects in IE.
+ return isNumber(value) && value != +value;
+ }
+
+ /**
+ * Checks if `value` is a native function.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
+ * @example
+ *
+ * _.isNative(Array.prototype.push);
+ * // => true
+ *
+ * _.isNative(_);
+ * // => false
+ */
+ function isNative(value) {
+ if (value == null) {
+ return false;
+ }
+ if (objToString.call(value) == funcTag) {
+ return reNative.test(fnToString.call(value));
+ }
+ return (isObjectLike(value) && reHostCtor.test(value)) || false;
+ }
+
+ /**
+ * Checks if `value` is `null`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
+ * @example
+ *
+ * _.isNull(null);
+ * // => true
+ *
+ * _.isNull(void 0);
+ * // => false
+ */
+ function isNull(value) {
+ return value === null;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Number` primitive or object.
+ *
+ * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified
+ * as numbers, use the `_.isFinite` method.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isNumber(8.4);
+ * // => true
+ *
+ * _.isNumber(NaN);
+ * // => true
+ *
+ * _.isNumber('8.4');
+ * // => false
+ */
+ function isNumber(value) {
+ return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
+ *
+ * **Note:** This method assumes objects created by the `Object` constructor
+ * have no inherited enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * }
+ *
+ * _.isPlainObject(new Foo);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ *
+ * _.isPlainObject(Object.create(null));
+ * // => true
+ */
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
+ if (!(value && objToString.call(value) == objectTag)) {
+ return false;
+ }
+ var valueOf = value.valueOf,
+ objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
+
+ return objProto
+ ? (value == objProto || getPrototypeOf(value) == objProto)
+ : shimIsPlainObject(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `RegExp` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isRegExp(/abc/);
+ * // => true
+ *
+ * _.isRegExp('/abc/');
+ * // => false
+ */
+ function isRegExp(value) {
+ return (isObjectLike(value) && objToString.call(value) == regexpTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a `String` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isString('abc');
+ * // => true
+ *
+ * _.isString(1);
+ * // => false
+ */
+ function isString(value) {
+ return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+ function isTypedArray(value) {
+ return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false;
+ }
+
+ /**
+ * Checks if `value` is `undefined`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+ * @example
+ *
+ * _.isUndefined(void 0);
+ * // => true
+ *
+ * _.isUndefined(null);
+ * // => false
+ */
+ function isUndefined(value) {
+ return typeof value == 'undefined';
+ }
+
+ /**
+ * Converts `value` to an array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Array} Returns the converted array.
+ * @example
+ *
+ * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3);
+ * // => [2, 3]
+ */
+ function toArray(value) {
+ var length = value ? value.length : 0;
+ if (!isLength(length)) {
+ return values(value);
+ }
+ if (!length) {
+ return [];
+ }
+ return arrayCopy(value);
+ }
+
+ /**
+ * Converts `value` to a plain object flattening inherited enumerable
+ * properties of `value` to own properties of the plain object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Object} Returns the converted plain object.
+ * @example
+ *
+ * function Foo() {
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.assign({ 'a': 1 }, new Foo);
+ * // => { 'a': 1, 'b': 2 }
+ *
+ * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+ * // => { 'a': 1, 'b': 2, 'c': 3 }
+ */
+ function toPlainObject(value) {
+ return baseCopy(value, keysIn(value));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources overwrite property assignments of previous sources.
+ * If `customizer` is provided it is invoked to produce the assigned values.
+ * The `customizer` is bound to `thisArg` and invoked with five arguments;
+ * (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @alias extend
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+ * // => { 'user': 'fred', 'age': 40 }
+ *
+ * // using a customizer callback
+ * var defaults = _.partialRight(_.assign, function(value, other) {
+ * return typeof value == 'undefined' ? other : value;
+ * });
+ *
+ * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ var assign = createAssigner(baseAssign);
+
+ /**
+ * Creates an object that inherits from the given `prototype` object. If a
+ * `properties` object is provided its own enumerable properties are assigned
+ * to the created object.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} prototype The object to inherit from.
+ * @param {Object} [properties] The properties to assign to the object.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * function Circle() {
+ * Shape.call(this);
+ * }
+ *
+ * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
+ *
+ * var circle = new Circle;
+ * circle instanceof Circle;
+ * // => true
+ *
+ * circle instanceof Shape;
+ * // => true
+ */
+ function create(prototype, properties, guard) {
+ var result = baseCreate(prototype);
+ if (guard && isIterateeCall(prototype, properties, guard)) {
+ properties = null;
+ }
+ return properties ? baseCopy(properties, result, keys(properties)) : result;
+ }
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object for all destination properties that resolve to `undefined`. Once a
+ * property is set, additional defaults of the same property are ignored.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function defaults(object) {
+ if (object == null) {
+ return object;
+ }
+ var args = arrayCopy(arguments);
+ args.push(assignDefaults);
+ return assign.apply(undefined, args);
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it returns the key of the
+ * first element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findKey(users, function(chr) { return chr.age < 40; });
+ * // => 'barney' (iteration order is not guaranteed)
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findKey(users, { 'age': 1 });
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findKey(users, 'active');
+ * // => 'barney'
+ */
+ function findKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwn, true);
+ }
+
+ /**
+ * This method is like `_.findKey` except that it iterates over elements of
+ * a collection in the opposite order.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findLastKey(users, function(chr) { return chr.age < 40; });
+ * // => returns `pebbles` assuming `_.findKey` returns `barney`
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastKey(users, { 'age': 36 });
+ * // => 'barney'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastKey(users, 'active');
+ * // => 'pebbles'
+ */
+ function findLastKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwnRight, true);
+ }
+
+ /**
+ * Iterates over own and inherited enumerable properties of an object invoking
+ * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, key, object). Iterator functions may exit
+ * iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forIn(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed)
+ */
+ function forIn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * This method is like `_.forIn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forInRight(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c'
+ */
+ function forInRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keysIn);
+ }
+
+ /**
+ * Iterates over own enumerable properties of an object invoking `iteratee`
+ * for each property. The `iteratee` is bound to `thisArg` and invoked with
+ * three arguments; (value, key, object). Iterator functions may exit iteration
+ * early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs '0', '1', and 'length' (iteration order is not guaranteed)
+ */
+ function forOwn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return baseForOwn(object, iteratee);
+ }
+
+ /**
+ * This method is like `_.forOwn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
+ */
+ function forOwnRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * Creates an array of function property names from all enumerable properties,
+ * own and inherited, of `object`.
+ *
+ * @static
+ * @memberOf _
+ * @alias methods
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of property names.
+ * @example
+ *
+ * _.functions(_);
+ * // => ['all', 'any', 'bind', ...]
+ */
+ function functions(object) {
+ return baseFunctions(object, keysIn(object));
+ }
+
+ /**
+ * Checks if `key` exists as a direct property of `object` instead of an
+ * inherited property.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @param {string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` is a direct property, else `false`.
+ * @example
+ *
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+ * // => true
+ */
+ function has(object, key) {
+ return object ? hasOwnProperty.call(object, key) : false;
+ }
+
+ /**
+ * Creates an object composed of the inverted keys and values of `object`.
+ * If `object` contains duplicate values, subsequent values overwrite property
+ * assignments of previous values unless `multiValue` is `true`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to invert.
+ * @param {boolean} [multiValue] Allow multiple values per key.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new inverted object.
+ * @example
+ *
+ * _.invert({ 'first': 'fred', 'second': 'barney' });
+ * // => { 'fred': 'first', 'barney': 'second' }
+ *
+ * // without `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' });
+ * // => { 'fred': 'third', 'barney': 'second' }
+ *
+ * // with `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }, true);
+ * // => { 'fred': ['first', 'third'], 'barney': ['second'] }
+ */
+ function invert(object, multiValue, guard) {
+ if (guard && isIterateeCall(object, multiValue, guard)) {
+ multiValue = null;
+ }
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key];
+
+ if (multiValue) {
+ if (hasOwnProperty.call(result, value)) {
+ result[value].push(key);
+ } else {
+ result[value] = [key];
+ }
+ }
+ else {
+ result[value] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ var keys = !nativeKeys ? shimKeys : function(object) {
+ if (object) {
+ var Ctor = object.constructor,
+ length = object.length;
+ }
+ if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
+ (typeof object != 'function' && (length && isLength(length)))) {
+ return shimKeys(object);
+ }
+ return isObject(object) ? nativeKeys(object) : [];
+ };
+
+ /**
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+ */
+ function keysIn(object) {
+ if (object == null) {
+ return [];
+ }
+ if (!isObject(object)) {
+ object = Object(object);
+ }
+ var length = object.length;
+ length = (length && isLength(length) &&
+ (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0;
+
+ var Ctor = object.constructor,
+ index = -1,
+ isProto = typeof Ctor == 'function' && Ctor.prototype == object,
+ result = Array(length),
+ skipIndexes = length > 0;
+
+ while (++index < length) {
+ result[index] = (index + '');
+ }
+ for (var key in object) {
+ if (!(skipIndexes && isIndex(key, length)) &&
+ !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object with the same keys as `object` and values generated by
+ * running each own enumerable property of `object` through `iteratee`. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * If a property name is provided for `iteratee` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `iteratee` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the new mapped object.
+ * @example
+ *
+ * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(n) { return n * 3; });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ *
+ * var users = {
+ * 'fred': { 'user': 'fred', 'age': 40 },
+ * 'pebbles': { 'user': 'pebbles', 'age': 1 }
+ * };
+ *
+ * // using the "_.property" callback shorthand
+ * _.mapValues(users, 'age');
+ * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+ */
+ function mapValues(object, iteratee, thisArg) {
+ var result = {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ baseForOwn(object, function(value, key, object) {
+ result[key] = iteratee(value, key, object);
+ });
+ return result;
+ }
+
+ /**
+ * Recursively merges own enumerable properties of the source object(s), that
+ * don't resolve to `undefined` into the destination object. Subsequent sources
+ * overwrite property assignments of previous sources. If `customizer` is
+ * provided it is invoked to produce the merged values of the destination and
+ * source properties. If `customizer` returns `undefined` merging is handled
+ * by the method instead. The `customizer` is bound to `thisArg` and invoked
+ * with five arguments; (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var users = {
+ * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
+ * };
+ *
+ * var ages = {
+ * 'data': [{ 'age': 36 }, { 'age': 40 }]
+ * };
+ *
+ * _.merge(users, ages);
+ * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
+ *
+ * // using a customizer callback
+ * var object = {
+ * 'fruits': ['apple'],
+ * 'vegetables': ['beet']
+ * };
+ *
+ * var other = {
+ * 'fruits': ['banana'],
+ * 'vegetables': ['carrot']
+ * };
+ *
+ * _.merge(object, other, function(a, b) {
+ * return _.isArray(a) ? a.concat(b) : undefined;
+ * });
+ * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
+ */
+ var merge = createAssigner(baseMerge);
+
+ /**
+ * The opposite of `_.pick`; this method creates an object composed of the
+ * own and inherited enumerable properties of `object` that are not omitted.
+ * Property names may be specified as individual arguments or as arrays of
+ * property names. If `predicate` is provided it is invoked for each property
+ * of `object` omitting the properties `predicate` returns truthy for. The
+ * predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to omit, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.omit(object, 'age');
+ * // => { 'user': 'fred' }
+ *
+ * _.omit(object, _.isNumber);
+ * // => { 'user': 'fred' }
+ */
+ function omit(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ if (typeof predicate != 'function') {
+ var props = arrayMap(baseFlatten(arguments, false, false, 1), String);
+ return pickByArray(object, baseDifference(keysIn(object), props));
+ }
+ predicate = bindCallback(predicate, thisArg, 3);
+ return pickByCallback(object, function(value, key, object) {
+ return !predicate(value, key, object);
+ });
+ }
+
+ /**
+ * Creates a two dimensional array of the key-value pairs for `object`,
+ * e.g. `[[key1, value1], [key2, value2]]`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of key-value pairs.
+ * @example
+ *
+ * _.pairs({ 'barney': 36, 'fred': 40 });
+ * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
+ */
+ function pairs(object) {
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var key = props[index];
+ result[index] = [key, object[key]];
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object composed of the picked `object` properties. Property
+ * names may be specified as individual arguments or as arrays of property
+ * names. If `predicate` is provided it is invoked for each property of `object`
+ * picking the properties `predicate` returns truthy for. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to pick, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.pick(object, 'user');
+ * // => { 'user': 'fred' }
+ *
+ * _.pick(object, _.isString);
+ * // => { 'user': 'fred' }
+ */
+ function pick(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ return typeof predicate == 'function'
+ ? pickByCallback(object, bindCallback(predicate, thisArg, 3))
+ : pickByArray(object, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Resolves the value of property `key` on `object`. If the value of `key` is
+ * a function it is invoked with the `this` binding of `object` and its result
+ * is returned, else the property value is returned. If the property value is
+ * `undefined` the `defaultValue` is used in its place.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the property to resolve.
+ * @param {*} [defaultValue] The value returned if the property value
+ * resolves to `undefined`.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': _.constant(40) };
+ *
+ * _.result(object, 'user');
+ * // => 'fred'
+ *
+ * _.result(object, 'age');
+ * // => 40
+ *
+ * _.result(object, 'status', 'busy');
+ * // => 'busy'
+ *
+ * _.result(object, 'status', _.constant('busy'));
+ * // => 'busy'
+ */
+ function result(object, key, defaultValue) {
+ var value = object == null ? undefined : object[key];
+ if (typeof value == 'undefined') {
+ value = defaultValue;
+ }
+ return isFunction(value) ? value.call(object) : value;
+ }
+
+ /**
+ * An alternative to `_.reduce`; this method transforms `object` to a new
+ * `accumulator` object which is the result of running each of its own enumerable
+ * properties through `iteratee`, with each invocation potentially mutating
+ * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked
+ * with four arguments; (accumulator, value, key, object). Iterator functions
+ * may exit iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Array|Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The custom accumulator value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var squares = _.transform([1, 2, 3, 4, 5, 6], function(result, n) {
+ * n *= n;
+ * if (n % 2) {
+ * return result.push(n) < 3;
+ * }
+ * });
+ * // => [1, 9, 25]
+ *
+ * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ */
+ function transform(object, iteratee, accumulator, thisArg) {
+ var isArr = isArray(object) || isTypedArray(object);
+ iteratee = getCallback(iteratee, thisArg, 4);
+
+ if (accumulator == null) {
+ if (isArr || isObject(object)) {
+ var Ctor = object.constructor;
+ if (isArr) {
+ accumulator = isArray(object) ? new Ctor : [];
+ } else {
+ accumulator = baseCreate(typeof Ctor == 'function' && Ctor.prototype);
+ }
+ } else {
+ accumulator = {};
+ }
+ }
+ (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) {
+ return iteratee(accumulator, value, index, object);
+ });
+ return accumulator;
+ }
+
+ /**
+ * Creates an array of the own enumerable property values of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.values(new Foo);
+ * // => [1, 2] (iteration order is not guaranteed)
+ *
+ * _.values('hi');
+ * // => ['h', 'i']
+ */
+ function values(object) {
+ return baseValues(object, keys(object));
+ }
+
+ /**
+ * Creates an array of the own and inherited enumerable property values
+ * of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.valuesIn(new Foo);
+ * // => [1, 2, 3] (iteration order is not guaranteed)
+ */
+ function valuesIn(object) {
+ return baseValues(object, keysIn(object));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Produces a random number between `min` and `max` (inclusive). If only one
+ * argument is provided a number between `0` and the given number is returned.
+ * If `floating` is `true`, or either `min` or `max` are floats, a floating-point
+ * number is returned instead of an integer.
+ *
+ * @static
+ * @memberOf _
+ * @category Number
+ * @param {number} [min=0] The minimum possible value.
+ * @param {number} [max=1] The maximum possible value.
+ * @param {boolean} [floating] Specify returning a floating-point number.
+ * @returns {number} Returns the random number.
+ * @example
+ *
+ * _.random(0, 5);
+ * // => an integer between 0 and 5
+ *
+ * _.random(5);
+ * // => also an integer between 0 and 5
+ *
+ * _.random(5, true);
+ * // => a floating-point number between 0 and 5
+ *
+ * _.random(1.2, 5.2);
+ * // => a floating-point number between 1.2 and 5.2
+ */
+ function random(min, max, floating) {
+ if (floating && isIterateeCall(min, max, floating)) {
+ max = floating = null;
+ }
+ var noMin = min == null,
+ noMax = max == null;
+
+ if (floating == null) {
+ if (noMax && typeof min == 'boolean') {
+ floating = min;
+ min = 1;
+ }
+ else if (typeof max == 'boolean') {
+ floating = max;
+ noMax = true;
+ }
+ }
+ if (noMin && noMax) {
+ max = 1;
+ noMax = false;
+ }
+ min = +min || 0;
+ if (noMax) {
+ max = min;
+ min = 0;
+ } else {
+ max = +max || 0;
+ }
+ if (floating || min % 1 || max % 1) {
+ var rand = nativeRandom();
+ return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max);
+ }
+ return baseRandom(min, max);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Converts `string` to camel case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/CamelCase) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the camel cased string.
+ * @example
+ *
+ * _.camelCase('Foo Bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('--foo-bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('__foo_bar__');
+ * // => 'fooBar'
+ */
+ var camelCase = createCompounder(function(result, word, index) {
+ word = word.toLowerCase();
+ return index ? (result + word.charAt(0).toUpperCase() + word.slice(1)) : word;
+ });
+
+ /**
+ * Capitalizes the first character of `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to capitalize.
+ * @returns {string} Returns the capitalized string.
+ * @example
+ *
+ * _.capitalize('fred');
+ * // => 'Fred'
+ */
+ function capitalize(string) {
+ string = baseToString(string);
+ return string && (string.charAt(0).toUpperCase() + string.slice(1));
+ }
+
+ /**
+ * Deburrs `string` by converting latin-1 supplementary letters to basic latin letters.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to deburr.
+ * @returns {string} Returns the deburred string.
+ * @example
+ *
+ * _.deburr('déjà vu');
+ * // => 'deja vu'
+ */
+ function deburr(string) {
+ string = baseToString(string);
+ return string && string.replace(reLatin1, deburrLetter);
+ }
+
+ /**
+ * Checks if `string` ends with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=string.length] The position to search from.
+ * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`.
+ * @example
+ *
+ * _.endsWith('abc', 'c');
+ * // => true
+ *
+ * _.endsWith('abc', 'b');
+ * // => false
+ *
+ * _.endsWith('abc', 'b', 2);
+ * // => true
+ */
+ function endsWith(string, target, position) {
+ string = baseToString(string);
+ target = (target + '');
+
+ var length = string.length;
+ position = (typeof position == 'undefined' ? length : nativeMin(position < 0 ? 0 : (+position || 0), length)) - target.length;
+ return position >= 0 && string.indexOf(target, position) == position;
+ }
+
+ /**
+ * Converts the characters "&", "<", ">", '"', "'", and '`', in `string` to
+ * their corresponding HTML entities.
+ *
+ * **Note:** No other characters are escaped. To escape additional characters
+ * use a third-party library like [_he_](http://mths.be/he).
+ *
+ * Though the ">" character is escaped for symmetry, characters like
+ * ">" and "/" don't require escaping in HTML and have no special meaning
+ * unless they're part of a tag or unquoted attribute value.
+ * See [Mathias Bynens's article](http://mathiasbynens.be/notes/ambiguous-ampersands)
+ * (under "semi-related fun fact") for more details.
+ *
+ * Backticks are escaped because in Internet Explorer < 9, they can break out
+ * of attribute values or HTML comments. See [#102](http://html5sec.org/#102),
+ * [#108](http://html5sec.org/#108), and [#133](http://html5sec.org/#133) of
+ * the [HTML5 Security Cheatsheet](http://html5sec.org/) for more details.
+ *
+ * When working with HTML you should always quote attribute values to reduce
+ * XSS vectors. See [Ryan Grove's article](http://wonko.com/post/html-escaping)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function escape(string) {
+ // Reset `lastIndex` because in IE < 9 `String#replace` does not.
+ string = baseToString(string);
+ return (string && reHasUnescapedHtml.test(string))
+ ? string.replace(reUnescapedHtml, escapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*",
+ * "+", "(", ")", "[", "]", "{" and "}" in `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escapeRegExp('[lodash](https://lodash.com/)');
+ * // => '\[lodash\]\(https://lodash\.com/\)'
+ */
+ function escapeRegExp(string) {
+ string = baseToString(string);
+ return (string && reHasRegExpChars.test(string))
+ ? string.replace(reRegExpChars, '\\$&')
+ : string;
+ }
+
+ /**
+ * Converts `string` to kebab case (a.k.a. spinal case).
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Letter_case#Computers) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the kebab cased string.
+ * @example
+ *
+ * _.kebabCase('Foo Bar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('fooBar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('__foo_bar__');
+ * // => 'foo-bar'
+ */
+ var kebabCase = createCompounder(function(result, word, index) {
+ return result + (index ? '-' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Pads `string` on the left and right sides if it is shorter then the given
+ * padding length. The `chars` string may be truncated if the number of padding
+ * characters can't be evenly divided by the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.pad('abc', 8);
+ * // => ' abc '
+ *
+ * _.pad('abc', 8, '_-');
+ * // => '_-abc_-_'
+ *
+ * _.pad('abc', 3);
+ * // => 'abc'
+ */
+ function pad(string, length, chars) {
+ string = baseToString(string);
+ length = +length;
+
+ var strLength = string.length;
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return string;
+ }
+ var mid = (length - strLength) / 2,
+ leftLength = floor(mid),
+ rightLength = ceil(mid);
+
+ chars = createPad('', rightLength, chars);
+ return chars.slice(0, leftLength) + string + chars;
+ }
+
+ /**
+ * Pads `string` on the left side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padLeft('abc', 6);
+ * // => ' abc'
+ *
+ * _.padLeft('abc', 6, '_-');
+ * // => '_-_abc'
+ *
+ * _.padLeft('abc', 3);
+ * // => 'abc'
+ */
+ function padLeft(string, length, chars) {
+ string = baseToString(string);
+ return string && (createPad(string, length, chars) + string);
+ }
+
+ /**
+ * Pads `string` on the right side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padRight('abc', 6);
+ * // => 'abc '
+ *
+ * _.padRight('abc', 6, '_-');
+ * // => 'abc_-_'
+ *
+ * _.padRight('abc', 3);
+ * // => 'abc'
+ */
+ function padRight(string, length, chars) {
+ string = baseToString(string);
+ return string && (string + createPad(string, length, chars));
+ }
+
+ /**
+ * Converts `string` to an integer of the specified radix. If `radix` is
+ * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal,
+ * in which case a `radix` of `16` is used.
+ *
+ * **Note:** This method aligns with the ES5 implementation of `parseInt`.
+ * See the [ES5 spec](http://es5.github.io/#E) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} string The string to convert.
+ * @param {number} [radix] The radix to interpret `value` by.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {number} Returns the converted integer.
+ * @example
+ *
+ * _.parseInt('08');
+ * // => 8
+ *
+ * _.map(['6', '08', '10'], _.parseInt);
+ * // => [6, 8, 10]
+ */
+ function parseInt(string, radix, guard) {
+ if (guard && isIterateeCall(string, radix, guard)) {
+ radix = 0;
+ }
+ return nativeParseInt(string, radix);
+ }
+ // Fallback for environments with pre-ES5 implementations.
+ if (nativeParseInt(whitespace + '08') != 8) {
+ parseInt = function(string, radix, guard) {
+ // Firefox < 21 and Opera < 15 follow ES3 for `parseInt` and
+ // Chrome fails to trim leading <BOM> whitespace characters.
+ // See https://code.google.com/p/v8/issues/detail?id=3109.
+ if (guard ? isIterateeCall(string, radix, guard) : radix == null) {
+ radix = 0;
+ } else if (radix) {
+ radix = +radix;
+ }
+ string = trim(string);
+ return nativeParseInt(string, radix || (reHexPrefix.test(string) ? 16 : 10));
+ };
+ }
+
+ /**
+ * Repeats the given string `n` times.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to repeat.
+ * @param {number} [n=0] The number of times to repeat the string.
+ * @returns {string} Returns the repeated string.
+ * @example
+ *
+ * _.repeat('*', 3);
+ * // => '***'
+ *
+ * _.repeat('abc', 2);
+ * // => 'abcabc'
+ *
+ * _.repeat('abc', 0);
+ * // => ''
+ */
+ function repeat(string, n) {
+ var result = '';
+ string = baseToString(string);
+ n = +n;
+ if (n < 1 || !string || !nativeIsFinite(n)) {
+ return result;
+ }
+ // Leverage the exponentiation by squaring algorithm for a faster repeat.
+ // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring.
+ do {
+ if (n % 2) {
+ result += string;
+ }
+ n = floor(n / 2);
+ string += string;
+ } while (n);
+
+ return result;
+ }
+
+ /**
+ * Converts `string` to snake case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Snake_case) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the snake cased string.
+ * @example
+ *
+ * _.snakeCase('Foo Bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('--foo-bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('fooBar');
+ * // => 'foo_bar'
+ */
+ var snakeCase = createCompounder(function(result, word, index) {
+ return result + (index ? '_' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Checks if `string` starts with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=0] The position to search from.
+ * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`.
+ * @example
+ *
+ * _.startsWith('abc', 'a');
+ * // => true
+ *
+ * _.startsWith('abc', 'b');
+ * // => false
+ *
+ * _.startsWith('abc', 'b', 1);
+ * // => true
+ */
+ function startsWith(string, target, position) {
+ string = baseToString(string);
+ position = position == null ? 0 : nativeMin(position < 0 ? 0 : (+position || 0), string.length);
+ return string.lastIndexOf(target, position) == position;
+ }
+
+ /**
+ * Creates a compiled template function that can interpolate data properties
+ * in "interpolate" delimiters, HTML-escape interpolated data properties in
+ * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+ * properties may be accessed as free variables in the template. If a setting
+ * object is provided it takes precedence over `_.templateSettings` values.
+ *
+ * **Note:** In the development build `_.template` utilizes sourceURLs for easier debugging.
+ * See the [HTML5 Rocks article on sourcemaps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+ * for more details.
+ *
+ * For more information on precompiling templates see
+ * [Lo-Dash's custom builds documentation](https://lodash.com/custom-builds).
+ *
+ * For more information on Chrome extension sandboxes see
+ * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The template string.
+ * @param {Object} [options] The options object.
+ * @param {RegExp} [options.escape] The HTML "escape" delimiter.
+ * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
+ * @param {Object} [options.imports] An object to import into the template as free variables.
+ * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
+ * @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
+ * @param {string} [options.variable] The data object variable name.
+ * @param- {Object} [otherOptions] Enables the legacy `options` param signature.
+ * @returns {Function} Returns the compiled template function.
+ * @example
+ *
+ * // using the "interpolate" delimiter to create a compiled template
+ * var compiled = _.template('hello <%= user %>!');
+ * compiled({ 'user': 'fred' });
+ * // => 'hello fred!'
+ *
+ * // using the HTML "escape" delimiter to escape data property values
+ * var compiled = _.template('<b><%- value %></b>');
+ * compiled({ 'value': '<script>' });
+ * // => '<b><script></b>'
+ *
+ * // using the "evaluate" delimiter to execute JavaScript and generate HTML
+ * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the internal `print` function in "evaluate" delimiters
+ * var compiled = _.template('<% print("hello " + user); %>!');
+ * compiled({ 'user': 'barney' });
+ * // => 'hello barney!'
+ *
+ * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
+ * var compiled = _.template('hello ${ user }!');
+ * compiled({ 'user': 'pebbles' });
+ * // => 'hello pebbles!'
+ *
+ * // using custom template delimiters
+ * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+ * var compiled = _.template('hello {{ user }}!');
+ * compiled({ 'user': 'mustache' });
+ * // => 'hello mustache!'
+ *
+ * // using backslashes to treat delimiters as plain text
+ * var compiled = _.template('<%= "\\<%- value %\\>" %>');
+ * compiled({ 'value': 'ignored' });
+ * // => '<%- value %>'
+ *
+ * // using the `imports` option to import `jQuery` as `jq`
+ * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
+ * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
+ * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
+ * compiled(data);
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
+ *
+ * // using the `variable` option to ensure a with-statement isn't used in the compiled template
+ * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
+ * compiled.source;
+ * // => function(data) {
+ * var __t, __p = '';
+ * __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
+ * return __p;
+ * }
+ *
+ * // using the `source` property to inline compiled templates for meaningful
+ * // line numbers in error messages and a stack trace
+ * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
+ * var JST = {\
+ * "main": ' + _.template(mainText).source + '\
+ * };\
+ * ');
+ */
+ function template(string, options, otherOptions) {
+ // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/)
+ // and Laura Doktorova's doT.js (https://github.com/olado/doT).
+ var settings = lodash.templateSettings;
+
+ if (otherOptions && isIterateeCall(string, options, otherOptions)) {
+ options = otherOptions = null;
+ }
+ string = baseToString(string);
+ options = baseAssign(baseAssign({}, otherOptions || options), settings, assignOwnDefaults);
+
+ var imports = baseAssign(baseAssign({}, options.imports), settings.imports, assignOwnDefaults),
+ importsKeys = keys(imports),
+ importsValues = baseValues(imports, importsKeys);
+
+ var isEscaping,
+ isEvaluating,
+ index = 0,
+ interpolate = options.interpolate || reNoMatch,
+ source = "__p += '";
+
+ // Compile the regexp to match each delimiter.
+ var reDelimiters = RegExp(
+ (options.escape || reNoMatch).source + '|' +
+ interpolate.source + '|' +
+ (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
+ (options.evaluate || reNoMatch).source + '|$'
+ , 'g');
+
+ // Use a sourceURL for easier debugging.
+ // See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl.
+ var sourceURL = '//# sourceURL=' +
+ ('sourceURL' in options
+ ? options.sourceURL
+ : ('lodash.templateSources[' + (++templateCounter) + ']')
+ ) + '\n';
+
+ string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
+ interpolateValue || (interpolateValue = esTemplateValue);
+
+ // Escape characters that can't be included in string literals.
+ source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
+
+ // Replace delimiters with snippets.
+ if (escapeValue) {
+ isEscaping = true;
+ source += "' +\n__e(" + escapeValue + ") +\n'";
+ }
+ if (evaluateValue) {
+ isEvaluating = true;
+ source += "';\n" + evaluateValue + ";\n__p += '";
+ }
+ if (interpolateValue) {
+ source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
+ }
+ index = offset + match.length;
+
+ // The JS engine embedded in Adobe products requires returning the `match`
+ // string in order to produce the correct `offset` value.
+ return match;
+ });
+
+ source += "';\n";
+
+ // If `variable` is not specified wrap a with-statement around the generated
+ // code to add the data object to the top of the scope chain.
+ var variable = options.variable;
+ if (!variable) {
+ source = 'with (obj) {\n' + source + '\n}\n';
+ }
+ // Cleanup code by stripping empty strings.
+ source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
+ .replace(reEmptyStringMiddle, '$1')
+ .replace(reEmptyStringTrailing, '$1;');
+
+ // Frame code as the function body.
+ source = 'function(' + (variable || 'obj') + ') {\n' +
+ (variable
+ ? ''
+ : 'obj || (obj = {});\n'
+ ) +
+ "var __t, __p = ''" +
+ (isEscaping
+ ? ', __e = _.escape'
+ : ''
+ ) +
+ (isEvaluating
+ ? ', __j = Array.prototype.join;\n' +
+ "function print() { __p += __j.call(arguments, '') }\n"
+ : ';\n'
+ ) +
+ source +
+ 'return __p\n}';
+
+ var result = attempt(function() {
+ return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues);
+ });
+
+ // Provide the compiled function's source by its `toString` method or
+ // the `source` property as a convenience for inlining compiled templates.
+ result.source = source;
+ if (isError(result)) {
+ throw result;
+ }
+ return result;
+ }
+
+ /**
+ * Removes leading and trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trim(' abc ');
+ * // => 'abc'
+ *
+ * _.trim('-_-abc-_-', '_-');
+ * // => 'abc'
+ *
+ * _.map([' foo ', ' bar '], _.trim);
+ * // => ['foo', 'bar]
+ */
+ function trim(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string), trimmedRightIndex(string) + 1);
+ }
+ chars = baseToString(chars);
+ return string.slice(charsLeftIndex(string, chars), charsRightIndex(string, chars) + 1);
+ }
+
+ /**
+ * Removes leading whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimLeft(' abc ');
+ * // => 'abc '
+ *
+ * _.trimLeft('-_-abc-_-', '_-');
+ * // => 'abc-_-'
+ */
+ function trimLeft(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string))
+ }
+ return string.slice(charsLeftIndex(string, baseToString(chars)));
+ }
+
+ /**
+ * Removes trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimRight(' abc ');
+ * // => ' abc'
+ *
+ * _.trimRight('-_-abc-_-', '_-');
+ * // => '-_-abc'
+ */
+ function trimRight(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(0, trimmedRightIndex(string) + 1)
+ }
+ return string.slice(0, charsRightIndex(string, baseToString(chars)) + 1);
+ }
+
+ /**
+ * Truncates `string` if it is longer than the given maximum string length.
+ * The last characters of the truncated string are replaced with the omission
+ * string which defaults to "...".
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to truncate.
+ * @param {Object|number} [options] The options object or maximum string length.
+ * @param {number} [options.length=30] The maximum string length.
+ * @param {string} [options.omission='...'] The string to indicate text is omitted.
+ * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the truncated string.
+ * @example
+ *
+ * _.trunc('hi-diddly-ho there, neighborino');
+ * // => 'hi-diddly-ho there, neighbo...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', 24);
+ * // => 'hi-diddly-ho there, n...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': ' ' });
+ * // => 'hi-diddly-ho there,...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': /,? +/ });
+ * //=> 'hi-diddly-ho there...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'omission': ' [...]' });
+ * // => 'hi-diddly-ho there, neig [...]'
+ */
+ function trunc(string, options, guard) {
+ if (guard && isIterateeCall(string, options, guard)) {
+ options = null;
+ }
+ var length = DEFAULT_TRUNC_LENGTH,
+ omission = DEFAULT_TRUNC_OMISSION;
+
+ if (options != null) {
+ if (isObject(options)) {
+ var separator = 'separator' in options ? options.separator : separator;
+ length = 'length' in options ? +options.length || 0 : length;
+ omission = 'omission' in options ? baseToString(options.omission) : omission;
+ } else {
+ length = +options || 0;
+ }
+ }
+ string = baseToString(string);
+ if (length >= string.length) {
+ return string;
+ }
+ var end = length - omission.length;
+ if (end < 1) {
+ return omission;
+ }
+ var result = string.slice(0, end);
+ if (separator == null) {
+ return result + omission;
+ }
+ if (isRegExp(separator)) {
+ if (string.slice(end).search(separator)) {
+ var match,
+ newEnd,
+ substring = string.slice(0, end);
+
+ if (!separator.global) {
+ separator = RegExp(separator.source, (reFlags.exec(separator) || '') + 'g');
+ }
+ separator.lastIndex = 0;
+ while ((match = separator.exec(substring))) {
+ newEnd = match.index;
+ }
+ result = result.slice(0, newEnd == null ? end : newEnd);
+ }
+ } else if (string.indexOf(separator, end) != end) {
+ var index = result.lastIndexOf(separator);
+ if (index > -1) {
+ result = result.slice(0, index);
+ }
+ }
+ return result + omission;
+ }
+
+ /**
+ * The inverse of `_.escape`; this method converts the HTML entities
+ * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to their
+ * corresponding characters.
+ *
+ * **Note:** No other HTML entities are unescaped. To unescape additional HTML
+ * entities use a third-party library like [_he_](http://mths.be/he).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to unescape.
+ * @returns {string} Returns the unescaped string.
+ * @example
+ *
+ * _.unescape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function unescape(string) {
+ string = baseToString(string);
+ return (string && reHasEscapedHtml.test(string))
+ ? string.replace(reEscapedHtml, unescapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Splits `string` into an array of its words.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to inspect.
+ * @param {RegExp|string} [pattern] The pattern to match words.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the words of `string`.
+ * @example
+ *
+ * _.words('fred, barney, & pebbles');
+ * // => ['fred', 'barney', 'pebbles']
+ *
+ * _.words('fred, barney, & pebbles', /[^, ]+/g);
+ * // => ['fred', 'barney', '&', 'pebbles']
+ */
+ function words(string, pattern, guard) {
+ if (guard && isIterateeCall(string, pattern, guard)) {
+ pattern = null;
+ }
+ string = baseToString(string);
+ return string.match(pattern || reWords) || [];
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Attempts to invoke `func`, returning either the result or the caught
+ * error object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} func The function to attempt.
+ * @returns {*} Returns the `func` result or error object.
+ * @example
+ *
+ * // avoid throwing errors for invalid selectors
+ * var elements = _.attempt(function() {
+ * return document.querySelectorAll(selector);
+ * });
+ *
+ * if (_.isError(elements)) {
+ * elements = [];
+ * }
+ */
+ function attempt(func) {
+ try {
+ return func();
+ } catch(e) {
+ return isError(e) ? e : Error(e);
+ }
+ }
+
+ /**
+ * Creates a function bound to an optional `thisArg`. If `func` is a property
+ * name the created callback returns the property value for a given element.
+ * If `func` is an object the created callback returns `true` for elements
+ * that contain the equivalent object properties, otherwise it returns `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias iteratee
+ * @category Utility
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the callback.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // wrap to create custom callback shorthands
+ * _.callback = _.wrap(_.callback, function(callback, func, thisArg) {
+ * var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
+ * if (!match) {
+ * return callback(func, thisArg);
+ * }
+ * return function(object) {
+ * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
+ * };
+ * });
+ *
+ * _.filter(users, 'age__gt36');
+ * // => [{ 'user': 'fred', 'age': 40 }]
+ */
+ function callback(func, thisArg, guard) {
+ if (guard && isIterateeCall(func, thisArg, guard)) {
+ thisArg = null;
+ }
+ return baseCallback(func, thisArg);
+ }
+
+ /**
+ * Creates a function that returns `value`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value The value to return from the new function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var getter = _.constant(object);
+ * getter() === object;
+ * // => true
+ */
+ function constant(value) {
+ return function() {
+ return value;
+ };
+ }
+
+ /**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.identity(object) === object;
+ * // => true
+ */
+ function identity(value) {
+ return value;
+ }
+
+ /**
+ * Creates a function which performs a deep comparison between a given object
+ * and `source`, returning `true` if the given object has equivalent property
+ * values, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 36 }
+ * ];
+ *
+ * var matchesAge = _.matches({ 'age': 36 });
+ *
+ * _.filter(users, matchesAge);
+ * // => [{ 'user': 'barney', 'age': 36 }]
+ *
+ * _.find(users, matchesAge);
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function matches(source) {
+ return baseMatches(source, true);
+ }
+
+ /**
+ * Adds all own enumerable function properties of a source object to the
+ * destination object. If `object` is a function then methods are added to
+ * its prototype as well.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Function|Object} [object=this] object The destination object.
+ * @param {Object} source The object of functions to add.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.chain=true] Specify whether the functions added
+ * are chainable.
+ * @returns {Function|Object} Returns `object`.
+ * @example
+ *
+ * function vowels(string) {
+ * return _.filter(string, function(v) {
+ * return /[aeiou]/i.test(v);
+ * });
+ * }
+ *
+ * _.mixin({ 'vowels': vowels });
+ * _.vowels('fred');
+ * // => ['e']
+ *
+ * _('fred').vowels().value();
+ * // => ['e']
+ *
+ * _.mixin({ 'vowels': vowels }, { 'chain': false });
+ * _('fred').vowels();
+ * // => ['e']
+ */
+ function mixin(object, source, options) {
+ if (options == null) {
+ var isObj = isObject(source),
+ props = isObj && keys(source),
+ methodNames = props && props.length && baseFunctions(source, props);
+
+ if (!(methodNames ? methodNames.length : isObj)) {
+ methodNames = false;
+ options = source;
+ source = object;
+ object = this;
+ }
+ }
+ if (!methodNames) {
+ methodNames = baseFunctions(source, keys(source));
+ }
+ var chain = true,
+ index = -1,
+ isFunc = isFunction(object),
+ length = methodNames.length;
+
+ if (options === false) {
+ chain = false;
+ } else if (isObject(options) && 'chain' in options) {
+ chain = options.chain;
+ }
+ while (++index < length) {
+ var methodName = methodNames[index],
+ func = source[methodName];
+
+ object[methodName] = func;
+ if (isFunc) {
+ object.prototype[methodName] = (function(func) {
+ return function() {
+ var chainAll = this.__chain__;
+ if (chain || chainAll) {
+ var result = object(this.__wrapped__);
+ (result.__actions__ = arrayCopy(this.__actions__)).push({ 'func': func, 'args': arguments, 'thisArg': object });
+ result.__chain__ = chainAll;
+ return result;
+ }
+ var args = [this.value()];
+ push.apply(args, arguments);
+ return func.apply(object, args);
+ };
+ }(func));
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Reverts the `_` variable to its previous value and returns a reference to
+ * the `lodash` function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @returns {Function} Returns the `lodash` function.
+ * @example
+ *
+ * var lodash = _.noConflict();
+ */
+ function noConflict() {
+ context._ = oldDash;
+ return this;
+ }
+
+ /**
+ * A no-operation function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.noop(object) === undefined;
+ * // => true
+ */
+ function noop() {
+ // No operation performed.
+ }
+
+ /**
+ * Creates a function which returns the property value of `key` on a given object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * var getName = _.property('user');
+ *
+ * _.map(users, getName);
+ * // => ['fred', barney']
+ *
+ * _.pluck(_.sortBy(users, getName), 'user');
+ * // => ['barney', 'fred']
+ */
+ function property(key) {
+ return baseProperty(key + '');
+ }
+
+ /**
+ * The inverse of `_.property`; this method creates a function which returns
+ * the property value of a given key on `object`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} object The object to inspect.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40, 'active': true };
+ * _.map(['active', 'user'], _.propertyOf(object));
+ * // => [true, 'fred']
+ *
+ * var object = { 'a': 3, 'b': 1, 'c': 2 };
+ * _.sortBy(['a', 'b', 'c'], _.propertyOf(object));
+ * // => ['b', 'c', 'a']
+ */
+ function propertyOf(object) {
+ return function(key) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * Creates an array of numbers (positive and/or negative) progressing from
+ * `start` up to, but not including, `end`. If `start` is less than `end` a
+ * zero-length range is created unless a negative `step` is specified.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} [start=0] The start of the range.
+ * @param {number} end The end of the range.
+ * @param {number} [step=1] The value to increment or decrement by.
+ * @returns {Array} Returns the new array of numbers.
+ * @example
+ *
+ * _.range(4);
+ * // => [0, 1, 2, 3]
+ *
+ * _.range(1, 5);
+ * // => [1, 2, 3, 4]
+ *
+ * _.range(0, 20, 5);
+ * // => [0, 5, 10, 15]
+ *
+ * _.range(0, -4, -1);
+ * // => [0, -1, -2, -3]
+ *
+ * _.range(1, 4, 0);
+ * // => [1, 1, 1]
+ *
+ * _.range(0);
+ * // => []
+ */
+ function range(start, end, step) {
+ if (step && isIterateeCall(start, end, step)) {
+ end = step = null;
+ }
+ start = +start || 0;
+ step = step == null ? 1 : (+step || 0);
+
+ if (end == null) {
+ end = start;
+ start = 0;
+ } else {
+ end = +end || 0;
+ }
+ // Use `Array(length)` so engines like Chakra and V8 avoid slower modes.
+ // See http://youtu.be/XAqIpGU8ZZk#t=17m25s.
+ var index = -1,
+ length = nativeMax(ceil((end - start) / (step || 1)), 0),
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = start;
+ start += step;
+ }
+ return result;
+ }
+
+ /**
+ * Invokes the iteratee function `n` times, returning an array of the results
+ * of each invocation. The `iteratee` is bound to `thisArg` and invoked with
+ * one argument; (index).
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * var diceRolls = _.times(3, _.partial(_.random, 1, 6, false));
+ * // => [3, 6, 4]
+ *
+ * _.times(3, function(n) { mage.castSpell(n); });
+ * // => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2` respectively
+ *
+ * _.times(3, function(n) { this.cast(n); }, mage);
+ * // => also invokes `mage.castSpell(n)` three times
+ */
+ function times(n, iteratee, thisArg) {
+ n = +n;
+
+ // Exit early to avoid a JSC JIT bug in Safari 8
+ // where `Array(0)` is treated as `Array(1)`.
+ if (n < 1 || !nativeIsFinite(n)) {
+ return [];
+ }
+ var index = -1,
+ result = Array(nativeMin(n, MAX_ARRAY_LENGTH));
+
+ iteratee = bindCallback(iteratee, thisArg, 1);
+ while (++index < n) {
+ if (index < MAX_ARRAY_LENGTH) {
+ result[index] = iteratee(index);
+ } else {
+ iteratee(index);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Generates a unique ID. If `prefix` is provided the ID is appended to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} [prefix] The value to prefix the ID with.
+ * @returns {string} Returns the unique ID.
+ * @example
+ *
+ * _.uniqueId('contact_');
+ * // => 'contact_104'
+ *
+ * _.uniqueId();
+ * // => '105'
+ */
+ function uniqueId(prefix) {
+ var id = ++idCounter;
+ return baseToString(prefix) + id;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ // Ensure `new LodashWrapper` is an instance of `lodash`.
+ LodashWrapper.prototype = lodash.prototype;
+
+ // Add functions to the `Map` cache.
+ MapCache.prototype['delete'] = mapDelete;
+ MapCache.prototype.get = mapGet;
+ MapCache.prototype.has = mapHas;
+ MapCache.prototype.set = mapSet;
+
+ // Add functions to the `Set` cache.
+ SetCache.prototype.push = cachePush;
+
+ // Assign cache to `_.memoize`.
+ memoize.Cache = MapCache;
+
+ // Add functions that return wrapped values when chaining.
+ lodash.after = after;
+ lodash.ary = ary;
+ lodash.assign = assign;
+ lodash.at = at;
+ lodash.before = before;
+ lodash.bind = bind;
+ lodash.bindAll = bindAll;
+ lodash.bindKey = bindKey;
+ lodash.callback = callback;
+ lodash.chain = chain;
+ lodash.chunk = chunk;
+ lodash.compact = compact;
+ lodash.constant = constant;
+ lodash.countBy = countBy;
+ lodash.create = create;
+ lodash.curry = curry;
+ lodash.curryRight = curryRight;
+ lodash.debounce = debounce;
+ lodash.defaults = defaults;
+ lodash.defer = defer;
+ lodash.delay = delay;
+ lodash.difference = difference;
+ lodash.drop = drop;
+ lodash.dropRight = dropRight;
+ lodash.dropRightWhile = dropRightWhile;
+ lodash.dropWhile = dropWhile;
+ lodash.filter = filter;
+ lodash.flatten = flatten;
+ lodash.flattenDeep = flattenDeep;
+ lodash.flow = flow;
+ lodash.flowRight = flowRight;
+ lodash.forEach = forEach;
+ lodash.forEachRight = forEachRight;
+ lodash.forIn = forIn;
+ lodash.forInRight = forInRight;
+ lodash.forOwn = forOwn;
+ lodash.forOwnRight = forOwnRight;
+ lodash.functions = functions;
+ lodash.groupBy = groupBy;
+ lodash.indexBy = indexBy;
+ lodash.initial = initial;
+ lodash.intersection = intersection;
+ lodash.invert = invert;
+ lodash.invoke = invoke;
+ lodash.keys = keys;
+ lodash.keysIn = keysIn;
+ lodash.map = map;
+ lodash.mapValues = mapValues;
+ lodash.matches = matches;
+ lodash.memoize = memoize;
+ lodash.merge = merge;
+ lodash.mixin = mixin;
+ lodash.negate = negate;
+ lodash.omit = omit;
+ lodash.once = once;
+ lodash.pairs = pairs;
+ lodash.partial = partial;
+ lodash.partialRight = partialRight;
+ lodash.partition = partition;
+ lodash.pick = pick;
+ lodash.pluck = pluck;
+ lodash.property = property;
+ lodash.propertyOf = propertyOf;
+ lodash.pull = pull;
+ lodash.pullAt = pullAt;
+ lodash.range = range;
+ lodash.rearg = rearg;
+ lodash.reject = reject;
+ lodash.remove = remove;
+ lodash.rest = rest;
+ lodash.shuffle = shuffle;
+ lodash.slice = slice;
+ lodash.sortBy = sortBy;
+ lodash.sortByAll = sortByAll;
+ lodash.take = take;
+ lodash.takeRight = takeRight;
+ lodash.takeRightWhile = takeRightWhile;
+ lodash.takeWhile = takeWhile;
+ lodash.tap = tap;
+ lodash.throttle = throttle;
+ lodash.thru = thru;
+ lodash.times = times;
+ lodash.toArray = toArray;
+ lodash.toPlainObject = toPlainObject;
+ lodash.transform = transform;
+ lodash.union = union;
+ lodash.uniq = uniq;
+ lodash.unzip = unzip;
+ lodash.values = values;
+ lodash.valuesIn = valuesIn;
+ lodash.where = where;
+ lodash.without = without;
+ lodash.wrap = wrap;
+ lodash.xor = xor;
+ lodash.zip = zip;
+ lodash.zipObject = zipObject;
+
+ // Add aliases.
+ lodash.backflow = flowRight;
+ lodash.collect = map;
+ lodash.compose = flowRight;
+ lodash.each = forEach;
+ lodash.eachRight = forEachRight;
+ lodash.extend = assign;
+ lodash.iteratee = callback;
+ lodash.methods = functions;
+ lodash.object = zipObject;
+ lodash.select = filter;
+ lodash.tail = rest;
+ lodash.unique = uniq;
+
+ // Add functions to `lodash.prototype`.
+ mixin(lodash, lodash);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions that return unwrapped values when chaining.
+ lodash.attempt = attempt;
+ lodash.camelCase = camelCase;
+ lodash.capitalize = capitalize;
+ lodash.clone = clone;
+ lodash.cloneDeep = cloneDeep;
+ lodash.deburr = deburr;
+ lodash.endsWith = endsWith;
+ lodash.escape = escape;
+ lodash.escapeRegExp = escapeRegExp;
+ lodash.every = every;
+ lodash.find = find;
+ lodash.findIndex = findIndex;
+ lodash.findKey = findKey;
+ lodash.findLast = findLast;
+ lodash.findLastIndex = findLastIndex;
+ lodash.findLastKey = findLastKey;
+ lodash.findWhere = findWhere;
+ lodash.first = first;
+ lodash.has = has;
+ lodash.identity = identity;
+ lodash.includes = includes;
+ lodash.indexOf = indexOf;
+ lodash.isArguments = isArguments;
+ lodash.isArray = isArray;
+ lodash.isBoolean = isBoolean;
+ lodash.isDate = isDate;
+ lodash.isElement = isElement;
+ lodash.isEmpty = isEmpty;
+ lodash.isEqual = isEqual;
+ lodash.isError = isError;
+ lodash.isFinite = isFinite;
+ lodash.isFunction = isFunction;
+ lodash.isMatch = isMatch;
+ lodash.isNaN = isNaN;
+ lodash.isNative = isNative;
+ lodash.isNull = isNull;
+ lodash.isNumber = isNumber;
+ lodash.isObject = isObject;
+ lodash.isPlainObject = isPlainObject;
+ lodash.isRegExp = isRegExp;
+ lodash.isString = isString;
+ lodash.isTypedArray = isTypedArray;
+ lodash.isUndefined = isUndefined;
+ lodash.kebabCase = kebabCase;
+ lodash.last = last;
+ lodash.lastIndexOf = lastIndexOf;
+ lodash.max = max;
+ lodash.min = min;
+ lodash.noConflict = noConflict;
+ lodash.noop = noop;
+ lodash.now = now;
+ lodash.pad = pad;
+ lodash.padLeft = padLeft;
+ lodash.padRight = padRight;
+ lodash.parseInt = parseInt;
+ lodash.random = random;
+ lodash.reduce = reduce;
+ lodash.reduceRight = reduceRight;
+ lodash.repeat = repeat;
+ lodash.result = result;
+ lodash.runInContext = runInContext;
+ lodash.size = size;
+ lodash.snakeCase = snakeCase;
+ lodash.some = some;
+ lodash.sortedIndex = sortedIndex;
+ lodash.sortedLastIndex = sortedLastIndex;
+ lodash.startsWith = startsWith;
+ lodash.template = template;
+ lodash.trim = trim;
+ lodash.trimLeft = trimLeft;
+ lodash.trimRight = trimRight;
+ lodash.trunc = trunc;
+ lodash.unescape = unescape;
+ lodash.uniqueId = uniqueId;
+ lodash.words = words;
+
+ // Add aliases.
+ lodash.all = every;
+ lodash.any = some;
+ lodash.contains = includes;
+ lodash.detect = find;
+ lodash.foldl = reduce;
+ lodash.foldr = reduceRight;
+ lodash.head = first;
+ lodash.include = includes;
+ lodash.inject = reduce;
+
+ mixin(lodash, (function() {
+ var source = {};
+ baseForOwn(lodash, function(func, methodName) {
+ if (!lodash.prototype[methodName]) {
+ source[methodName] = func;
+ }
+ });
+ return source;
+ }()), false);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions capable of returning wrapped and unwrapped values when chaining.
+ lodash.sample = sample;
+
+ lodash.prototype.sample = function(n) {
+ if (!this.__chain__ && n == null) {
+ return sample(this.value());
+ }
+ return this.thru(function(value) {
+ return sample(value, n);
+ });
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The semantic version number.
+ *
+ * @static
+ * @memberOf _
+ * @type string
+ */
+ lodash.VERSION = VERSION;
+
+ // Assign default placeholders.
+ arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
+ lodash[methodName].placeholder = lodash;
+ });
+
+ // Add `LazyWrapper` methods that accept an `iteratee` value.
+ arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
+ var isFilter = index == LAZY_FILTER_FLAG;
+
+ LazyWrapper.prototype[methodName] = function(iteratee, thisArg) {
+ var result = this.clone(),
+ filtered = result.filtered,
+ iteratees = result.iteratees || (result.iteratees = []);
+
+ result.filtered = filtered || isFilter || (index == LAZY_WHILE_FLAG && result.dir < 0);
+ iteratees.push({ 'iteratee': getCallback(iteratee, thisArg, 3), 'type': index });
+ return result;
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
+ arrayEach(['drop', 'take'], function(methodName, index) {
+ var countName = methodName + 'Count',
+ whileName = methodName + 'While';
+
+ LazyWrapper.prototype[methodName] = function(n) {
+ n = n == null ? 1 : nativeMax(+n || 0, 0);
+
+ var result = this.clone();
+ if (result.filtered) {
+ var value = result[countName];
+ result[countName] = index ? nativeMin(value, n) : (value + n);
+ } else {
+ var views = result.views || (result.views = []);
+ views.push({ 'size': n, 'type': methodName + (result.dir < 0 ? 'Right' : '') });
+ }
+ return result;
+ };
+
+ LazyWrapper.prototype[methodName + 'Right'] = function(n) {
+ return this.reverse()[methodName](n).reverse();
+ };
+
+ LazyWrapper.prototype[methodName + 'RightWhile'] = function(predicate, thisArg) {
+ return this.reverse()[whileName](predicate, thisArg).reverse();
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.first` and `_.last`.
+ arrayEach(['first', 'last'], function(methodName, index) {
+ var takeName = 'take' + (index ? 'Right': '');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[takeName](1).value()[0];
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.initial` and `_.rest`.
+ arrayEach(['initial', 'rest'], function(methodName, index) {
+ var dropName = 'drop' + (index ? '' : 'Right');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[dropName](1);
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.pluck` and `_.where`.
+ arrayEach(['pluck', 'where'], function(methodName, index) {
+ var operationName = index ? 'filter' : 'map',
+ createCallback = index ? matches : property;
+
+ LazyWrapper.prototype[methodName] = function(value) {
+ return this[operationName](createCallback(value));
+ };
+ });
+
+ LazyWrapper.prototype.dropWhile = function(iteratee, thisArg) {
+ var done,
+ lastIndex,
+ isRight = this.dir < 0;
+
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ done = done && (isRight ? index < lastIndex : index > lastIndex);
+ lastIndex = index;
+ return done || (done = !iteratee(value, index, array));
+ });
+ };
+
+ LazyWrapper.prototype.reject = function(iteratee, thisArg) {
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ return !iteratee(value, index, array);
+ });
+ };
+
+ LazyWrapper.prototype.slice = function(start, end) {
+ start = start == null ? 0 : (+start || 0);
+ var result = start < 0 ? this.takeRight(-start) : this.drop(start);
+
+ if (typeof end != 'undefined') {
+ end = (+end || 0);
+ result = end < 0 ? result.dropRight(-end) : result.take(end - start);
+ }
+ return result;
+ };
+
+ // Add `LazyWrapper` methods to `lodash.prototype`.
+ baseForOwn(LazyWrapper.prototype, function(func, methodName) {
+ var retUnwrapped = /^(?:first|last)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var value = this.__wrapped__,
+ args = arguments,
+ chainAll = this.__chain__,
+ isHybrid = !!this.__actions__.length,
+ isLazy = value instanceof LazyWrapper,
+ onlyLazy = isLazy && !isHybrid;
+
+ if (retUnwrapped && !chainAll) {
+ return onlyLazy
+ ? func.call(value)
+ : lodash[methodName](this.value());
+ }
+ var interceptor = function(value) {
+ var otherArgs = [value];
+ push.apply(otherArgs, args);
+ return lodash[methodName].apply(lodash, otherArgs);
+ };
+ if (isLazy || isArray(value)) {
+ var wrapper = onlyLazy ? value : new LazyWrapper(this),
+ result = func.apply(wrapper, args);
+
+ if (!retUnwrapped && (isHybrid || result.actions)) {
+ var actions = result.actions || (result.actions = []);
+ actions.push({ 'func': thru, 'args': [interceptor], 'thisArg': lodash });
+ }
+ return new LodashWrapper(result, chainAll);
+ }
+ return this.thru(interceptor);
+ };
+ });
+
+ // Add `Array.prototype` functions to `lodash.prototype`.
+ arrayEach(['concat', 'join', 'pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
+ var func = arrayProto[methodName],
+ chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
+ retUnwrapped = /^(?:join|pop|shift)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var args = arguments;
+ if (retUnwrapped && !this.__chain__) {
+ return func.apply(this.value(), args);
+ }
+ return this[chainName](function(value) {
+ return func.apply(value, args);
+ });
+ };
+ });
+
+ // Add functions to the lazy wrapper.
+ LazyWrapper.prototype.clone = lazyClone;
+ LazyWrapper.prototype.reverse = lazyReverse;
+ LazyWrapper.prototype.value = lazyValue;
+
+ // Add chaining functions to the lodash wrapper.
+ lodash.prototype.chain = wrapperChain;
+ lodash.prototype.reverse = wrapperReverse;
+ lodash.prototype.toString = wrapperToString;
+ lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
+
+ // Add function aliases to the lodash wrapper.
+ lodash.prototype.collect = lodash.prototype.map;
+ lodash.prototype.head = lodash.prototype.first;
+ lodash.prototype.select = lodash.prototype.filter;
+ lodash.prototype.tail = lodash.prototype.rest;
+
+ return lodash;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // Export Lo-Dash.
+ var _ = runInContext();
+
+ // Some AMD build optimizers like r.js check for condition patterns like the following:
+ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ // Expose Lo-Dash to the global object when an AMD loader is present to avoid
+ // errors in cases where Lo-Dash is loaded by a script tag and not intended
+ // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch.
+ root._ = _;
+
+ // Define as an anonymous module so, through path mapping, it can be
+ // referenced as the "underscore" module.
+ define(function() {
+ return _;
+ });
+ }
+ // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
+ else if (freeExports && freeModule) {
+ // Export for Node.js or RingoJS.
+ if (moduleExports) {
+ (freeModule.exports = _)._ = _;
+ }
+ // Export for Narwhal or Rhino -require.
+ else {
+ freeExports._ = _;
+ }
+ }
+ else {
+ // Export for a browser or Rhino.
+ root._ = _;
+ }
+}.call(this));
diff --git a/debian/libjs-lodash/usr/share/javascript/lodash.min.js b/debian/libjs-lodash/usr/share/javascript/lodash.min.js
new file mode 100644
index 0000000..3e889fe
--- /dev/null
+++ b/debian/libjs-lodash/usr/share/javascript/lodash.min.js
@@ -0,0 +1,10 @@
+/**
+ * @license
+ * Lo-Dash 3.0.0 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern -o ./lodash.js`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */(function(){function kt(e,t){if(e!==t){var n=e===e,r=t===t;if(e>t||!n||typeof e=="undefined"&&r)return 1;if(e<t||!r||typeof t=="undefined"&&n)return-1}return 0}function Lt(e,t,n){if(t!==t)return It(e,n);var r=(n||0)-1,i=e.length;while(++r<i)if(e[r]===t)return r;return-1}function At(e,t){var n=e.length;e.sort(t);while(n--)e[n]=e[n].value;return e}function Ot(e){return typeof e=="string"?e:e==null?"":e+""}function Mt(e){return e.charCodeAt(0)}function _t(e,t){var n=-1,r=e.length;while(+ [...]
+),h=(f?h.replace(z,""):h).replace(W,"$1").replace(X,"$1;"),h="function("+(v||"obj")+") {\n"+(v?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(a?", __e = _.escape":"")+(f?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+h+"return __p\n}";var m=Iu(function(){return yt(o,d+"return "+h).apply(e,u)});m.source=h;if(_o(m))throw m;return m}function Du(e,t,n){var r=e;return e=Ot(e),e?(n?Ci(r,t,n):t==null)?e.slice(Wt(e),Xt(e)+1):(t=Ot(t),e.slice(_t(e,t [...]
\ No newline at end of file
diff --git a/debian/node-lodash.debhelper.log b/debian/node-lodash.debhelper.log
new file mode 100644
index 0000000..4c7ea2f
--- /dev/null
+++ b/debian/node-lodash.debhelper.log
@@ -0,0 +1,19 @@
+dh_auto_configure
+override_dh_auto_build dh_auto_build
+dh_auto_build
+dh_auto_test
+dh_prep
+dh_auto_install
+dh_install
+dh_installdocs
+dh_installchangelogs
+dh_perl
+dh_link
+dh_compress
+dh_fixperms
+dh_installdeb
+dh_gencontrol
+dh_md5sums
+dh_builddeb
+dh_builddeb
+dh_builddeb
diff --git a/debian/node-lodash.substvars b/debian/node-lodash.substvars
new file mode 100644
index 0000000..abd3ebe
--- /dev/null
+++ b/debian/node-lodash.substvars
@@ -0,0 +1 @@
+misc:Depends=
diff --git a/debian/node-lodash/DEBIAN/control b/debian/node-lodash/DEBIAN/control
new file mode 100644
index 0000000..c9c8db1
--- /dev/null
+++ b/debian/node-lodash/DEBIAN/control
@@ -0,0 +1,14 @@
+Package: node-lodash
+Version: 3.0+dfsg-1
+Architecture: all
+Maintainer: Debian Javascript Maintainers <pkg-javascript-devel at lists.alioth.debian.org>
+Installed-Size: 406
+Depends: nodejs
+Section: web
+Priority: optional
+Homepage: http://lodash.com/
+Description: Lo-dash is a Node.js utility library
+ Lo-dash is a Node.js utility library delivering
+ consistency, customization, performance, & extras.
+ .
+ Node.js is an event-based server-side JavaScript engine.
diff --git a/debian/node-lodash/DEBIAN/md5sums b/debian/node-lodash/DEBIAN/md5sums
new file mode 100644
index 0000000..205f84d
--- /dev/null
+++ b/debian/node-lodash/DEBIAN/md5sums
@@ -0,0 +1,4 @@
+df9e34edcc0e8a40bc98651f84b18016 usr/lib/nodejs/lodash.js
+d847f37415cc31d38348e3225ef7f1e2 usr/share/doc/node-lodash/README.md
+e22bea7778f243fadfd1647c48477f11 usr/share/doc/node-lodash/changelog.Debian.gz
+b366291265b4bbb8290c20e3bbf1beff usr/share/doc/node-lodash/copyright
diff --git a/debian/node-lodash/usr/lib/nodejs/lodash.js b/debian/node-lodash/usr/lib/nodejs/lodash.js
new file mode 100644
index 0000000..4ecebb5
--- /dev/null
+++ b/debian/node-lodash/usr/lib/nodejs/lodash.js
@@ -0,0 +1,10784 @@
+/**
+ * @license
+ * Lo-Dash 3.0.0 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern -o ./lodash.js`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+;(function() {
+
+ /** Used as a safe reference for `undefined` in pre ES5 environments. */
+ var undefined;
+
+ /** Used as the semantic version number. */
+ var VERSION = '3.0.0';
+
+ /** Used to compose bitmasks for wrapper metadata. */
+ var BIND_FLAG = 1,
+ BIND_KEY_FLAG = 2,
+ CURRY_BOUND_FLAG = 4,
+ CURRY_FLAG = 8,
+ CURRY_RIGHT_FLAG = 16,
+ PARTIAL_FLAG = 32,
+ PARTIAL_RIGHT_FLAG = 64,
+ REARG_FLAG = 128,
+ ARY_FLAG = 256;
+
+ /** Used as default options for `_.trunc`. */
+ var DEFAULT_TRUNC_LENGTH = 30,
+ DEFAULT_TRUNC_OMISSION = '...';
+
+ /** Used to detect when a function becomes hot. */
+ var HOT_COUNT = 150,
+ HOT_SPAN = 16;
+
+ /** Used to indicate the type of lazy iteratees. */
+ var LAZY_FILTER_FLAG = 0,
+ LAZY_MAP_FLAG = 1,
+ LAZY_WHILE_FLAG = 2;
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used as the internal argument placeholder. */
+ var PLACEHOLDER = '__lodash_placeholder__';
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /** Used to match empty string literals in compiled template source. */
+ var reEmptyStringLeading = /\b__p \+= '';/g,
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+ /** Used to match HTML entities and HTML characters. */
+ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g,
+ reUnescapedHtml = /[&<>"'`]/g,
+ reHasEscapedHtml = RegExp(reEscapedHtml.source),
+ reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
+
+ /** Used to match template delimiters. */
+ var reEscape = /<%-([\s\S]+?)%>/g,
+ reEvaluate = /<%([\s\S]+?)%>/g,
+ reInterpolate = /<%=([\s\S]+?)%>/g;
+
+ /**
+ * Used to match ES6 template delimiters.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literal-lexical-components)
+ * for more details.
+ */
+ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
+
+ /** Used to detect named functions. */
+ var reFuncName = /^\s*function[ \n\r\t]+\w/;
+
+ /** Used to detect hexadecimal string values. */
+ var reHexPrefix = /^0[xX]/;
+
+ /** Used to detect host constructors (Safari > 5). */
+ var reHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to match latin-1 supplementary letters (excluding mathematical operators). */
+ var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g;
+
+ /** Used to ensure capturing order of template delimiters. */
+ var reNoMatch = /($^)/;
+
+ /**
+ * Used to match `RegExp` special characters.
+ * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
+ * for more details.
+ */
+ var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
+ reHasRegExpChars = RegExp(reRegExpChars.source);
+
+ /** Used to detect functions containing a `this` reference. */
+ var reThis = /\bthis\b/;
+
+ /** Used to match unescaped characters in compiled string literals. */
+ var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
+
+ /** Used to match words to create compound words. */
+ var reWords = (function() {
+ var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]',
+ lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+';
+
+ return RegExp(upper + '{2,}(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g');
+ }());
+
+ /** Used to detect and test for whitespace. */
+ var whitespace = (
+ // Basic whitespace characters.
+ ' \t\x0b\f\xa0\ufeff' +
+
+ // Line terminators.
+ '\n\r\u2028\u2029' +
+
+ // Unicode category "Zs" space separators.
+ '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
+ );
+
+ /** Used to assign default `context` object properties. */
+ var contextProps = [
+ 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array',
+ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number',
+ 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document',
+ 'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array',
+ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
+ 'window', 'WinRTError'
+ ];
+
+ /** Used to make template sourceURLs easier to identify. */
+ var templateCounter = -1;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dateTag] = typedArrayTags[errorTag] =
+ typedArrayTags[funcTag] = typedArrayTags[mapTag] =
+ typedArrayTags[numberTag] = typedArrayTags[objectTag] =
+ typedArrayTags[regexpTag] = typedArrayTags[setTag] =
+ typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag] = cloneableTags[arrayTag] =
+ cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
+ cloneableTags[dateTag] = cloneableTags[float32Tag] =
+ cloneableTags[float64Tag] = cloneableTags[int8Tag] =
+ cloneableTags[int16Tag] = cloneableTags[int32Tag] =
+ cloneableTags[numberTag] = cloneableTags[objectTag] =
+ cloneableTags[regexpTag] = cloneableTags[stringTag] =
+ cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+ cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+ cloneableTags[errorTag] = cloneableTags[funcTag] =
+ cloneableTags[mapTag] = cloneableTags[setTag] =
+ cloneableTags[weakMapTag] = false;
+
+ /** Used as an internal `_.debounce` options object by `_.throttle`. */
+ var debounceOptions = {
+ 'leading': false,
+ 'maxWait': 0,
+ 'trailing': false
+ };
+
+ /** Used to map latin-1 supplementary letters to basic latin letters. */
+ var deburredLetters = {
+ '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+ '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+ '\xc7': 'C', '\xe7': 'c',
+ '\xd0': 'D', '\xf0': 'd',
+ '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+ '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+ '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+ '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
+ '\xd1': 'N', '\xf1': 'n',
+ '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+ '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+ '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+ '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
+ '\xc6': 'Ae', '\xe6': 'ae',
+ '\xde': 'Th', '\xfe': 'th',
+ '\xdf': 'ss'
+ };
+
+ /** Used to map characters to HTML entities. */
+ var htmlEscapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
+ };
+
+ /** Used to map HTML entities to characters. */
+ var htmlUnescapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ ''': "'",
+ '`': '`'
+ };
+
+ /** Used to determine if values are of the language type `Object`. */
+ var objectTypes = {
+ 'function': true,
+ 'object': true
+ };
+
+ /** Used to escape characters for inclusion in compiled string literals. */
+ var stringEscapes = {
+ '\\': '\\',
+ "'": "'",
+ '\n': 'n',
+ '\r': 'r',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ /**
+ * Used as a reference to the global object.
+ *
+ * The `this` value is used if it is the global object to avoid Greasemonkey's
+ * restricted `window` object, otherwise the `window` object is used.
+ */
+ var root = (objectTypes[typeof window] && window !== (this && this.window)) ? window : this;
+
+ /** Detect free variable `exports`. */
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
+
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */
+ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
+ root = freeGlobal;
+ }
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The base implementation of `compareAscending` which compares values and
+ * sorts them in ascending order without guaranteeing a stable sort.
+ *
+ * @private
+ * @param {*} value The value to compare to `other`.
+ * @param {*} other The value to compare to `value`.
+ * @returns {number} Returns the sort order indicator for `value`.
+ */
+ function baseCompareAscending(value, other) {
+ if (value !== other) {
+ var valIsReflexive = value === value,
+ othIsReflexive = other === other;
+
+ if (value > other || !valIsReflexive || (typeof value == 'undefined' && othIsReflexive)) {
+ return 1;
+ }
+ if (value < other || !othIsReflexive || (typeof other == 'undefined' && valIsReflexive)) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * The base implementation of `_.indexOf` without support for binary searches.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseIndexOf(array, value, fromIndex) {
+ if (value !== value) {
+ return indexOfNaN(array, fromIndex);
+ }
+ var index = (fromIndex || 0) - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.sortBy` and `_.sortByAll` which uses `comparer`
+ * to define the sort order of `array` and replaces criteria objects with their
+ * corresponding values.
+ *
+ * @private
+ * @param {Array} array The array to sort.
+ * @param {Function} comparer The function to define sort order.
+ * @returns {Array} Returns `array`.
+ */
+ function baseSortBy(array, comparer) {
+ var length = array.length;
+
+ array.sort(comparer);
+ while (length--) {
+ array[length] = array[length].value;
+ }
+ return array;
+ }
+
+ /**
+ * Converts `value` to a string if it is not one. An empty string is returned
+ * for `null` or `undefined` values.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ if (typeof value == 'string') {
+ return value;
+ }
+ return value == null ? '' : (value + '');
+ }
+
+ /**
+ * Used by `_.max` and `_.min` as the default callback for string values.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the code unit of the first character of the string.
+ */
+ function charAtCallback(string) {
+ return string.charCodeAt(0);
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the first character not found in `chars`.
+ */
+ function charsLeftIndex(string, chars) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the last character not found in `chars`.
+ */
+ function charsRightIndex(string, chars) {
+ var index = string.length;
+
+ while (index-- && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.sortBy` to compare transformed elements of a collection and stable
+ * sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareAscending(object, other) {
+ return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index);
+ }
+
+ /**
+ * Used by `_.sortByAll` to compare multiple properties of each element
+ * in a collection and stable sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareMultipleAscending(object, other) {
+ var index = -1,
+ objCriteria = object.criteria,
+ othCriteria = other.criteria,
+ length = objCriteria.length;
+
+ while (++index < length) {
+ var result = baseCompareAscending(objCriteria[index], othCriteria[index]);
+ if (result) {
+ return result;
+ }
+ }
+ // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+ // that causes it, under certain circumstances, to provide the same value
+ // for `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247.
+ //
+ // This also ensures a stable sort in V8 and other engines.
+ // See https://code.google.com/p/v8/issues/detail?id=90.
+ return object.index - other.index;
+ }
+
+ /**
+ * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
+ *
+ * @private
+ * @param {string} letter The matched letter to deburr.
+ * @returns {string} Returns the deburred letter.
+ */
+ function deburrLetter(letter) {
+ return deburredLetters[letter];
+ }
+
+ /**
+ * Used by `_.escape` to convert characters to HTML entities.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeHtmlChar(chr) {
+ return htmlEscapes[chr];
+ }
+
+ /**
+ * Used by `_.template` to escape characters for inclusion in compiled
+ * string literals.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeStringChar(chr) {
+ return '\\' + stringEscapes[chr];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `NaN` is found in `array`.
+ * If `fromRight` is provided elements of `array` are iterated from right to left.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {number} [fromIndex] The index to search from.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched `NaN`, else `-1`.
+ */
+ function indexOfNaN(array, fromIndex, fromRight) {
+ var length = array.length,
+ index = fromRight ? (fromIndex || length) : ((fromIndex || 0) - 1);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var other = array[index];
+ if (other !== other) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if `value` is object-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ */
+ function isObjectLike(value) {
+ return (value && typeof value == 'object') || false;
+ }
+
+ /**
+ * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a
+ * character code is whitespace.
+ *
+ * @private
+ * @param {number} charCode The character code to inspect.
+ * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`.
+ */
+ function isSpace(charCode) {
+ return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 ||
+ (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279)));
+ }
+
+ /**
+ * Replaces all `placeholder` elements in `array` with an internal placeholder
+ * and returns an array of their indexes.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {*} placeholder The placeholder to replace.
+ * @returns {Array} Returns the new array of placeholder indexes.
+ */
+ function replaceHolders(array, placeholder) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ if (array[index] === placeholder) {
+ array[index] = PLACEHOLDER;
+ result[++resIndex] = index;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * An implementation of `_.uniq` optimized for sorted arrays without support
+ * for callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function sortedUniq(array, iteratee) {
+ var seen,
+ index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (!index || seen !== computed) {
+ seen = computed;
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the first non-whitespace character.
+ */
+ function trimmedLeftIndex(string) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the last non-whitespace character.
+ */
+ function trimmedRightIndex(string) {
+ var index = string.length;
+
+ while (index-- && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} chr The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ function unescapeHtmlChar(chr) {
+ return htmlUnescapes[chr];
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Create a new pristine `lodash` function using the given `context` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} [context=root] The context object.
+ * @returns {Function} Returns a new `lodash` function.
+ * @example
+ *
+ * _.mixin({ 'add': function(a, b) { return a + b; } });
+ *
+ * var lodash = _.runInContext();
+ * lodash.mixin({ 'sub': function(a, b) { return a - b; } });
+ *
+ * _.isFunction(_.add);
+ * // => true
+ * _.isFunction(_.sub);
+ * // => false
+ *
+ * lodash.isFunction(lodash.add);
+ * // => false
+ * lodash.isFunction(lodash.sub);
+ * // => true
+ *
+ * // using `context` to mock `Date#getTime` use in `_.now`
+ * var mock = _.runInContext({
+ * 'Date': function() {
+ * return { 'getTime': getTimeMock };
+ * }
+ * });
+ *
+ * // or creating a suped-up `defer` in Node.js
+ * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+ */
+ function runInContext(context) {
+ // Avoid issues with some ES3 environments that attempt to use values, named
+ // after built-in constructors like `Object`, for the creation of literals.
+ // ES5 clears this up by stating that literals must use built-in constructors.
+ // See http://es5.github.io/#x11.1.5.
+ context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
+
+ /** Native constructor references. */
+ var Array = context.Array,
+ Date = context.Date,
+ Error = context.Error,
+ Function = context.Function,
+ Math = context.Math,
+ Number = context.Number,
+ Object = context.Object,
+ RegExp = context.RegExp,
+ String = context.String,
+ TypeError = context.TypeError;
+
+ /** Used for native method references. */
+ var arrayProto = Array.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect DOM support. */
+ var document = (document = context.window) && document.document;
+
+ /** Used to resolve the decompiled source of functions. */
+ var fnToString = Function.prototype.toString;
+
+ /** Used to the length of n-tuples for `_.unzip`. */
+ var getLength = baseProperty('length');
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to generate unique IDs. */
+ var idCounter = 0;
+
+ /**
+ * Used to resolve the `toStringTag` of values.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
+ * for more details.
+ */
+ var objToString = objectProto.toString;
+
+ /** Used to restore the original `_` reference in `_.noConflict`. */
+ var oldDash = context._;
+
+ /** Used to detect if a method is native. */
+ var reNative = RegExp('^' +
+ escapeRegExp(objToString)
+ .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Native method references. */
+ var ArrayBuffer = isNative(ArrayBuffer = context.ArrayBuffer) && ArrayBuffer,
+ bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice,
+ ceil = Math.ceil,
+ clearTimeout = context.clearTimeout,
+ floor = Math.floor,
+ getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
+ push = arrayProto.push,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ Set = isNative(Set = context.Set) && Set,
+ setTimeout = context.setTimeout,
+ splice = arrayProto.splice,
+ Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array,
+ unshift = arrayProto.unshift,
+ WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap;
+
+ /** Used to clone array buffers. */
+ var Float64Array = (function() {
+ // Safari 5 errors when using an array buffer to initialize a typed array
+ // where the array buffer's `byteLength` is not a multiple of the typed
+ // array's `BYTES_PER_ELEMENT`.
+ try {
+ var func = isNative(func = context.Float64Array) && func,
+ result = new func(new ArrayBuffer(10), 0, 1) && func;
+ } catch(e) {}
+ return result;
+ }());
+
+ /* Native method references for those with the same name as other `lodash` methods. */
+ var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
+ nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
+ nativeIsFinite = context.isFinite,
+ nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
+ nativeMax = Math.max,
+ nativeMin = Math.min,
+ nativeNow = isNative(nativeNow = Date.now) && nativeNow,
+ nativeNumIsFinite = isNative(nativeNumIsFinite = Number.isFinite) && nativeNumIsFinite,
+ nativeParseInt = context.parseInt,
+ nativeRandom = Math.random;
+
+ /** Used as references for `-Infinity` and `Infinity`. */
+ var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY,
+ POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
+
+ /** Used as references for the maximum length and index of an array. */
+ var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1,
+ MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+ HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+ /** Used as the size, in bytes, of each `Float64Array` element. */
+ var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;
+
+ /**
+ * Used as the maximum length of an array-like value.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
+ * for more details.
+ */
+ var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
+
+ /** Used to store function metadata. */
+ var metaMap = WeakMap && new WeakMap;
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object which wraps `value` to enable intuitive chaining.
+ * Methods that operate on and return arrays, collections, and functions can
+ * be chained together. Methods that return a boolean or single value will
+ * automatically end the chain returning the unwrapped value. Explicit chaining
+ * may be enabled using `_.chain`. The execution of chained methods is lazy,
+ * that is, execution is deferred until `_#value` is implicitly or explicitly
+ * called.
+ *
+ * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
+ * fusion is an optimization that merges iteratees to avoid creating intermediate
+ * arrays and reduce the number of iteratee executions.
+ *
+ * Chaining is supported in custom builds as long as the `_#value` method is
+ * directly or indirectly included in the build.
+ *
+ * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
+ * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
+ * and `unshift`
+ *
+ * The wrapper functions that support shortcut fusion are:
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `first`,
+ * `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, `slice`,
+ * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `where`
+ *
+ * The chainable wrapper functions are:
+ * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
+ * `callback`, `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`,
+ * `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`,
+ * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`,
+ * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`,
+ * `initial`, `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`,
+ * `mapValues`, `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`,
+ * `omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`,
+ * `pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`,
+ * `rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
+ * `sortBy`, `sortByAll`, `splice`, `take`, `takeRight`, `takeRightWhile`,
+ * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
+ * `transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`,
+ * `where`, `without`, `wrap`, `xor`, `zip`, and `zipObject`
+ *
+ * The wrapper functions that are **not** chainable by default are:
+ * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
+ * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`,
+ * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`,
+ * `identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`,
+ * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`,
+ * `isFunction`, `isMatch` , `isNative`, `isNaN`, `isNull`, `isNumber`,
+ * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`,
+ * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`,
+ * `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`,
+ * `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`,
+ * `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`,
+ * `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
+ * `unescape`, `uniqueId`, `value`, and `words`
+ *
+ * The wrapper function `sample` will return a wrapped value when `n` is provided,
+ * otherwise an unwrapped value is returned.
+ *
+ * @name _
+ * @constructor
+ * @category Chain
+ * @param {*} value The value to wrap in a `lodash` instance.
+ * @returns {Object} Returns a `lodash` instance.
+ * @example
+ *
+ * var wrapped = _([1, 2, 3]);
+ *
+ * // returns an unwrapped value
+ * wrapped.reduce(function(sum, n) { return sum + n; });
+ * // => 6
+ *
+ * // returns a wrapped value
+ * var squares = wrapped.map(function(n) { return n * n; });
+ *
+ * _.isArray(squares);
+ * // => false
+ *
+ * _.isArray(squares.value());
+ * // => true
+ */
+ function lodash(value) {
+ if (isObjectLike(value) && !isArray(value)) {
+ if (value instanceof LodashWrapper) {
+ return value;
+ }
+ if (hasOwnProperty.call(value, '__wrapped__')) {
+ return new LodashWrapper(value.__wrapped__, value.__chain__, arrayCopy(value.__actions__));
+ }
+ }
+ return new LodashWrapper(value);
+ }
+
+ /**
+ * The base constructor for creating `lodash` wrapper objects.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
+ * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
+ */
+ function LodashWrapper(value, chainAll, actions) {
+ this.__actions__ = actions || [];
+ this.__chain__ = !!chainAll;
+ this.__wrapped__ = value;
+ }
+
+ /**
+ * An object environment feature flags.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ var support = lodash.support = {};
+
+ (function(x) {
+
+ /**
+ * Detect if functions can be decompiled by `Function#toString`
+ * (all but Firefox OS certified apps, older Opera mobile browsers, and
+ * the PlayStation 3; forced `false` for Windows 8 apps).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
+
+ /**
+ * Detect if `Function#name` is supported (all but IE).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcNames = typeof Function.name == 'string';
+
+ /**
+ * Detect if the DOM is supported.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ try {
+ support.dom = document.createDocumentFragment().nodeType === 11;
+ } catch(e) {
+ support.dom = false;
+ }
+
+ /**
+ * Detect if `arguments` object indexes are non-enumerable.
+ *
+ * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object
+ * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat
+ * `arguments` object indexes as non-enumerable and fail `hasOwnProperty`
+ * checks for indexes that exceed their function's formal parameters with
+ * associated values of `0`.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ try {
+ support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1);
+ } catch(e) {
+ support.nonEnumArgs = true;
+ }
+ }(0, 0));
+
+ /**
+ * By default, the template delimiters used by Lo-Dash are like those in
+ * embedded Ruby (ERB). Change the following template settings to use
+ * alternative delimiters.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ lodash.templateSettings = {
+
+ /**
+ * Used to detect `data` property values to be HTML-escaped.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'escape': reEscape,
+
+ /**
+ * Used to detect code to be evaluated.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'evaluate': reEvaluate,
+
+ /**
+ * Used to detect `data` property values to inject.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'interpolate': reInterpolate,
+
+ /**
+ * Used to reference the data object in the template text.
+ *
+ * @memberOf _.templateSettings
+ * @type string
+ */
+ 'variable': '',
+
+ /**
+ * Used to import variables into the compiled template.
+ *
+ * @memberOf _.templateSettings
+ * @type Object
+ */
+ 'imports': {
+
+ /**
+ * A reference to the `lodash` function.
+ *
+ * @memberOf _.templateSettings.imports
+ * @type Function
+ */
+ '_': lodash
+ }
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ */
+ function LazyWrapper(value) {
+ this.actions = null;
+ this.dir = 1;
+ this.dropCount = 0;
+ this.filtered = false;
+ this.iteratees = null;
+ this.takeCount = POSITIVE_INFINITY;
+ this.views = null;
+ this.wrapped = value;
+ }
+
+ /**
+ * Creates a clone of the lazy wrapper object.
+ *
+ * @private
+ * @name clone
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the cloned `LazyWrapper` object.
+ */
+ function lazyClone() {
+ var actions = this.actions,
+ iteratees = this.iteratees,
+ views = this.views,
+ result = new LazyWrapper(this.wrapped);
+
+ result.actions = actions ? arrayCopy(actions) : null;
+ result.dir = this.dir;
+ result.dropCount = this.dropCount;
+ result.filtered = this.filtered;
+ result.iteratees = iteratees ? arrayCopy(iteratees) : null;
+ result.takeCount = this.takeCount;
+ result.views = views ? arrayCopy(views) : null;
+ return result;
+ }
+
+ /**
+ * Reverses the direction of lazy iteration.
+ *
+ * @private
+ * @name reverse
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the new reversed `LazyWrapper` object.
+ */
+ function lazyReverse() {
+ var filtered = this.filtered,
+ result = filtered ? new LazyWrapper(this) : this.clone();
+
+ result.dir = this.dir * -1;
+ result.filtered = filtered;
+ return result;
+ }
+
+ /**
+ * Extracts the unwrapped value from its lazy wrapper.
+ *
+ * @private
+ * @name value
+ * @memberOf LazyWrapper
+ * @returns {*} Returns the unwrapped value.
+ */
+ function lazyValue() {
+ var array = this.wrapped.value();
+ if (!isArray(array)) {
+ return baseWrapperValue(array, this.actions);
+ }
+ var dir = this.dir,
+ isRight = dir < 0,
+ length = array.length,
+ view = getView(0, length, this.views),
+ start = view.start,
+ end = view.end,
+ dropCount = this.dropCount,
+ takeCount = nativeMin(end - start, this.takeCount - dropCount),
+ index = isRight ? end : start - 1,
+ iteratees = this.iteratees,
+ iterLength = iteratees ? iteratees.length : 0,
+ resIndex = 0,
+ result = [];
+
+ outer:
+ while (length-- && resIndex < takeCount) {
+ index += dir;
+
+ var iterIndex = -1,
+ value = array[index];
+
+ while (++iterIndex < iterLength) {
+ var data = iteratees[iterIndex],
+ iteratee = data.iteratee,
+ computed = iteratee(value, index, array),
+ type = data.type;
+
+ if (type == LAZY_MAP_FLAG) {
+ value = computed;
+ } else if (!computed) {
+ if (type == LAZY_FILTER_FLAG) {
+ continue outer;
+ } else {
+ break outer;
+ }
+ }
+ }
+ if (dropCount) {
+ dropCount--;
+ } else {
+ result[resIndex++] = value;
+ }
+ }
+ return isRight ? result.reverse() : result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a cache object to store key/value pairs.
+ *
+ * @private
+ * @static
+ * @name Cache
+ * @memberOf _.memoize
+ */
+ function MapCache() {
+ this.__data__ = {};
+ }
+
+ /**
+ * Removes `key` and its value from the cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`.
+ */
+ function mapDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the cached value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the cached value.
+ */
+ function mapGet(key) {
+ return key == '__proto__' ? undefined : this.__data__[key];
+ }
+
+ /**
+ * Checks if a cached value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapHas(key) {
+ return key != '__proto__' && hasOwnProperty.call(this.__data__, key);
+ }
+
+ /**
+ * Adds `value` to `key` of the cache.
+ *
+ * @private
+ * @name set
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to cache.
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache object.
+ */
+ function mapSet(key, value) {
+ if (key != '__proto__') {
+ this.__data__[key] = value;
+ }
+ return this;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ *
+ * Creates a cache object to store unique values.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var length = values ? values.length : 0;
+
+ this.data = { 'hash': nativeCreate(null), 'set': new Set };
+ while (length--) {
+ this.push(values[length]);
+ }
+ }
+
+ /**
+ * Checks if `value` is in `cache` mimicking the return signature of
+ * `_.indexOf` by returning `0` if the value is found, else `-1`.
+ *
+ * @private
+ * @param {Object} cache The cache to search.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `0` if `value` is found, else `-1`.
+ */
+ function cacheIndexOf(cache, value) {
+ var data = cache.data,
+ result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
+
+ return result ? 0 : -1;
+ }
+
+ /**
+ * Adds `value` to the cache.
+ *
+ * @private
+ * @name push
+ * @memberOf SetCache
+ * @param {*} value The value to cache.
+ */
+ function cachePush(value) {
+ var data = this.data;
+ if (typeof value == 'string' || isObject(value)) {
+ data.set.add(value);
+ } else {
+ data.hash[value] = true;
+ }
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayCopy(source, array) {
+ var index = -1,
+ length = source.length;
+
+ array || (array = Array(length));
+ while (++index < length) {
+ array[index] = source[index];
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEach` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEachRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEachRight(array, iteratee) {
+ var length = array.length;
+
+ while (length--) {
+ if (iteratee(array[length], length, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.every` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ */
+ function arrayEvery(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (!predicate(array[index], index, array)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A specialized version of `_.filter` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function arrayFilter(array, predicate) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.map` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function arrayMap(array, iteratee) {
+ var index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = iteratee(array[index], index, array);
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.max` for arrays without support for iteratees.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the maximum value.
+ */
+ function arrayMax(array) {
+ var index = -1,
+ length = array.length,
+ result = NEGATIVE_INFINITY;
+
+ while (++index < length) {
+ var value = array[index];
+ if (value > result) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.min` for arrays without support for iteratees.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the minimum value.
+ */
+ function arrayMin(array) {
+ var index = -1,
+ length = array.length,
+ result = POSITIVE_INFINITY;
+
+ while (++index < length) {
+ var value = array[index];
+ if (value < result) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.reduce` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the first element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduce(array, iteratee, accumulator, initFromArray) {
+ var index = -1,
+ length = array.length;
+
+ if (initFromArray && length) {
+ accumulator = array[++index];
+ }
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.reduceRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the last element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduceRight(array, iteratee, accumulator, initFromArray) {
+ var length = array.length;
+ if (initFromArray && length) {
+ accumulator = array[--length];
+ }
+ while (length--) {
+ accumulator = iteratee(accumulator, array[length], length, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.some` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Used by `_.defaults` to customize its `_.assign` use.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignDefaults(objectValue, sourceValue) {
+ return typeof objectValue == 'undefined' ? sourceValue : objectValue;
+ }
+
+ /**
+ * Used by `_.template` to customize its `_.assign` use.
+ *
+ * **Note:** This method is like `assignDefaults` except that it ignores
+ * inherited property values when checking if a property is `undefined`.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @param {string} key The key associated with the object and source values.
+ * @param {Object} object The destination object.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignOwnDefaults(objectValue, sourceValue, key, object) {
+ return (typeof objectValue == 'undefined' || !hasOwnProperty.call(object, key))
+ ? sourceValue
+ : objectValue;
+ }
+
+ /**
+ * The base implementation of `_.assign` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseAssign(object, source, customizer) {
+ var props = keys(source);
+ if (!customizer) {
+ return baseCopy(source, object, props);
+ }
+ var index = -1,
+ length = props.length
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key],
+ result = customizer(value, source[key], key, object, source);
+
+ if ((result === result ? result !== value : value === value) ||
+ (typeof value == 'undefined' && !(key in object))) {
+ object[key] = result;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.at` without support for strings and individual
+ * key arguments.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {number[]|string[]} [props] The property names or indexes of elements to pick.
+ * @returns {Array} Returns the new array of picked elements.
+ */
+ function baseAt(collection, props) {
+ var index = -1,
+ length = collection.length,
+ isArr = isLength(length),
+ propsLength = props.length,
+ result = Array(propsLength);
+
+ while(++index < propsLength) {
+ var key = props[index];
+ if (isArr) {
+ key = parseFloat(key);
+ result[index] = isIndex(key, length) ? collection[key] : undefined;
+ } else {
+ result[index] = collection[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copies the properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Array} props The property names to copy.
+ * @returns {Object} Returns `object`.
+ */
+ function baseCopy(source, object, props) {
+ if (!props) {
+ props = object;
+ object = {};
+ }
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ object[key] = source[key];
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.bindAll` without support for individual
+ * method name arguments.
+ *
+ * @private
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {string[]} methodNames The object method names to bind.
+ * @returns {Object} Returns `object`.
+ */
+ function baseBindAll(object, methodNames) {
+ var index = -1,
+ length = methodNames.length;
+
+ while (++index < length) {
+ var key = methodNames[index];
+ object[key] = createWrapper(object[key], BIND_FLAG, object);
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.callback` which supports specifying the
+ * number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function baseCallback(func, thisArg, argCount) {
+ var type = typeof func;
+ if (type == 'function') {
+ return (typeof thisArg != 'undefined' && isBindable(func))
+ ? bindCallback(func, thisArg, argCount)
+ : func;
+ }
+ if (func == null) {
+ return identity;
+ }
+ // Handle "_.property" and "_.matches" style callback shorthands.
+ return type == 'object'
+ ? baseMatches(func, !argCount)
+ : baseProperty(argCount ? baseToString(func) : func);
+ }
+
+ /**
+ * The base implementation of `_.clone` without support for argument juggling
+ * and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The object `value` belongs to.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates clones with source counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
+ var result;
+ if (customizer) {
+ result = object ? customizer(value, key, object) : customizer(value);
+ }
+ if (typeof result != 'undefined') {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return arrayCopy(value, result);
+ }
+ } else {
+ var tag = objToString.call(value),
+ isFunc = tag == funcTag;
+
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ result = initCloneObject(isFunc ? {} : value);
+ if (!isDeep) {
+ return baseCopy(value, result, keys(value));
+ }
+ } else {
+ return cloneableTags[tag]
+ ? initCloneByTag(value, tag, isDeep)
+ : (object ? value : {});
+ }
+ }
+ // Check for circular references and return corresponding clone.
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == value) {
+ return stackB[length];
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate it with its clone.
+ stackA.push(value);
+ stackB.push(result);
+
+ // Recursively populate clone (susceptible to call stack limits).
+ (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
+ result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+ var baseCreate = (function() {
+ function Object() {}
+ return function(prototype) {
+ if (isObject(prototype)) {
+ Object.prototype = prototype;
+ var result = new Object;
+ Object.prototype = null;
+ }
+ return result || context.Object();
+ };
+ }());
+
+ /**
+ * The base implementation of `_.delay` and `_.defer` which accepts an index
+ * of where to slice the arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {Object} args The `arguments` object to slice and provide to `func`.
+ * @returns {number} Returns the timer id.
+ */
+ function baseDelay(func, wait, args, fromIndex) {
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return setTimeout(function() { func.apply(undefined, baseSlice(args, fromIndex)); }, wait);
+ }
+
+ /**
+ * The base implementation of `_.difference` which accepts a single array
+ * of values to exclude.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Array} values The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ */
+ function baseDifference(array, values) {
+ var length = array ? array.length : 0,
+ result = [];
+
+ if (!length) {
+ return result;
+ }
+ var index = -1,
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf,
+ cache = isCommon && values.length >= 200 && createCache(values),
+ valuesLength = values.length;
+
+ if (cache) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ values = cache;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index];
+
+ if (isCommon && value === value) {
+ var valuesIndex = valuesLength;
+ while (valuesIndex--) {
+ if (values[valuesIndex] === value) {
+ continue outer;
+ }
+ }
+ result.push(value);
+ }
+ else if (indexOf(values, value) < 0) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.forEach` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEach(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwn(collection, iteratee);
+ }
+ var index = -1,
+ iterable = toObject(collection);
+
+ while (++index < length) {
+ if (iteratee(iterable[index], index, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.forEachRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEachRight(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwnRight(collection, iteratee);
+ }
+ var iterable = toObject(collection);
+ while (length--) {
+ if (iteratee(iterable[length], length, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.every` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`
+ */
+ function baseEvery(collection, predicate) {
+ var result = true;
+ baseEach(collection, function(value, index, collection) {
+ result = !!predicate(value, index, collection);
+ return result;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.filter` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function baseFilter(collection, predicate) {
+ var result = [];
+ baseEach(collection, function(value, index, collection) {
+ if (predicate(value, index, collection)) {
+ result.push(value);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
+ * without support for callback shorthands and `this` binding, which iterates
+ * over `collection` using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @param {boolean} [retKey] Specify returning the key of the found element
+ * instead of the element itself.
+ * @returns {*} Returns the found element or its key, else `undefined`.
+ */
+ function baseFind(collection, predicate, eachFunc, retKey) {
+ var result;
+ eachFunc(collection, function(value, key, collection) {
+ if (predicate(value, key, collection)) {
+ result = retKey ? key : value;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.flatten` with added support for restricting
+ * flattening and specifying the start index.
+ *
+ * @private
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param {boolean} [isStrict] Restrict flattening to arrays and `arguments` objects.
+ * @param {number} [fromIndex=0] The index to start from.
+ * @returns {Array} Returns the new flattened array.
+ */
+ function baseFlatten(array, isDeep, isStrict, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+
+ if (isObjectLike(value) && isLength(value.length) && (isArray(value) || isArguments(value))) {
+ if (isDeep) {
+ // Recursively flatten arrays (susceptible to call stack limits).
+ value = baseFlatten(value, isDeep, isStrict);
+ }
+ var valIndex = -1,
+ valLength = value.length;
+
+ result.length += valLength;
+ while (++valIndex < valLength) {
+ result[++resIndex] = value[valIndex];
+ }
+ } else if (!isStrict) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `baseForIn` and `baseForOwn` which iterates
+ * over `object` properties returned by `keysFunc` invoking `iteratee` for
+ * each property. Iterator functions may exit iteration early by explicitly
+ * returning `false`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ function baseFor(object, iteratee, keysFunc) {
+ var index = -1,
+ iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * This function is like `baseFor` except that it iterates over properties
+ * in the opposite order.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForRight(object, iteratee, keysFunc) {
+ var iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (length--) {
+ var key = props[length];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.forIn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForIn(object, iteratee) {
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * The base implementation of `_.forOwn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwn(object, iteratee) {
+ return baseFor(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.forOwnRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwnRight(object, iteratee) {
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.functions` which creates an array of
+ * `object` function property names filtered from those provided.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Array} props The property names to filter.
+ * @returns {Array} Returns the new array of filtered property names.
+ */
+ function baseFunctions(object, props) {
+ var index = -1,
+ length = props.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var key = props[index];
+ if (isFunction(object[key])) {
+ result[++resIndex] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.invoke` which requires additional arguments
+ * to be provided as an array of arguments rather than individually.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {Array} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseInvoke(collection, methodName, args) {
+ var index = -1,
+ isFunc = typeof methodName == 'function',
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value) {
+ var func = isFunc ? methodName : (value != null && value[methodName]);
+ result[++index] = func ? func.apply(value, args) : undefined;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isEqual` without support for `this` binding
+ * `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, customizer, isWhere, stackA, stackB) {
+ // Exit early for identical values.
+ if (value === other) {
+ // Treat `+0` vs. `-0` as not equal.
+ return value !== 0 || (1 / value == 1 / other);
+ }
+ var valType = typeof value,
+ othType = typeof other;
+
+ // Exit early for unlike primitive values.
+ if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') ||
+ value == null || other == null) {
+ // Return `false` unless both values are `NaN`.
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, baseIsEqual, customizer, isWhere, stackA, stackB);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA=[]] Tracks traversed `value` objects.
+ * @param {Array} [stackB=[]] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = arrayTag,
+ othTag = arrayTag;
+
+ if (!objIsArr) {
+ objTag = objToString.call(object);
+ if (objTag == argsTag) {
+ objTag = objectTag;
+ } else if (objTag != objectTag) {
+ objIsArr = isTypedArray(object);
+ }
+ }
+ if (!othIsArr) {
+ othTag = objToString.call(other);
+ if (othTag == argsTag) {
+ othTag = objectTag;
+ } else if (othTag != objectTag) {
+ othIsArr = isTypedArray(other);
+ }
+ }
+ var objIsObj = objTag == objectTag,
+ othIsObj = othTag == objectTag,
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && !(objIsArr || objIsObj)) {
+ return equalByTag(object, other, objTag);
+ }
+ var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (valWrapped || othWrapped) {
+ return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isWhere, stackA, stackB);
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ // Assume cyclic structures are equal.
+ // The algorithm for detecting cyclic structures is adapted from ES 5.1
+ // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3).
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == object) {
+ return stackB[length] == other;
+ }
+ }
+ // Add `object` and `other` to the stack of traversed objects.
+ stackA.push(object);
+ stackB.push(other);
+
+ var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isWhere, stackA, stackB);
+
+ stackA.pop();
+ stackB.pop();
+
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isMatch` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Object} source The object to inspect.
+ * @param {Array} props The source property names to match.
+ * @param {Array} values The source values to match.
+ * @param {Array} strictCompareFlags Strict comparison flags for source values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ */
+ function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
+ var length = props.length;
+ if (object == null) {
+ return !length;
+ }
+ var index = -1,
+ noCustomizer = !customizer;
+
+ while (++index < length) {
+ if ((noCustomizer && strictCompareFlags[index])
+ ? values[index] !== object[props[index]]
+ : !hasOwnProperty.call(object, props[index])
+ ) {
+ return false;
+ }
+ }
+ index = -1;
+ while (++index < length) {
+ var key = props[index];
+ if (noCustomizer && strictCompareFlags[index]) {
+ var result = hasOwnProperty.call(object, key);
+ } else {
+ var objValue = object[key],
+ srcValue = values[index];
+
+ result = customizer ? customizer(objValue, srcValue, key) : undefined;
+ if (typeof result == 'undefined') {
+ result = baseIsEqual(srcValue, objValue, customizer, true);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.map` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function baseMap(collection, iteratee) {
+ var result = [];
+ baseEach(collection, function(value, key, collection) {
+ result.push(iteratee(value, key, collection));
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.matches` which supports specifying whether
+ * `source` should be cloned.
+ *
+ * @private
+ * @param {Object} source The object of property values to match.
+ * @param {boolean} [isCloned] Specify cloning the source object.
+ * @returns {Function} Returns the new function.
+ */
+ function baseMatches(source, isCloned) {
+ var props = keys(source),
+ length = props.length;
+
+ if (length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return function(object) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ };
+ }
+ }
+ if (isCloned) {
+ source = baseClone(source, true);
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = source[props[length]];
+ values[length] = value;
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return function(object) {
+ return baseIsMatch(object, props, values, strictCompareFlags);
+ };
+ }
+
+ /**
+ * The base implementation of `_.merge` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseMerge(object, source, customizer, stackA, stackB) {
+ var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
+
+ (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
+ if (isObjectLike(srcValue)) {
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+ return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ }
+ if ((isSrcArr || typeof result != 'undefined') &&
+ (isCommon || (result === result ? result !== value : value === value))) {
+ object[key] = result;
+ }
+ });
+ return object;
+ }
+
+ /**
+ * A specialized version of `baseMerge` for arrays and objects which performs
+ * deep merges and tracks traversed objects enabling objects with circular
+ * references to be merged.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {string} key The key of the value to merge.
+ * @param {Function} mergeFunc The function to merge values.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
+ var length = stackA.length,
+ srcValue = source[key];
+
+ while (length--) {
+ if (stackA[length] == srcValue) {
+ object[key] = stackB[length];
+ return;
+ }
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) {
+ result = isArray(value)
+ ? value
+ : (value ? arrayCopy(value) : []);
+ }
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+ result = isArguments(value)
+ ? toPlainObject(value)
+ : (isPlainObject(value) ? value : {});
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate
+ // it with its merged value.
+ stackA.push(srcValue);
+ stackB.push(result);
+
+ if (isCommon) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
+ } else if (result === result ? result !== value : value === value) {
+ object[key] = result;
+ }
+ }
+
+ /**
+ * The base implementation of `_.property` which does not coerce `key` to a string.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * The base implementation of `_.pullAt` without support for individual
+ * index arguments.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {number[]} indexes The indexes of elements to remove.
+ * @returns {Array} Returns the new array of removed elements.
+ */
+ function basePullAt(array, indexes) {
+ var length = indexes.length,
+ result = baseAt(array, indexes);
+
+ indexes.sort(baseCompareAscending);
+ while (length--) {
+ var index = parseFloat(indexes[length]);
+ if (index != previous && isIndex(index)) {
+ var previous = index;
+ splice.call(array, index, 1);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.random` without support for argument juggling
+ * and returning floating-point numbers.
+ *
+ * @private
+ * @param {number} min The minimum possible value.
+ * @param {number} max The maximum possible value.
+ * @returns {number} Returns the random number.
+ */
+ function baseRandom(min, max) {
+ return min + floor(nativeRandom() * (max - min + 1));
+ }
+
+ /**
+ * The base implementation of `_.reduce` and `_.reduceRight` without support
+ * for callback shorthands or `this` binding, which iterates over `collection`
+ * using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} accumulator The initial value.
+ * @param {boolean} initFromCollection Specify using the first or last element
+ * of `collection` as the initial value.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @returns {*} Returns the accumulated value.
+ */
+ function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
+ eachFunc(collection, function(value, index, collection) {
+ accumulator = initFromCollection
+ ? (initFromCollection = false, value)
+ : iteratee(accumulator, value, index, collection)
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `setData` without support for hot loop detection.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var baseSetData = !metaMap ? identity : function(func, data) {
+ metaMap.set(func, data);
+ return func;
+ };
+
+ /**
+ * The base implementation of `_.slice` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseSlice(array, start, end) {
+ var index = -1,
+ length = array.length;
+
+ start = start == null ? 0 : (+start || 0);
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = (typeof end == 'undefined' || end > length) ? length : (+end || 0);
+ if (end < 0) {
+ end += length;
+ }
+ length = start > end ? 0 : (end - start);
+
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = array[index + start];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.some` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function baseSome(collection, predicate) {
+ var result;
+
+ baseEach(collection, function(value, index, collection) {
+ result = predicate(value, index, collection);
+ return !result;
+ });
+ return !!result;
+ }
+
+ /**
+ * The base implementation of `_.uniq` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function baseUniq(array, iteratee) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = array.length,
+ isCommon = indexOf == baseIndexOf,
+ isLarge = isCommon && length >= 200,
+ seen = isLarge && createCache(),
+ result = [];
+
+ if (seen) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ } else {
+ isLarge = false;
+ seen = iteratee ? [] : result;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (isCommon && value === value) {
+ var seenIndex = seen.length;
+ while (seenIndex--) {
+ if (seen[seenIndex] === computed) {
+ continue outer;
+ }
+ }
+ if (iteratee) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ else if (indexOf(seen, computed) < 0) {
+ if (iteratee || isLarge) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.values` and `_.valuesIn` which creates an
+ * array of `object` property values corresponding to the property names
+ * returned by `keysFunc`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} props The property names to get values for.
+ * @returns {Object} Returns the array of property values.
+ */
+ function baseValues(object, props) {
+ var index = -1,
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = object[props[index]];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `wrapperValue` which returns the result of
+ * performing a sequence of actions on the unwrapped `value`, where each
+ * successive action is supplied the return value of the previous.
+ *
+ * @private
+ * @param {*} value The unwrapped value.
+ * @param {Array} actions Actions to peform to resolve the unwrapped value.
+ * @returns {*} Returns the resolved unwrapped value.
+ */
+ function baseWrapperValue(value, actions) {
+ var result = value;
+ if (result instanceof LazyWrapper) {
+ result = result.value();
+ }
+ var index = -1,
+ length = actions.length;
+
+ while (++index < length) {
+ var args = [result],
+ action = actions[index];
+
+ push.apply(args, action.args);
+ result = action.func.apply(action.thisArg, args);
+ }
+ return result;
+ }
+
+ /**
+ * Performs a binary search of `array` to determine the index at which `value`
+ * should be inserted into `array` in order to maintain its sort order.
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndex(array, value, retHighest) {
+ var low = 0,
+ high = array ? array.length : low;
+
+ if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+ while (low < high) {
+ var mid = (low + high) >>> 1,
+ computed = array[mid];
+
+ if (retHighest ? (computed <= value) : (computed < value)) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return high;
+ }
+ return binaryIndexBy(array, value, identity, retHighest);
+ }
+
+ /**
+ * This function is like `binaryIndex` except that it invokes `iteratee` for
+ * `value` and each element of `array` to compute their sort ranking. The
+ * iteratee is invoked with one argument; (value).
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndexBy(array, value, iteratee, retHighest) {
+ value = iteratee(value);
+
+ var low = 0,
+ high = array ? array.length : 0,
+ valIsNaN = value !== value,
+ valIsUndef = typeof value == 'undefined';
+
+ while (low < high) {
+ var mid = floor((low + high) / 2),
+ computed = iteratee(array[mid]),
+ isReflexive = computed === computed;
+
+ if (valIsNaN) {
+ var setLow = isReflexive || retHighest;
+ } else if (valIsUndef) {
+ setLow = isReflexive && (retHighest || typeof computed != 'undefined');
+ } else {
+ setLow = retHighest ? (computed <= value) : (computed < value);
+ }
+ if (setLow) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return nativeMin(high, MAX_ARRAY_INDEX);
+ }
+
+ /**
+ * A specialized version of `baseCallback` which only supports `this` binding
+ * and specifying the number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function bindCallback(func, thisArg, argCount) {
+ if (typeof func != 'function') {
+ return identity;
+ }
+ if (typeof thisArg == 'undefined') {
+ return func;
+ }
+ switch (argCount) {
+ case 1: return function(value) {
+ return func.call(thisArg, value);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ case 5: return function(value, other, key, object, source) {
+ return func.call(thisArg, value, other, key, object, source);
+ };
+ }
+ return function() {
+ return func.apply(thisArg, arguments);
+ };
+ }
+
+ /**
+ * Creates a clone of the given array buffer.
+ *
+ * @private
+ * @param {ArrayBuffer} buffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+ function bufferClone(buffer) {
+ return bufferSlice.call(buffer, 0);
+ }
+ if (!bufferSlice) {
+ // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`.
+ bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) {
+ var byteLength = buffer.byteLength,
+ floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
+ offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
+ result = new ArrayBuffer(byteLength);
+
+ if (floatLength) {
+ var view = new Float64Array(result, 0, floatLength);
+ view.set(new Float64Array(buffer, 0, floatLength));
+ }
+ if (byteLength != offset) {
+ view = new Uint8Array(result, offset);
+ view.set(new Uint8Array(buffer, offset));
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates an array that is the composition of partially applied arguments,
+ * placeholders, and provided arguments into a single array of arguments.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to prepend to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgs(args, partials, holders) {
+ var holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ leftIndex = -1,
+ leftLength = partials.length,
+ result = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ result[leftIndex] = partials[leftIndex];
+ }
+ while (++argsIndex < holdersLength) {
+ result[holders[argsIndex]] = args[argsIndex];
+ }
+ while (argsLength--) {
+ result[leftIndex++] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * This function is like `composeArgs` except that the arguments composition
+ * is tailored for `_.partialRight`.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to append to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgsRight(args, partials, holders) {
+ var holdersIndex = -1,
+ holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ rightIndex = -1,
+ rightLength = partials.length,
+ result = Array(argsLength + rightLength);
+
+ while (++argsIndex < argsLength) {
+ result[argsIndex] = args[argsIndex];
+ }
+ var pad = argsIndex;
+ while (++rightIndex < rightLength) {
+ result[pad + rightIndex] = partials[rightIndex];
+ }
+ while (++holdersIndex < holdersLength) {
+ result[pad + holders[holdersIndex]] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * Creates a function that aggregates a collection, creating an accumulator
+ * object composed from the results of running each element in the collection
+ * through an iteratee. The `setter` sets the keys and values of the accumulator
+ * object. If `initializer` is provided initializes the accumulator object.
+ *
+ * @private
+ * @param {Function} setter The function to set keys and values of the accumulator object.
+ * @param {Function} [initializer] The function to initialize the accumulator object.
+ * @returns {Function} Returns the new aggregator function.
+ */
+ function createAggregator(setter, initializer) {
+ return function(collection, iteratee, thisArg) {
+ var result = initializer ? initializer() : {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ setter(result, value, iteratee(value, index, collection), collection);
+ }
+ } else {
+ baseEach(collection, function(value, key, collection) {
+ setter(result, value, iteratee(value, key, collection), collection);
+ });
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that assigns properties of source object(s) to a given
+ * destination object.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return function() {
+ var length = arguments.length,
+ object = arguments[0];
+
+ if (length < 2 || object == null) {
+ return object;
+ }
+ if (length > 3 && isIterateeCall(arguments[1], arguments[2], arguments[3])) {
+ length = 2;
+ }
+ // Juggle arguments.
+ if (length > 3 && typeof arguments[length - 2] == 'function') {
+ var customizer = bindCallback(arguments[--length - 1], arguments[length--], 5);
+ } else if (length > 2 && typeof arguments[length - 1] == 'function') {
+ customizer = arguments[--length];
+ }
+ var index = 0;
+ while (++index < length) {
+ var source = arguments[index];
+ if (source) {
+ assigner(object, source, customizer);
+ }
+ }
+ return object;
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the `this`
+ * binding of `thisArg`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createBindWrapper(func, thisArg) {
+ var Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ return (this instanceof wrapper ? Ctor : func).apply(thisArg, arguments);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `Set` cache object to optimize linear searches of large arrays.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
+ */
+ var createCache = !(nativeCreate && Set) ? constant(null) : function(values) {
+ return new SetCache(values);
+ };
+
+ /**
+ * Creates a function that produces compound words out of the words in a
+ * given string.
+ *
+ * @private
+ * @param {Function} callback The function to combine each word.
+ * @returns {Function} Returns the new compounder function.
+ */
+ function createCompounder(callback) {
+ return function(string) {
+ var index = -1,
+ array = words(deburr(string)),
+ length = array.length,
+ result = '';
+
+ while (++index < length) {
+ result = callback(result, array[index], index);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that produces an instance of `Ctor` regardless of
+ * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+ *
+ * @private
+ * @param {Function} Ctor The constructor to wrap.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createCtorWrapper(Ctor) {
+ return function() {
+ var thisBinding = baseCreate(Ctor.prototype),
+ result = Ctor.apply(thisBinding, arguments);
+
+ // Mimic the constructor's `return` behavior.
+ // See http://es5.github.io/#x13.2.2.
+ return isObject(result) ? result : thisBinding;
+ };
+ }
+
+ /**
+ * Creates a function that gets the extremum value of a collection.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to get the extremum value from an array.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the maximum,
+ * extremum value.
+ * @returns {Function} Returns the new extremum function.
+ */
+ function createExtremum(arrayFunc, isMin) {
+ return function(collection, iteratee, thisArg) {
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ var func = getCallback(),
+ noIteratee = iteratee == null;
+
+ if (!(func === baseCallback && noIteratee)) {
+ noIteratee = false;
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ if (noIteratee) {
+ var isArr = isArray(collection);
+ if (!isArr && isString(collection)) {
+ iteratee = charAtCallback;
+ } else {
+ return arrayFunc(isArr ? collection : toIterable(collection));
+ }
+ }
+ return extremumBy(collection, iteratee, isMin);
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with optional `this`
+ * binding of, partial application, and currying.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
+ * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+ var isAry = bitmask & ARY_FLAG,
+ isBind = bitmask & BIND_FLAG,
+ isBindKey = bitmask & BIND_KEY_FLAG,
+ isCurry = bitmask & CURRY_FLAG,
+ isCurryBound = bitmask & CURRY_BOUND_FLAG,
+ isCurryRight = bitmask & CURRY_RIGHT_FLAG;
+
+ var Ctor = !isBindKey && createCtorWrapper(func),
+ key = func;
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it to other functions.
+ var length = arguments.length,
+ index = length,
+ args = Array(length);
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ if (partials) {
+ args = composeArgs(args, partials, holders);
+ }
+ if (partialsRight) {
+ args = composeArgsRight(args, partialsRight, holdersRight);
+ }
+ if (isCurry || isCurryRight) {
+ var placeholder = wrapper.placeholder,
+ argsHolders = replaceHolders(args, placeholder);
+
+ length -= argsHolders.length;
+ if (length < arity) {
+ var newArgPos = argPos ? arrayCopy(argPos) : null,
+ newArity = nativeMax(arity - length, 0),
+ newsHolders = isCurry ? argsHolders : null,
+ newHoldersRight = isCurry ? null : argsHolders,
+ newPartials = isCurry ? args : null,
+ newPartialsRight = isCurry ? null : args;
+
+ bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
+ bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
+
+ if (!isCurryBound) {
+ bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
+ }
+ var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity);
+ result.placeholder = placeholder;
+ return result;
+ }
+ }
+ var thisBinding = isBind ? thisArg : this;
+ if (isBindKey) {
+ func = thisBinding[key];
+ }
+ if (argPos) {
+ args = reorder(args, argPos);
+ }
+ if (isAry && ary < args.length) {
+ args.length = ary;
+ }
+ return (this instanceof wrapper ? (Ctor || createCtorWrapper(func)) : func).apply(thisBinding, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates the pad required for `string` based on the given padding length.
+ * The `chars` string may be truncated if the number of padding characters
+ * exceeds the padding length.
+ *
+ * @private
+ * @param {string} string The string to create padding for.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the pad for `string`.
+ */
+ function createPad(string, length, chars) {
+ var strLength = string.length;
+ length = +length;
+
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return '';
+ }
+ var padLength = length - strLength;
+ chars = chars == null ? ' ' : baseToString(chars);
+ return repeat(chars, ceil(padLength / chars.length)).slice(0, padLength);
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the optional `this`
+ * binding of `thisArg` and the `partials` prepended to those provided to
+ * the wrapper.
+ *
+ * @private
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} partials The arguments to prepend to those provided to the new function.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createPartialWrapper(func, bitmask, thisArg, partials) {
+ var isBind = bitmask & BIND_FLAG,
+ Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it `func`.
+ var argsIndex = -1,
+ argsLength = arguments.length,
+ leftIndex = -1,
+ leftLength = partials.length,
+ args = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ args[leftIndex] = partials[leftIndex];
+ }
+ while (argsLength--) {
+ args[leftIndex++] = arguments[++argsIndex];
+ }
+ return (this instanceof wrapper ? Ctor : func).apply(isBind ? thisArg : this, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a function that either curries or invokes `func` with optional
+ * `this` binding and partially applied arguments.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags.
+ * The bitmask may be composed of the following flags:
+ * 1 - `_.bind`
+ * 2 - `_.bindKey`
+ * 4 - `_.curry` or `_.curryRight` of a bound function
+ * 8 - `_.curry`
+ * 16 - `_.curryRight`
+ * 32 - `_.partial`
+ * 64 - `_.partialRight`
+ * 128 - `_.rearg`
+ * 256 - `_.ary`
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to be partially applied.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
+ var isBindKey = bitmask & BIND_KEY_FLAG;
+ if (!isBindKey && !isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var length = partials ? partials.length : 0;
+ if (!length) {
+ bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
+ partials = holders = null;
+ }
+ length -= (holders ? holders.length : 0);
+ if (bitmask & PARTIAL_RIGHT_FLAG) {
+ var partialsRight = partials,
+ holdersRight = holders;
+
+ partials = holders = null;
+ }
+ var data = !isBindKey && getData(func),
+ newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
+
+ if (data && data !== true) {
+ mergeData(newData, data);
+ bitmask = newData[1];
+ arity = newData[9];
+ }
+ newData[9] = arity == null
+ ? (isBindKey ? 0 : func.length)
+ : (nativeMax(arity - length, 0) || 0);
+
+ if (bitmask == BIND_FLAG) {
+ var result = createBindWrapper(newData[0], newData[2]);
+ } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
+ result = createPartialWrapper.apply(null, newData);
+ } else {
+ result = createHybridWrapper.apply(null, newData);
+ }
+ var setter = data ? baseSetData : setData;
+ return setter(result, newData);
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing arrays.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var index = -1,
+ arrLength = array.length,
+ othLength = other.length,
+ result = true;
+
+ if (arrLength != othLength && !(isWhere && othLength > arrLength)) {
+ return false;
+ }
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (result && ++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, arrValue, index)
+ : customizer(arrValue, othValue, index);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (isWhere) {
+ var othIndex = othLength;
+ while (othIndex--) {
+ othValue = other[othIndex];
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ if (result) {
+ break;
+ }
+ }
+ } else {
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ }
+ return !!result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} value The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag) {
+ switch (tag) {
+ case boolTag:
+ case dateTag:
+ // Coerce dates and booleans to numbers, dates to milliseconds and booleans
+ // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
+ return +object == +other;
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case numberTag:
+ // Treat `NaN` vs. `NaN` as equal.
+ return (object != +object)
+ ? other != +other
+ // But, treat `-0` vs. `+0` as not equal.
+ : (object == 0 ? ((1 / object) == (1 / other)) : object == +other);
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings (http://es5.github.io/#x15.10.6.4) and
+ // treat strings primitives and string objects as equal.
+ return object == baseToString(other);
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objProps = keys(object),
+ objLength = objProps.length,
+ othProps = keys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isWhere) {
+ return false;
+ }
+ var hasCtor,
+ index = -1;
+
+ while (++index < objLength) {
+ var key = objProps[index],
+ result = hasOwnProperty.call(other, key);
+
+ if (result) {
+ var objValue = object[key],
+ othValue = other[key];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, objValue, key)
+ : customizer(objValue, othValue, key);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare objects (susceptible to call stack limits).
+ result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ hasCtor || (hasCtor = key == 'constructor');
+ }
+ if (!hasCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Gets the extremum value of `collection` invoking `iteratee` for each value
+ * in `collection` to generate the criterion by which the value is ranked.
+ * The `iteratee` is invoked with three arguments; (value, index, collection).
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the
+ * maximum, extremum value.
+ * @returns {*} Returns the extremum value.
+ */
+ function extremumBy(collection, iteratee, isMin) {
+ var exValue = isMin ? POSITIVE_INFINITY : NEGATIVE_INFINITY,
+ computed = exValue,
+ result = computed;
+
+ baseEach(collection, function(value, index, collection) {
+ var current = iteratee(value, index, collection);
+ if ((isMin ? current < computed : current > computed) || (current === exValue && current === result)) {
+ computed = current;
+ result = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Gets the appropriate "callback" function. If the `_.callback` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseCallback` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function} Returns the chosen function or its result.
+ */
+ function getCallback(func, thisArg, argCount) {
+ var result = lodash.callback || callback;
+ result = result === callback ? baseCallback : result;
+ return argCount ? result(func, thisArg, argCount) : result;
+ }
+
+ /**
+ * Gets metadata for `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {*} Returns the metadata for `func`.
+ */
+ var getData = !metaMap ? noop : function(func) {
+ return metaMap.get(func);
+ };
+
+ /**
+ * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseIndexOf` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function|number} Returns the chosen function or its result.
+ */
+ function getIndexOf(collection, target, fromIndex) {
+ var result = lodash.indexOf || indexOf;
+ result = result === indexOf ? baseIndexOf : result;
+ return collection ? result(collection, target, fromIndex) : result;
+ }
+
+ /**
+ * Gets the view, applying any `transforms` to the `start` and `end` positions.
+ *
+ * @private
+ * @param {number} start The start of the view.
+ * @param {number} end The end of the view.
+ * @param {Array} [transforms] The transformations to apply to the view.
+ * @returns {Object} Returns an object containing the `start` and `end`
+ * positions of the view.
+ */
+ function getView(start, end, transforms) {
+ var index = -1,
+ length = transforms ? transforms.length : 0;
+
+ while (++index < length) {
+ var data = transforms[index],
+ size = data.size;
+
+ switch (data.type) {
+ case 'drop': start += size; break;
+ case 'dropRight': end -= size; break;
+ case 'take': end = nativeMin(end, start + size); break;
+ case 'takeRight': start = nativeMax(start, end - size); break;
+ }
+ }
+ return { 'start': start, 'end': end };
+ }
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = new array.constructor(length);
+
+ // Add array properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ /**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneObject(object) {
+ var Ctor = object.constructor;
+ if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
+ Ctor = Object;
+ }
+ return new Ctor;
+ }
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return bufferClone(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ var buffer = object.buffer;
+ return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ var result = new Ctor(object.source, reFlags.exec(object));
+ result.lastIndex = object.lastIndex;
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `func` is eligible for `this` binding.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is eligible, else `false`.
+ */
+ function isBindable(func) {
+ var support = lodash.support,
+ result = !(support.funcNames ? func.name : support.funcDecomp);
+
+ if (!result) {
+ var source = fnToString.call(func);
+ if (!support.funcNames) {
+ result = !reFuncName.test(source);
+ }
+ if (!result) {
+ // Check if `func` references the `this` keyword and store the result.
+ result = reThis.test(source) || isNative(func);
+ baseSetData(func, result);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ value = +value;
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return value > -1 && value % 1 == 0 && value < length;
+ }
+
+ /**
+ * Checks if the provided arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number') {
+ var length = object.length,
+ prereq = isLength(length) && isIndex(index, length);
+ } else {
+ prereq = type == 'string' && index in value;
+ }
+ return prereq && object[index] === value;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+ function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` if suitable for strict
+ * equality comparisons, else `false`.
+ */
+ function isStrictComparable(value) {
+ return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value));
+ }
+
+ /**
+ * Merges the function metadata of `source` into `data`.
+ *
+ * Merging metadata reduces the number of wrappers required to invoke a function.
+ * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+ * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
+ * augment function arguments, making the order in which they are executed important,
+ * preventing the merging of metadata. However, we make an exception for a safe
+ * common case where curried functions have `_.ary` and or `_.rearg` applied.
+ *
+ * @private
+ * @param {Array} data The destination metadata.
+ * @param {Array} source The source metadata.
+ * @returns {Array} Returns `data`.
+ */
+ function mergeData(data, source) {
+ var bitmask = data[1],
+ srcBitmask = source[1],
+ newBitmask = bitmask | srcBitmask;
+
+ var arityFlags = ARY_FLAG | REARG_FLAG,
+ bindFlags = BIND_FLAG | BIND_KEY_FLAG,
+ comboFlags = arityFlags | bindFlags | CURRY_BOUND_FLAG | CURRY_RIGHT_FLAG;
+
+ var isAry = bitmask & ARY_FLAG && !(srcBitmask & ARY_FLAG),
+ isRearg = bitmask & REARG_FLAG && !(srcBitmask & REARG_FLAG),
+ argPos = (isRearg ? data : source)[7],
+ ary = (isAry ? data : source)[8];
+
+ var isCommon = !(bitmask >= REARG_FLAG && srcBitmask > bindFlags) &&
+ !(bitmask > bindFlags && srcBitmask >= REARG_FLAG);
+
+ var isCombo = (newBitmask >= arityFlags && newBitmask <= comboFlags) &&
+ (bitmask < REARG_FLAG || ((isRearg || isAry) && argPos.length <= ary));
+
+ // Exit early if metadata can't be merged.
+ if (!(isCommon || isCombo)) {
+ return data;
+ }
+ // Use source `thisArg` if available.
+ if (srcBitmask & BIND_FLAG) {
+ data[2] = source[2];
+ // Set when currying a bound function.
+ newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
+ }
+ // Compose partial arguments.
+ var value = source[3];
+ if (value) {
+ var partials = data[3];
+ data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
+ data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
+ }
+ // Compose partial right arguments.
+ value = source[5];
+ if (value) {
+ partials = data[5];
+ data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
+ data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
+ }
+ // Use source `argPos` if available.
+ value = source[7];
+ if (value) {
+ data[7] = arrayCopy(value);
+ }
+ // Use source `ary` if it's smaller.
+ if (srcBitmask & ARY_FLAG) {
+ data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
+ }
+ // Use source `arity` if one is not provided.
+ if (data[9] == null) {
+ data[9] = source[9];
+ }
+ // Use source `func` and merge bitmasks.
+ data[0] = source[0];
+ data[1] = newBitmask;
+
+ return data;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties specified
+ * by the `props` array.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {string[]} props The property names to pick.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByArray(object, props) {
+ object = toObject(object);
+
+ var index = -1,
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index];
+ if (key in object) {
+ result[key] = object[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties `predicate`
+ * returns truthy for.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByCallback(object, predicate) {
+ var result = {};
+ baseForIn(object, function(value, key, object) {
+ if (predicate(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Reorder `array` according to the specified indexes where the element at
+ * the first index is assigned as the first element, the element at
+ * the second index is assigned as the second element, and so on.
+ *
+ * @private
+ * @param {Array} array The array to reorder.
+ * @param {Array} indexes The arranged array indexes.
+ * @returns {Array} Returns `array`.
+ */
+ function reorder(array, indexes) {
+ var arrLength = array.length,
+ length = nativeMin(indexes.length, arrLength),
+ oldArray = arrayCopy(array);
+
+ while (length--) {
+ var index = indexes[length];
+ array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
+ }
+ return array;
+ }
+
+ /**
+ * Sets metadata for `func`.
+ *
+ * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+ * period of time, it will trip its breaker and transition to an identity function
+ * to avoid garbage collection pauses in V8. See https://code.google.com/p/v8/issues/detail?id=2070.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var setData = (function() {
+ var count = 0,
+ lastCalled = 0;
+
+ return function(key, value) {
+ var stamp = now(),
+ remaining = HOT_SPAN - (stamp - lastCalled);
+
+ lastCalled = stamp;
+ if (remaining > 0) {
+ if (++count >= HOT_COUNT) {
+ return key;
+ }
+ } else {
+ count = 0;
+ }
+ return baseSetData(key, value);
+ };
+ }());
+
+ /**
+ * A fallback implementation of `_.isPlainObject` which checks if `value`
+ * is an object created by the `Object` constructor or has a `[[Prototype]]`
+ * of `null`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ */
+ function shimIsPlainObject(value) {
+ var Ctor,
+ support = lodash.support;
+
+ // Exit early for non `Object` objects.
+ if (!(isObjectLike(value) && objToString.call(value) == objectTag) ||
+ (!hasOwnProperty.call(value, 'constructor') &&
+ (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
+ return false;
+ }
+ // IE < 9 iterates inherited properties before own properties. If the first
+ // iterated property is an object's own property then there are no inherited
+ // enumerable properties.
+ var result;
+ // In most environments an object's own properties are iterated before
+ // its inherited properties. If the last iterated property is an object's
+ // own property then there are no inherited enumerable properties.
+ baseForIn(value, function(subValue, key) {
+ result = key;
+ });
+ return typeof result == 'undefined' || hasOwnProperty.call(value, result);
+ }
+
+ /**
+ * A fallback implementation of `Object.keys` which creates an array of the
+ * own enumerable property names of `object`.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ */
+ function shimKeys(object) {
+ var props = keysIn(object),
+ propsLength = props.length,
+ length = propsLength && object.length,
+ support = lodash.support;
+
+ var allowIndexes = length && isLength(length) &&
+ (isArray(object) || (support.nonEnumArgs && isArguments(object)));
+
+ var index = -1,
+ result = [];
+
+ while (++index < propsLength) {
+ var key = props[index];
+ if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `value` to an array-like object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Array|Object} Returns the array-like object.
+ */
+ function toIterable(value) {
+ if (value == null) {
+ return [];
+ }
+ if (!isLength(value.length)) {
+ return values(value);
+ }
+ return isObject(value) ? value : Object(value);
+ }
+
+ /**
+ * Converts `value` to an object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Object} Returns the object.
+ */
+ function toObject(value) {
+ return isObject(value) ? value : Object(value);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements split into groups the length of `size`.
+ * If `collection` can't be split evenly, the final chunk will be the remaining
+ * elements.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to process.
+ * @param {numer} [size=1] The length of each chunk.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new array containing chunks.
+ * @example
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 2);
+ * // => [['a', 'b'], ['c', 'd']]
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 3);
+ * // => [['a', 'b', 'c'], ['d']]
+ */
+ function chunk(array, size, guard) {
+ if (guard ? isIterateeCall(array, size, guard) : size == null) {
+ size = 1;
+ } else {
+ size = nativeMax(+size || 1, 1);
+ }
+ var index = 0,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = Array(ceil(length / size));
+
+ while (index < length) {
+ result[++resIndex] = baseSlice(array, index, (index += size));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array with all falsey values removed. The values `false`, `null`,
+ * `0`, `""`, `undefined`, and `NaN` are falsey.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to compact.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.compact([0, 1, false, 2, '', 3]);
+ * // => [1, 2, 3]
+ */
+ function compact(array) {
+ var index = -1,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all values of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The arrays of values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.difference([1, 2, 3], [5, 2, 10]);
+ * // => [1, 3]
+ */
+ function difference() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var value = arguments[index];
+ if (isArray(value) || isArguments(value)) {
+ break;
+ }
+ }
+ return baseDifference(value, baseFlatten(arguments, false, true, ++index));
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.drop([1, 2, 3]);
+ * // => [2, 3]
+ *
+ * _.drop([1, 2, 3], 2);
+ * // => [3]
+ *
+ * _.drop([1, 2, 3], 5);
+ * // => []
+ *
+ * _.drop([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function drop(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRight([1, 2, 3]);
+ * // => [1, 2]
+ *
+ * _.dropRight([1, 2, 3], 2);
+ * // => [1]
+ *
+ * _.dropRight([1, 2, 3], 5);
+ * // => []
+ *
+ * _.dropRight([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function dropRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the end.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [1]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropRightWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function dropRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, 0, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the beginning.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['pebbles']
+ */
+ function dropWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, index);
+ }
+
+ /**
+ * This method is like `_.find` except that it returns the index of the first
+ * element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findIndex(users, function(chr) { return chr.age < 40; });
+ * // => 0
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findIndex(users, { 'age': 1 });
+ * // => 2
+ *
+ * // using the "_.property" callback shorthand
+ * _.findIndex(users, 'active');
+ * // => 1
+ */
+ function findIndex(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it iterates over elements
+ * of `collection` from right to left.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findLastIndex(users, function(chr) { return chr.age < 40; });
+ * // => 2
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastIndex(users, { 'age': 40 });
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastIndex(users, 'active');
+ * // => 0
+ */
+ function findLastIndex(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length--) {
+ if (predicate(array[length], length, array)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Gets the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias head
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the first element of `array`.
+ * @example
+ *
+ * _.first([1, 2, 3]);
+ * // => 1
+ *
+ * _.first([]);
+ * // => undefined
+ */
+ function first(array) {
+ return array ? array[0] : undefined;
+ }
+
+ /**
+ * Flattens a nested array. If `isDeep` is `true` the array is recursively
+ * flattened, otherwise it is only flattened a single level.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flatten([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, [[4]]];
+ *
+ * // using `isDeep`
+ * _.flatten([1, [2], [3, [[4]]]], true);
+ * // => [1, 2, 3, 4];
+ */
+ function flatten(array, isDeep, guard) {
+ var length = array ? array.length : 0;
+ if (guard && isIterateeCall(array, isDeep, guard)) {
+ isDeep = false;
+ }
+ return length ? baseFlatten(array, isDeep) : [];
+ }
+
+ /**
+ * Recursively flattens a nested array.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to recursively flatten.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flattenDeep([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, 4];
+ */
+ function flattenDeep(array) {
+ var length = array ? array.length : 0;
+ return length ? baseFlatten(array, true) : [];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found in `array`
+ * using `SameValueZero` for equality comparisons. If `fromIndex` is negative,
+ * it is used as the offset from the end of `array`. If `array` is sorted
+ * providing `true` for `fromIndex` performs a faster binary search.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=0] The index to search from or `true`
+ * to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 1
+ *
+ * // using `fromIndex`
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 4
+ *
+ * // performing a binary search
+ * _.indexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 2
+ */
+ function indexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else if (fromIndex) {
+ var index = binaryIndex(array, value),
+ other = array[index];
+
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ return baseIndexOf(array, value, fromIndex);
+ }
+
+ /**
+ * Gets all but the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.initial([1, 2, 3]);
+ * // => [1, 2]
+ */
+ function initial(array) {
+ return dropRight(array, 1);
+ }
+
+ /**
+ * Creates an array of unique values in all provided arrays using `SameValueZero`
+ * for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of shared values.
+ * @example
+ *
+ * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2]
+ */
+ function intersection() {
+ var args = [],
+ argsIndex = -1,
+ argsLength = arguments.length,
+ caches = [],
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf;
+
+ while (++argsIndex < argsLength) {
+ var value = arguments[argsIndex];
+ if (isArray(value) || isArguments(value)) {
+ args.push(value);
+ caches.push(isCommon && value.length >= 120 && createCache(argsIndex && value));
+ }
+ }
+ argsLength = args.length;
+ var array = args[0],
+ index = -1,
+ length = array ? array.length : 0,
+ result = [],
+ seen = caches[0];
+
+ outer:
+ while (++index < length) {
+ value = array[index];
+ if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value)) < 0) {
+ argsIndex = argsLength;
+ while (--argsIndex) {
+ var cache = caches[argsIndex];
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
+ continue outer;
+ }
+ }
+ if (seen) {
+ seen.push(value);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the last element of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ */
+ function last(array) {
+ var length = array ? array.length : 0;
+ return length ? array[length - 1] : undefined;
+ }
+
+ /**
+ * This method is like `_.indexOf` except that it iterates over elements of
+ * `array` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=array.length-1] The index to search from
+ * or `true` to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 4
+ *
+ * // using `fromIndex`
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 1
+ *
+ * // performing a binary search
+ * _.lastIndexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 3
+ */
+ function lastIndexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ var index = length;
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1;
+ } else if (fromIndex) {
+ index = binaryIndex(array, value, true) - 1;
+ var other = array[index];
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ if (value !== value) {
+ return indexOfNaN(array, index, true);
+ }
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all provided values from `array` using `SameValueZero` for equality
+ * comparisons.
+ *
+ * **Notes:**
+ * - Unlike `_.without`, this method mutates `array`.
+ * - `SameValueZero` comparisons are like strict equality comparisons, e.g. `===`,
+ * except that `NaN` matches `NaN`. See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...*} [values] The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3, 1, 2, 3];
+ * _.pull(array, 2, 3);
+ * console.log(array);
+ * // => [1, 1]
+ */
+ function pull() {
+ var array = arguments[0];
+ if (!(array && array.length)) {
+ return array;
+ }
+ var index = 0,
+ indexOf = getIndexOf(),
+ length = arguments.length;
+
+ while (++index < length) {
+ var fromIndex = 0,
+ value = arguments[index];
+
+ while ((fromIndex = indexOf(array, value, fromIndex)) > -1) {
+ splice.call(array, fromIndex, 1);
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Removes elements from `array` corresponding to the given indexes and returns
+ * an array of the removed elements. Indexes may be specified as an array of
+ * indexes or as individual arguments.
+ *
+ * **Note:** Unlike `_.at`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...(number|number[])} [indexes] The indexes of elements to remove,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [5, 10, 15, 20];
+ * var evens = _.pullAt(array, [1, 3]);
+ *
+ * console.log(array);
+ * // => [5, 15]
+ *
+ * console.log(evens);
+ * // => [10, 20]
+ */
+ function pullAt(array) {
+ return basePullAt(array || [], baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Removes all elements from `array` that `predicate` returns truthy for
+ * and returns an array of the removed elements. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** Unlike `_.filter`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [1, 2, 3, 4];
+ * var evens = _.remove(array, function(n) { return n % 2 == 0; });
+ *
+ * console.log(array);
+ * // => [1, 3]
+ *
+ * console.log(evens);
+ * // => [2, 4]
+ */
+ function remove(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0,
+ result = [];
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result.push(value);
+ splice.call(array, index--, 1);
+ length--;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets all but the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias tail
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.rest([1, 2, 3]);
+ * // => [2, 3]
+ */
+ function rest(array) {
+ return drop(array, 1);
+ }
+
+ /**
+ * Creates a slice of `array` from `start` up to, but not including, `end`.
+ *
+ * **Note:** This function is used instead of `Array#slice` to support node
+ * lists in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function slice(array, start, end) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
+ start = 0;
+ end = length;
+ }
+ return baseSlice(array, start, end);
+ }
+
+ /**
+ * Uses a binary search to determine the lowest index at which `value` should
+ * be inserted into `array` in order to maintain its sort order. If an iteratee
+ * function is provided it is invoked for `value` and each element of `array`
+ * to compute their sort ranking. The iteratee is bound to `thisArg` and
+ * invoked with one argument; (value).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([30, 50], 40);
+ * // => 1
+ *
+ * _.sortedIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 2
+ *
+ * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } };
+ *
+ * // using an iteratee function
+ * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) {
+ * return this.data[word];
+ * }, dict);
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
+ * // => 1
+ */
+ function sortedIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1));
+ }
+
+ /**
+ * This method is like `_.sortedIndex` except that it returns the highest
+ * index at which `value` should be inserted into `array` in order to
+ * maintain its sort order.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedLastIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 4
+ */
+ function sortedLastIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value, true)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1), true);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.take([1, 2, 3]);
+ * // => [1]
+ *
+ * _.take([1, 2, 3], 2);
+ * // => [1, 2]
+ *
+ * _.take([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.take([1, 2, 3], 0);
+ * // => []
+ */
+ function take(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRight([1, 2, 3]);
+ * // => [3]
+ *
+ * _.takeRight([1, 2, 3], 2);
+ * // => [2, 3]
+ *
+ * _.takeRight([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.takeRight([1, 2, 3], 0);
+ * // => []
+ */
+ function takeRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the end. Elements are
+ * taken until `predicate` returns falsey. The predicate is bound to `thisArg`
+ * and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [2, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeRightWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['pebbles']
+ */
+ function takeRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the beginning. Elements
+ * are taken until `predicate` returns falsey. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [1, 2]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function takeWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, 0, index);
+ }
+
+ /**
+ * Creates an array of unique values, in order, of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2, 3, 5, 4]
+ */
+ function union() {
+ return baseUniq(baseFlatten(arguments, false, true));
+ }
+
+ /**
+ * Creates a duplicate-value-free version of an array using `SameValueZero`
+ * for equality comparisons. Providing `true` for `isSorted` performs a faster
+ * search algorithm for sorted arrays. If an iteratee function is provided it
+ * is invoked for each value in the array to generate the criterion by which
+ * uniqueness is computed. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias unique
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {boolean} [isSorted] Specify the array is sorted.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ * @example
+ *
+ * _.uniq([1, 2, 1]);
+ * // => [1, 2]
+ *
+ * // using `isSorted`
+ * _.uniq([1, 1, 2], true);
+ * // => [1, 2]
+ *
+ * // using an iteratee function
+ * _.uniq([1, 2.5, 1.5, 2], function(n) { return this.floor(n); }, Math);
+ * // => [1, 2.5]
+ *
+ * // using the "_.property" callback shorthand
+ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniq(array, isSorted, iteratee, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ // Juggle arguments.
+ if (typeof isSorted != 'boolean' && isSorted != null) {
+ thisArg = iteratee;
+ iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted;
+ isSorted = false;
+ }
+ var func = getCallback();
+ if (!(func === baseCallback && iteratee == null)) {
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ return (isSorted && getIndexOf() == baseIndexOf)
+ ? sortedUniq(array, iteratee)
+ : baseUniq(array, iteratee);
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts an array of grouped
+ * elements and creates an array regrouping the elements to their pre `_.zip`
+ * configuration.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ *
+ * _.unzip(zipped);
+ * // => [['fred', 'barney'], [30, 40], [true, false]]
+ */
+ function unzip(array) {
+ var index = -1,
+ length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = arrayMap(array, baseProperty(index));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all provided values using `SameValueZero` for
+ * equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to filter.
+ * @param {...*} [values] The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+ * // => [2, 3, 4]
+ */
+ function without(array) {
+ return baseDifference(array, baseSlice(arguments, 1));
+ }
+
+ /**
+ * Creates an array that is the symmetric difference of the provided arrays.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Symmetric_difference) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of values.
+ * @example
+ *
+ * _.xor([1, 2, 3], [5, 2, 1, 4]);
+ * // => [3, 5, 4]
+ *
+ * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+ * // => [1, 4, 5]
+ */
+ function xor() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var array = arguments[index];
+ if (isArray(array) || isArguments(array)) {
+ var result = result
+ ? baseDifference(result, array).concat(baseDifference(array, result))
+ : array;
+ }
+ }
+ return result ? baseUniq(result) : [];
+ }
+
+ /**
+ * Creates an array of grouped elements, the first of which contains the first
+ * elements of the given arrays, the second of which contains the second elements
+ * of the given arrays, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ */
+ function zip() {
+ var length = arguments.length,
+ array = Array(length);
+
+ while (length--) {
+ array[length] = arguments[length];
+ }
+ return unzip(array);
+ }
+
+ /**
+ * Creates an object composed from arrays of property names and values. Provide
+ * either a single two dimensional array, e.g. `[[key1, value1], [key2, value2]]`
+ * or two arrays, one of property names and one of corresponding values.
+ *
+ * @static
+ * @memberOf _
+ * @alias object
+ * @category Array
+ * @param {Array} props The property names.
+ * @param {Array} [values=[]] The property values.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.zipObject(['fred', 'barney'], [30, 40]);
+ * // => { 'fred': 30, 'barney': 40 }
+ */
+ function zipObject(props, values) {
+ var index = -1,
+ length = props ? props.length : 0,
+ result = {};
+
+ if (length && !values && !isArray(props[0])) {
+ values = [];
+ }
+ while (++index < length) {
+ var key = props[index];
+ if (values) {
+ result[key] = values[index];
+ } else if (key) {
+ result[key[0]] = key[1];
+ }
+ }
+ return result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object that wraps `value` with explicit method
+ * chaining enabled.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to wrap.
+ * @returns {Object} Returns the new `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'pebbles', 'age': 1 }
+ * ];
+ *
+ * var youngest = _.chain(users)
+ * .sortBy('age')
+ * .map(function(chr) { return chr.user + ' is ' + chr.age; })
+ * .first()
+ * .value();
+ * // => 'pebbles is 1'
+ */
+ function chain(value) {
+ var result = lodash(value);
+ result.__chain__ = true;
+ return result;
+ }
+
+ /**
+ * This method invokes `interceptor` and returns `value`. The interceptor is
+ * bound to `thisArg` and invoked with one argument; (value). The purpose of
+ * this method is to "tap into" a method chain in order to perform operations
+ * on intermediate results within the chain.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .tap(function(array) { array.pop(); })
+ * .reverse()
+ * .value();
+ * // => [2, 1]
+ */
+ function tap(value, interceptor, thisArg) {
+ interceptor.call(thisArg, value);
+ return value;
+ }
+
+ /**
+ * This method is like `_.tap` except that it returns the result of `interceptor`.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns the result of `interceptor`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .last()
+ * .thru(function(value) { return [value]; })
+ * .value();
+ * // => [3]
+ */
+ function thru(value, interceptor, thisArg) {
+ return interceptor.call(thisArg, value);
+ }
+
+ /**
+ * Enables explicit method chaining on the wrapper object.
+ *
+ * @name chain
+ * @memberOf _
+ * @category Chain
+ * @returns {*} Returns the `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // without explicit chaining
+ * _(users).first();
+ * // => { 'user': 'barney', 'age': 36 }
+ *
+ * // with explicit chaining
+ * _(users).chain()
+ * .first()
+ * .pick('user')
+ * .value();
+ * // => { 'user': 'barney' }
+ */
+ function wrapperChain() {
+ return chain(this);
+ }
+
+ /**
+ * Reverses the wrapped array so the first element becomes the last, the
+ * second element becomes the second to last, and so on.
+ *
+ * **Note:** This method mutates the wrapped array.
+ *
+ * @name reverse
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new reversed `lodash` object.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _(array).reverse().value()
+ * // => [3, 2, 1]
+ *
+ * console.log(array);
+ * // => [3, 2, 1]
+ */
+ function wrapperReverse() {
+ var value = this.__wrapped__;
+ if (value instanceof LazyWrapper) {
+ return new LodashWrapper(value.reverse());
+ }
+ return this.thru(function(value) {
+ return value.reverse();
+ });
+ }
+
+ /**
+ * Produces the result of coercing the unwrapped value to a string.
+ *
+ * @name toString
+ * @memberOf _
+ * @category Chain
+ * @returns {string} Returns the coerced string value.
+ * @example
+ *
+ * _([1, 2, 3]).toString();
+ * // => '1,2,3'
+ */
+ function wrapperToString() {
+ return (this.value() + '');
+ }
+
+ /**
+ * Executes the chained sequence to extract the unwrapped value.
+ *
+ * @name value
+ * @memberOf _
+ * @alias toJSON, valueOf
+ * @category Chain
+ * @returns {*} Returns the resolved unwrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperValue() {
+ return baseWrapperValue(this.__wrapped__, this.__actions__);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements corresponding to the given keys, or indexes,
+ * of `collection`. Keys may be specified as individual arguments or as arrays
+ * of keys.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(number|number[]|string|string[])} [props] The property names
+ * or indexes of elements to pick, specified individually or in arrays.
+ * @returns {Array} Returns the new array of picked elements.
+ * @example
+ *
+ * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
+ * // => ['a', 'c', 'e']
+ *
+ * _.at(['fred', 'barney', 'pebbles'], 0, 2);
+ * // => ['fred', 'pebbles']
+ */
+ function at(collection) {
+ var length = collection ? collection.length : 0;
+ if (isLength(length)) {
+ collection = toIterable(collection);
+ }
+ return baseAt(collection, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Checks if `value` is in `collection` using `SameValueZero` for equality
+ * comparisons. If `fromIndex` is negative, it is used as the offset from
+ * the end of `collection`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias contains, include
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {*} target The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {boolean} Returns `true` if a matching element is found, else `false`.
+ * @example
+ *
+ * _.includes([1, 2, 3], 1);
+ * // => true
+ *
+ * _.includes([1, 2, 3], 1, 2);
+ * // => false
+ *
+ * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
+ * // => true
+ *
+ * _.includes('pebbles', 'eb');
+ * // => true
+ */
+ function includes(collection, target, fromIndex) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ collection = values(collection);
+ length = collection.length;
+ }
+ if (!length) {
+ return false;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else {
+ fromIndex = 0;
+ }
+ return (typeof collection == 'string' || !isArray(collection) && isString(collection))
+ ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
+ : (getIndexOf(collection, target, fromIndex) > -1);
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the number of times the key was returned by `iteratee`.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy(['one', 'two', 'three'], 'length');
+ * // => { '3': 2, '5': 1 }
+ */
+ var countBy = createAggregator(function(result, value, key) {
+ hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1);
+ });
+
+ /**
+ * Checks if `predicate` returns truthy for **all** elements of `collection`.
+ * The predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias all
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes']);
+ * // => false
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.every(users, 'age');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.every(users, { 'age': 36 });
+ * // => false
+ */
+ function every(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayEvery : baseEvery;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning an array of all elements
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias select
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var evens = _.filter([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [2, 4]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.filter(users, 'active'), 'user');
+ * // => ['fred']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.filter(users, { 'age': 36 }), 'user');
+ * // => ['barney']
+ */
+ function filter(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning the first element
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias detect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.result(_.find(users, function(chr) { return chr.age < 40; }), 'user');
+ * // => 'barney'
+ *
+ * // using the "_.matches" callback shorthand
+ * _.result(_.find(users, { 'age': 1 }), 'user');
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.result(_.find(users, 'active'), 'user');
+ * // => 'fred'
+ */
+ function find(collection, predicate, thisArg) {
+ if (isArray(collection)) {
+ var index = findIndex(collection, predicate, thisArg);
+ return index > -1 ? collection[index] : undefined;
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEach);
+ }
+
+ /**
+ * This method is like `_.find` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * _.findLast([1, 2, 3, 4], function(n) { return n % 2 == 1; });
+ * // => 3
+ */
+ function findLast(collection, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEachRight);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning the first element that has equivalent property
+ * values.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy' },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy' }
+ * ];
+ *
+ * _.result(_.findWhere(users, { 'status': 'busy' }), 'user');
+ * // => 'barney'
+ *
+ * _.result(_.findWhere(users, { 'age': 40 }), 'user');
+ * // => 'fred'
+ */
+ function findWhere(collection, source) {
+ return find(collection, matches(source));
+ }
+
+ /**
+ * Iterates over elements of `collection` invoking `iteratee` for each element.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection). Iterator functions may exit iteration early
+ * by explicitly returning `false`.
+ *
+ * **Note:** As with other "Collections" methods, objects with a `length` property
+ * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+ * may be used for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEach(function(n) { console.log(n); });
+ * // => logs each value from left to right and returns the array
+ *
+ * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(n, key) { console.log(n, key); });
+ * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
+ */
+ function forEach(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEach(collection, iteratee)
+ : baseEach(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * This method is like `_.forEach` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias eachRight
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEachRight(function(n) { console.log(n); }).join(',');
+ * // => logs each value from right to left and returns the array
+ */
+ function forEachRight(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEachRight(collection, iteratee)
+ : baseEachRight(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is an array of the elements responsible for generating the key.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * // using the "_.property" callback shorthand
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
+ */
+ var groupBy = createAggregator(function(result, value, key) {
+ if (hasOwnProperty.call(result, key)) {
+ result[key].push(value);
+ } else {
+ result[key] = [value];
+ }
+ });
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the last element responsible for generating the key. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * var keyData = [
+ * { 'dir': 'left', 'code': 97 },
+ * { 'dir': 'right', 'code': 100 }
+ * ];
+ *
+ * _.indexBy(keyData, 'dir');
+ * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) { return String.fromCharCode(object.code); });
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) { return this.fromCharCode(object.code); }, String);
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ */
+ var indexBy = createAggregator(function(result, value, key) {
+ result[key] = value;
+ });
+
+ /**
+ * Invokes the method named by `methodName` on each element in `collection`,
+ * returning an array of the results of each invoked method. Any additional
+ * arguments are provided to each invoked method. If `methodName` is a function
+ * it is invoked for, and `this` bound to, each element in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {...*} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+ * // => [[1, 5, 7], [1, 2, 3]]
+ *
+ * _.invoke([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
+ */
+ function invoke(collection, methodName) {
+ return baseInvoke(collection, methodName, baseSlice(arguments, 2));
+ }
+
+ /**
+ * Creates an array of values by running each element in `collection` through
+ * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias collect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new mapped array.
+ * @example
+ *
+ * _.map([1, 2, 3], function(n) { return n * 3; });
+ * // => [3, 6, 9]
+ *
+ * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(n) { return n * 3; });
+ * // => [3, 6, 9] (iteration order is not guaranteed)
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(users, 'user');
+ * // => ['barney', 'fred']
+ */
+ function map(collection, iteratee, thisArg) {
+ var func = isArray(collection) ? arrayMap : baseMap;
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return func(collection, iteratee);
+ }
+
+ /**
+ * Gets the maximum value of `collection`. If `collection` is empty or falsey
+ * `-Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the maximum value.
+ * @example
+ *
+ * _.max([4, 2, 8, 6]);
+ * // => 8
+ *
+ * _.max([]);
+ * // => -Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.max(users, function(chr) { return chr.age; });
+ * // => { 'user': 'fred', 'age': 40 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.max(users, 'age');
+ * // => { 'user': 'fred', 'age': 40 };
+ */
+ var max = createExtremum(arrayMax);
+
+ /**
+ * Gets the minimum value of `collection`. If `collection` is empty or falsey
+ * `Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the minimum value.
+ * @example
+ *
+ * _.min([4, 2, 8, 6]);
+ * // => 2
+ *
+ * _.min([]);
+ * // => Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.min(users, function(chr) { return chr.age; });
+ * // => { 'user': 'barney', 'age': 36 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.min(users, 'age');
+ * // => { 'user': 'barney', 'age': 36 };
+ */
+ var min = createExtremum(arrayMin, true);
+
+ /**
+ * Creates an array of elements split into two groups, the first of which
+ * contains elements `predicate` returns truthy for, while the second of which
+ * contains elements `predicate` returns falsey for. The predicate is bound
+ * to `thisArg` and invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the array of grouped elements.
+ * @example
+ *
+ * _.partition([1, 2, 3], function(n) { return n % 2; });
+ * // => [[1, 3], [2]]
+ *
+ * _.partition([1.2, 2.3, 3.4], function(n) { return this.floor(n) % 2; }, Math);
+ * // => [[1, 3], [2]]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * // using the "_.matches" callback shorthand
+ * _.map(_.partition(users, { 'age': 1 }), function(array) { return _.pluck(array, 'user'); });
+ * // => [['pebbles'], ['barney', 'fred']]
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(_.partition(users, 'active'), function(array) { return _.pluck(array, 'user'); });
+ * // => [['fred'], ['barney', 'pebbles']]
+ */
+ var partition = createAggregator(function(result, value, key) {
+ result[key ? 0 : 1].push(value);
+ }, function() { return [[], []]; });
+
+ /**
+ * Gets the value of `key` from all elements in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {string} key The key of the property to pluck.
+ * @returns {Array} Returns the property values.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.pluck(users, 'user');
+ * // => ['barney', 'fred']
+ *
+ * var userIndex = _.indexBy(users, 'user');
+ * _.pluck(userIndex, 'age');
+ * // => [36, 40] (iteration order is not guaranteed)
+ */
+ function pluck(collection, key) {
+ return map(collection, property(key));
+ }
+
+ /**
+ * Reduces `collection` to a value which is the accumulated result of running
+ * each element in `collection` through `iteratee`, where each successive
+ * invocation is supplied the return value of the previous. If `accumulator`
+ * is not provided the first element of `collection` is used as the initial
+ * value. The `iteratee` is bound to `thisArg`and invoked with four arguments;
+ * (accumulator, value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @alias foldl, inject
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var sum = _.reduce([1, 2, 3], function(sum, n) { return sum + n; });
+ * // => 6
+ *
+ * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * return result;
+ * }, {});
+ * // => { 'a': 3, 'b': 6, 'c': 9 } (iteration order is not guaranteed)
+ */
+ function reduce(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduce : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEach);
+ }
+
+ /**
+ * This method is like `_.reduce` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias foldr
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var array = [[0, 1], [2, 3], [4, 5]];
+ * _.reduceRight(array, function(flattened, other) { return flattened.concat(other); }, []);
+ * // => [4, 5, 2, 3, 0, 1]
+ */
+ function reduceRight(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduceRight : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEachRight);
+ }
+
+ /**
+ * The opposite of `_.filter`; this method returns the elements of `collection`
+ * that `predicate` does **not** return truthy for.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var odds = _.reject([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [1, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.reject(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.reject(users, { 'age': 36 }), 'user');
+ * // => ['fred']
+ */
+ function reject(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, function(value, index, collection) {
+ return !predicate(value, index, collection);
+ });
+ }
+
+ /**
+ * Gets a random element or `n` random elements from a collection.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to sample.
+ * @param {number} [n] The number of elements to sample.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {*} Returns the random sample(s).
+ * @example
+ *
+ * _.sample([1, 2, 3, 4]);
+ * // => 2
+ *
+ * _.sample([1, 2, 3, 4], 2);
+ * // => [3, 1]
+ */
+ function sample(collection, n, guard) {
+ if (guard ? isIterateeCall(collection, n, guard) : n == null) {
+ collection = toIterable(collection);
+ var length = collection.length;
+ return length > 0 ? collection[baseRandom(0, length - 1)] : undefined;
+ }
+ var result = shuffle(collection);
+ result.length = nativeMin(n < 0 ? 0 : (+n || 0), result.length);
+ return result;
+ }
+
+ /**
+ * Creates an array of shuffled values, using a version of the Fisher-Yates
+ * shuffle. See [Wikipedia](http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to shuffle.
+ * @returns {Array} Returns the new shuffled array.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4]);
+ * // => [4, 1, 3, 2]
+ */
+ function shuffle(collection) {
+ collection = toIterable(collection);
+
+ var index = -1,
+ length = collection.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var rand = baseRandom(0, index);
+ if (index != rand) {
+ result[index] = result[rand];
+ }
+ result[rand] = collection[index];
+ }
+ return result;
+ }
+
+ /**
+ * Gets the size of `collection` by returning `collection.length` for
+ * array-like values or the number of own enumerable properties for objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @returns {number} Returns the size of `collection`.
+ * @example
+ *
+ * _.size([1, 2]);
+ * // => 2
+ *
+ * _.size({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => 3
+ *
+ * _.size('pebbles');
+ * // => 7
+ */
+ function size(collection) {
+ var length = collection ? collection.length : 0;
+ return isLength(length) ? length : keys(collection).length;
+ }
+
+ /**
+ * Checks if `predicate` returns truthy for **any** element of `collection`.
+ * The function returns as soon as it finds a passing value and does not iterate
+ * over the entire collection. The predicate is bound to `thisArg` and invoked
+ * with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias any
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.some([null, 0, 'yes', false], Boolean);
+ * // => true
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.some(users, 'active');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.some(users, { 'age': 1 });
+ * // => false
+ */
+ function some(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arraySome : baseSome;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Creates an array of elements, sorted in ascending order by the results of
+ * running each element in a collection through `iteratee`. This method performs
+ * a stable sort, that is, it preserves the original sort order of equal elements.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Array|Function|Object|string} [iteratee=_.identity] The function
+ * invoked per iteration. If a property name or an object is provided it is
+ * used to create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * _.sortBy([1, 2, 3], function(n) { return Math.sin(n); });
+ * // => [3, 1, 2]
+ *
+ * _.sortBy([1, 2, 3], function(n) { return this.sin(n); }, Math);
+ * // => [3, 1, 2]
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'pebbles' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.sortBy(users, 'user'), 'user');
+ * // => ['barney', 'fred', 'pebbles']
+ */
+ function sortBy(collection, iteratee, thisArg) {
+ var index = -1,
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ iteratee = getCallback(iteratee, thisArg, 3);
+ baseEach(collection, function(value, key, collection) {
+ result[++index] = { 'criteria': iteratee(value, key, collection), 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareAscending);
+ }
+
+ /**
+ * This method is like `_.sortBy` except that it sorts by property names
+ * instead of an iteratee function.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(string|string[])} props The property names to sort by,
+ * specified as individual property names or arrays of property names.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 26 },
+ * { 'user': 'fred', 'age': 30 }
+ * ];
+ *
+ * _.map(_.sortByAll(users, ['user', 'age']), _.values);
+ * // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
+ */
+ function sortByAll(collection) {
+ var args = arguments;
+ if (args.length > 3 && isIterateeCall(args[1], args[2], args[3])) {
+ args = [collection, args[1]];
+ }
+ var index = -1,
+ length = collection ? collection.length : 0,
+ props = baseFlatten(args, false, false, 1),
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value, key, collection) {
+ var length = props.length,
+ criteria = Array(length);
+
+ while (length--) {
+ criteria[length] = value == null ? undefined : value[props[length]];
+ }
+ result[++index] = { 'criteria': criteria, 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareMultipleAscending);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning an array of all elements that have equivalent
+ * property values.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy', 'pets': ['hoppy'] },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy', 'pets': ['baby puss', 'dino'] }
+ * ];
+ *
+ * _.pluck(_.where(users, { 'age': 36 }), 'user');
+ * // => ['barney']
+ *
+ * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user');
+ * // => ['fred']
+ *
+ * _.pluck(_.where(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function where(collection, source) {
+ return filter(collection, matches(source));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Gets the number of milliseconds that have elapsed since the Unix epoch
+ * (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @category Date
+ * @example
+ *
+ * _.defer(function(stamp) { console.log(_.now() - stamp); }, _.now());
+ * // => logs the number of milliseconds it took for the deferred function to be invoked
+ */
+ var now = nativeNow || function() {
+ return new Date().getTime();
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The opposite of `_.before`; this method creates a function that invokes
+ * `func` once it is called `n` or more times.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls before `func` is invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var saves = ['profile', 'settings'];
+ *
+ * var done = _.after(saves.length, function() {
+ * console.log('done saving!');
+ * });
+ *
+ * _.forEach(saves, function(type) {
+ * asyncSave({ 'type': type, 'complete': done });
+ * });
+ * // => logs 'done saving!' after the two async saves have completed
+ */
+ function after(n, func) {
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ n = nativeIsFinite(n = +n) ? n : 0;
+ return function() {
+ if (--n < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ }
+
+ /**
+ * Creates a function that accepts up to `n` arguments ignoring any
+ * additional arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to cap arguments for.
+ * @param {number} [n=func.length] The arity cap.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+ * // => [6, 8, 10]
+ */
+ function ary(func, n, guard) {
+ if (guard && isIterateeCall(func, n, guard)) {
+ n = null;
+ }
+ n = n == null ? func.length : (+n || 0);
+ return createWrapper(func, ARY_FLAG, null, null, null, null, n);
+ }
+
+ /**
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it is called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * jQuery('#add').on('click', _.before(5, addContactToList));
+ * // => allows adding up to 4 contacts to the list
+ */
+ function before(n, func) {
+ var result;
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ return function() {
+ if (--n > 0) {
+ result = func.apply(this, arguments);
+ } else {
+ func = null;
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of `thisArg`
+ * and prepends any additional `_.bind` arguments to those provided to the
+ * bound function.
+ *
+ * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** Unlike native `Function#bind` this method does not set the `length`
+ * property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var greet = function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * };
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * var bound = _.bind(greet, object, 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * // using placeholders
+ * var bound = _.bind(greet, object, _, '!');
+ * bound('hi');
+ * // => 'hi fred!'
+ */
+ function bind(func, thisArg) {
+ var bitmask = BIND_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bind.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(func, bitmask, thisArg, partials, holders);
+ }
+
+ /**
+ * Binds methods of an object to the object itself, overwriting the existing
+ * method. Method names may be specified as individual arguments or as arrays
+ * of method names. If no method names are provided all enumerable function
+ * properties, own and inherited, of `object` are bound.
+ *
+ * **Note:** This method does not set the `length` property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {...(string|string[])} [methodNames] The object method names to bind,
+ * specified as individual method names or arrays of method names.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var view = {
+ * 'label': 'docs',
+ * 'onClick': function() { console.log('clicked ' + this.label); }
+ * };
+ *
+ * _.bindAll(view);
+ * jQuery('#docs').on('click', view.onClick);
+ * // => logs 'clicked docs' when the element is clicked
+ */
+ function bindAll(object) {
+ return baseBindAll(object,
+ arguments.length > 1
+ ? baseFlatten(arguments, false, false, 1)
+ : functions(object)
+ );
+ }
+
+ /**
+ * Creates a function that invokes the method at `object[key]` and prepends
+ * any additional `_.bindKey` arguments to those provided to the bound function.
+ *
+ * This method differs from `_.bind` by allowing bound functions to reference
+ * methods that may be redefined or don't yet exist.
+ * See [Peter Michaux's article](http://michaux.ca/articles/lazy-function-definition-pattern)
+ * for more details.
+ *
+ * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object the method belongs to.
+ * @param {string} key The key of the method.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var object = {
+ * 'user': 'fred',
+ * 'greet': function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * }
+ * };
+ *
+ * var bound = _.bindKey(object, 'greet', 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * object.greet = function(greeting, punctuation) {
+ * return greeting + 'ya ' + this.user + punctuation;
+ * };
+ *
+ * bound('!');
+ * // => 'hiya fred!'
+ *
+ * // using placeholders
+ * var bound = _.bindKey(object, 'greet', _, '!');
+ * bound('hi');
+ * // => 'hiya fred!'
+ */
+ function bindKey(object, key) {
+ var bitmask = BIND_FLAG | BIND_KEY_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bindKey.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(key, bitmask, object, partials, holders);
+ }
+
+ /**
+ * Creates a function that accepts one or more arguments of `func` that when
+ * called either invokes `func` returning its result, if all `func` arguments
+ * have been provided, or returns a function that accepts one or more of the
+ * remaining `func` arguments, and so on. The arity of `func` may be specified
+ * if `func.length` is not sufficient.
+ *
+ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curry(abc);
+ *
+ * curried(1)(2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(1)(_, 3)(2);
+ * // => [1, 2, 3]
+ */
+ function curry(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curry.placeholder;
+ return result;
+ }
+
+ /**
+ * This method is like `_.curry` except that arguments are applied to `func`
+ * in the manner of `_.partialRight` instead of `_.partial`.
+ *
+ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curryRight(abc);
+ *
+ * curried(3)(2)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(2, 3)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(3)(1, _)(2);
+ * // => [1, 2, 3]
+ */
+ function curryRight(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_RIGHT_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curryRight.placeholder;
+ return result;
+ }
+
+ /**
+ * Creates a function that delays invoking `func` until after `wait` milliseconds
+ * have elapsed since the last time it was invoked. The created function comes
+ * with a `cancel` method to cancel delayed invocations. Provide an options
+ * object to indicate that `func` should be invoked on the leading and/or
+ * trailing edge of the `wait` timeout. Subsequent calls to the debounced
+ * function return the result of the last `func` invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the debounced function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.debounce` and `_.throttle`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} wait The number of milliseconds to delay.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=false] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {number} [options.maxWait] The maximum time `func` is allowed to be
+ * delayed before it is invoked.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // avoid costly calculations while the window size is in flux
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+ *
+ * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
+ * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
+ *
+ * // ensure `batchLog` is invoked once after 1 second of debounced calls
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', _.debounce(batchLog, 250, {
+ * 'maxWait': 1000
+ * }));
+ *
+ * // cancel a debounced call
+ * var todoChanges = _.debounce(batchLog, 1000);
+ * Object.observe(models.todo, todoChanges);
+ *
+ * Object.observe(models, function(changes) {
+ * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
+ * todoChanges.cancel();
+ * }
+ * }, ['delete']);
+ *
+ * // ...at some point `models.todo` is changed
+ * models.todo.completed = true;
+ *
+ * // ...before 1 second has passed `models.todo` is deleted
+ * // which cancels the debounced `todoChanges` call
+ * delete models.todo;
+ */
+ function debounce(func, wait, options) {
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = wait < 0 ? 0 : wait;
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (isObject(options)) {
+ leading = options.leading;
+ maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+
+ function cancel() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ }
+
+ function delayed() {
+ var remaining = wait - (now() - stamp);
+ if (remaining <= 0 || remaining > wait) {
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ var isCalled = trailingCall;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
+ }
+ }
+
+ function maxDelayed() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ }
+
+ function debounced() {
+ args = arguments;
+ stamp = now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0 || remaining > maxWait;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ return debounced;
+ }
+
+ /**
+ * Defers invoking the `func` until the current call stack has cleared. Any
+ * additional arguments are provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to defer.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.defer(function(text) { console.log(text); }, 'deferred');
+ * // logs 'deferred' after one or more milliseconds
+ */
+ function defer(func) {
+ return baseDelay(func, 1, arguments, 1);
+ }
+
+ /**
+ * Invokes `func` after `wait` milliseconds. Any additional arguments are
+ * provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.delay(function(text) { console.log(text); }, 1000, 'later');
+ * // => logs 'later' after one second
+ */
+ function delay(func, wait) {
+ return baseDelay(func, wait, arguments, 2);
+ }
+
+ /**
+ * Creates a function that returns the result of invoking the provided
+ * functions with the `this` binding of the created function, where each
+ * successive invocation is supplied the return value of the previous.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function add(x, y) {
+ * return x + y;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flow(add, square);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ function flow() {
+ var funcs = arguments,
+ length = funcs.length;
+
+ if (!length) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = 0,
+ result = funcs[index].apply(this, arguments);
+
+ while (++index < length) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * This method is like `_.flow` except that it creates a function that
+ * invokes the provided functions from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias backflow, compose
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function add(x, y) {
+ * return x + y;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flowRight(square, add);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ function flowRight() {
+ var funcs = arguments,
+ fromIndex = funcs.length - 1;
+
+ if (fromIndex < 0) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = fromIndex,
+ result = funcs[index].apply(this, arguments);
+
+ while (index--) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is coerced to a string and used as the
+ * cache key. The `func` is invoked with the `this` binding of the memoized
+ * function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the ES6 `Map` method interface
+ * of `get`, `has`, and `set`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoizing function.
+ * @example
+ *
+ * var upperCase = _.memoize(function(string) {
+ * return string.toUpperCase();
+ * });
+ *
+ * upperCase('fred');
+ * // => 'FRED'
+ *
+ * // modifying the result cache
+ * upperCase.cache.set('fred, 'BARNEY');
+ * upperCase('fred');
+ * // => 'BARNEY'
+ *
+ * // replacing `_.memoize.Cache`
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'barney' };
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'fred' }
+ *
+ * _.memoize.Cache = WeakMap;
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'barney' }
+ */
+ function memoize(func, resolver) {
+ if (!isFunction(func) || (resolver && !isFunction(resolver))) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var cache = memoized.cache,
+ key = resolver ? resolver.apply(this, arguments) : arguments[0];
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, arguments);
+ cache.set(key, result);
+ return result;
+ };
+ memoized.cache = new memoize.Cache;
+ return memoized;
+ }
+
+ /**
+ * Creates a function that negates the result of the predicate `func`. The
+ * `func` predicate is invoked with the `this` binding and arguments of the
+ * created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} predicate The predicate to negate.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function isEven(n) {
+ * return n % 2 == 0;
+ * }
+ *
+ * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+ * // => [1, 3, 5]
+ */
+ function negate(predicate) {
+ if (!isFunction(predicate)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
+ }
+
+ /**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first call. The `func` is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // `initialize` invokes `createApplication` once
+ */
+ function once(func) {
+ return before(func, 2);
+ }
+
+ /**
+ * Creates a function that invokes `func` with `partial` arguments prepended
+ * to those provided to the new function. This method is like `_.bind` except
+ * it does **not** alter the `this` binding.
+ *
+ * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var sayHelloTo = _.partial(greet, 'hello');
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ *
+ * // using placeholders
+ * var greetFred = _.partial(greet, _, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ */
+ function partial(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partial.placeholder);
+
+ return createWrapper(func, PARTIAL_FLAG, null, partials, holders);
+ }
+
+ /**
+ * This method is like `_.partial` except that partially applied arguments
+ * are appended to those provided to the new function.
+ *
+ * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var greetFred = _.partialRight(greet, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ *
+ * // using placeholders
+ * var sayHelloTo = _.partialRight(greet, 'hello', _);
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ */
+ function partialRight(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partialRight.placeholder);
+
+ return createWrapper(func, PARTIAL_RIGHT_FLAG, null, partials, holders);
+ }
+
+ /**
+ * Creates a function that invokes `func` with arguments arranged according
+ * to the specified indexes where the argument value at the first index is
+ * provided as the first argument, the argument value at the second index is
+ * provided as the second argument, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to rearrange arguments for.
+ * @param {...(number|number[])} indexes The arranged argument indexes,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var rearged = _.rearg(function(a, b, c) {
+ * return [a, b, c];
+ * }, 2, 0, 1);
+ *
+ * rearged('b', 'c', 'a')
+ * // => ['a', 'b', 'c']
+ *
+ * var map = _.rearg(_.map, [1, 0]);
+ * map(function(n) { return n * 3; }, [1, 2, 3]);
+ * // => [3, 6, 9]
+ */
+ function rearg(func) {
+ var indexes = baseFlatten(arguments, false, false, 1);
+ return createWrapper(func, REARG_FLAG, null, null, null, indexes);
+ }
+
+ /**
+ * Creates a function that only invokes `func` at most once per every `wait`
+ * milliseconds. The created function comes with a `cancel` method to cancel
+ * delayed invocations. Provide an options object to indicate that `func`
+ * should be invoked on the leading and/or trailing edge of the `wait` timeout.
+ * Subsequent calls to the throttled function return the result of the last
+ * `func` call.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the throttled function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.throttle` and `_.debounce`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} wait The number of milliseconds to throttle invocations to.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=true] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // avoid excessively updating the position while scrolling
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+ *
+ * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false })
+ * jQuery('.interactive').on('click', throttled);
+ *
+ * // cancel a trailing throttled call
+ * jQuery(window).on('popstate', throttled.cancel);
+ */
+ function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ if (options === false) {
+ leading = false;
+ } else if (isObject(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+ debounceOptions.leading = leading;
+ debounceOptions.maxWait = +wait;
+ debounceOptions.trailing = trailing;
+ return debounce(func, wait, debounceOptions);
+ }
+
+ /**
+ * Creates a function that provides `value` to the wrapper function as its
+ * first argument. Any additional arguments provided to the function are
+ * appended to those provided to the wrapper function. The wrapper is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {*} value The value to wrap.
+ * @param {Function} wrapper The wrapper function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var p = _.wrap(_.escape, function(func, text) {
+ * return '<p>' + func(text) + '</p>';
+ * });
+ *
+ * p('fred, barney, & pebbles');
+ * // => '<p>fred, barney, & pebbles</p>'
+ */
+ function wrap(value, wrapper) {
+ wrapper = wrapper == null ? identity : wrapper;
+ return createWrapper(wrapper, PARTIAL_FLAG, null, [value], []);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
+ * otherwise they are assigned by reference. If `customizer` is provided it is
+ * invoked to produce the cloned values. If `customizer` returns `undefined`
+ * cloning is handled by the method instead. The `customizer` is bound to
+ * `thisArg` and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var shallow = _.clone(users);
+ * shallow[0] === users[0];
+ * // => true
+ *
+ * var deep = _.clone(users, true);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var body = _.clone(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(false) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 0
+ */
+ function clone(value, isDeep, customizer, thisArg) {
+ // Juggle arguments.
+ if (typeof isDeep != 'boolean' && isDeep != null) {
+ thisArg = customizer;
+ customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep;
+ isDeep = false;
+ }
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, isDeep, customizer);
+ }
+
+ /**
+ * Creates a deep clone of `value`. If `customizer` is provided it is invoked
+ * to produce the cloned values. If `customizer` returns `undefined` cloning
+ * is handled by the method instead. The `customizer` is bound to `thisArg`
+ * and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the deep cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var deep = _.cloneDeep(users);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var el = _.cloneDeep(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(true) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 20
+ */
+ function cloneDeep(value, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, true, customizer);
+ }
+
+ /**
+ * Checks if `value` is classified as an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * (function() { return _.isArguments(arguments); })();
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ var length = isObjectLike(value) ? value.length : undefined;
+ return (isLength(length) && objToString.call(value) == argsTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * (function() { return _.isArray(arguments); })();
+ * // => false
+ */
+ var isArray = nativeIsArray || function(value) {
+ return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false;
+ };
+
+ /**
+ * Checks if `value` is classified as a boolean primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isBoolean(false);
+ * // => true
+ *
+ * _.isBoolean(null);
+ * // => false
+ */
+ function isBoolean(value) {
+ return (value === true || value === false || isObjectLike(value) && objToString.call(value) == boolTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Date` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isDate(new Date);
+ * // => true
+ *
+ * _.isDate('Mon April 23 2012');
+ * // => false
+ */
+ function isDate(value) {
+ return (isObjectLike(value) && objToString.call(value) == dateTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a DOM element.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
+ * @example
+ *
+ * _.isElement(document.body);
+ * // => true
+ *
+ * _.isElement('<body>');
+ * // => false
+ */
+ function isElement(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) &&
+ objToString.call(value).indexOf('Element') > -1) || false;
+ }
+ // Fallback for environments without DOM support.
+ if (!support.dom) {
+ isElement = function(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value)) || false;
+ };
+ }
+
+ /**
+ * Checks if a value is empty. A value is considered empty unless it is an
+ * `arguments` object, array, string, or jQuery-like collection with a length
+ * greater than `0` or an object with own enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Array|Object|string} value The value to inspect.
+ * @returns {boolean} Returns `true` if `value` is empty, else `false`.
+ * @example
+ *
+ * _.isEmpty(null);
+ * // => true
+ *
+ * _.isEmpty(true);
+ * // => true
+ *
+ * _.isEmpty(1);
+ * // => true
+ *
+ * _.isEmpty([1, 2, 3]);
+ * // => false
+ *
+ * _.isEmpty({ 'a': 1 });
+ * // => false
+ */
+ function isEmpty(value) {
+ if (value == null) {
+ return true;
+ }
+ var length = value.length;
+ if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) ||
+ (isObjectLike(value) && isFunction(value.splice)))) {
+ return !length;
+ }
+ return !keys(value).length;
+ }
+
+ /**
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent. If `customizer` is provided it is invoked to compare values.
+ * If `customizer` returns `undefined` comparisons are handled by the method
+ * instead. The `customizer` is bound to `thisArg` and invoked with three
+ * arguments; (value, other [, index|key]).
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Functions and DOM nodes
+ * are **not** supported. Provide a customizer function to extend support
+ * for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'fred' };
+ *
+ * object == other;
+ * // => false
+ *
+ * _.isEqual(object, other);
+ * // => true
+ *
+ * // using a customizer callback
+ * var array = ['hello', 'goodbye'];
+ * var other = ['hi', 'goodbye'];
+ *
+ * _.isEqual(array, other, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isEqual(value, other, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && isStrictComparable(value) && isStrictComparable(other)) {
+ return value === other;
+ }
+ var result = customizer ? customizer(value, other) : undefined;
+ return typeof result == 'undefined' ? baseIsEqual(value, other, customizer) : !!result;
+ }
+
+ /**
+ * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+ * `SyntaxError`, `TypeError`, or `URIError` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
+ * @example
+ *
+ * _.isError(new Error);
+ * // => true
+ *
+ * _.isError(Error);
+ * // => false
+ */
+ function isError(value) {
+ return (isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a finite primitive number.
+ *
+ * **Note:** This method is based on ES6 `Number.isFinite`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
+ * @example
+ *
+ * _.isFinite(10);
+ * // => true
+ *
+ * _.isFinite('10');
+ * // => false
+ *
+ * _.isFinite(true);
+ * // => false
+ *
+ * _.isFinite(Object(10));
+ * // => false
+ *
+ * _.isFinite(Infinity);
+ * // => false
+ */
+ var isFinite = nativeNumIsFinite || function(value) {
+ return typeof value == 'number' && nativeIsFinite(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // Avoid a Chakra JIT bug in compatibility modes of IE 11.
+ // See https://github.com/jashkenas/underscore/issues/1621.
+ return typeof value == 'function' || false;
+ }
+ // Fallback for environments that return incorrect `typeof` operator results.
+ if (isFunction(/x/) || (Uint8Array && !isFunction(Uint8Array))) {
+ isFunction = function(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in older versions of Chrome and Safari which return 'function' for regexes
+ // and Safari 8 equivalents which return 'object' for typed array constructors.
+ return objToString.call(value) == funcTag;
+ };
+ }
+
+ /**
+ * Checks if `value` is the language type of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * **Note:** See the [ES5 spec](http://es5.github.io/#x8) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+ function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291.
+ var type = typeof value;
+ return type == 'function' || (value && type == 'object') || false;
+ }
+
+ /**
+ * Performs a deep comparison between `object` and `source` to determine if
+ * `object` contains equivalent property values. If `customizer` is provided
+ * it is invoked to compare values. If `customizer` returns `undefined`
+ * comparisons are handled by the method instead. The `customizer` is bound
+ * to `thisArg` and invoked with three arguments; (value, other, index|key).
+ *
+ * **Note:** This method supports comparing properties of arrays, booleans,
+ * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions
+ * and DOM nodes are **not** supported. Provide a customizer function to extend
+ * support for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Object} source The object to inspect.
+ * @param {Object} source The object of property values to match.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.isMatch(object, { 'age': 40 });
+ * // => true
+ *
+ * _.isMatch(object, { 'age': 36 });
+ * // => false
+ *
+ * // using a customizer callback
+ * var object = { 'greeting': 'hello' };
+ * var source = { 'greeting': 'hi' };
+ *
+ * _.isMatch(object, source, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isMatch(object, source, customizer, thisArg) {
+ var props = keys(source),
+ length = props.length;
+
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ }
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = values[length] = source[props[length]];
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return baseIsMatch(object, props, values, strictCompareFlags, customizer);
+ }
+
+ /**
+ * Checks if `value` is `NaN`.
+ *
+ * **Note:** This method is not the same as native `isNaN` which returns `true`
+ * for `undefined` and other non-numeric values. See the [ES5 spec](http://es5.github.io/#x15.1.2.4)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+ * @example
+ *
+ * _.isNaN(NaN);
+ * // => true
+ *
+ * _.isNaN(new Number(NaN));
+ * // => true
+ *
+ * isNaN(undefined);
+ * // => true
+ *
+ * _.isNaN(undefined);
+ * // => false
+ */
+ function isNaN(value) {
+ // An `NaN` primitive is the only value that is not equal to itself.
+ // Perform the `toStringTag` check first to avoid errors with some host objects in IE.
+ return isNumber(value) && value != +value;
+ }
+
+ /**
+ * Checks if `value` is a native function.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
+ * @example
+ *
+ * _.isNative(Array.prototype.push);
+ * // => true
+ *
+ * _.isNative(_);
+ * // => false
+ */
+ function isNative(value) {
+ if (value == null) {
+ return false;
+ }
+ if (objToString.call(value) == funcTag) {
+ return reNative.test(fnToString.call(value));
+ }
+ return (isObjectLike(value) && reHostCtor.test(value)) || false;
+ }
+
+ /**
+ * Checks if `value` is `null`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
+ * @example
+ *
+ * _.isNull(null);
+ * // => true
+ *
+ * _.isNull(void 0);
+ * // => false
+ */
+ function isNull(value) {
+ return value === null;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Number` primitive or object.
+ *
+ * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified
+ * as numbers, use the `_.isFinite` method.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isNumber(8.4);
+ * // => true
+ *
+ * _.isNumber(NaN);
+ * // => true
+ *
+ * _.isNumber('8.4');
+ * // => false
+ */
+ function isNumber(value) {
+ return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
+ *
+ * **Note:** This method assumes objects created by the `Object` constructor
+ * have no inherited enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * }
+ *
+ * _.isPlainObject(new Foo);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ *
+ * _.isPlainObject(Object.create(null));
+ * // => true
+ */
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
+ if (!(value && objToString.call(value) == objectTag)) {
+ return false;
+ }
+ var valueOf = value.valueOf,
+ objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
+
+ return objProto
+ ? (value == objProto || getPrototypeOf(value) == objProto)
+ : shimIsPlainObject(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `RegExp` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isRegExp(/abc/);
+ * // => true
+ *
+ * _.isRegExp('/abc/');
+ * // => false
+ */
+ function isRegExp(value) {
+ return (isObjectLike(value) && objToString.call(value) == regexpTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a `String` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isString('abc');
+ * // => true
+ *
+ * _.isString(1);
+ * // => false
+ */
+ function isString(value) {
+ return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+ function isTypedArray(value) {
+ return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false;
+ }
+
+ /**
+ * Checks if `value` is `undefined`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+ * @example
+ *
+ * _.isUndefined(void 0);
+ * // => true
+ *
+ * _.isUndefined(null);
+ * // => false
+ */
+ function isUndefined(value) {
+ return typeof value == 'undefined';
+ }
+
+ /**
+ * Converts `value` to an array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Array} Returns the converted array.
+ * @example
+ *
+ * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3);
+ * // => [2, 3]
+ */
+ function toArray(value) {
+ var length = value ? value.length : 0;
+ if (!isLength(length)) {
+ return values(value);
+ }
+ if (!length) {
+ return [];
+ }
+ return arrayCopy(value);
+ }
+
+ /**
+ * Converts `value` to a plain object flattening inherited enumerable
+ * properties of `value` to own properties of the plain object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Object} Returns the converted plain object.
+ * @example
+ *
+ * function Foo() {
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.assign({ 'a': 1 }, new Foo);
+ * // => { 'a': 1, 'b': 2 }
+ *
+ * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+ * // => { 'a': 1, 'b': 2, 'c': 3 }
+ */
+ function toPlainObject(value) {
+ return baseCopy(value, keysIn(value));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources overwrite property assignments of previous sources.
+ * If `customizer` is provided it is invoked to produce the assigned values.
+ * The `customizer` is bound to `thisArg` and invoked with five arguments;
+ * (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @alias extend
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+ * // => { 'user': 'fred', 'age': 40 }
+ *
+ * // using a customizer callback
+ * var defaults = _.partialRight(_.assign, function(value, other) {
+ * return typeof value == 'undefined' ? other : value;
+ * });
+ *
+ * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ var assign = createAssigner(baseAssign);
+
+ /**
+ * Creates an object that inherits from the given `prototype` object. If a
+ * `properties` object is provided its own enumerable properties are assigned
+ * to the created object.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} prototype The object to inherit from.
+ * @param {Object} [properties] The properties to assign to the object.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * function Circle() {
+ * Shape.call(this);
+ * }
+ *
+ * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
+ *
+ * var circle = new Circle;
+ * circle instanceof Circle;
+ * // => true
+ *
+ * circle instanceof Shape;
+ * // => true
+ */
+ function create(prototype, properties, guard) {
+ var result = baseCreate(prototype);
+ if (guard && isIterateeCall(prototype, properties, guard)) {
+ properties = null;
+ }
+ return properties ? baseCopy(properties, result, keys(properties)) : result;
+ }
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object for all destination properties that resolve to `undefined`. Once a
+ * property is set, additional defaults of the same property are ignored.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function defaults(object) {
+ if (object == null) {
+ return object;
+ }
+ var args = arrayCopy(arguments);
+ args.push(assignDefaults);
+ return assign.apply(undefined, args);
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it returns the key of the
+ * first element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findKey(users, function(chr) { return chr.age < 40; });
+ * // => 'barney' (iteration order is not guaranteed)
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findKey(users, { 'age': 1 });
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findKey(users, 'active');
+ * // => 'barney'
+ */
+ function findKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwn, true);
+ }
+
+ /**
+ * This method is like `_.findKey` except that it iterates over elements of
+ * a collection in the opposite order.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findLastKey(users, function(chr) { return chr.age < 40; });
+ * // => returns `pebbles` assuming `_.findKey` returns `barney`
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastKey(users, { 'age': 36 });
+ * // => 'barney'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastKey(users, 'active');
+ * // => 'pebbles'
+ */
+ function findLastKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwnRight, true);
+ }
+
+ /**
+ * Iterates over own and inherited enumerable properties of an object invoking
+ * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, key, object). Iterator functions may exit
+ * iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forIn(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed)
+ */
+ function forIn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * This method is like `_.forIn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forInRight(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c'
+ */
+ function forInRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keysIn);
+ }
+
+ /**
+ * Iterates over own enumerable properties of an object invoking `iteratee`
+ * for each property. The `iteratee` is bound to `thisArg` and invoked with
+ * three arguments; (value, key, object). Iterator functions may exit iteration
+ * early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs '0', '1', and 'length' (iteration order is not guaranteed)
+ */
+ function forOwn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return baseForOwn(object, iteratee);
+ }
+
+ /**
+ * This method is like `_.forOwn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
+ */
+ function forOwnRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * Creates an array of function property names from all enumerable properties,
+ * own and inherited, of `object`.
+ *
+ * @static
+ * @memberOf _
+ * @alias methods
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of property names.
+ * @example
+ *
+ * _.functions(_);
+ * // => ['all', 'any', 'bind', ...]
+ */
+ function functions(object) {
+ return baseFunctions(object, keysIn(object));
+ }
+
+ /**
+ * Checks if `key` exists as a direct property of `object` instead of an
+ * inherited property.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @param {string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` is a direct property, else `false`.
+ * @example
+ *
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+ * // => true
+ */
+ function has(object, key) {
+ return object ? hasOwnProperty.call(object, key) : false;
+ }
+
+ /**
+ * Creates an object composed of the inverted keys and values of `object`.
+ * If `object` contains duplicate values, subsequent values overwrite property
+ * assignments of previous values unless `multiValue` is `true`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to invert.
+ * @param {boolean} [multiValue] Allow multiple values per key.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new inverted object.
+ * @example
+ *
+ * _.invert({ 'first': 'fred', 'second': 'barney' });
+ * // => { 'fred': 'first', 'barney': 'second' }
+ *
+ * // without `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' });
+ * // => { 'fred': 'third', 'barney': 'second' }
+ *
+ * // with `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }, true);
+ * // => { 'fred': ['first', 'third'], 'barney': ['second'] }
+ */
+ function invert(object, multiValue, guard) {
+ if (guard && isIterateeCall(object, multiValue, guard)) {
+ multiValue = null;
+ }
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key];
+
+ if (multiValue) {
+ if (hasOwnProperty.call(result, value)) {
+ result[value].push(key);
+ } else {
+ result[value] = [key];
+ }
+ }
+ else {
+ result[value] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ var keys = !nativeKeys ? shimKeys : function(object) {
+ if (object) {
+ var Ctor = object.constructor,
+ length = object.length;
+ }
+ if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
+ (typeof object != 'function' && (length && isLength(length)))) {
+ return shimKeys(object);
+ }
+ return isObject(object) ? nativeKeys(object) : [];
+ };
+
+ /**
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+ */
+ function keysIn(object) {
+ if (object == null) {
+ return [];
+ }
+ if (!isObject(object)) {
+ object = Object(object);
+ }
+ var length = object.length;
+ length = (length && isLength(length) &&
+ (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0;
+
+ var Ctor = object.constructor,
+ index = -1,
+ isProto = typeof Ctor == 'function' && Ctor.prototype == object,
+ result = Array(length),
+ skipIndexes = length > 0;
+
+ while (++index < length) {
+ result[index] = (index + '');
+ }
+ for (var key in object) {
+ if (!(skipIndexes && isIndex(key, length)) &&
+ !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object with the same keys as `object` and values generated by
+ * running each own enumerable property of `object` through `iteratee`. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * If a property name is provided for `iteratee` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `iteratee` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the new mapped object.
+ * @example
+ *
+ * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(n) { return n * 3; });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ *
+ * var users = {
+ * 'fred': { 'user': 'fred', 'age': 40 },
+ * 'pebbles': { 'user': 'pebbles', 'age': 1 }
+ * };
+ *
+ * // using the "_.property" callback shorthand
+ * _.mapValues(users, 'age');
+ * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+ */
+ function mapValues(object, iteratee, thisArg) {
+ var result = {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ baseForOwn(object, function(value, key, object) {
+ result[key] = iteratee(value, key, object);
+ });
+ return result;
+ }
+
+ /**
+ * Recursively merges own enumerable properties of the source object(s), that
+ * don't resolve to `undefined` into the destination object. Subsequent sources
+ * overwrite property assignments of previous sources. If `customizer` is
+ * provided it is invoked to produce the merged values of the destination and
+ * source properties. If `customizer` returns `undefined` merging is handled
+ * by the method instead. The `customizer` is bound to `thisArg` and invoked
+ * with five arguments; (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var users = {
+ * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
+ * };
+ *
+ * var ages = {
+ * 'data': [{ 'age': 36 }, { 'age': 40 }]
+ * };
+ *
+ * _.merge(users, ages);
+ * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
+ *
+ * // using a customizer callback
+ * var object = {
+ * 'fruits': ['apple'],
+ * 'vegetables': ['beet']
+ * };
+ *
+ * var other = {
+ * 'fruits': ['banana'],
+ * 'vegetables': ['carrot']
+ * };
+ *
+ * _.merge(object, other, function(a, b) {
+ * return _.isArray(a) ? a.concat(b) : undefined;
+ * });
+ * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
+ */
+ var merge = createAssigner(baseMerge);
+
+ /**
+ * The opposite of `_.pick`; this method creates an object composed of the
+ * own and inherited enumerable properties of `object` that are not omitted.
+ * Property names may be specified as individual arguments or as arrays of
+ * property names. If `predicate` is provided it is invoked for each property
+ * of `object` omitting the properties `predicate` returns truthy for. The
+ * predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to omit, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.omit(object, 'age');
+ * // => { 'user': 'fred' }
+ *
+ * _.omit(object, _.isNumber);
+ * // => { 'user': 'fred' }
+ */
+ function omit(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ if (typeof predicate != 'function') {
+ var props = arrayMap(baseFlatten(arguments, false, false, 1), String);
+ return pickByArray(object, baseDifference(keysIn(object), props));
+ }
+ predicate = bindCallback(predicate, thisArg, 3);
+ return pickByCallback(object, function(value, key, object) {
+ return !predicate(value, key, object);
+ });
+ }
+
+ /**
+ * Creates a two dimensional array of the key-value pairs for `object`,
+ * e.g. `[[key1, value1], [key2, value2]]`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of key-value pairs.
+ * @example
+ *
+ * _.pairs({ 'barney': 36, 'fred': 40 });
+ * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
+ */
+ function pairs(object) {
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var key = props[index];
+ result[index] = [key, object[key]];
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object composed of the picked `object` properties. Property
+ * names may be specified as individual arguments or as arrays of property
+ * names. If `predicate` is provided it is invoked for each property of `object`
+ * picking the properties `predicate` returns truthy for. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to pick, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.pick(object, 'user');
+ * // => { 'user': 'fred' }
+ *
+ * _.pick(object, _.isString);
+ * // => { 'user': 'fred' }
+ */
+ function pick(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ return typeof predicate == 'function'
+ ? pickByCallback(object, bindCallback(predicate, thisArg, 3))
+ : pickByArray(object, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Resolves the value of property `key` on `object`. If the value of `key` is
+ * a function it is invoked with the `this` binding of `object` and its result
+ * is returned, else the property value is returned. If the property value is
+ * `undefined` the `defaultValue` is used in its place.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the property to resolve.
+ * @param {*} [defaultValue] The value returned if the property value
+ * resolves to `undefined`.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': _.constant(40) };
+ *
+ * _.result(object, 'user');
+ * // => 'fred'
+ *
+ * _.result(object, 'age');
+ * // => 40
+ *
+ * _.result(object, 'status', 'busy');
+ * // => 'busy'
+ *
+ * _.result(object, 'status', _.constant('busy'));
+ * // => 'busy'
+ */
+ function result(object, key, defaultValue) {
+ var value = object == null ? undefined : object[key];
+ if (typeof value == 'undefined') {
+ value = defaultValue;
+ }
+ return isFunction(value) ? value.call(object) : value;
+ }
+
+ /**
+ * An alternative to `_.reduce`; this method transforms `object` to a new
+ * `accumulator` object which is the result of running each of its own enumerable
+ * properties through `iteratee`, with each invocation potentially mutating
+ * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked
+ * with four arguments; (accumulator, value, key, object). Iterator functions
+ * may exit iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Array|Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The custom accumulator value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var squares = _.transform([1, 2, 3, 4, 5, 6], function(result, n) {
+ * n *= n;
+ * if (n % 2) {
+ * return result.push(n) < 3;
+ * }
+ * });
+ * // => [1, 9, 25]
+ *
+ * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ */
+ function transform(object, iteratee, accumulator, thisArg) {
+ var isArr = isArray(object) || isTypedArray(object);
+ iteratee = getCallback(iteratee, thisArg, 4);
+
+ if (accumulator == null) {
+ if (isArr || isObject(object)) {
+ var Ctor = object.constructor;
+ if (isArr) {
+ accumulator = isArray(object) ? new Ctor : [];
+ } else {
+ accumulator = baseCreate(typeof Ctor == 'function' && Ctor.prototype);
+ }
+ } else {
+ accumulator = {};
+ }
+ }
+ (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) {
+ return iteratee(accumulator, value, index, object);
+ });
+ return accumulator;
+ }
+
+ /**
+ * Creates an array of the own enumerable property values of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.values(new Foo);
+ * // => [1, 2] (iteration order is not guaranteed)
+ *
+ * _.values('hi');
+ * // => ['h', 'i']
+ */
+ function values(object) {
+ return baseValues(object, keys(object));
+ }
+
+ /**
+ * Creates an array of the own and inherited enumerable property values
+ * of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.valuesIn(new Foo);
+ * // => [1, 2, 3] (iteration order is not guaranteed)
+ */
+ function valuesIn(object) {
+ return baseValues(object, keysIn(object));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Produces a random number between `min` and `max` (inclusive). If only one
+ * argument is provided a number between `0` and the given number is returned.
+ * If `floating` is `true`, or either `min` or `max` are floats, a floating-point
+ * number is returned instead of an integer.
+ *
+ * @static
+ * @memberOf _
+ * @category Number
+ * @param {number} [min=0] The minimum possible value.
+ * @param {number} [max=1] The maximum possible value.
+ * @param {boolean} [floating] Specify returning a floating-point number.
+ * @returns {number} Returns the random number.
+ * @example
+ *
+ * _.random(0, 5);
+ * // => an integer between 0 and 5
+ *
+ * _.random(5);
+ * // => also an integer between 0 and 5
+ *
+ * _.random(5, true);
+ * // => a floating-point number between 0 and 5
+ *
+ * _.random(1.2, 5.2);
+ * // => a floating-point number between 1.2 and 5.2
+ */
+ function random(min, max, floating) {
+ if (floating && isIterateeCall(min, max, floating)) {
+ max = floating = null;
+ }
+ var noMin = min == null,
+ noMax = max == null;
+
+ if (floating == null) {
+ if (noMax && typeof min == 'boolean') {
+ floating = min;
+ min = 1;
+ }
+ else if (typeof max == 'boolean') {
+ floating = max;
+ noMax = true;
+ }
+ }
+ if (noMin && noMax) {
+ max = 1;
+ noMax = false;
+ }
+ min = +min || 0;
+ if (noMax) {
+ max = min;
+ min = 0;
+ } else {
+ max = +max || 0;
+ }
+ if (floating || min % 1 || max % 1) {
+ var rand = nativeRandom();
+ return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max);
+ }
+ return baseRandom(min, max);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Converts `string` to camel case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/CamelCase) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the camel cased string.
+ * @example
+ *
+ * _.camelCase('Foo Bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('--foo-bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('__foo_bar__');
+ * // => 'fooBar'
+ */
+ var camelCase = createCompounder(function(result, word, index) {
+ word = word.toLowerCase();
+ return index ? (result + word.charAt(0).toUpperCase() + word.slice(1)) : word;
+ });
+
+ /**
+ * Capitalizes the first character of `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to capitalize.
+ * @returns {string} Returns the capitalized string.
+ * @example
+ *
+ * _.capitalize('fred');
+ * // => 'Fred'
+ */
+ function capitalize(string) {
+ string = baseToString(string);
+ return string && (string.charAt(0).toUpperCase() + string.slice(1));
+ }
+
+ /**
+ * Deburrs `string` by converting latin-1 supplementary letters to basic latin letters.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to deburr.
+ * @returns {string} Returns the deburred string.
+ * @example
+ *
+ * _.deburr('déjà vu');
+ * // => 'deja vu'
+ */
+ function deburr(string) {
+ string = baseToString(string);
+ return string && string.replace(reLatin1, deburrLetter);
+ }
+
+ /**
+ * Checks if `string` ends with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=string.length] The position to search from.
+ * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`.
+ * @example
+ *
+ * _.endsWith('abc', 'c');
+ * // => true
+ *
+ * _.endsWith('abc', 'b');
+ * // => false
+ *
+ * _.endsWith('abc', 'b', 2);
+ * // => true
+ */
+ function endsWith(string, target, position) {
+ string = baseToString(string);
+ target = (target + '');
+
+ var length = string.length;
+ position = (typeof position == 'undefined' ? length : nativeMin(position < 0 ? 0 : (+position || 0), length)) - target.length;
+ return position >= 0 && string.indexOf(target, position) == position;
+ }
+
+ /**
+ * Converts the characters "&", "<", ">", '"', "'", and '`', in `string` to
+ * their corresponding HTML entities.
+ *
+ * **Note:** No other characters are escaped. To escape additional characters
+ * use a third-party library like [_he_](http://mths.be/he).
+ *
+ * Though the ">" character is escaped for symmetry, characters like
+ * ">" and "/" don't require escaping in HTML and have no special meaning
+ * unless they're part of a tag or unquoted attribute value.
+ * See [Mathias Bynens's article](http://mathiasbynens.be/notes/ambiguous-ampersands)
+ * (under "semi-related fun fact") for more details.
+ *
+ * Backticks are escaped because in Internet Explorer < 9, they can break out
+ * of attribute values or HTML comments. See [#102](http://html5sec.org/#102),
+ * [#108](http://html5sec.org/#108), and [#133](http://html5sec.org/#133) of
+ * the [HTML5 Security Cheatsheet](http://html5sec.org/) for more details.
+ *
+ * When working with HTML you should always quote attribute values to reduce
+ * XSS vectors. See [Ryan Grove's article](http://wonko.com/post/html-escaping)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function escape(string) {
+ // Reset `lastIndex` because in IE < 9 `String#replace` does not.
+ string = baseToString(string);
+ return (string && reHasUnescapedHtml.test(string))
+ ? string.replace(reUnescapedHtml, escapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*",
+ * "+", "(", ")", "[", "]", "{" and "}" in `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escapeRegExp('[lodash](https://lodash.com/)');
+ * // => '\[lodash\]\(https://lodash\.com/\)'
+ */
+ function escapeRegExp(string) {
+ string = baseToString(string);
+ return (string && reHasRegExpChars.test(string))
+ ? string.replace(reRegExpChars, '\\$&')
+ : string;
+ }
+
+ /**
+ * Converts `string` to kebab case (a.k.a. spinal case).
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Letter_case#Computers) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the kebab cased string.
+ * @example
+ *
+ * _.kebabCase('Foo Bar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('fooBar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('__foo_bar__');
+ * // => 'foo-bar'
+ */
+ var kebabCase = createCompounder(function(result, word, index) {
+ return result + (index ? '-' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Pads `string` on the left and right sides if it is shorter then the given
+ * padding length. The `chars` string may be truncated if the number of padding
+ * characters can't be evenly divided by the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.pad('abc', 8);
+ * // => ' abc '
+ *
+ * _.pad('abc', 8, '_-');
+ * // => '_-abc_-_'
+ *
+ * _.pad('abc', 3);
+ * // => 'abc'
+ */
+ function pad(string, length, chars) {
+ string = baseToString(string);
+ length = +length;
+
+ var strLength = string.length;
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return string;
+ }
+ var mid = (length - strLength) / 2,
+ leftLength = floor(mid),
+ rightLength = ceil(mid);
+
+ chars = createPad('', rightLength, chars);
+ return chars.slice(0, leftLength) + string + chars;
+ }
+
+ /**
+ * Pads `string` on the left side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padLeft('abc', 6);
+ * // => ' abc'
+ *
+ * _.padLeft('abc', 6, '_-');
+ * // => '_-_abc'
+ *
+ * _.padLeft('abc', 3);
+ * // => 'abc'
+ */
+ function padLeft(string, length, chars) {
+ string = baseToString(string);
+ return string && (createPad(string, length, chars) + string);
+ }
+
+ /**
+ * Pads `string` on the right side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padRight('abc', 6);
+ * // => 'abc '
+ *
+ * _.padRight('abc', 6, '_-');
+ * // => 'abc_-_'
+ *
+ * _.padRight('abc', 3);
+ * // => 'abc'
+ */
+ function padRight(string, length, chars) {
+ string = baseToString(string);
+ return string && (string + createPad(string, length, chars));
+ }
+
+ /**
+ * Converts `string` to an integer of the specified radix. If `radix` is
+ * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal,
+ * in which case a `radix` of `16` is used.
+ *
+ * **Note:** This method aligns with the ES5 implementation of `parseInt`.
+ * See the [ES5 spec](http://es5.github.io/#E) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} string The string to convert.
+ * @param {number} [radix] The radix to interpret `value` by.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {number} Returns the converted integer.
+ * @example
+ *
+ * _.parseInt('08');
+ * // => 8
+ *
+ * _.map(['6', '08', '10'], _.parseInt);
+ * // => [6, 8, 10]
+ */
+ function parseInt(string, radix, guard) {
+ if (guard && isIterateeCall(string, radix, guard)) {
+ radix = 0;
+ }
+ return nativeParseInt(string, radix);
+ }
+ // Fallback for environments with pre-ES5 implementations.
+ if (nativeParseInt(whitespace + '08') != 8) {
+ parseInt = function(string, radix, guard) {
+ // Firefox < 21 and Opera < 15 follow ES3 for `parseInt` and
+ // Chrome fails to trim leading <BOM> whitespace characters.
+ // See https://code.google.com/p/v8/issues/detail?id=3109.
+ if (guard ? isIterateeCall(string, radix, guard) : radix == null) {
+ radix = 0;
+ } else if (radix) {
+ radix = +radix;
+ }
+ string = trim(string);
+ return nativeParseInt(string, radix || (reHexPrefix.test(string) ? 16 : 10));
+ };
+ }
+
+ /**
+ * Repeats the given string `n` times.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to repeat.
+ * @param {number} [n=0] The number of times to repeat the string.
+ * @returns {string} Returns the repeated string.
+ * @example
+ *
+ * _.repeat('*', 3);
+ * // => '***'
+ *
+ * _.repeat('abc', 2);
+ * // => 'abcabc'
+ *
+ * _.repeat('abc', 0);
+ * // => ''
+ */
+ function repeat(string, n) {
+ var result = '';
+ string = baseToString(string);
+ n = +n;
+ if (n < 1 || !string || !nativeIsFinite(n)) {
+ return result;
+ }
+ // Leverage the exponentiation by squaring algorithm for a faster repeat.
+ // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring.
+ do {
+ if (n % 2) {
+ result += string;
+ }
+ n = floor(n / 2);
+ string += string;
+ } while (n);
+
+ return result;
+ }
+
+ /**
+ * Converts `string` to snake case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Snake_case) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the snake cased string.
+ * @example
+ *
+ * _.snakeCase('Foo Bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('--foo-bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('fooBar');
+ * // => 'foo_bar'
+ */
+ var snakeCase = createCompounder(function(result, word, index) {
+ return result + (index ? '_' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Checks if `string` starts with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=0] The position to search from.
+ * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`.
+ * @example
+ *
+ * _.startsWith('abc', 'a');
+ * // => true
+ *
+ * _.startsWith('abc', 'b');
+ * // => false
+ *
+ * _.startsWith('abc', 'b', 1);
+ * // => true
+ */
+ function startsWith(string, target, position) {
+ string = baseToString(string);
+ position = position == null ? 0 : nativeMin(position < 0 ? 0 : (+position || 0), string.length);
+ return string.lastIndexOf(target, position) == position;
+ }
+
+ /**
+ * Creates a compiled template function that can interpolate data properties
+ * in "interpolate" delimiters, HTML-escape interpolated data properties in
+ * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+ * properties may be accessed as free variables in the template. If a setting
+ * object is provided it takes precedence over `_.templateSettings` values.
+ *
+ * **Note:** In the development build `_.template` utilizes sourceURLs for easier debugging.
+ * See the [HTML5 Rocks article on sourcemaps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+ * for more details.
+ *
+ * For more information on precompiling templates see
+ * [Lo-Dash's custom builds documentation](https://lodash.com/custom-builds).
+ *
+ * For more information on Chrome extension sandboxes see
+ * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The template string.
+ * @param {Object} [options] The options object.
+ * @param {RegExp} [options.escape] The HTML "escape" delimiter.
+ * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
+ * @param {Object} [options.imports] An object to import into the template as free variables.
+ * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
+ * @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
+ * @param {string} [options.variable] The data object variable name.
+ * @param- {Object} [otherOptions] Enables the legacy `options` param signature.
+ * @returns {Function} Returns the compiled template function.
+ * @example
+ *
+ * // using the "interpolate" delimiter to create a compiled template
+ * var compiled = _.template('hello <%= user %>!');
+ * compiled({ 'user': 'fred' });
+ * // => 'hello fred!'
+ *
+ * // using the HTML "escape" delimiter to escape data property values
+ * var compiled = _.template('<b><%- value %></b>');
+ * compiled({ 'value': '<script>' });
+ * // => '<b><script></b>'
+ *
+ * // using the "evaluate" delimiter to execute JavaScript and generate HTML
+ * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the internal `print` function in "evaluate" delimiters
+ * var compiled = _.template('<% print("hello " + user); %>!');
+ * compiled({ 'user': 'barney' });
+ * // => 'hello barney!'
+ *
+ * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
+ * var compiled = _.template('hello ${ user }!');
+ * compiled({ 'user': 'pebbles' });
+ * // => 'hello pebbles!'
+ *
+ * // using custom template delimiters
+ * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+ * var compiled = _.template('hello {{ user }}!');
+ * compiled({ 'user': 'mustache' });
+ * // => 'hello mustache!'
+ *
+ * // using backslashes to treat delimiters as plain text
+ * var compiled = _.template('<%= "\\<%- value %\\>" %>');
+ * compiled({ 'value': 'ignored' });
+ * // => '<%- value %>'
+ *
+ * // using the `imports` option to import `jQuery` as `jq`
+ * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
+ * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
+ * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
+ * compiled(data);
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
+ *
+ * // using the `variable` option to ensure a with-statement isn't used in the compiled template
+ * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
+ * compiled.source;
+ * // => function(data) {
+ * var __t, __p = '';
+ * __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
+ * return __p;
+ * }
+ *
+ * // using the `source` property to inline compiled templates for meaningful
+ * // line numbers in error messages and a stack trace
+ * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
+ * var JST = {\
+ * "main": ' + _.template(mainText).source + '\
+ * };\
+ * ');
+ */
+ function template(string, options, otherOptions) {
+ // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/)
+ // and Laura Doktorova's doT.js (https://github.com/olado/doT).
+ var settings = lodash.templateSettings;
+
+ if (otherOptions && isIterateeCall(string, options, otherOptions)) {
+ options = otherOptions = null;
+ }
+ string = baseToString(string);
+ options = baseAssign(baseAssign({}, otherOptions || options), settings, assignOwnDefaults);
+
+ var imports = baseAssign(baseAssign({}, options.imports), settings.imports, assignOwnDefaults),
+ importsKeys = keys(imports),
+ importsValues = baseValues(imports, importsKeys);
+
+ var isEscaping,
+ isEvaluating,
+ index = 0,
+ interpolate = options.interpolate || reNoMatch,
+ source = "__p += '";
+
+ // Compile the regexp to match each delimiter.
+ var reDelimiters = RegExp(
+ (options.escape || reNoMatch).source + '|' +
+ interpolate.source + '|' +
+ (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
+ (options.evaluate || reNoMatch).source + '|$'
+ , 'g');
+
+ // Use a sourceURL for easier debugging.
+ // See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl.
+ var sourceURL = '//# sourceURL=' +
+ ('sourceURL' in options
+ ? options.sourceURL
+ : ('lodash.templateSources[' + (++templateCounter) + ']')
+ ) + '\n';
+
+ string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
+ interpolateValue || (interpolateValue = esTemplateValue);
+
+ // Escape characters that can't be included in string literals.
+ source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
+
+ // Replace delimiters with snippets.
+ if (escapeValue) {
+ isEscaping = true;
+ source += "' +\n__e(" + escapeValue + ") +\n'";
+ }
+ if (evaluateValue) {
+ isEvaluating = true;
+ source += "';\n" + evaluateValue + ";\n__p += '";
+ }
+ if (interpolateValue) {
+ source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
+ }
+ index = offset + match.length;
+
+ // The JS engine embedded in Adobe products requires returning the `match`
+ // string in order to produce the correct `offset` value.
+ return match;
+ });
+
+ source += "';\n";
+
+ // If `variable` is not specified wrap a with-statement around the generated
+ // code to add the data object to the top of the scope chain.
+ var variable = options.variable;
+ if (!variable) {
+ source = 'with (obj) {\n' + source + '\n}\n';
+ }
+ // Cleanup code by stripping empty strings.
+ source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
+ .replace(reEmptyStringMiddle, '$1')
+ .replace(reEmptyStringTrailing, '$1;');
+
+ // Frame code as the function body.
+ source = 'function(' + (variable || 'obj') + ') {\n' +
+ (variable
+ ? ''
+ : 'obj || (obj = {});\n'
+ ) +
+ "var __t, __p = ''" +
+ (isEscaping
+ ? ', __e = _.escape'
+ : ''
+ ) +
+ (isEvaluating
+ ? ', __j = Array.prototype.join;\n' +
+ "function print() { __p += __j.call(arguments, '') }\n"
+ : ';\n'
+ ) +
+ source +
+ 'return __p\n}';
+
+ var result = attempt(function() {
+ return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues);
+ });
+
+ // Provide the compiled function's source by its `toString` method or
+ // the `source` property as a convenience for inlining compiled templates.
+ result.source = source;
+ if (isError(result)) {
+ throw result;
+ }
+ return result;
+ }
+
+ /**
+ * Removes leading and trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trim(' abc ');
+ * // => 'abc'
+ *
+ * _.trim('-_-abc-_-', '_-');
+ * // => 'abc'
+ *
+ * _.map([' foo ', ' bar '], _.trim);
+ * // => ['foo', 'bar]
+ */
+ function trim(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string), trimmedRightIndex(string) + 1);
+ }
+ chars = baseToString(chars);
+ return string.slice(charsLeftIndex(string, chars), charsRightIndex(string, chars) + 1);
+ }
+
+ /**
+ * Removes leading whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimLeft(' abc ');
+ * // => 'abc '
+ *
+ * _.trimLeft('-_-abc-_-', '_-');
+ * // => 'abc-_-'
+ */
+ function trimLeft(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string))
+ }
+ return string.slice(charsLeftIndex(string, baseToString(chars)));
+ }
+
+ /**
+ * Removes trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimRight(' abc ');
+ * // => ' abc'
+ *
+ * _.trimRight('-_-abc-_-', '_-');
+ * // => '-_-abc'
+ */
+ function trimRight(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(0, trimmedRightIndex(string) + 1)
+ }
+ return string.slice(0, charsRightIndex(string, baseToString(chars)) + 1);
+ }
+
+ /**
+ * Truncates `string` if it is longer than the given maximum string length.
+ * The last characters of the truncated string are replaced with the omission
+ * string which defaults to "...".
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to truncate.
+ * @param {Object|number} [options] The options object or maximum string length.
+ * @param {number} [options.length=30] The maximum string length.
+ * @param {string} [options.omission='...'] The string to indicate text is omitted.
+ * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the truncated string.
+ * @example
+ *
+ * _.trunc('hi-diddly-ho there, neighborino');
+ * // => 'hi-diddly-ho there, neighbo...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', 24);
+ * // => 'hi-diddly-ho there, n...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': ' ' });
+ * // => 'hi-diddly-ho there,...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': /,? +/ });
+ * //=> 'hi-diddly-ho there...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'omission': ' [...]' });
+ * // => 'hi-diddly-ho there, neig [...]'
+ */
+ function trunc(string, options, guard) {
+ if (guard && isIterateeCall(string, options, guard)) {
+ options = null;
+ }
+ var length = DEFAULT_TRUNC_LENGTH,
+ omission = DEFAULT_TRUNC_OMISSION;
+
+ if (options != null) {
+ if (isObject(options)) {
+ var separator = 'separator' in options ? options.separator : separator;
+ length = 'length' in options ? +options.length || 0 : length;
+ omission = 'omission' in options ? baseToString(options.omission) : omission;
+ } else {
+ length = +options || 0;
+ }
+ }
+ string = baseToString(string);
+ if (length >= string.length) {
+ return string;
+ }
+ var end = length - omission.length;
+ if (end < 1) {
+ return omission;
+ }
+ var result = string.slice(0, end);
+ if (separator == null) {
+ return result + omission;
+ }
+ if (isRegExp(separator)) {
+ if (string.slice(end).search(separator)) {
+ var match,
+ newEnd,
+ substring = string.slice(0, end);
+
+ if (!separator.global) {
+ separator = RegExp(separator.source, (reFlags.exec(separator) || '') + 'g');
+ }
+ separator.lastIndex = 0;
+ while ((match = separator.exec(substring))) {
+ newEnd = match.index;
+ }
+ result = result.slice(0, newEnd == null ? end : newEnd);
+ }
+ } else if (string.indexOf(separator, end) != end) {
+ var index = result.lastIndexOf(separator);
+ if (index > -1) {
+ result = result.slice(0, index);
+ }
+ }
+ return result + omission;
+ }
+
+ /**
+ * The inverse of `_.escape`; this method converts the HTML entities
+ * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to their
+ * corresponding characters.
+ *
+ * **Note:** No other HTML entities are unescaped. To unescape additional HTML
+ * entities use a third-party library like [_he_](http://mths.be/he).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to unescape.
+ * @returns {string} Returns the unescaped string.
+ * @example
+ *
+ * _.unescape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function unescape(string) {
+ string = baseToString(string);
+ return (string && reHasEscapedHtml.test(string))
+ ? string.replace(reEscapedHtml, unescapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Splits `string` into an array of its words.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to inspect.
+ * @param {RegExp|string} [pattern] The pattern to match words.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the words of `string`.
+ * @example
+ *
+ * _.words('fred, barney, & pebbles');
+ * // => ['fred', 'barney', 'pebbles']
+ *
+ * _.words('fred, barney, & pebbles', /[^, ]+/g);
+ * // => ['fred', 'barney', '&', 'pebbles']
+ */
+ function words(string, pattern, guard) {
+ if (guard && isIterateeCall(string, pattern, guard)) {
+ pattern = null;
+ }
+ string = baseToString(string);
+ return string.match(pattern || reWords) || [];
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Attempts to invoke `func`, returning either the result or the caught
+ * error object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} func The function to attempt.
+ * @returns {*} Returns the `func` result or error object.
+ * @example
+ *
+ * // avoid throwing errors for invalid selectors
+ * var elements = _.attempt(function() {
+ * return document.querySelectorAll(selector);
+ * });
+ *
+ * if (_.isError(elements)) {
+ * elements = [];
+ * }
+ */
+ function attempt(func) {
+ try {
+ return func();
+ } catch(e) {
+ return isError(e) ? e : Error(e);
+ }
+ }
+
+ /**
+ * Creates a function bound to an optional `thisArg`. If `func` is a property
+ * name the created callback returns the property value for a given element.
+ * If `func` is an object the created callback returns `true` for elements
+ * that contain the equivalent object properties, otherwise it returns `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias iteratee
+ * @category Utility
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the callback.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // wrap to create custom callback shorthands
+ * _.callback = _.wrap(_.callback, function(callback, func, thisArg) {
+ * var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
+ * if (!match) {
+ * return callback(func, thisArg);
+ * }
+ * return function(object) {
+ * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
+ * };
+ * });
+ *
+ * _.filter(users, 'age__gt36');
+ * // => [{ 'user': 'fred', 'age': 40 }]
+ */
+ function callback(func, thisArg, guard) {
+ if (guard && isIterateeCall(func, thisArg, guard)) {
+ thisArg = null;
+ }
+ return baseCallback(func, thisArg);
+ }
+
+ /**
+ * Creates a function that returns `value`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value The value to return from the new function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var getter = _.constant(object);
+ * getter() === object;
+ * // => true
+ */
+ function constant(value) {
+ return function() {
+ return value;
+ };
+ }
+
+ /**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.identity(object) === object;
+ * // => true
+ */
+ function identity(value) {
+ return value;
+ }
+
+ /**
+ * Creates a function which performs a deep comparison between a given object
+ * and `source`, returning `true` if the given object has equivalent property
+ * values, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 36 }
+ * ];
+ *
+ * var matchesAge = _.matches({ 'age': 36 });
+ *
+ * _.filter(users, matchesAge);
+ * // => [{ 'user': 'barney', 'age': 36 }]
+ *
+ * _.find(users, matchesAge);
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function matches(source) {
+ return baseMatches(source, true);
+ }
+
+ /**
+ * Adds all own enumerable function properties of a source object to the
+ * destination object. If `object` is a function then methods are added to
+ * its prototype as well.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Function|Object} [object=this] object The destination object.
+ * @param {Object} source The object of functions to add.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.chain=true] Specify whether the functions added
+ * are chainable.
+ * @returns {Function|Object} Returns `object`.
+ * @example
+ *
+ * function vowels(string) {
+ * return _.filter(string, function(v) {
+ * return /[aeiou]/i.test(v);
+ * });
+ * }
+ *
+ * _.mixin({ 'vowels': vowels });
+ * _.vowels('fred');
+ * // => ['e']
+ *
+ * _('fred').vowels().value();
+ * // => ['e']
+ *
+ * _.mixin({ 'vowels': vowels }, { 'chain': false });
+ * _('fred').vowels();
+ * // => ['e']
+ */
+ function mixin(object, source, options) {
+ if (options == null) {
+ var isObj = isObject(source),
+ props = isObj && keys(source),
+ methodNames = props && props.length && baseFunctions(source, props);
+
+ if (!(methodNames ? methodNames.length : isObj)) {
+ methodNames = false;
+ options = source;
+ source = object;
+ object = this;
+ }
+ }
+ if (!methodNames) {
+ methodNames = baseFunctions(source, keys(source));
+ }
+ var chain = true,
+ index = -1,
+ isFunc = isFunction(object),
+ length = methodNames.length;
+
+ if (options === false) {
+ chain = false;
+ } else if (isObject(options) && 'chain' in options) {
+ chain = options.chain;
+ }
+ while (++index < length) {
+ var methodName = methodNames[index],
+ func = source[methodName];
+
+ object[methodName] = func;
+ if (isFunc) {
+ object.prototype[methodName] = (function(func) {
+ return function() {
+ var chainAll = this.__chain__;
+ if (chain || chainAll) {
+ var result = object(this.__wrapped__);
+ (result.__actions__ = arrayCopy(this.__actions__)).push({ 'func': func, 'args': arguments, 'thisArg': object });
+ result.__chain__ = chainAll;
+ return result;
+ }
+ var args = [this.value()];
+ push.apply(args, arguments);
+ return func.apply(object, args);
+ };
+ }(func));
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Reverts the `_` variable to its previous value and returns a reference to
+ * the `lodash` function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @returns {Function} Returns the `lodash` function.
+ * @example
+ *
+ * var lodash = _.noConflict();
+ */
+ function noConflict() {
+ context._ = oldDash;
+ return this;
+ }
+
+ /**
+ * A no-operation function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.noop(object) === undefined;
+ * // => true
+ */
+ function noop() {
+ // No operation performed.
+ }
+
+ /**
+ * Creates a function which returns the property value of `key` on a given object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * var getName = _.property('user');
+ *
+ * _.map(users, getName);
+ * // => ['fred', barney']
+ *
+ * _.pluck(_.sortBy(users, getName), 'user');
+ * // => ['barney', 'fred']
+ */
+ function property(key) {
+ return baseProperty(key + '');
+ }
+
+ /**
+ * The inverse of `_.property`; this method creates a function which returns
+ * the property value of a given key on `object`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} object The object to inspect.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40, 'active': true };
+ * _.map(['active', 'user'], _.propertyOf(object));
+ * // => [true, 'fred']
+ *
+ * var object = { 'a': 3, 'b': 1, 'c': 2 };
+ * _.sortBy(['a', 'b', 'c'], _.propertyOf(object));
+ * // => ['b', 'c', 'a']
+ */
+ function propertyOf(object) {
+ return function(key) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * Creates an array of numbers (positive and/or negative) progressing from
+ * `start` up to, but not including, `end`. If `start` is less than `end` a
+ * zero-length range is created unless a negative `step` is specified.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} [start=0] The start of the range.
+ * @param {number} end The end of the range.
+ * @param {number} [step=1] The value to increment or decrement by.
+ * @returns {Array} Returns the new array of numbers.
+ * @example
+ *
+ * _.range(4);
+ * // => [0, 1, 2, 3]
+ *
+ * _.range(1, 5);
+ * // => [1, 2, 3, 4]
+ *
+ * _.range(0, 20, 5);
+ * // => [0, 5, 10, 15]
+ *
+ * _.range(0, -4, -1);
+ * // => [0, -1, -2, -3]
+ *
+ * _.range(1, 4, 0);
+ * // => [1, 1, 1]
+ *
+ * _.range(0);
+ * // => []
+ */
+ function range(start, end, step) {
+ if (step && isIterateeCall(start, end, step)) {
+ end = step = null;
+ }
+ start = +start || 0;
+ step = step == null ? 1 : (+step || 0);
+
+ if (end == null) {
+ end = start;
+ start = 0;
+ } else {
+ end = +end || 0;
+ }
+ // Use `Array(length)` so engines like Chakra and V8 avoid slower modes.
+ // See http://youtu.be/XAqIpGU8ZZk#t=17m25s.
+ var index = -1,
+ length = nativeMax(ceil((end - start) / (step || 1)), 0),
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = start;
+ start += step;
+ }
+ return result;
+ }
+
+ /**
+ * Invokes the iteratee function `n` times, returning an array of the results
+ * of each invocation. The `iteratee` is bound to `thisArg` and invoked with
+ * one argument; (index).
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * var diceRolls = _.times(3, _.partial(_.random, 1, 6, false));
+ * // => [3, 6, 4]
+ *
+ * _.times(3, function(n) { mage.castSpell(n); });
+ * // => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2` respectively
+ *
+ * _.times(3, function(n) { this.cast(n); }, mage);
+ * // => also invokes `mage.castSpell(n)` three times
+ */
+ function times(n, iteratee, thisArg) {
+ n = +n;
+
+ // Exit early to avoid a JSC JIT bug in Safari 8
+ // where `Array(0)` is treated as `Array(1)`.
+ if (n < 1 || !nativeIsFinite(n)) {
+ return [];
+ }
+ var index = -1,
+ result = Array(nativeMin(n, MAX_ARRAY_LENGTH));
+
+ iteratee = bindCallback(iteratee, thisArg, 1);
+ while (++index < n) {
+ if (index < MAX_ARRAY_LENGTH) {
+ result[index] = iteratee(index);
+ } else {
+ iteratee(index);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Generates a unique ID. If `prefix` is provided the ID is appended to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} [prefix] The value to prefix the ID with.
+ * @returns {string} Returns the unique ID.
+ * @example
+ *
+ * _.uniqueId('contact_');
+ * // => 'contact_104'
+ *
+ * _.uniqueId();
+ * // => '105'
+ */
+ function uniqueId(prefix) {
+ var id = ++idCounter;
+ return baseToString(prefix) + id;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ // Ensure `new LodashWrapper` is an instance of `lodash`.
+ LodashWrapper.prototype = lodash.prototype;
+
+ // Add functions to the `Map` cache.
+ MapCache.prototype['delete'] = mapDelete;
+ MapCache.prototype.get = mapGet;
+ MapCache.prototype.has = mapHas;
+ MapCache.prototype.set = mapSet;
+
+ // Add functions to the `Set` cache.
+ SetCache.prototype.push = cachePush;
+
+ // Assign cache to `_.memoize`.
+ memoize.Cache = MapCache;
+
+ // Add functions that return wrapped values when chaining.
+ lodash.after = after;
+ lodash.ary = ary;
+ lodash.assign = assign;
+ lodash.at = at;
+ lodash.before = before;
+ lodash.bind = bind;
+ lodash.bindAll = bindAll;
+ lodash.bindKey = bindKey;
+ lodash.callback = callback;
+ lodash.chain = chain;
+ lodash.chunk = chunk;
+ lodash.compact = compact;
+ lodash.constant = constant;
+ lodash.countBy = countBy;
+ lodash.create = create;
+ lodash.curry = curry;
+ lodash.curryRight = curryRight;
+ lodash.debounce = debounce;
+ lodash.defaults = defaults;
+ lodash.defer = defer;
+ lodash.delay = delay;
+ lodash.difference = difference;
+ lodash.drop = drop;
+ lodash.dropRight = dropRight;
+ lodash.dropRightWhile = dropRightWhile;
+ lodash.dropWhile = dropWhile;
+ lodash.filter = filter;
+ lodash.flatten = flatten;
+ lodash.flattenDeep = flattenDeep;
+ lodash.flow = flow;
+ lodash.flowRight = flowRight;
+ lodash.forEach = forEach;
+ lodash.forEachRight = forEachRight;
+ lodash.forIn = forIn;
+ lodash.forInRight = forInRight;
+ lodash.forOwn = forOwn;
+ lodash.forOwnRight = forOwnRight;
+ lodash.functions = functions;
+ lodash.groupBy = groupBy;
+ lodash.indexBy = indexBy;
+ lodash.initial = initial;
+ lodash.intersection = intersection;
+ lodash.invert = invert;
+ lodash.invoke = invoke;
+ lodash.keys = keys;
+ lodash.keysIn = keysIn;
+ lodash.map = map;
+ lodash.mapValues = mapValues;
+ lodash.matches = matches;
+ lodash.memoize = memoize;
+ lodash.merge = merge;
+ lodash.mixin = mixin;
+ lodash.negate = negate;
+ lodash.omit = omit;
+ lodash.once = once;
+ lodash.pairs = pairs;
+ lodash.partial = partial;
+ lodash.partialRight = partialRight;
+ lodash.partition = partition;
+ lodash.pick = pick;
+ lodash.pluck = pluck;
+ lodash.property = property;
+ lodash.propertyOf = propertyOf;
+ lodash.pull = pull;
+ lodash.pullAt = pullAt;
+ lodash.range = range;
+ lodash.rearg = rearg;
+ lodash.reject = reject;
+ lodash.remove = remove;
+ lodash.rest = rest;
+ lodash.shuffle = shuffle;
+ lodash.slice = slice;
+ lodash.sortBy = sortBy;
+ lodash.sortByAll = sortByAll;
+ lodash.take = take;
+ lodash.takeRight = takeRight;
+ lodash.takeRightWhile = takeRightWhile;
+ lodash.takeWhile = takeWhile;
+ lodash.tap = tap;
+ lodash.throttle = throttle;
+ lodash.thru = thru;
+ lodash.times = times;
+ lodash.toArray = toArray;
+ lodash.toPlainObject = toPlainObject;
+ lodash.transform = transform;
+ lodash.union = union;
+ lodash.uniq = uniq;
+ lodash.unzip = unzip;
+ lodash.values = values;
+ lodash.valuesIn = valuesIn;
+ lodash.where = where;
+ lodash.without = without;
+ lodash.wrap = wrap;
+ lodash.xor = xor;
+ lodash.zip = zip;
+ lodash.zipObject = zipObject;
+
+ // Add aliases.
+ lodash.backflow = flowRight;
+ lodash.collect = map;
+ lodash.compose = flowRight;
+ lodash.each = forEach;
+ lodash.eachRight = forEachRight;
+ lodash.extend = assign;
+ lodash.iteratee = callback;
+ lodash.methods = functions;
+ lodash.object = zipObject;
+ lodash.select = filter;
+ lodash.tail = rest;
+ lodash.unique = uniq;
+
+ // Add functions to `lodash.prototype`.
+ mixin(lodash, lodash);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions that return unwrapped values when chaining.
+ lodash.attempt = attempt;
+ lodash.camelCase = camelCase;
+ lodash.capitalize = capitalize;
+ lodash.clone = clone;
+ lodash.cloneDeep = cloneDeep;
+ lodash.deburr = deburr;
+ lodash.endsWith = endsWith;
+ lodash.escape = escape;
+ lodash.escapeRegExp = escapeRegExp;
+ lodash.every = every;
+ lodash.find = find;
+ lodash.findIndex = findIndex;
+ lodash.findKey = findKey;
+ lodash.findLast = findLast;
+ lodash.findLastIndex = findLastIndex;
+ lodash.findLastKey = findLastKey;
+ lodash.findWhere = findWhere;
+ lodash.first = first;
+ lodash.has = has;
+ lodash.identity = identity;
+ lodash.includes = includes;
+ lodash.indexOf = indexOf;
+ lodash.isArguments = isArguments;
+ lodash.isArray = isArray;
+ lodash.isBoolean = isBoolean;
+ lodash.isDate = isDate;
+ lodash.isElement = isElement;
+ lodash.isEmpty = isEmpty;
+ lodash.isEqual = isEqual;
+ lodash.isError = isError;
+ lodash.isFinite = isFinite;
+ lodash.isFunction = isFunction;
+ lodash.isMatch = isMatch;
+ lodash.isNaN = isNaN;
+ lodash.isNative = isNative;
+ lodash.isNull = isNull;
+ lodash.isNumber = isNumber;
+ lodash.isObject = isObject;
+ lodash.isPlainObject = isPlainObject;
+ lodash.isRegExp = isRegExp;
+ lodash.isString = isString;
+ lodash.isTypedArray = isTypedArray;
+ lodash.isUndefined = isUndefined;
+ lodash.kebabCase = kebabCase;
+ lodash.last = last;
+ lodash.lastIndexOf = lastIndexOf;
+ lodash.max = max;
+ lodash.min = min;
+ lodash.noConflict = noConflict;
+ lodash.noop = noop;
+ lodash.now = now;
+ lodash.pad = pad;
+ lodash.padLeft = padLeft;
+ lodash.padRight = padRight;
+ lodash.parseInt = parseInt;
+ lodash.random = random;
+ lodash.reduce = reduce;
+ lodash.reduceRight = reduceRight;
+ lodash.repeat = repeat;
+ lodash.result = result;
+ lodash.runInContext = runInContext;
+ lodash.size = size;
+ lodash.snakeCase = snakeCase;
+ lodash.some = some;
+ lodash.sortedIndex = sortedIndex;
+ lodash.sortedLastIndex = sortedLastIndex;
+ lodash.startsWith = startsWith;
+ lodash.template = template;
+ lodash.trim = trim;
+ lodash.trimLeft = trimLeft;
+ lodash.trimRight = trimRight;
+ lodash.trunc = trunc;
+ lodash.unescape = unescape;
+ lodash.uniqueId = uniqueId;
+ lodash.words = words;
+
+ // Add aliases.
+ lodash.all = every;
+ lodash.any = some;
+ lodash.contains = includes;
+ lodash.detect = find;
+ lodash.foldl = reduce;
+ lodash.foldr = reduceRight;
+ lodash.head = first;
+ lodash.include = includes;
+ lodash.inject = reduce;
+
+ mixin(lodash, (function() {
+ var source = {};
+ baseForOwn(lodash, function(func, methodName) {
+ if (!lodash.prototype[methodName]) {
+ source[methodName] = func;
+ }
+ });
+ return source;
+ }()), false);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions capable of returning wrapped and unwrapped values when chaining.
+ lodash.sample = sample;
+
+ lodash.prototype.sample = function(n) {
+ if (!this.__chain__ && n == null) {
+ return sample(this.value());
+ }
+ return this.thru(function(value) {
+ return sample(value, n);
+ });
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The semantic version number.
+ *
+ * @static
+ * @memberOf _
+ * @type string
+ */
+ lodash.VERSION = VERSION;
+
+ // Assign default placeholders.
+ arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
+ lodash[methodName].placeholder = lodash;
+ });
+
+ // Add `LazyWrapper` methods that accept an `iteratee` value.
+ arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
+ var isFilter = index == LAZY_FILTER_FLAG;
+
+ LazyWrapper.prototype[methodName] = function(iteratee, thisArg) {
+ var result = this.clone(),
+ filtered = result.filtered,
+ iteratees = result.iteratees || (result.iteratees = []);
+
+ result.filtered = filtered || isFilter || (index == LAZY_WHILE_FLAG && result.dir < 0);
+ iteratees.push({ 'iteratee': getCallback(iteratee, thisArg, 3), 'type': index });
+ return result;
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
+ arrayEach(['drop', 'take'], function(methodName, index) {
+ var countName = methodName + 'Count',
+ whileName = methodName + 'While';
+
+ LazyWrapper.prototype[methodName] = function(n) {
+ n = n == null ? 1 : nativeMax(+n || 0, 0);
+
+ var result = this.clone();
+ if (result.filtered) {
+ var value = result[countName];
+ result[countName] = index ? nativeMin(value, n) : (value + n);
+ } else {
+ var views = result.views || (result.views = []);
+ views.push({ 'size': n, 'type': methodName + (result.dir < 0 ? 'Right' : '') });
+ }
+ return result;
+ };
+
+ LazyWrapper.prototype[methodName + 'Right'] = function(n) {
+ return this.reverse()[methodName](n).reverse();
+ };
+
+ LazyWrapper.prototype[methodName + 'RightWhile'] = function(predicate, thisArg) {
+ return this.reverse()[whileName](predicate, thisArg).reverse();
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.first` and `_.last`.
+ arrayEach(['first', 'last'], function(methodName, index) {
+ var takeName = 'take' + (index ? 'Right': '');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[takeName](1).value()[0];
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.initial` and `_.rest`.
+ arrayEach(['initial', 'rest'], function(methodName, index) {
+ var dropName = 'drop' + (index ? '' : 'Right');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[dropName](1);
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.pluck` and `_.where`.
+ arrayEach(['pluck', 'where'], function(methodName, index) {
+ var operationName = index ? 'filter' : 'map',
+ createCallback = index ? matches : property;
+
+ LazyWrapper.prototype[methodName] = function(value) {
+ return this[operationName](createCallback(value));
+ };
+ });
+
+ LazyWrapper.prototype.dropWhile = function(iteratee, thisArg) {
+ var done,
+ lastIndex,
+ isRight = this.dir < 0;
+
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ done = done && (isRight ? index < lastIndex : index > lastIndex);
+ lastIndex = index;
+ return done || (done = !iteratee(value, index, array));
+ });
+ };
+
+ LazyWrapper.prototype.reject = function(iteratee, thisArg) {
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ return !iteratee(value, index, array);
+ });
+ };
+
+ LazyWrapper.prototype.slice = function(start, end) {
+ start = start == null ? 0 : (+start || 0);
+ var result = start < 0 ? this.takeRight(-start) : this.drop(start);
+
+ if (typeof end != 'undefined') {
+ end = (+end || 0);
+ result = end < 0 ? result.dropRight(-end) : result.take(end - start);
+ }
+ return result;
+ };
+
+ // Add `LazyWrapper` methods to `lodash.prototype`.
+ baseForOwn(LazyWrapper.prototype, function(func, methodName) {
+ var retUnwrapped = /^(?:first|last)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var value = this.__wrapped__,
+ args = arguments,
+ chainAll = this.__chain__,
+ isHybrid = !!this.__actions__.length,
+ isLazy = value instanceof LazyWrapper,
+ onlyLazy = isLazy && !isHybrid;
+
+ if (retUnwrapped && !chainAll) {
+ return onlyLazy
+ ? func.call(value)
+ : lodash[methodName](this.value());
+ }
+ var interceptor = function(value) {
+ var otherArgs = [value];
+ push.apply(otherArgs, args);
+ return lodash[methodName].apply(lodash, otherArgs);
+ };
+ if (isLazy || isArray(value)) {
+ var wrapper = onlyLazy ? value : new LazyWrapper(this),
+ result = func.apply(wrapper, args);
+
+ if (!retUnwrapped && (isHybrid || result.actions)) {
+ var actions = result.actions || (result.actions = []);
+ actions.push({ 'func': thru, 'args': [interceptor], 'thisArg': lodash });
+ }
+ return new LodashWrapper(result, chainAll);
+ }
+ return this.thru(interceptor);
+ };
+ });
+
+ // Add `Array.prototype` functions to `lodash.prototype`.
+ arrayEach(['concat', 'join', 'pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
+ var func = arrayProto[methodName],
+ chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
+ retUnwrapped = /^(?:join|pop|shift)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var args = arguments;
+ if (retUnwrapped && !this.__chain__) {
+ return func.apply(this.value(), args);
+ }
+ return this[chainName](function(value) {
+ return func.apply(value, args);
+ });
+ };
+ });
+
+ // Add functions to the lazy wrapper.
+ LazyWrapper.prototype.clone = lazyClone;
+ LazyWrapper.prototype.reverse = lazyReverse;
+ LazyWrapper.prototype.value = lazyValue;
+
+ // Add chaining functions to the lodash wrapper.
+ lodash.prototype.chain = wrapperChain;
+ lodash.prototype.reverse = wrapperReverse;
+ lodash.prototype.toString = wrapperToString;
+ lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
+
+ // Add function aliases to the lodash wrapper.
+ lodash.prototype.collect = lodash.prototype.map;
+ lodash.prototype.head = lodash.prototype.first;
+ lodash.prototype.select = lodash.prototype.filter;
+ lodash.prototype.tail = lodash.prototype.rest;
+
+ return lodash;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // Export Lo-Dash.
+ var _ = runInContext();
+
+ // Some AMD build optimizers like r.js check for condition patterns like the following:
+ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ // Expose Lo-Dash to the global object when an AMD loader is present to avoid
+ // errors in cases where Lo-Dash is loaded by a script tag and not intended
+ // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch.
+ root._ = _;
+
+ // Define as an anonymous module so, through path mapping, it can be
+ // referenced as the "underscore" module.
+ define(function() {
+ return _;
+ });
+ }
+ // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
+ else if (freeExports && freeModule) {
+ // Export for Node.js or RingoJS.
+ if (moduleExports) {
+ (freeModule.exports = _)._ = _;
+ }
+ // Export for Narwhal or Rhino -require.
+ else {
+ freeExports._ = _;
+ }
+ }
+ else {
+ // Export for a browser or Rhino.
+ root._ = _;
+ }
+}.call(this));
diff --git a/debian/node-lodash/usr/share/doc/node-lodash/README.md b/debian/node-lodash/usr/share/doc/node-lodash/README.md
new file mode 100644
index 0000000..4c74d5d
--- /dev/null
+++ b/debian/node-lodash/usr/share/doc/node-lodash/README.md
@@ -0,0 +1,16 @@
+# lodash v3.0.0
+
+The [modern build](https://github.com/lodash/lodash/wiki/Build-Differences) of [Lo-Dash](https://lodash.com/) with packages for [Bower](http://bower.io/), [Component](http://component.github.io/), & [Volo](http://volojs.org/).
+
+Generated using [lodash-cli](https://www.npmjs.com/package/lodash-cli):
+```bash
+$ lodash modern -o ./lodash.js
+```
+
+## Module formats
+
+Lo-Dash is also available in a variety of other builds & module formats.
+
+ * npm packages for [modern](https://www.npmjs.com/package/lodash), [compatibility](https://www.npmjs.com/package/lodash-compat), & [per method](https://www.npmjs.com/browse/keyword/lodash-modularized) builds
+ * AMD modules for [modern](https://github.com/lodash/lodash/tree/3.0.0-amd) & [compatibility](https://github.com/lodash/lodash-compat/tree/3.0.0-amd) builds
+ * ES modules for the [modern](https://github.com/lodash/lodash/tree/3.0.0-es) build
diff --git a/debian/node-lodash/usr/share/doc/node-lodash/changelog.Debian.gz b/debian/node-lodash/usr/share/doc/node-lodash/changelog.Debian.gz
new file mode 100644
index 0000000..687c87b
Binary files /dev/null and b/debian/node-lodash/usr/share/doc/node-lodash/changelog.Debian.gz differ
diff --git a/debian/copyright b/debian/node-lodash/usr/share/doc/node-lodash/copyright
similarity index 94%
copy from debian/copyright
copy to debian/node-lodash/usr/share/doc/node-lodash/copyright
index 7bbb0c3..5ec2eda 100644
--- a/debian/copyright
+++ b/debian/node-lodash/usr/share/doc/node-lodash/copyright
@@ -6,55 +6,28 @@ Source: https://github.com/lodash/lodash
vendor/firebug-lite/skin/xp/textEditorBorders.png
vendor/curl/dist/curl-kitchen-sink/curl.js
+
Files: *
-Copyright: 2013 John-David Dalton
+Copyright: 2012-2015 John-David Dalton
License: Expat
Files: vendor/backbone/*
-Copyright: 2010-2011 Jeremy Ashkenas, DocumentCloud
- 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+Copyright: 2010-2014 Jeremy Ashkenas, DocumentCloud
License: Expat
Files: vendor/benchmark.js/*
-Copyright: 2010-2013 Mathias Bynens
- 2012-2014 John-David Dalton
-License: Expat
-
-Files: vendor/curl/*
-Copyright: 2010-2013 Brian Cavalier and John Hann
+Copyright: 2010-2015 Mathias Bynens
License: Expat
-Files: vendor/dojo/*
-Copyright: 2005-2013, The Dojo Foundation
-License: BSD-3-clause-Dojo or AFL-2.1-clause-Dojo
-
Files: vendor/firebug-lite/*
Copyright: 2007, Parakey Inc.
License: BSD-3-clause-Parakey
-Files: vendor/jquery/*
- vendor/qunit/*
-Copyright: 2012 jQuery Foundation and other contributors
-License: Expat
-
Files: vendor/json-js/*
-Copyright: 2010 Douglas Crockford
License: public-domain
-Files: vendor/platform.js
-Copyright: 2010-2013 John-David Dalton
-License: Expat
-
-Files: vendor/qunit-extras/*
-Copyright: 2011-2012 John-David Dalton
-License: Expat
-
-Files: vendor/requirejs/*
-Copyright: 2010-2011, The Dojo Foundation
-License: BSD-3-clause-Dojo or Expat
-
Files: vendor/underscore/*
-Copyright: 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+Copyright: 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
License: Expat
License: AFL-2.1-clause-Dojo
diff --git a/doc/README.md b/doc/README.md
index a506ac3..9e0d4c8 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -1,2876 +1,4505 @@
-# <a href="http://lodash.com/">Lo-Dash</a> <span>v2.4.1</span>
-
-<!-- div -->
+# <a href="https://lodash.com/">Lo-Dash</a> <span>v3.0.0</span>
+<!-- div class="toc-container" -->
<!-- div -->
-## <a id="arrays"></a>`Arrays`
+## <a id="array"></a>`Array`
+* <a href="#_chunkarray-size1">`_.chunk`</a>
* <a href="#_compactarray">`_.compact`</a>
* <a href="#_differencearray-values">`_.difference`</a>
-* <a href="#_restarray-callback1-thisarg" class="alias">`_.drop` -> `rest`</a>
-* <a href="#_findindexarray-callbackidentity-thisarg">`_.findIndex`</a>
-* <a href="#_findlastindexarray-callbackidentity-thisarg">`_.findLastIndex`</a>
-* <a href="#_firstarray-callback-thisarg">`_.first`</a>
-* <a href="#_flattenarray-isshallowfalse-callbackidentity-thisarg">`_.flatten`</a>
-* <a href="#_firstarray-callback-thisarg" class="alias">`_.head` -> `first`</a>
+* <a href="#_droparray-n1">`_.drop`</a>
+* <a href="#_droprightarray-n1">`_.dropRight`</a>
+* <a href="#_droprightwhilearray-predicate_identity-thisarg">`_.dropRightWhile`</a>
+* <a href="#_dropwhilearray-predicate_identity-thisarg">`_.dropWhile`</a>
+* <a href="#_findindexarray-predicate_identity-thisarg">`_.findIndex`</a>
+* <a href="#_findlastindexarray-predicate_identity-thisarg">`_.findLastIndex`</a>
+* <a href="#_firstarray">`_.first`</a>
+* <a href="#_flattenarray-isdeep">`_.flatten`</a>
+* <a href="#_flattendeeparray">`_.flattenDeep`</a>
+* <a href="#_firstarray" class="alias">`_.head` -> `first`</a>
* <a href="#_indexofarray-value-fromindex0">`_.indexOf`</a>
-* <a href="#_initialarray-callback1-thisarg">`_.initial`</a>
-* <a href="#_intersectionarray">`_.intersection`</a>
-* <a href="#_lastarray-callback-thisarg">`_.last`</a>
-* <a href="#_lastindexofarray-value-fromindexarraylength-1">`_.lastIndexOf`</a>
-* <a href="#_zipobjectkeys-values" class="alias">`_.object` -> `zipObject`</a>
-* <a href="#_pullarray-value">`_.pull`</a>
-* <a href="#_rangestart0-end-step1">`_.range`</a>
-* <a href="#_removearray-callbackidentity-thisarg">`_.remove`</a>
-* <a href="#_restarray-callback1-thisarg">`_.rest`</a>
-* <a href="#_sortedindexarray-value-callbackidentity-thisarg">`_.sortedIndex`</a>
-* <a href="#_restarray-callback1-thisarg" class="alias">`_.tail` -> `rest`</a>
-* <a href="#_firstarray-callback-thisarg" class="alias">`_.take` -> `first`</a>
-* <a href="#_unionarray">`_.union`</a>
-* <a href="#_uniqarray-issortedfalse-callbackidentity-thisarg">`_.uniq`</a>
-* <a href="#_uniqarray-issortedfalse-callbackidentity-thisarg" class="alias">`_.unique` -> `uniq`</a>
-* <a href="#_ziparray" class="alias">`_.unzip` -> `zip`</a>
-* <a href="#_withoutarray-value">`_.without`</a>
-* <a href="#_xorarray">`_.xor`</a>
-* <a href="#_ziparray">`_.zip`</a>
-* <a href="#_zipobjectkeys-values">`_.zipObject`</a>
-
-<!-- /div -->
-
-
-<!-- div -->
-
-## `Chaining`
+* <a href="#_initialarray">`_.initial`</a>
+* <a href="#_intersectionarrays">`_.intersection`</a>
+* <a href="#_lastarray">`_.last`</a>
+* <a href="#_lastindexofarray-value">`_.lastIndexOf`</a>
+* <a href="#_zipobjectprops-values" class="alias">`_.object` -> `zipObject`</a>
+* <a href="#_pullarray-values">`_.pull`</a>
+* <a href="#_pullatarray-indexes">`_.pullAt`</a>
+* <a href="#_removearray-predicate_identity-thisarg">`_.remove`</a>
+* <a href="#_restarray">`_.rest`</a>
+* <a href="#_slicearray-start0">`_.slice`</a>
+* <a href="#_sortedindexarray-value-iteratee_identity-thisarg">`_.sortedIndex`</a>
+* <a href="#_sortedlastindexarray-value-iteratee_identity-thisarg">`_.sortedLastIndex`</a>
+* <a href="#_restarray" class="alias">`_.tail` -> `rest`</a>
+* <a href="#_takearray-n1">`_.take`</a>
+* <a href="#_takerightarray-n1">`_.takeRight`</a>
+* <a href="#_takerightwhilearray-predicate_identity-thisarg">`_.takeRightWhile`</a>
+* <a href="#_takewhilearray-predicate_identity-thisarg">`_.takeWhile`</a>
+* <a href="#_unionarrays">`_.union`</a>
+* <a href="#_uniqarray-issorted-iteratee-thisarg">`_.uniq`</a>
+* <a href="#_uniqarray-issorted-iteratee-thisarg" class="alias">`_.unique` -> `uniq`</a>
+* <a href="#_unziparray">`_.unzip`</a>
+* <a href="#_withoutarray-values">`_.without`</a>
+* <a href="#_xorarrays">`_.xor`</a>
+* <a href="#_ziparrays">`_.zip`</a>
+* <a href="#_zipobjectprops-values">`_.zipObject`</a>
+
+<!-- /div -->
+
+<!-- div -->
+
+## <a id="chain"></a>`Chain`
* <a href="#_value">`_`</a>
* <a href="#_chainvalue">`_.chain`</a>
-* <a href="#_tapvalue-interceptor">`_.tap`</a>
+* <a href="#_tapvalue-interceptor-thisarg">`_.tap`</a>
+* <a href="#_thruvalue-interceptor-thisarg">`_.thru`</a>
* <a href="#_prototypechain">`_.prototype.chain`</a>
+* <a href="#_prototypereverse">`_.prototype.reverse`</a>
+* <a href="#_prototypevalue" class="alias">`_.prototype.toJSON` -> `value`</a>
* <a href="#_prototypetostring">`_.prototype.toString`</a>
-* <a href="#_prototypevalueof" class="alias">`_.prototype.value` -> `valueOf`</a>
-* <a href="#_prototypevalueof">`_.prototype.valueOf`</a>
-
-<!-- /div -->
-
-
-<!-- div -->
-
-## `Collections`
-* <a href="#_everycollection-callbackidentity-thisarg" class="alias">`_.all` -> `every`</a>
-* <a href="#_somecollection-callbackidentity-thisarg" class="alias">`_.any` -> `some`</a>
-* <a href="#_atcollection-index">`_.at`</a>
-* <a href="#_mapcollection-callbackidentity-thisarg" class="alias">`_.collect` -> `map`</a>
-* <a href="#_containscollection-target-fromindex0">`_.contains`</a>
-* <a href="#_countbycollection-callbackidentity-thisarg">`_.countBy`</a>
-* <a href="#_findcollection-callbackidentity-thisarg" class="alias">`_.detect` -> `find`</a>
-* <a href="#_foreachcollection-callbackidentity-thisarg" class="alias">`_.each` -> `forEach`</a>
-* <a href="#_foreachrightcollection-callbackidentity-thisarg" class="alias">`_.eachRight` -> `forEachRight`</a>
-* <a href="#_everycollection-callbackidentity-thisarg">`_.every`</a>
-* <a href="#_filtercollection-callbackidentity-thisarg">`_.filter`</a>
-* <a href="#_findcollection-callbackidentity-thisarg">`_.find`</a>
-* <a href="#_findlastcollection-callbackidentity-thisarg">`_.findLast`</a>
-* <a href="#_findcollection-callbackidentity-thisarg" class="alias">`_.findWhere` -> `find`</a>
-* <a href="#_reducecollection-callbackidentity-accumulator-thisarg" class="alias">`_.foldl` -> `reduce`</a>
-* <a href="#_reducerightcollection-callbackidentity-accumulator-thisarg" class="alias">`_.foldr` -> `reduceRight`</a>
-* <a href="#_foreachcollection-callbackidentity-thisarg">`_.forEach`</a>
-* <a href="#_foreachrightcollection-callbackidentity-thisarg">`_.forEachRight`</a>
-* <a href="#_groupbycollection-callbackidentity-thisarg">`_.groupBy`</a>
-* <a href="#_containscollection-target-fromindex0" class="alias">`_.include` -> `contains`</a>
-* <a href="#_indexbycollection-callbackidentity-thisarg">`_.indexBy`</a>
-* <a href="#_reducecollection-callbackidentity-accumulator-thisarg" class="alias">`_.inject` -> `reduce`</a>
-* <a href="#_invokecollection-methodname-arg">`_.invoke`</a>
-* <a href="#_mapcollection-callbackidentity-thisarg">`_.map`</a>
-* <a href="#_maxcollection-callbackidentity-thisarg">`_.max`</a>
-* <a href="#_mincollection-callbackidentity-thisarg">`_.min`</a>
-* <a href="#_pluckcollection-property">`_.pluck`</a>
-* <a href="#_reducecollection-callbackidentity-accumulator-thisarg">`_.reduce`</a>
-* <a href="#_reducerightcollection-callbackidentity-accumulator-thisarg">`_.reduceRight`</a>
-* <a href="#_rejectcollection-callbackidentity-thisarg">`_.reject`</a>
+* <a href="#_prototypevalue">`_.prototype.value`</a>
+* <a href="#_prototypevalue" class="alias">`_.prototype.valueOf` -> `value`</a>
+
+<!-- /div -->
+
+<!-- div -->
+
+## <a id="collection"></a>`Collection`
+* <a href="#_everycollection-predicate_identity-thisarg" class="alias">`_.all` -> `every`</a>
+* <a href="#_somecollection-predicate_identity-thisarg" class="alias">`_.any` -> `some`</a>
+* <a href="#_atcollection-props">`_.at`</a>
+* <a href="#_mapcollection-iteratee_identity-thisarg" class="alias">`_.collect` -> `map`</a>
+* <a href="#_includescollection-target-fromindex0" class="alias">`_.contains` -> `includes`</a>
+* <a href="#_countbycollection-iteratee_identity-thisarg">`_.countBy`</a>
+* <a href="#_findcollection-predicate_identity-thisarg" class="alias">`_.detect` -> `find`</a>
+* <a href="#_foreachcollection-iteratee_identity-thisarg" class="alias">`_.each` -> `forEach`</a>
+* <a href="#_foreachrightcollection-iteratee_identity-thisarg" class="alias">`_.eachRight` -> `forEachRight`</a>
+* <a href="#_everycollection-predicate_identity-thisarg">`_.every`</a>
+* <a href="#_filtercollection-predicate_identity-thisarg">`_.filter`</a>
+* <a href="#_findcollection-predicate_identity-thisarg">`_.find`</a>
+* <a href="#_findlastcollection-predicate_identity-thisarg">`_.findLast`</a>
+* <a href="#_findwherecollection-source">`_.findWhere`</a>
+* <a href="#_reducecollection-iteratee_identity-accumulator-thisarg" class="alias">`_.foldl` -> `reduce`</a>
+* <a href="#_reducerightcollection-iteratee_identity-accumulator-thisarg" class="alias">`_.foldr` -> `reduceRight`</a>
+* <a href="#_foreachcollection-iteratee_identity-thisarg">`_.forEach`</a>
+* <a href="#_foreachrightcollection-iteratee_identity-thisarg">`_.forEachRight`</a>
+* <a href="#_groupbycollection-iteratee_identity-thisarg">`_.groupBy`</a>
+* <a href="#_includescollection-target-fromindex0" class="alias">`_.include` -> `includes`</a>
+* <a href="#_includescollection-target-fromindex0">`_.includes`</a>
+* <a href="#_indexbycollection-iteratee_identity-thisarg">`_.indexBy`</a>
+* <a href="#_reducecollection-iteratee_identity-accumulator-thisarg" class="alias">`_.inject` -> `reduce`</a>
+* <a href="#_invokecollection-methodname-args">`_.invoke`</a>
+* <a href="#_mapcollection-iteratee_identity-thisarg">`_.map`</a>
+* <a href="#_maxcollection-iteratee-thisarg">`_.max`</a>
+* <a href="#_mincollection-iteratee-thisarg">`_.min`</a>
+* <a href="#_partitioncollection-predicate_identity-thisarg">`_.partition`</a>
+* <a href="#_pluckcollection-key">`_.pluck`</a>
+* <a href="#_reducecollection-iteratee_identity-accumulator-thisarg">`_.reduce`</a>
+* <a href="#_reducerightcollection-iteratee_identity-accumulator-thisarg">`_.reduceRight`</a>
+* <a href="#_rejectcollection-predicate_identity-thisarg">`_.reject`</a>
* <a href="#_samplecollection-n">`_.sample`</a>
-* <a href="#_filtercollection-callbackidentity-thisarg" class="alias">`_.select` -> `filter`</a>
+* <a href="#_filtercollection-predicate_identity-thisarg" class="alias">`_.select` -> `filter`</a>
* <a href="#_shufflecollection">`_.shuffle`</a>
* <a href="#_sizecollection">`_.size`</a>
-* <a href="#_somecollection-callbackidentity-thisarg">`_.some`</a>
-* <a href="#_sortbycollection-callbackidentity-thisarg">`_.sortBy`</a>
-* <a href="#_toarraycollection">`_.toArray`</a>
-* <a href="#_wherecollection-props">`_.where`</a>
+* <a href="#_somecollection-predicate_identity-thisarg">`_.some`</a>
+* <a href="#_sortbycollection-iteratee_identity-thisarg">`_.sortBy`</a>
+* <a href="#_sortbyallcollection-props">`_.sortByAll`</a>
+* <a href="#_wherecollection-source">`_.where`</a>
<!-- /div -->
+<!-- div -->
+
+## <a id="date"></a>`Date`
+* <a href="#_now">`_.now`</a>
+
+<!-- /div -->
<!-- div -->
-## `Functions`
+## <a id="function"></a>`Function`
* <a href="#_aftern-func">`_.after`</a>
-* <a href="#_bindfunc-thisarg-arg">`_.bind`</a>
-* <a href="#_bindallobject-methodname">`_.bindAll`</a>
-* <a href="#_bindkeyobject-key-arg">`_.bindKey`</a>
-* <a href="#_composefunc">`_.compose`</a>
-* <a href="#_curryfunc-arityfunclength">`_.curry`</a>
-* <a href="#_debouncefunc-wait-options-optionsmaxwait">`_.debounce`</a>
-* <a href="#_deferfunc-arg">`_.defer`</a>
-* <a href="#_delayfunc-wait-arg">`_.delay`</a>
+* <a href="#_aryfunc">`_.ary`</a>
+* <a href="#_flowrightfuncs" class="alias">`_.backflow` -> `flowRight`</a>
+* <a href="#_beforen-func">`_.before`</a>
+* <a href="#_bindfunc-thisarg-args">`_.bind`</a>
+* <a href="#_bindallobject-methodnames">`_.bindAll`</a>
+* <a href="#_bindkeyobject-key-args">`_.bindKey`</a>
+* <a href="#_flowrightfuncs" class="alias">`_.compose` -> `flowRight`</a>
+* <a href="#_curryfunc">`_.curry`</a>
+* <a href="#_curryrightfunc">`_.curryRight`</a>
+* <a href="#_debouncefunc-wait-options-optionsleadingfalse-optionsmaxwait-optionstrailingtrue">`_.debounce`</a>
+* <a href="#_deferfunc-args">`_.defer`</a>
+* <a href="#_delayfunc-wait-args">`_.delay`</a>
+* <a href="#_flowfuncs">`_.flow`</a>
+* <a href="#_flowrightfuncs">`_.flowRight`</a>
* <a href="#_memoizefunc-resolver">`_.memoize`</a>
+* <a href="#_negatepredicate">`_.negate`</a>
* <a href="#_oncefunc">`_.once`</a>
-* <a href="#_partialfunc-arg">`_.partial`</a>
-* <a href="#_partialrightfunc-arg">`_.partialRight`</a>
-* <a href="#_throttlefunc-wait-options">`_.throttle`</a>
+* <a href="#_partialfunc-args">`_.partial`</a>
+* <a href="#_partialrightfunc-args">`_.partialRight`</a>
+* <a href="#_reargfunc-indexes">`_.rearg`</a>
+* <a href="#_throttlefunc-wait-options-optionsleadingtrue-optionstrailingtrue">`_.throttle`</a>
* <a href="#_wrapvalue-wrapper">`_.wrap`</a>
<!-- /div -->
-
<!-- div -->
-## `Objects`
-* <a href="#_assignobject-source-callback-thisarg">`_.assign`</a>
-* <a href="#_clonevalue-isdeepfalse-callback-thisarg">`_.clone`</a>
-* <a href="#_clonedeepvalue-callback-thisarg">`_.cloneDeep`</a>
-* <a href="#_createprototype-properties">`_.create`</a>
-* <a href="#_defaultsobject-source">`_.defaults`</a>
-* <a href="#_assignobject-source-callback-thisarg" class="alias">`_.extend` -> `assign`</a>
-* <a href="#_findkeyobject-callbackidentity-thisarg">`_.findKey`</a>
-* <a href="#_findlastkeyobject-callbackidentity-thisarg">`_.findLastKey`</a>
-* <a href="#_forinobject-callbackidentity-thisarg">`_.forIn`</a>
-* <a href="#_forinrightobject-callbackidentity-thisarg">`_.forInRight`</a>
-* <a href="#_forownobject-callbackidentity-thisarg">`_.forOwn`</a>
-* <a href="#_forownrightobject-callbackidentity-thisarg">`_.forOwnRight`</a>
-* <a href="#_functionsobject">`_.functions`</a>
-* <a href="#_hasobject-key">`_.has`</a>
-* <a href="#_invertobject">`_.invert`</a>
+## <a id="lang"></a>`Lang`
+* <a href="#_clonevalue-isdeep-customizer-thisarg">`_.clone`</a>
+* <a href="#_clonedeepvalue-customizer-thisarg">`_.cloneDeep`</a>
* <a href="#_isargumentsvalue">`_.isArguments`</a>
* <a href="#_isarrayvalue">`_.isArray`</a>
* <a href="#_isbooleanvalue">`_.isBoolean`</a>
* <a href="#_isdatevalue">`_.isDate`</a>
* <a href="#_iselementvalue">`_.isElement`</a>
* <a href="#_isemptyvalue">`_.isEmpty`</a>
-* <a href="#_isequala-b-callback-thisarg">`_.isEqual`</a>
+* <a href="#_isequalvalue-other-customizer-thisarg">`_.isEqual`</a>
+* <a href="#_iserrorvalue">`_.isError`</a>
* <a href="#_isfinitevalue">`_.isFinite`</a>
* <a href="#_isfunctionvalue">`_.isFunction`</a>
+* <a href="#_ismatchsource-source-customizer-thisarg">`_.isMatch`</a>
* <a href="#_isnanvalue">`_.isNaN`</a>
+* <a href="#_isnativevalue">`_.isNative`</a>
* <a href="#_isnullvalue">`_.isNull`</a>
* <a href="#_isnumbervalue">`_.isNumber`</a>
* <a href="#_isobjectvalue">`_.isObject`</a>
* <a href="#_isplainobjectvalue">`_.isPlainObject`</a>
* <a href="#_isregexpvalue">`_.isRegExp`</a>
* <a href="#_isstringvalue">`_.isString`</a>
+* <a href="#_istypedarrayvalue">`_.isTypedArray`</a>
* <a href="#_isundefinedvalue">`_.isUndefined`</a>
+* <a href="#_toarrayvalue">`_.toArray`</a>
+* <a href="#_toplainobjectvalue">`_.toPlainObject`</a>
+
+<!-- /div -->
+
+<!-- div -->
+
+## <a id="number"></a>`Number`
+* <a href="#_randommin0-max1-floating">`_.random`</a>
+
+<!-- /div -->
+
+<!-- div -->
+
+## <a id="object"></a>`Object`
+* <a href="#_assignobject-sources-customizer-thisarg">`_.assign`</a>
+* <a href="#_createprototype-properties">`_.create`</a>
+* <a href="#_defaultsobject-sources">`_.defaults`</a>
+* <a href="#_assignobject-sources-customizer-thisarg" class="alias">`_.extend` -> `assign`</a>
+* <a href="#_findkeyobject-predicate_identity-thisarg">`_.findKey`</a>
+* <a href="#_findlastkeyobject-predicate_identity-thisarg">`_.findLastKey`</a>
+* <a href="#_forinobject-iteratee_identity-thisarg">`_.forIn`</a>
+* <a href="#_forinrightobject-iteratee_identity-thisarg">`_.forInRight`</a>
+* <a href="#_forownobject-iteratee_identity-thisarg">`_.forOwn`</a>
+* <a href="#_forownrightobject-iteratee_identity-thisarg">`_.forOwnRight`</a>
+* <a href="#_functionsobject">`_.functions`</a>
+* <a href="#_hasobject-key">`_.has`</a>
+* <a href="#_invertobject-multivalue">`_.invert`</a>
* <a href="#_keysobject">`_.keys`</a>
-* <a href="#_mapvaluesobject-callbackidentity-thisarg">`_.mapValues`</a>
-* <a href="#_mergeobject-source-callback-thisarg">`_.merge`</a>
+* <a href="#_keysinobject">`_.keysIn`</a>
+* <a href="#_mapvaluesobject-iteratee_identity-thisarg">`_.mapValues`</a>
+* <a href="#_mergeobject-sources-customizer-thisarg">`_.merge`</a>
* <a href="#_functionsobject" class="alias">`_.methods` -> `functions`</a>
-* <a href="#_omitobject-callback-thisarg">`_.omit`</a>
+* <a href="#_omitobject-predicate-thisarg">`_.omit`</a>
* <a href="#_pairsobject">`_.pairs`</a>
-* <a href="#_pickobject-callback-thisarg">`_.pick`</a>
-* <a href="#_transformobject-callbackidentity-accumulator-thisarg">`_.transform`</a>
+* <a href="#_pickobject-predicate-thisarg">`_.pick`</a>
+* <a href="#_resultobject-key-defaultvalue">`_.result`</a>
+* <a href="#_transformobject-iteratee_identity-accumulator-thisarg">`_.transform`</a>
* <a href="#_valuesobject">`_.values`</a>
+* <a href="#_valuesinobject">`_.valuesIn`</a>
<!-- /div -->
+<!-- div -->
+
+## <a id="string"></a>`String`
+* <a href="#_camelcasestring">`_.camelCase`</a>
+* <a href="#_capitalizestring">`_.capitalize`</a>
+* <a href="#_deburrstring">`_.deburr`</a>
+* <a href="#_endswithstring-target-positionstringlength">`_.endsWith`</a>
+* <a href="#_escapestring">`_.escape`</a>
+* <a href="#_escaperegexpstring">`_.escapeRegExp`</a>
+* <a href="#_kebabcasestring">`_.kebabCase`</a>
+* <a href="#_padstring-length0-chars">`_.pad`</a>
+* <a href="#_padleftstring-length0-chars">`_.padLeft`</a>
+* <a href="#_padrightstring-length0-chars">`_.padRight`</a>
+* <a href="#_parseintstring-radix">`_.parseInt`</a>
+* <a href="#_repeatstring-n0">`_.repeat`</a>
+* <a href="#_snakecasestring">`_.snakeCase`</a>
+* <a href="#_startswithstring-target-position0">`_.startsWith`</a>
+* <a href="#_templatestring-options-optionsescape-optionsevaluate-optionsimports-optionsinterpolate-optionssourceurl-optionsvariable">`_.template`</a>
+* <a href="#_trimstring-charswhitespace">`_.trim`</a>
+* <a href="#_trimleftstring-charswhitespace">`_.trimLeft`</a>
+* <a href="#_trimrightstring-charswhitespace">`_.trimRight`</a>
+* <a href="#_truncstring-options-optionslength30-optionsomission-optionsseparator">`_.trunc`</a>
+* <a href="#_unescapestring">`_.unescape`</a>
+* <a href="#_wordsstring-pattern">`_.words`</a>
+
+<!-- /div -->
<!-- div -->
-## `Utilities`
-* <a href="#_now">`_.now`</a>
+## <a id="utility"></a>`Utility`
+* <a href="#_attemptfunc">`_.attempt`</a>
+* <a href="#_callbackfunc_identity-thisarg">`_.callback`</a>
* <a href="#_constantvalue">`_.constant`</a>
-* <a href="#_createcallbackfuncidentity-thisarg-argcount">`_.createCallback`</a>
-* <a href="#_escapestring">`_.escape`</a>
* <a href="#_identityvalue">`_.identity`</a>
-* <a href="#_mixinobjectlodash-source-options">`_.mixin`</a>
+* <a href="#_callbackfunc_identity-thisarg" class="alias">`_.iteratee` -> `callback`</a>
+* <a href="#_matchessource">`_.matches`</a>
+* <a href="#_mixinobjectthis-source-options-optionschaintrue">`_.mixin`</a>
* <a href="#_noconflict">`_.noConflict`</a>
* <a href="#_noop">`_.noop`</a>
-* <a href="#_parseintvalue-radix">`_.parseInt`</a>
* <a href="#_propertykey">`_.property`</a>
-* <a href="#_randommin0-max1-floatingfalse">`_.random`</a>
-* <a href="#_resultobject-key">`_.result`</a>
+* <a href="#_propertyofobject">`_.propertyOf`</a>
+* <a href="#_rangestart0-end-step1">`_.range`</a>
* <a href="#_runincontextcontextroot">`_.runInContext`</a>
-* <a href="#_templatetext-data-options-optionsescape-optionsevaluate-optionsimports-optionsinterpolate-sourceurl-variable">`_.template`</a>
-* <a href="#_timesn-callback-thisarg">`_.times`</a>
-* <a href="#_unescapestring">`_.unescape`</a>
+* <a href="#_timesn-iteratee_identity-thisarg">`_.times`</a>
* <a href="#_uniqueidprefix">`_.uniqueId`</a>
<!-- /div -->
-
<!-- div -->
-## `Methods`
+## <a id="methods"></a>`Methods`
* <a href="#_templatesettingsimports_">`_.templateSettings.imports._`</a>
<!-- /div -->
-
<!-- div -->
-## `Properties`
+## <a id="properties"></a>`Properties`
* <a href="#_version">`_.VERSION`</a>
* <a href="#_support">`_.support`</a>
-* <a href="#_supportargsclass">`_.support.argsClass`</a>
-* <a href="#_supportargsobject">`_.support.argsObject`</a>
+* <a href="#_supportargstag">`_.support.argsTag`</a>
* <a href="#_supportenumerrorprops">`_.support.enumErrorProps`</a>
* <a href="#_supportenumprototypes">`_.support.enumPrototypes`</a>
* <a href="#_supportfuncdecomp">`_.support.funcDecomp`</a>
* <a href="#_supportfuncnames">`_.support.funcNames`</a>
-* <a href="#_supportnonenumargs">`_.support.nonEnumArgs`</a>
+* <a href="#_supportnodetag">`_.support.nodeTag`</a>
* <a href="#_supportnonenumshadows">`_.support.nonEnumShadows`</a>
+* <a href="#_supportnonenumstrings">`_.support.nonEnumStrings`</a>
* <a href="#_supportownlast">`_.support.ownLast`</a>
* <a href="#_supportspliceobjects">`_.support.spliceObjects`</a>
* <a href="#_supportunindexedchars">`_.support.unindexedChars`</a>
* <a href="#_templatesettings">`_.templateSettings`</a>
* <a href="#_templatesettingsescape">`_.templateSettings.escape`</a>
* <a href="#_templatesettingsevaluate">`_.templateSettings.evaluate`</a>
+* <a href="#_templatesettingsimports">`_.templateSettings.imports`</a>
* <a href="#_templatesettingsinterpolate">`_.templateSettings.interpolate`</a>
* <a href="#_templatesettingsvariable">`_.templateSettings.variable`</a>
-* <a href="#_templatesettingsimports">`_.templateSettings.imports`</a>
<!-- /div -->
-
<!-- /div -->
+<!-- div class="doc-container" -->
<!-- div -->
+## `“Array” Methods`
<!-- div -->
-## `“Arrays” Methods`
+### <a id="_chunkarray-size1"></a>`_.chunk(array, [size=1])`
+<a href="#_chunkarray-size1">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4095 "View in source") [Ⓣ][1]
+
+Creates an array of elements split into groups the length of `size`.
+If `collection` can't be split evenly, the final chunk will be the remaining
+elements.
+
+#### Arguments
+1. `array` *(Array)*: The array to process.
+2. `[size=1]` *(numer)*: The length of each chunk.
+
+#### Returns
+*(Array)*: Returns the new array containing chunks.
+
+#### Example
+```js
+_.chunk(['a', 'b', 'c', 'd'], 2);
+// => [['a', 'b'], ['c', 'd']]
+
+_.chunk(['a', 'b', 'c', 'd'], 3);
+// => [['a', 'b', 'c'], ['d']]
+```
+* * *
+
+<!-- /div -->
<!-- div -->
### <a id="_compactarray"></a>`_.compact(array)`
-<a href="#_compactarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4479 "View in source") [Ⓣ][1]
+<a href="#_compactarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4126 "View in source") [Ⓣ][1]
-Creates an array with all falsey values removed. The values `false`, `null`, `0`, `""`, `undefined`, and `NaN` are all falsey.
+Creates an array with all falsey values removed. The values `false`, `null`,
+`0`, `""`, `undefined`, and `NaN` are falsey.
#### Arguments
1. `array` *(Array)*: The array to compact.
#### Returns
-*(Array)*: Returns a new array of filtered values.
+*(Array)*: Returns the new array of filtered values.
#### Example
```js
_.compact([0, 1, false, 2, '', 3]);
// => [1, 2, 3]
```
-
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_differencearray-values"></a>`_.difference(array, [values])`
-<a href="#_differencearray-values">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4508 "View in source") [Ⓣ][1]
+<a href="#_differencearray-values">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4161 "View in source") [Ⓣ][1]
-Creates an array excluding all values of the provided arrays using strict equality for comparisons, i.e. `===`.
+Creates an array excluding all values of the provided arrays using
+`SameValueZero` for equality comparisons.
+ *Note:** `SameValueZero` comparisons are like strict equality comparisons,
+e.g. `===`, except that `NaN` matches `NaN`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+for more details.
#### Arguments
-1. `array` *(Array)*: The array to process.
+1. `array` *(Array)*: The array to inspect.
2. `[values]` *(...Array)*: The arrays of values to exclude.
#### Returns
-*(Array)*: Returns a new array of filtered values.
+*(Array)*: Returns the new array of filtered values.
#### Example
```js
-_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
-// => [1, 3, 4]
+_.difference([1, 2, 3], [5, 2, 10]);
+// => [1, 3]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_findindexarray-callbackidentity-thisarg"></a>`_.findIndex(array, [callback=identity], [thisArg])`
-<a href="#_findindexarray-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4553 "View in source") [Ⓣ][1]
+### <a id="_droparray-n1"></a>`_.drop(array, [n=1])`
+<a href="#_droparray-n1">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4199 "View in source") [Ⓣ][1]
-This method is like `_.find` except that it returns the index of the first element that passes the callback check, instead of the element itself.
-
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Creates a slice of `array` with `n` elements dropped from the beginning.
#### Arguments
-1. `array` *(Array)*: The array to search.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `array` *(Array)*: The array to query.
+2. `[n=1]` *(number)*: The number of elements to drop.
#### Returns
-*(number)*: Returns the index of the found element, else `-1`.
+*(Array)*: Returns the slice of `array`.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36, 'blocked': false },
- { 'name': 'fred', 'age': 40, 'blocked': true },
- { 'name': 'pebbles', 'age': 1, 'blocked': false }
-];
+_.drop([1, 2, 3]);
+// => [2, 3]
-_.findIndex(characters, function(chr) {
- return chr.age < 20;
-});
-// => 2
+_.drop([1, 2, 3], 2);
+// => [3]
-// using "_.where" callback shorthand
-_.findIndex(characters, { 'age': 36 });
-// => 0
+_.drop([1, 2, 3], 5);
+// => []
-// using "_.pluck" callback shorthand
-_.findIndex(characters, 'blocked');
-// => 1
+_.drop([1, 2, 3], 0);
+// => [1, 2, 3]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_findlastindexarray-callbackidentity-thisarg"></a>`_.findLastIndex(array, [callback=identity], [thisArg])`
-<a href="#_findlastindexarray-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4607 "View in source") [Ⓣ][1]
-
-This method is like `_.findIndex` except that it iterates over elements of a `collection` from right to left.
+### <a id="_droprightarray-n1"></a>`_.dropRight(array, [n=1])`
+<a href="#_droprightarray-n1">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4235 "View in source") [Ⓣ][1]
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Creates a slice of `array` with `n` elements dropped from the end.
#### Arguments
-1. `array` *(Array)*: The array to search.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `array` *(Array)*: The array to query.
+2. `[n=1]` *(number)*: The number of elements to drop.
#### Returns
-*(number)*: Returns the index of the found element, else `-1`.
+*(Array)*: Returns the slice of `array`.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36, 'blocked': true },
- { 'name': 'fred', 'age': 40, 'blocked': false },
- { 'name': 'pebbles', 'age': 1, 'blocked': true }
-];
+_.dropRight([1, 2, 3]);
+// => [1, 2]
-_.findLastIndex(characters, function(chr) {
- return chr.age > 30;
-});
-// => 1
+_.dropRight([1, 2, 3], 2);
+// => [1]
-// using "_.where" callback shorthand
-_.findLastIndex(characters, { 'age': 36 });
-// => 0
+_.dropRight([1, 2, 3], 5);
+// => []
-// using "_.pluck" callback shorthand
-_.findLastIndex(characters, 'blocked');
-// => 2
+_.dropRight([1, 2, 3], 0);
+// => [1, 2, 3]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_firstarray-callback-thisarg"></a>`_.first(array, [callback], [thisArg])`
-<a href="#_firstarray-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4669 "View in source") [Ⓣ][1]
+### <a id="_droprightwhilearray-predicate_identity-thisarg"></a>`_.dropRightWhile(array, [predicate=_.identity], [thisArg])`
+<a href="#_droprightwhilearray-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4287 "View in source") [Ⓣ][1]
-Gets the first element or first `n` elements of an array. If a callback is provided elements at the beginning of the array are returned as long as the callback returns truey. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
+Creates a slice of `array` excluding elements dropped from the end.
+Elements are dropped until `predicate` returns falsey. The predicate is
+bound to `thisArg` and invoked with three arguments; (value, index, array).
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
-
-#### Aliases
-*_.head, _.take*
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
#### Arguments
1. `array` *(Array)*: The array to query.
-2. `[callback]` *(Function|Object|number|string)*: The function called per element or the number of elements to return. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per element.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(*)*: Returns the first element(s) of `array`.
+*(Array)*: Returns the slice of `array`.
#### Example
```js
-_.first([1, 2, 3]);
-// => 1
-
-_.first([1, 2, 3], 2);
-// => [1, 2]
-
-_.first([1, 2, 3], function(num) {
- return num < 3;
-});
-// => [1, 2]
+_.dropRightWhile([1, 2, 3], function(n) { return n > 1; });
+// => [1]
-var characters = [
- { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
- { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
- { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
+var users = [
+ { 'user': 'barney', 'status': 'busy', 'active': false },
+ { 'user': 'fred', 'status': 'busy', 'active': true },
+ { 'user': 'pebbles', 'status': 'away', 'active': true }
];
-// using "_.pluck" callback shorthand
-_.first(characters, 'blocked');
-// => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
+// using the "_.property" callback shorthand
+_.pluck(_.dropRightWhile(users, 'active'), 'user');
+// => ['barney']
-// using "_.where" callback shorthand
-_.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
+// using the "_.matches" callback shorthand
+_.pluck(_.dropRightWhile(users, { 'status': 'away' }), 'user');
// => ['barney', 'fred']
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_flattenarray-isshallowfalse-callbackidentity-thisarg"></a>`_.flatten(array, [isShallow=false], [callback=identity], [thisArg])`
-<a href="#_flattenarray-isshallowfalse-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4729 "View in source") [Ⓣ][1]
+### <a id="_dropwhilearray-predicate_identity-thisarg"></a>`_.dropWhile(array, [predicate=_.identity], [thisArg])`
+<a href="#_dropwhilearray-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4337 "View in source") [Ⓣ][1]
-Flattens a nested array *(the nesting can be to any depth)*. If `isShallow` is truey, the array will only be flattened a single level. If a callback is provided each element of the array is passed through the callback before flattening. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
+Creates a slice of `array` excluding elements dropped from the beginning.
+Elements are dropped until `predicate` returns falsey. The predicate is
+bound to `thisArg` and invoked with three arguments; (value, index, array).
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
#### Arguments
-1. `array` *(Array)*: The array to flatten.
-2. `[isShallow=false]` *(boolean)*: A flag to restrict flattening to a single level.
-3. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `array` *(Array)*: The array to query.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per element.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(Array)*: Returns a new flattened array.
+*(Array)*: Returns the slice of `array`.
#### Example
```js
-_.flatten([1, [2], [3, [[4]]]]);
-// => [1, 2, 3, 4];
-
-_.flatten([1, [2], [3, [[4]]]], true);
-// => [1, 2, 3, [[4]]];
+_.dropWhile([1, 2, 3], function(n) { return n < 3; });
+// => [3]
-var characters = [
- { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
- { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
+var users = [
+ { 'user': 'barney', 'status': 'busy', 'active': true },
+ { 'user': 'fred', 'status': 'busy', 'active': false },
+ { 'user': 'pebbles', 'status': 'away', 'active': true }
];
-// using "_.pluck" callback shorthand
-_.flatten(characters, 'pets');
-// => ['hoppy', 'baby puss', 'dino']
-```
+// using the "_.property" callback shorthand
+_.pluck(_.dropWhile(users, 'active'), 'user');
+// => ['fred', 'pebbles']
+// using the "_.matches" callback shorthand
+_.pluck(_.dropWhile(users, { 'status': 'busy' }), 'user');
+// => ['pebbles']
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_indexofarray-value-fromindex0"></a>`_.indexOf(array, value, [fromIndex=0])`
-<a href="#_indexofarray-value-fromindex0">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4766 "View in source") [Ⓣ][1]
+### <a id="_findindexarray-predicate_identity-thisarg"></a>`_.findIndex(array, [predicate=_.identity], [thisArg])`
+<a href="#_findindexarray-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4387 "View in source") [Ⓣ][1]
+
+This method is like `_.find` except that it returns the index of the first
+element `predicate` returns truthy for, instead of the element itself.
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
-Gets the index at which the first occurrence of `value` is found using strict equality for comparisons, i.e. `===`. If the array is already sorted providing `true` for `fromIndex` will run a faster binary search.
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
#### Arguments
1. `array` *(Array)*: The array to search.
-2. `value` *(*)*: The value to search for.
-3. `[fromIndex=0]` *(boolean|number)*: The index to search from or `true` to perform a binary search on a sorted array.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(number)*: Returns the index of the matched value or `-1`.
+*(number)*: Returns the index of the found element, else `-1`.
#### Example
```js
-_.indexOf([1, 2, 3, 1, 2, 3], 2);
-// => 1
+var users = [
+ { 'user': 'barney', 'age': 36, 'active': false },
+ { 'user': 'fred', 'age': 40, 'active': true },
+ { 'user': 'pebbles', 'age': 1, 'active': false }
+];
-_.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
-// => 4
+_.findIndex(users, function(chr) { return chr.age < 40; });
+// => 0
-_.indexOf([1, 1, 2, 2, 3, 3], 2, true);
+// using the "_.matches" callback shorthand
+_.findIndex(users, { 'age': 1 });
// => 2
-```
+// using the "_.property" callback shorthand
+_.findIndex(users, 'active');
+// => 1
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_initialarray-callback1-thisarg"></a>`_.initial(array, [callback=1], [thisArg])`
-<a href="#_initialarray-callback1-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4827 "View in source") [Ⓣ][1]
+### <a id="_findlastindexarray-predicate_identity-thisarg"></a>`_.findLastIndex(array, [predicate=_.identity], [thisArg])`
+<a href="#_findlastindexarray-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4439 "View in source") [Ⓣ][1]
-Gets all but the last element or last `n` elements of an array. If a callback is provided elements at the end of the array are excluded from the result as long as the callback returns truey. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
+This method is like `_.findIndex` except that it iterates over elements
+of `collection` from right to left.
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
#### Arguments
-1. `array` *(Array)*: The array to query.
-2. `[callback=1]` *(Function|Object|number|string)*: The function called per element or the number of elements to exclude. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `array` *(Array)*: The array to search.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(Array)*: Returns a slice of `array`.
+*(number)*: Returns the index of the found element, else `-1`.
#### Example
```js
-_.initial([1, 2, 3]);
-// => [1, 2]
-
-_.initial([1, 2, 3], 2);
-// => [1]
-
-_.initial([1, 2, 3], function(num) {
- return num > 1;
-});
-// => [1]
-
-var characters = [
- { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
- { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
- { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
+var users = [
+ { 'user': 'barney', 'age': 36, 'active': true },
+ { 'user': 'fred', 'age': 40, 'active': false },
+ { 'user': 'pebbles', 'age': 1, 'active': false }
];
-// using "_.pluck" callback shorthand
-_.initial(characters, 'blocked');
-// => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }]
+_.findLastIndex(users, function(chr) { return chr.age < 40; });
+// => 2
-// using "_.where" callback shorthand
-_.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
-// => ['barney', 'fred']
-```
+// using the "_.matches" callback shorthand
+_.findLastIndex(users, { 'age': 40 });
+// => 1
+// using the "_.property" callback shorthand
+_.findLastIndex(users, 'active');
+// => 0
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_intersectionarray"></a>`_.intersection([array])`
-<a href="#_intersectionarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4857 "View in source") [Ⓣ][1]
+### <a id="_firstarray"></a>`_.first(array)`
+<a href="#_firstarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4467 "View in source") [Ⓣ][1]
-Creates an array of unique values present in all provided arrays using strict equality for comparisons, i.e. `===`.
+Gets the first element of `array`.
#### Arguments
-1. `[array]` *(...Array)*: The arrays to inspect.
+1. `array` *(Array)*: The array to query.
#### Returns
-*(Array)*: Returns an array of shared values.
+*(*)*: Returns the first element of `array`.
#### Example
```js
-_.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-// => [1, 2]
-```
+_.first([1, 2, 3]);
+// => 1
+_.first([]);
+// => undefined
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_lastarray-callback-thisarg"></a>`_.last(array, [callback], [thisArg])`
-<a href="#_lastarray-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4957 "View in source") [Ⓣ][1]
-
-Gets the last element or last `n` elements of an array. If a callback is provided elements at the end of the array are returned as long as the callback returns truey. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
+### <a id="_flattenarray-isdeep"></a>`_.flatten(array, [isDeep])`
+<a href="#_flattenarray-isdeep">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4491 "View in source") [Ⓣ][1]
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Flattens a nested array. If `isDeep` is `true` the array is recursively
+flattened, otherwise it is only flattened a single level.
#### Arguments
-1. `array` *(Array)*: The array to query.
-2. `[callback]` *(Function|Object|number|string)*: The function called per element or the number of elements to return. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `array` *(Array)*: The array to flatten.
+2. `[isDeep]` *(boolean)*: Specify a deep flatten.
#### Returns
-*(*)*: Returns the last element(s) of `array`.
+*(Array)*: Returns the new flattened array.
#### Example
```js
-_.last([1, 2, 3]);
-// => 3
+_.flatten([1, [2], [3, [[4]]]]);
+// => [1, 2, 3, [[4]]];
-_.last([1, 2, 3], 2);
-// => [2, 3]
+// using `isDeep`
+_.flatten([1, [2], [3, [[4]]]], true);
+// => [1, 2, 3, 4];
+```
+* * *
-_.last([1, 2, 3], function(num) {
- return num > 1;
-});
-// => [2, 3]
+<!-- /div -->
-var characters = [
- { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
- { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
- { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
-];
+<!-- div -->
-// using "_.pluck" callback shorthand
-_.pluck(_.last(characters, 'blocked'), 'name');
-// => ['fred', 'pebbles']
+### <a id="_flattendeeparray"></a>`_.flattenDeep(array)`
+<a href="#_flattendeeparray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4512 "View in source") [Ⓣ][1]
-// using "_.where" callback shorthand
-_.last(characters, { 'employer': 'na' });
-// => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
-```
+Recursively flattens a nested array.
+
+#### Arguments
+1. `array` *(Array)*: The array to recursively flatten.
+
+#### Returns
+*(Array)*: Returns the new flattened array.
+#### Example
+```js
+_.flattenDeep([1, [2], [3, [[4]]]]);
+// => [1, 2, 3, 4];
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_lastindexofarray-value-fromindexarraylength-1"></a>`_.lastIndexOf(array, value, [fromIndex=array.length-1])`
-<a href="#_lastindexofarray-value-fromindexarraylength-1">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5003 "View in source") [Ⓣ][1]
-
-Gets the index at which the last occurrence of `value` is found using strict equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the offset from the end of the collection.
-
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+### <a id="_indexofarray-value-fromindex0"></a>`_.indexOf(array, value, [fromIndex=0])`
+<a href="#_indexofarray-value-fromindex0">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4549 "View in source") [Ⓣ][1]
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Gets the index at which the first occurrence of `value` is found in `array`
+using `SameValueZero` for equality comparisons. If `fromIndex` is negative,
+it is used as the offset from the end of `array`. If `array` is sorted
+providing `true` for `fromIndex` performs a faster binary search.
+ *Note:** `SameValueZero` comparisons are like strict equality comparisons,
+e.g. `===`, except that `NaN` matches `NaN`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+for more details.
#### Arguments
1. `array` *(Array)*: The array to search.
2. `value` *(*)*: The value to search for.
-3. `[fromIndex=array.length-1]` *(number)*: The index to search from.
+3. `[fromIndex=0]` *(boolean|number)*: The index to search from or `true` to perform a binary search on a sorted array.
#### Returns
-*(number)*: Returns the index of the matched value or `-1`.
+*(number)*: Returns the index of the matched value, else `-1`.
#### Example
```js
-_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+_.indexOf([1, 2, 3, 1, 2, 3], 2);
+// => 1
+
+// using `fromIndex`
+_.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
// => 4
-_.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
-// => 1
+// performing a binary search
+_.indexOf([4, 4, 5, 5, 6, 6], 5, true);
+// => 2
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_pullarray-value"></a>`_.pull(array, [value])`
-<a href="#_pullarray-value">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5033 "View in source") [Ⓣ][1]
+### <a id="_initialarray"></a>`_.initial(array)`
+<a href="#_initialarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4578 "View in source") [Ⓣ][1]
-Removes all provided values from the given array using strict equality for comparisons, i.e. `===`.
+Gets all but the last element of `array`.
#### Arguments
-1. `array` *(Array)*: The array to modify.
-2. `[value]` *(...*)*: The values to remove.
+1. `array` *(Array)*: The array to query.
#### Returns
-*(Array)*: Returns `array`.
+*(Array)*: Returns the slice of `array`.
#### Example
```js
-var array = [1, 2, 3, 1, 2, 3];
-_.pull(array, 2, 3);
-console.log(array);
-// => [1, 1]
+_.initial([1, 2, 3]);
+// => [1, 2]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_rangestart0-end-step1"></a>`_.range([start=0], end, [step=1])`
-<a href="#_rangestart0-end-step1">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5084 "View in source") [Ⓣ][1]
+### <a id="_intersectionarrays"></a>`_.intersection([arrays])`
+<a href="#_intersectionarrays">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4601 "View in source") [Ⓣ][1]
-Creates an array of numbers *(positive and/or negative)* progressing from `start` up to but not including `end`. If `start` is less than `stop` a zero-length range is created unless a negative `step` is specified.
+Creates an array of unique values in all provided arrays using `SameValueZero`
+for equality comparisons.
+ *Note:** `SameValueZero` comparisons are like strict equality comparisons,
+e.g. `===`, except that `NaN` matches `NaN`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+for more details.
#### Arguments
-1. `[start=0]` *(number)*: The start of the range.
-2. `end` *(number)*: The end of the range.
-3. `[step=1]` *(number)*: The value to increment or decrement by.
+1. `[arrays]` *(...Array)*: The arrays to inspect.
#### Returns
-*(Array)*: Returns a new range array.
+*(Array)*: Returns the new array of shared values.
#### Example
```js
-_.range(4);
-// => [0, 1, 2, 3]
-
-_.range(1, 5);
-// => [1, 2, 3, 4]
-
-_.range(0, 20, 5);
-// => [0, 5, 10, 15]
-
-_.range(0, -4, -1);
-// => [0, -1, -2, -3]
-
-_.range(1, 4, 0);
-// => [1, 1, 1]
-
-_.range(0);
-// => []
+_.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+// => [1, 2]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_removearray-callbackidentity-thisarg"></a>`_.remove(array, [callback=identity], [thisArg])`
-<a href="#_removearray-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5137 "View in source") [Ⓣ][1]
-
-Removes all elements from an array that the callback returns truey for and returns an array of removed elements. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
+### <a id="_lastarray"></a>`_.last(array)`
+<a href="#_lastarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4656 "View in source") [Ⓣ][1]
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Gets the last element of `array`.
#### Arguments
-1. `array` *(Array)*: The array to modify.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `array` *(Array)*: The array to query.
#### Returns
-*(Array)*: Returns a new array of removed elements.
+*(*)*: Returns the last element of `array`.
#### Example
```js
-var array = [1, 2, 3, 4, 5, 6];
-var evens = _.remove(array, function(num) { return num % 2 == 0; });
-
-console.log(array);
-// => [1, 3, 5]
-
-console.log(evens);
-// => [2, 4, 6]
+_.last([1, 2, 3]);
+// => 3
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_restarray-callback1-thisarg"></a>`_.rest(array, [callback=1], [thisArg])`
-<a href="#_restarray-callback1-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5206 "View in source") [Ⓣ][1]
+### <a id="_lastindexofarray-value"></a>`_.lastIndexOf(array, value)`
+<a href="#_lastindexofarray-value">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4686 "View in source") [Ⓣ][1]
-The opposite of `_.initial` this method gets all but the first element or first `n` elements of an array. If a callback function is provided elements at the beginning of the array are excluded from the result as long as the callback returns truey. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
+This method is like `_.indexOf` except that it iterates over elements of
+`array` from right to left.
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+#### Arguments
+1. `array` *(Array)*: The array to search.
+2. `value` *(*)*: The value to search for.
+3. `[fromIndex=array.length-1]` *(boolean|number)*: The index to search from or `true` to perform a binary search on a sorted array.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+#### Returns
+*(number)*: Returns the index of the matched value, else `-1`.
-#### Aliases
-*_.drop, _.tail*
+#### Example
+```js
+_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+// => 4
+
+// using `fromIndex`
+_.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+// => 1
+
+// performing a binary search
+_.lastIndexOf([4, 4, 5, 5, 6, 6], 5, true);
+// => 3
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_pullarray-values"></a>`_.pull(array, [values])`
+<a href="#_pullarray-values">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4733 "View in source") [Ⓣ][1]
+
+Removes all provided values from `array` using `SameValueZero` for equality
+comparisons.
+ *Notes:**
+- Unlike `_.without`, this method mutates `array`.
+- `SameValueZero` comparisons are like strict equality comparisons, e.g. `===`,
+except that `NaN` matches `NaN`. See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+for more details.
+
+#### Arguments
+1. `array` *(Array)*: The array to modify.
+2. `[values]` *(...*)*: The values to remove.
+
+#### Returns
+*(Array)*: Returns `array`.
+
+#### Example
+```js
+var array = [1, 2, 3, 1, 2, 3];
+_.pull(array, 2, 3);
+console.log(array);
+// => [1, 1]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_pullatarray-indexes"></a>`_.pullAt(array, [indexes])`
+<a href="#_pullatarray-indexes">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4778 "View in source") [Ⓣ][1]
+
+Removes elements from `array` corresponding to the given indexes and returns
+an array of the removed elements. Indexes may be specified as an array of
+indexes or as individual arguments.
+ *Note:** Unlike `_.at`, this method mutates `array`.
+
+#### Arguments
+1. `array` *(Array)*: The array to modify.
+2. `[indexes]` *(...(number|number[])*: The indexes of elements to remove, specified as individual indexes or arrays of indexes.
+
+#### Returns
+*(Array)*: Returns the new array of removed elements.
+
+#### Example
+```js
+var array = [5, 10, 15, 20];
+var evens = _.pullAt(array, [1, 3]);
+
+console.log(array);
+// => [5, 15]
+
+console.log(evens);
+// => [10, 20]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_removearray-predicate_identity-thisarg"></a>`_.remove(array, [predicate=_.identity], [thisArg])`
+<a href="#_removearray-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4816 "View in source") [Ⓣ][1]
+
+Removes all elements from `array` that `predicate` returns truthy for
+and returns an array of the removed elements. The predicate is bound to
+`thisArg` and invoked with three arguments; (value, index, array).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+ *Note:** Unlike `_.filter`, this method mutates `array`.
+
+#### Arguments
+1. `array` *(Array)*: The array to modify.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(Array)*: Returns the new array of removed elements.
+
+#### Example
+```js
+var array = [1, 2, 3, 4];
+var evens = _.remove(array, function(n) { return n % 2 == 0; });
+
+console.log(array);
+// => [1, 3]
+
+console.log(evens);
+// => [2, 4]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_restarray"></a>`_.rest(array)`
+<a href="#_restarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4847 "View in source") [Ⓣ][1]
+
+Gets all but the first element of `array`.
+
+#### Arguments
+1. `array` *(Array)*: The array to query.
+
+#### Returns
+*(Array)*: Returns the slice of `array`.
+
+#### Example
+```js
+_.rest([1, 2, 3]);
+// => [2, 3]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_slicearray-start0"></a>`_.slice(array, [start=0])`
+<a href="#_slicearray-start0">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4865 "View in source") [Ⓣ][1]
+
+Creates a slice of `array` from `start` up to, but not including, `end`.
+ *Note:** This function is used instead of `Array#slice` to support node
+lists in IE < 9 and to ensure dense arrays are returned.
+
+#### Arguments
+1. `array` *(Array)*: The array to slice.
+2. `[start=0]` *(number)*: The start position.
+3. `[end=array.length]` *(number)*: The end position.
+
+#### Returns
+*(Array)*: Returns the slice of `array`.
+
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_sortedindexarray-value-iteratee_identity-thisarg"></a>`_.sortedIndex(array, value, [iteratee=_.identity], [thisArg])`
+<a href="#_sortedindexarray-value-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4922 "View in source") [Ⓣ][1]
+
+Uses a binary search to determine the lowest index at which `value` should
+be inserted into `array` in order to maintain its sort order. If an iteratee
+function is provided it is invoked for `value` and each element of `array`
+to compute their sort ranking. The iteratee is bound to `thisArg` and
+invoked with one argument; (value).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `array` *(Array)*: The sorted array to inspect.
+2. `value` *(*)*: The value to evaluate.
+3. `[iteratee=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+4. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(number)*: Returns the index at which `value` should be inserted
+into `array`.
+
+#### Example
+```js
+_.sortedIndex([30, 50], 40);
+// => 1
+
+_.sortedIndex([4, 4, 5, 5, 6, 6], 5);
+// => 2
+
+var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } };
+
+// using an iteratee function
+_.sortedIndex(['thirty', 'fifty'], 'forty', function(word) {
+ return this.data[word];
+}, dict);
+// => 1
+
+// using the "_.property" callback shorthand
+_.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
+// => 1
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_sortedlastindexarray-value-iteratee_identity-thisarg"></a>`_.sortedLastIndex(array, value, [iteratee=_.identity], [thisArg])`
+<a href="#_sortedlastindexarray-value-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4950 "View in source") [Ⓣ][1]
+
+This method is like `_.sortedIndex` except that it returns the highest
+index at which `value` should be inserted into `array` in order to
+maintain its sort order.
+
+#### Arguments
+1. `array` *(Array)*: The sorted array to inspect.
+2. `value` *(*)*: The value to evaluate.
+3. `[iteratee=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+4. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(number)*: Returns the index at which `value` should be inserted
+into `array`.
+
+#### Example
+```js
+_.sortedLastIndex([4, 4, 5, 5, 6, 6], 5);
+// => 4
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_takearray-n1"></a>`_.take(array, [n=1])`
+<a href="#_takearray-n1">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L4982 "View in source") [Ⓣ][1]
+
+Creates a slice of `array` with `n` elements taken from the beginning.
+
+#### Arguments
+1. `array` *(Array)*: The array to query.
+2. `[n=1]` *(number)*: The number of elements to take.
+
+#### Returns
+*(Array)*: Returns the slice of `array`.
+
+#### Example
+```js
+_.take([1, 2, 3]);
+// => [1]
+
+_.take([1, 2, 3], 2);
+// => [1, 2]
+
+_.take([1, 2, 3], 5);
+// => [1, 2, 3]
+
+_.take([1, 2, 3], 0);
+// => []
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_takerightarray-n1"></a>`_.takeRight(array, [n=1])`
+<a href="#_takerightarray-n1">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5018 "View in source") [Ⓣ][1]
+
+Creates a slice of `array` with `n` elements taken from the end.
+
+#### Arguments
+1. `array` *(Array)*: The array to query.
+2. `[n=1]` *(number)*: The number of elements to take.
+
+#### Returns
+*(Array)*: Returns the slice of `array`.
+
+#### Example
+```js
+_.takeRight([1, 2, 3]);
+// => [3]
+
+_.takeRight([1, 2, 3], 2);
+// => [2, 3]
+
+_.takeRight([1, 2, 3], 5);
+// => [1, 2, 3]
+
+_.takeRight([1, 2, 3], 0);
+// => []
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_takerightwhilearray-predicate_identity-thisarg"></a>`_.takeRightWhile(array, [predicate=_.identity], [thisArg])`
+<a href="#_takerightwhilearray-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5070 "View in source") [Ⓣ][1]
+
+Creates a slice of `array` with elements taken from the end. Elements are
+taken until `predicate` returns falsey. The predicate is bound to `thisArg`
+and invoked with three arguments; (value, index, array).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `array` *(Array)*: The array to query.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per element.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(Array)*: Returns the slice of `array`.
+
+#### Example
+```js
+_.takeRightWhile([1, 2, 3], function(n) { return n > 1; });
+// => [2, 3]
+
+var users = [
+ { 'user': 'barney', 'status': 'busy', 'active': false },
+ { 'user': 'fred', 'status': 'busy', 'active': true },
+ { 'user': 'pebbles', 'status': 'away', 'active': true }
+];
+
+// using the "_.property" callback shorthand
+_.pluck(_.takeRightWhile(users, 'active'), 'user');
+// => ['fred', 'pebbles']
+
+// using the "_.matches" callback shorthand
+_.pluck(_.takeRightWhile(users, { 'status': 'away' }), 'user');
+// => ['pebbles']
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_takewhilearray-predicate_identity-thisarg"></a>`_.takeWhile(array, [predicate=_.identity], [thisArg])`
+<a href="#_takewhilearray-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5120 "View in source") [Ⓣ][1]
+
+Creates a slice of `array` with elements taken from the beginning. Elements
+are taken until `predicate` returns falsey. The predicate is bound to
+`thisArg` and invoked with three arguments; (value, index, array).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `array` *(Array)*: The array to query.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per element.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(Array)*: Returns the slice of `array`.
+
+#### Example
+```js
+_.takeWhile([1, 2, 3], function(n) { return n < 3; });
+// => [1, 2]
+
+var users = [
+ { 'user': 'barney', 'status': 'busy', 'active': true },
+ { 'user': 'fred', 'status': 'busy', 'active': false },
+ { 'user': 'pebbles', 'status': 'away', 'active': true }
+];
+
+// using the "_.property" callback shorthand
+_.pluck(_.takeWhile(users, 'active'), 'user');
+// => ['barney']
+
+// using the "_.matches" callback shorthand
+_.pluck(_.takeWhile(users, { 'status': 'busy' }), 'user');
+// => ['barney', 'fred']
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_unionarrays"></a>`_.union([arrays])`
+<a href="#_unionarrays">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5150 "View in source") [Ⓣ][1]
+
+Creates an array of unique values, in order, of the provided arrays using
+`SameValueZero` for equality comparisons.
+ *Note:** `SameValueZero` comparisons are like strict equality comparisons,
+e.g. `===`, except that `NaN` matches `NaN`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+for more details.
+
+#### Arguments
+1. `[arrays]` *(...Array)*: The arrays to inspect.
+
+#### Returns
+*(Array)*: Returns the new array of combined values.
+
+#### Example
+```js
+_.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+// => [1, 2, 3, 5, 4]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_uniqarray-issorted-iteratee-thisarg"></a>`_.uniq(array, [isSorted], [iteratee], [thisArg])`
+<a href="#_uniqarray-issorted-iteratee-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5202 "View in source") [Ⓣ][1]
+
+Creates a duplicate-value-free version of an array using `SameValueZero`
+for equality comparisons. Providing `true` for `isSorted` performs a faster
+search algorithm for sorted arrays. If an iteratee function is provided it
+is invoked for each value in the array to generate the criterion by which
+uniqueness is computed. The `iteratee` is bound to `thisArg` and invoked
+with three arguments; (value, index, array).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+ *Note:** `SameValueZero` comparisons are like strict equality comparisons,
+e.g. `===`, except that `NaN` matches `NaN`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+for more details.
+
+#### Arguments
+1. `array` *(Array)*: The array to inspect.
+2. `[isSorted]` *(boolean)*: Specify the array is sorted.
+3. `[iteratee]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+4. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Array)*: Returns the new duplicate-value-free array.
+
+#### Example
+```js
+_.uniq([1, 2, 1]);
+// => [1, 2]
+
+// using `isSorted`
+_.uniq([1, 1, 2], true);
+// => [1, 2]
+
+// using an iteratee function
+_.uniq([1, 2.5, 1.5, 2], function(n) { return this.floor(n); }, Math);
+// => [1, 2.5]
+
+// using the "_.property" callback shorthand
+_.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+// => [{ 'x': 1 }, { 'x': 2 }]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_unziparray"></a>`_.unzip(array)`
+<a href="#_unziparray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5240 "View in source") [Ⓣ][1]
+
+This method is like `_.zip` except that it accepts an array of grouped
+elements and creates an array regrouping the elements to their pre `_.zip`
+configuration.
+
+#### Arguments
+1. `array` *(Array)*: The array of grouped elements to process.
+
+#### Returns
+*(Array)*: Returns the new array of regrouped elements.
+
+#### Example
+```js
+var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
+// => [['fred', 30, true], ['barney', 40, false]]
+
+_.unzip(zipped);
+// => [['fred', 'barney'], [30, 40], [true, false]]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_withoutarray-values"></a>`_.without(array, [values])`
+<a href="#_withoutarray-values">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5271 "View in source") [Ⓣ][1]
+
+Creates an array excluding all provided values using `SameValueZero` for
+equality comparisons.
+ *Note:** `SameValueZero` comparisons are like strict equality comparisons,
+e.g. `===`, except that `NaN` matches `NaN`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+for more details.
+
+#### Arguments
+1. `array` *(Array)*: The array to filter.
+2. `[values]` *(...*)*: The values to exclude.
+
+#### Returns
+*(Array)*: Returns the new array of filtered values.
+
+#### Example
+```js
+_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+// => [2, 3, 4]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_xorarrays"></a>`_.xor([arrays])`
+<a href="#_xorarrays">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5293 "View in source") [Ⓣ][1]
+
+Creates an array that is the symmetric difference of the provided arrays.
+See [Wikipedia](http://en.wikipedia.org/wiki/Symmetric_difference) for
+more details.
+
+#### Arguments
+1. `[arrays]` *(...Array)*: The arrays to inspect.
+
+#### Returns
+*(Array)*: Returns the new array of values.
+
+#### Example
+```js
+_.xor([1, 2, 3], [5, 2, 1, 4]);
+// => [3, 5, 4]
+
+_.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+// => [1, 4, 5]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_ziparrays"></a>`_.zip([arrays])`
+<a href="#_ziparrays">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5323 "View in source") [Ⓣ][1]
+
+Creates an array of grouped elements, the first of which contains the first
+elements of the given arrays, the second of which contains the second elements
+of the given arrays, and so on.
+
+#### Arguments
+1. `[arrays]` *(...Array)*: The arrays to process.
+
+#### Returns
+*(Array)*: Returns the new array of grouped elements.
+
+#### Example
+```js
+_.zip(['fred', 'barney'], [30, 40], [true, false]);
+// => [['fred', 30, true], ['barney', 40, false]]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_zipobjectprops-values"></a>`_.zipObject(props, [values=[]])`
+<a href="#_zipobjectprops-values">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5350 "View in source") [Ⓣ][1]
+
+Creates an object composed from arrays of property names and values. Provide
+either a single two dimensional array, e.g. `[[key1, value1], [key2, value2]]`
+or two arrays, one of property names and one of corresponding values.
+
+#### Arguments
+1. `props` *(Array)*: The property names.
+2. `[values=[]]` *(Array)*: The property values.
+
+#### Returns
+*(Object)*: Returns the new object.
+
+#### Example
+```js
+_.zipObject(['fred', 'barney'], [30, 40]);
+// => { 'fred': 30, 'barney': 40 }
+```
+* * *
+
+<!-- /div -->
+
+<!-- /div -->
+
+<!-- div -->
+
+## `“Chain” Methods`
+
+<!-- div -->
+
+### <a id="_value"></a>`._(value)`
+<a href="#_value">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L918 "View in source") [Ⓣ][1]
+
+Creates a `lodash` object which wraps `value` to enable intuitive chaining.
+Methods that operate on and return arrays, collections, and functions can
+be chained together. Methods that return a boolean or single value will
+automatically end the chain returning the unwrapped value. Explicit chaining
+may be enabled using `_.chain`. The execution of chained methods is lazy,
+that is, execution is deferred until `_#value` is implicitly or explicitly
+called.
+
+Lazy evaluation allows several methods to support shortcut fusion. Shortcut
+fusion is an optimization that merges iteratees to avoid creating intermediate
+arrays and reduce the number of iteratee executions.
+
+Chaining is supported in custom builds as long as the `_#value` method is
+directly or indirectly included in the build.
+
+In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
+`concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
+and `unshift`
+
+The wrapper functions that support shortcut fusion are:
+`drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `first`,
+`initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, `slice`,
+`take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `where`
+
+The chainable wrapper functions are:
+`after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
+`callback`, `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`,
+`create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
+`drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`,
+`flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`,
+`forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`,
+`initial`, `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`,
+`mapValues`, `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`,
+`omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`,
+`pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`,
+`rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
+`sortBy`, `sortByAll`, `splice`, `take`, `takeRight`, `takeRightWhile`,
+`takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
+`transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`,
+`where`, `without`, `wrap`, `xor`, `zip`, and `zipObject`
+
+The wrapper functions that are **not** chainable by default are:
+`attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
+`endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`,
+`findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`,
+`identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`,
+`isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`,
+`isFunction`, `isMatch` , `isNative`, `isNaN`, `isNull`, `isNumber`,
+`isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`,
+`isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`,
+`noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`,
+`random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`,
+`shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`,
+`startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
+`unescape`, `uniqueId`, `value`, and `words`
+
+The wrapper function `sample` will return a wrapped value when `n` is provided,
+otherwise an unwrapped value is returned.
+
+#### Arguments
+1. `value` *(*)*: The value to wrap in a `lodash` instance.
+
+#### Returns
+*(Object)*: Returns a `lodash` instance.
+
+#### Example
+```js
+var wrapped = _([1, 2, 3]);
+
+// returns an unwrapped value
+wrapped.reduce(function(sum, n) { return sum + n; });
+// => 6
+
+// returns a wrapped value
+var squares = wrapped.map(function(n) { return n * n; });
+
+_.isArray(squares);
+// => false
+
+_.isArray(squares.value());
+// => true
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_chainvalue"></a>`_.chain(value)`
+<a href="#_chainvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5395 "View in source") [Ⓣ][1]
+
+Creates a `lodash` object that wraps `value` with explicit method
+chaining enabled.
+
+#### Arguments
+1. `value` *(*)*: The value to wrap.
+
+#### Returns
+*(Object)*: Returns the new `lodash` object.
+
+#### Example
+```js
+var users = [
+ { 'user': 'barney', 'age': 36 },
+ { 'user': 'fred', 'age': 40 },
+ { 'user': 'pebbles', 'age': 1 }
+];
+
+var youngest = _.chain(users)
+ .sortBy('age')
+ .map(function(chr) { return chr.user + ' is ' + chr.age; })
+ .first()
+ .value();
+// => 'pebbles is 1'
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_tapvalue-interceptor-thisarg"></a>`_.tap(value, interceptor, [thisArg])`
+<a href="#_tapvalue-interceptor-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5422 "View in source") [Ⓣ][1]
+
+This method invokes `interceptor` and returns `value`. The interceptor is
+bound to `thisArg` and invoked with one argument; (value). The purpose of
+this method is to "tap into" a method chain in order to perform operations
+on intermediate results within the chain.
+
+#### Arguments
+1. `value` *(*)*: The value to provide to `interceptor`.
+2. `interceptor` *(Function)*: The function to invoke.
+3. `[thisArg]` *(*)*: The `this` binding of `interceptor`.
+
+#### Returns
+*(*)*: Returns `value`.
+
+#### Example
+```js
+_([1, 2, 3])
+ .tap(function(array) { array.pop(); })
+ .reverse()
+ .value();
+// => [2, 1]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_thruvalue-interceptor-thisarg"></a>`_.thru(value, interceptor, [thisArg])`
+<a href="#_thruvalue-interceptor-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5445 "View in source") [Ⓣ][1]
+
+This method is like `_.tap` except that it returns the result of `interceptor`.
+
+#### Arguments
+1. `value` *(*)*: The value to provide to `interceptor`.
+2. `interceptor` *(Function)*: The function to invoke.
+3. `[thisArg]` *(*)*: The `this` binding of `interceptor`.
+
+#### Returns
+*(*)*: Returns the result of `interceptor`.
+
+#### Example
+```js
+_([1, 2, 3])
+ .last()
+ .thru(function(value) { return [value]; })
+ .value();
+// => [3]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_prototypechain"></a>`_.prototype.chain()`
+<a href="#_prototypechain">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5474 "View in source") [Ⓣ][1]
+
+Enables explicit method chaining on the wrapper object.
+
+#### Returns
+*(*)*: Returns the `lodash` object.
+
+#### Example
+```js
+var users = [
+ { 'user': 'barney', 'age': 36 },
+ { 'user': 'fred', 'age': 40 }
+];
+
+// without explicit chaining
+_(users).first();
+// => { 'user': 'barney', 'age': 36 }
+
+// with explicit chaining
+_(users).chain()
+ .first()
+ .pick('user')
+ .value();
+// => { 'user': 'barney' }
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_prototypereverse"></a>`_.prototype.reverse()`
+<a href="#_prototypereverse">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5498 "View in source") [Ⓣ][1]
+
+Reverses the wrapped array so the first element becomes the last, the
+second element becomes the second to last, and so on.
+ *Note:** This method mutates the wrapped array.
+
+#### Returns
+*(Object)*: Returns the new reversed `lodash` object.
+
+#### Example
+```js
+var array = [1, 2, 3];
+
+_(array).reverse().value()
+// => [3, 2, 1]
+
+console.log(array);
+// => [3, 2, 1]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_prototypetostring"></a>`_.prototype.toString()`
+<a href="#_prototypetostring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5520 "View in source") [Ⓣ][1]
+
+Produces the result of coercing the unwrapped value to a string.
+
+#### Returns
+*(string)*: Returns the coerced string value.
+
+#### Example
+```js
+_([1, 2, 3]).toString();
+// => '1,2,3'
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_prototypevalue"></a>`_.prototype.value()`
+<a href="#_prototypevalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5537 "View in source") [Ⓣ][1]
+
+Executes the chained sequence to extract the unwrapped value.
+
+#### Returns
+*(*)*: Returns the resolved unwrapped value.
+
+#### Example
+```js
+_([1, 2, 3]).value();
+// => [1, 2, 3]
+```
+* * *
+
+<!-- /div -->
+
+<!-- /div -->
+
+<!-- div -->
+
+## `“Collection” Methods`
+
+<!-- div -->
+
+### <a id="_atcollection-props"></a>`_.at(collection, [props])`
+<a href="#_atcollection-props">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5563 "View in source") [Ⓣ][1]
+
+Creates an array of elements corresponding to the given keys, or indexes,
+of `collection`. Keys may be specified as individual arguments or as arrays
+of keys.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[props]` *(...(number|number[]|string|string[])*: The property names or indexes of elements to pick, specified individually or in arrays.
+
+#### Returns
+*(Array)*: Returns the new array of picked elements.
+
+#### Example
+```js
+_.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
+// => ['a', 'c', 'e']
+
+_.at(['fred', 'barney', 'pebbles'], 0, 2);
+// => ['fred', 'pebbles']
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_countbycollection-iteratee_identity-thisarg"></a>`_.countBy(collection, [iteratee=_.identity], [thisArg])`
+<a href="#_countbycollection-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5656 "View in source") [Ⓣ][1]
+
+Creates an object composed of keys generated from the results of running
+each element of `collection` through `iteratee`. The corresponding value
+of each key is the number of times the key was returned by `iteratee`.
+The `iteratee` is bound to `thisArg` and invoked with three arguments;
+(value, index|key, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Object)*: Returns the composed aggregate object.
+
+#### Example
+```js
+_.countBy([4.3, 6.1, 6.4], function(n) { return Math.floor(n); });
+// => { '4': 1, '6': 2 }
+
+_.countBy([4.3, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+// => { '4': 1, '6': 2 }
+
+_.countBy(['one', 'two', 'three'], 'length');
+// => { '3': 2, '5': 1 }
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_everycollection-predicate_identity-thisarg"></a>`_.every(collection, [predicate=_.identity], [thisArg])`
+<a href="#_everycollection-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5701 "View in source") [Ⓣ][1]
+
+Checks if `predicate` returns truthy for **all** elements of `collection`.
+The predicate is bound to `thisArg` and invoked with three arguments;
+(value, index|key, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(boolean)*: Returns `true` if all elements pass the predicate check,
+else `false`.
+
+#### Example
+```js
+_.every([true, 1, null, 'yes']);
+// => false
+
+var users = [
+ { 'user': 'barney', 'age': 36 },
+ { 'user': 'fred', 'age': 40 }
+];
+
+// using the "_.property" callback shorthand
+_.every(users, 'age');
+// => true
+
+// using the "_.matches" callback shorthand
+_.every(users, { 'age': 36 });
+// => false
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_filtercollection-predicate_identity-thisarg"></a>`_.filter(collection, [predicate=_.identity], [thisArg])`
+<a href="#_filtercollection-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5749 "View in source") [Ⓣ][1]
+
+Iterates over elements of `collection`, returning an array of all elements
+`predicate` returns truthy for. The predicate is bound to `thisArg` and
+invoked with three arguments; (value, index|key, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(Array)*: Returns the new filtered array.
+
+#### Example
+```js
+var evens = _.filter([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+// => [2, 4]
+
+var users = [
+ { 'user': 'barney', 'age': 36, 'active': false },
+ { 'user': 'fred', 'age': 40, 'active': true }
+];
+
+// using the "_.property" callback shorthand
+_.pluck(_.filter(users, 'active'), 'user');
+// => ['fred']
+
+// using the "_.matches" callback shorthand
+_.pluck(_.filter(users, { 'age': 36 }), 'user');
+// => ['barney']
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_findcollection-predicate_identity-thisarg"></a>`_.find(collection, [predicate=_.identity], [thisArg])`
+<a href="#_findcollection-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5796 "View in source") [Ⓣ][1]
+
+Iterates over elements of `collection`, returning the first element
+`predicate` returns truthy for. The predicate is bound to `thisArg` and
+invoked with three arguments; (value, index|key, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to search.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(*)*: Returns the matched element, else `undefined`.
+
+#### Example
+```js
+var users = [
+ { 'user': 'barney', 'age': 36, 'active': false },
+ { 'user': 'fred', 'age': 40, 'active': true },
+ { 'user': 'pebbles', 'age': 1, 'active': false }
+];
+
+_.result(_.find(users, function(chr) { return chr.age < 40; }), 'user');
+// => 'barney'
+
+// using the "_.matches" callback shorthand
+_.result(_.find(users, { 'age': 1 }), 'user');
+// => 'pebbles'
+
+// using the "_.property" callback shorthand
+_.result(_.find(users, 'active'), 'user');
+// => 'fred'
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_findlastcollection-predicate_identity-thisarg"></a>`_.findLast(collection, [predicate=_.identity], [thisArg])`
+<a href="#_findlastcollection-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5823 "View in source") [Ⓣ][1]
+
+This method is like `_.find` except that it iterates over elements of
+`collection` from right to left.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to search.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(*)*: Returns the matched element, else `undefined`.
+
+#### Example
+```js
+_.findLast([1, 2, 3, 4], function(n) { return n % 2 == 1; });
+// => 3
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_findwherecollection-source"></a>`_.findWhere(collection, source)`
+<a href="#_findwherecollection-source">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5852 "View in source") [Ⓣ][1]
+
+Performs a deep comparison between each element in `collection` and the
+source object, returning the first element that has equivalent property
+values.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to search.
+2. `source` *(Object)*: The object of property values to match.
+
+#### Returns
+*(*)*: Returns the matched element, else `undefined`.
+
+#### Example
+```js
+var users = [
+ { 'user': 'barney', 'age': 36, 'status': 'busy' },
+ { 'user': 'fred', 'age': 40, 'status': 'busy' }
+];
+
+_.result(_.findWhere(users, { 'status': 'busy' }), 'user');
+// => 'barney'
+
+_.result(_.findWhere(users, { 'age': 40 }), 'user');
+// => 'fred'
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_foreachcollection-iteratee_identity-thisarg"></a>`_.forEach(collection, [iteratee=_.identity], [thisArg])`
+<a href="#_foreachcollection-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5882 "View in source") [Ⓣ][1]
+
+Iterates over elements of `collection` invoking `iteratee` for each element.
+The `iteratee` is bound to `thisArg` and invoked with three arguments;
+(value, index|key, collection). Iterator functions may exit iteration early
+by explicitly returning `false`.
+ *Note:** As with other "Collections" methods, objects with a `length` property
+are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+may be used for object iteration.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Array|Object|string)*: Returns `collection`.
+
+#### Example
+```js
+_([1, 2, 3]).forEach(function(n) { console.log(n); });
+// => logs each value from left to right and returns the array
+
+_.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(n, key) { console.log(n, key); });
+// => logs each value-key pair and returns the object (iteration order is not guaranteed)
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_foreachrightcollection-iteratee_identity-thisarg"></a>`_.forEachRight(collection, [iteratee=_.identity], [thisArg])`
+<a href="#_foreachrightcollection-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5905 "View in source") [Ⓣ][1]
+
+This method is like `_.forEach` except that it iterates over elements of
+`collection` from right to left.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Array|Object|string)*: Returns `collection`.
+
+#### Example
+```js
+_([1, 2, 3]).forEachRight(function(n) { console.log(n); }).join(',');
+// => logs each value from right to left and returns the array
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_groupbycollection-iteratee_identity-thisarg"></a>`_.groupBy(collection, [iteratee=_.identity], [thisArg])`
+<a href="#_groupbycollection-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5946 "View in source") [Ⓣ][1]
+
+Creates an object composed of keys generated from the results of running
+each element of `collection` through `iteratee`. The corresponding value
+of each key is an array of the elements responsible for generating the key.
+The `iteratee` is bound to `thisArg` and invoked with three arguments;
+(value, index|key, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Object)*: Returns the composed aggregate object.
+
+#### Example
+```js
+_.groupBy([4.2, 6.1, 6.4], function(n) { return Math.floor(n); });
+// => { '4': [4.2], '6': [6.1, 6.4] }
+
+_.groupBy([4.2, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+// => { '4': [4.2], '6': [6.1, 6.4] }
+
+// using the "_.property" callback shorthand
+_.groupBy(['one', 'two', 'three'], 'length');
+// => { '3': ['one', 'two'], '5': ['three'] }
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_includescollection-target-fromindex0"></a>`_.includes(collection, target, [fromIndex=0])`
+<a href="#_includescollection-target-fromindex0">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5603 "View in source") [Ⓣ][1]
+
+Checks if `value` is in `collection` using `SameValueZero` for equality
+comparisons. If `fromIndex` is negative, it is used as the offset from
+the end of `collection`.
+ *Note:** `SameValueZero` comparisons are like strict equality comparisons,
+e.g. `===`, except that `NaN` matches `NaN`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+for more details.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to search.
+2. `target` *(*)*: The value to search for.
+3. `[fromIndex=0]` *(number)*: The index to search from.
+
+#### Returns
+*(boolean)*: Returns `true` if a matching element is found, else `false`.
+
+#### Example
+```js
+_.includes([1, 2, 3], 1);
+// => true
+
+_.includes([1, 2, 3], 1, 2);
+// => false
+
+_.includes({ 'user': 'fred', 'age': 40 }, 'fred');
+// => true
+
+_.includes('pebbles', 'eb');
+// => true
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_indexbycollection-iteratee_identity-thisarg"></a>`_.indexBy(collection, [iteratee=_.identity], [thisArg])`
+<a href="#_indexbycollection-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L5993 "View in source") [Ⓣ][1]
+
+Creates an object composed of keys generated from the results of running
+each element of `collection` through `iteratee`. The corresponding value
+of each key is the last element responsible for generating the key. The
+iteratee function is bound to `thisArg` and invoked with three arguments;
+(value, index|key, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Object)*: Returns the composed aggregate object.
+
+#### Example
+```js
+var keyData = [
+ { 'dir': 'left', 'code': 97 },
+ { 'dir': 'right', 'code': 100 }
+];
+
+_.indexBy(keyData, 'dir');
+// => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+
+_.indexBy(keyData, function(object) { return String.fromCharCode(object.code); });
+// => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+
+_.indexBy(keyData, function(object) { return this.fromCharCode(object.code); }, String);
+// => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_invokecollection-methodname-args"></a>`_.invoke(collection, methodName, [args])`
+<a href="#_invokecollection-methodname-args">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6019 "View in source") [Ⓣ][1]
+
+Invokes the method named by `methodName` on each element in `collection`,
+returning an array of the results of each invoked method. Any additional
+arguments are provided to each invoked method. If `methodName` is a function
+it is invoked for, and `this` bound to, each element in `collection`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `methodName` *(Function|string)*: The name of the method to invoke or the function invoked per iteration.
+3. `[args]` *(...*)*: The arguments to invoke the method with.
+
+#### Returns
+*(Array)*: Returns the array of results.
+
+#### Example
+```js
+_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+// => [[1, 5, 7], [1, 2, 3]]
+
+_.invoke([123, 456], String.prototype.split, '');
+// => [['1', '2', '3'], ['4', '5', '6']]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_mapcollection-iteratee_identity-thisarg"></a>`_.map(collection, [iteratee=_.identity], [thisArg])`
+<a href="#_mapcollection-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6062 "View in source") [Ⓣ][1]
+
+Creates an array of values by running each element in `collection` through
+`iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
+arguments; (value, index|key, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Array)*: Returns the new mapped array.
+
+#### Example
+```js
+_.map([1, 2, 3], function(n) { return n * 3; });
+// => [3, 6, 9]
+
+_.map({ 'one': 1, 'two': 2, 'three': 3 }, function(n) { return n * 3; });
+// => [3, 6, 9] (iteration order is not guaranteed)
+
+var users = [
+ { 'user': 'barney' },
+ { 'user': 'fred' }
+];
+
+// using the "_.property" callback shorthand
+_.map(users, 'user');
+// => ['barney', 'fred']
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_maxcollection-iteratee-thisarg"></a>`_.max(collection, [iteratee], [thisArg])`
+<a href="#_maxcollection-iteratee-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6111 "View in source") [Ⓣ][1]
+
+Gets the maximum value of `collection`. If `collection` is empty or falsey
+`-Infinity` is returned. If an iteratee function is provided it is invoked
+for each value in `collection` to generate the criterion by which the value
+is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+arguments; (value, index, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(*)*: Returns the maximum value.
+
+#### Example
+```js
+_.max([4, 2, 8, 6]);
+// => 8
+
+_.max([]);
+// => -Infinity
+
+var users = [
+ { 'user': 'barney', 'age': 36 },
+ { 'user': 'fred', 'age': 40 }
+];
+
+_.max(users, function(chr) { return chr.age; });
+// => { 'user': 'fred', 'age': 40 };
+
+// using the "_.property" callback shorthand
+_.max(users, 'age');
+// => { 'user': 'fred', 'age': 40 };
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_mincollection-iteratee-thisarg"></a>`_.min(collection, [iteratee], [thisArg])`
+<a href="#_mincollection-iteratee-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6156 "View in source") [Ⓣ][1]
+
+Gets the minimum value of `collection`. If `collection` is empty or falsey
+`Infinity` is returned. If an iteratee function is provided it is invoked
+for each value in `collection` to generate the criterion by which the value
+is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+arguments; (value, index, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(*)*: Returns the minimum value.
+
+#### Example
+```js
+_.min([4, 2, 8, 6]);
+// => 2
+
+_.min([]);
+// => Infinity
+
+var users = [
+ { 'user': 'barney', 'age': 36 },
+ { 'user': 'fred', 'age': 40 }
+];
+
+_.min(users, function(chr) { return chr.age; });
+// => { 'user': 'barney', 'age': 36 };
+
+// using the "_.property" callback shorthand
+_.min(users, 'age');
+// => { 'user': 'barney', 'age': 36 };
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_partitioncollection-predicate_identity-thisarg"></a>`_.partition(collection, [predicate=_.identity], [thisArg])`
+<a href="#_partitioncollection-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6202 "View in source") [Ⓣ][1]
+
+Creates an array of elements split into two groups, the first of which
+contains elements `predicate` returns truthy for, while the second of which
+contains elements `predicate` returns falsey for. The predicate is bound
+to `thisArg` and invoked with three arguments; (value, index|key, collection).
+
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(Array)*: Returns the array of grouped elements.
+
+#### Example
+```js
+_.partition([1, 2, 3], function(n) { return n % 2; });
+// => [[1, 3], [2]]
+
+_.partition([1.2, 2.3, 3.4], function(n) { return this.floor(n) % 2; }, Math);
+// => [[1, 3], [2]]
+
+var users = [
+ { 'user': 'barney', 'age': 36, 'active': false },
+ { 'user': 'fred', 'age': 40, 'active': true },
+ { 'user': 'pebbles', 'age': 1, 'active': false }
+];
+
+// using the "_.matches" callback shorthand
+_.map(_.partition(users, { 'age': 1 }), function(array) { return _.pluck(array, 'user'); });
+// => [['pebbles'], ['barney', 'fred']]
+
+// using the "_.property" callback shorthand
+_.map(_.partition(users, 'active'), function(array) { return _.pluck(array, 'user'); });
+// => [['fred'], ['barney', 'pebbles']]
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_pluckcollection-key"></a>`_.pluck(collection, key)`
+<a href="#_pluckcollection-key">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6229 "View in source") [Ⓣ][1]
+
+Gets the value of `key` from all elements in `collection`.
#### Arguments
-1. `array` *(Array)*: The array to query.
-2. `[callback=1]` *(Function|Object|number|string)*: The function called per element or the number of elements to exclude. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `key` *(string)*: The key of the property to pluck.
#### Returns
-*(Array)*: Returns a slice of `array`.
+*(Array)*: Returns the property values.
#### Example
```js
-_.rest([1, 2, 3]);
-// => [2, 3]
-
-_.rest([1, 2, 3], 2);
-// => [3]
-
-_.rest([1, 2, 3], function(num) {
- return num < 3;
-});
-// => [3]
-
-var characters = [
- { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
- { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
- { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
+var users = [
+ { 'user': 'barney', 'age': 36 },
+ { 'user': 'fred', 'age': 40 }
];
-// using "_.pluck" callback shorthand
-_.pluck(_.rest(characters, 'blocked'), 'name');
-// => ['fred', 'pebbles']
+_.pluck(users, 'user');
+// => ['barney', 'fred']
-// using "_.where" callback shorthand
-_.rest(characters, { 'employer': 'slate' });
-// => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
+var userIndex = _.indexBy(users, 'user');
+_.pluck(userIndex, 'age');
+// => [36, 40] (iteration order is not guaranteed)
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_sortedindexarray-value-callbackidentity-thisarg"></a>`_.sortedIndex(array, value, [callback=identity], [thisArg])`
-<a href="#_sortedindexarray-value-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5270 "View in source") [Ⓣ][1]
-
-Uses a binary search to determine the smallest index at which a value should be inserted into a given sorted array in order to maintain the sort order of the array. If a callback is provided it will be executed for `value` and each element of `array` to compute their sort ranking. The callback is bound to `thisArg` and invoked with one argument; *(value)*.
-
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+### <a id="_reducecollection-iteratee_identity-accumulator-thisarg"></a>`_.reduce(collection, [iteratee=_.identity], [accumulator], [thisArg])`
+<a href="#_reducecollection-iteratee_identity-accumulator-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6261 "View in source") [Ⓣ][1]
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Reduces `collection` to a value which is the accumulated result of running
+each element in `collection` through `iteratee`, where each successive
+invocation is supplied the return value of the previous. If `accumulator`
+is not provided the first element of `collection` is used as the initial
+value. The `iteratee` is bound to `thisArg`and invoked with four arguments;
+(accumulator, value, index|key, collection).
#### Arguments
-1. `array` *(Array)*: The array to inspect.
-2. `value` *(*)*: The value to evaluate.
-3. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[accumulator]` *(*)*: The initial value.
+4. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
#### Returns
-*(number)*: Returns the index at which `value` should be inserted into `array`.
+*(*)*: Returns the accumulated value.
#### Example
```js
-_.sortedIndex([20, 30, 50], 40);
-// => 2
-
-// using "_.pluck" callback shorthand
-_.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
-// => 2
-
-var dict = {
- 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
-};
-
-_.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
- return dict.wordToNumber[word];
-});
-// => 2
+var sum = _.reduce([1, 2, 3], function(sum, n) { return sum + n; });
+// => 6
-_.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
- return this.wordToNumber[word];
-}, dict);
-// => 2
+var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ result[key] = n * 3;
+ return result;
+}, {});
+// => { 'a': 3, 'b': 6, 'c': 9 } (iteration order is not guaranteed)
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_unionarray"></a>`_.union([array])`
-<a href="#_unionarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5301 "View in source") [Ⓣ][1]
+### <a id="_reducerightcollection-iteratee_identity-accumulator-thisarg"></a>`_.reduceRight(collection, [iteratee=_.identity], [accumulator], [thisArg])`
+<a href="#_reducerightcollection-iteratee_identity-accumulator-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6285 "View in source") [Ⓣ][1]
-Creates an array of unique values, in order, of the provided arrays using strict equality for comparisons, i.e. `===`.
+This method is like `_.reduce` except that it iterates over elements of
+`collection` from right to left.
#### Arguments
-1. `[array]` *(...Array)*: The arrays to inspect.
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[accumulator]` *(*)*: The initial value.
+4. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
#### Returns
-*(Array)*: Returns an array of combined values.
+*(*)*: Returns the accumulated value.
#### Example
```js
-_.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
-// => [1, 2, 3, 5, 4]
+var array = [[0, 1], [2, 3], [4, 5]];
+_.reduceRight(array, function(flattened, other) { return flattened.concat(other); }, []);
+// => [4, 5, 2, 3, 0, 1]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_uniqarray-issortedfalse-callbackidentity-thisarg"></a>`_.uniq(array, [isSorted=false], [callback=identity], [thisArg])`
-<a href="#_uniqarray-issortedfalse-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5349 "View in source") [Ⓣ][1]
+### <a id="_rejectcollection-predicate_identity-thisarg"></a>`_.reject(collection, [predicate=_.identity], [thisArg])`
+<a href="#_rejectcollection-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6328 "View in source") [Ⓣ][1]
-Creates a duplicate-value-free version of an array using strict equality for comparisons, i.e. `===`. If the array is sorted, providing `true` for `isSorted` will use a faster algorithm. If a callback is provided each element of `array` is passed through the callback before uniqueness is computed. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, array)*.
+The opposite of `_.filter`; this method returns the elements of `collection`
+that `predicate` does **not** return truthy for.
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
-
-#### Aliases
-*_.unique*
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
#### Arguments
-1. `array` *(Array)*: The array to process.
-2. `[isSorted=false]` *(boolean)*: A flag to indicate that `array` is sorted.
-3. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(Array)*: Returns a duplicate-value-free array.
+*(Array)*: Returns the new filtered array.
#### Example
```js
-_.uniq([1, 2, 1, 3, 1]);
-// => [1, 2, 3]
+var odds = _.reject([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+// => [1, 3]
-_.uniq([1, 1, 2, 2, 3], true);
-// => [1, 2, 3]
-
-_.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
-// => ['A', 'b', 'C']
+var users = [
+ { 'user': 'barney', 'age': 36, 'active': false },
+ { 'user': 'fred', 'age': 40, 'active': true }
+];
-_.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
-// => [1, 2.5, 3]
+// using the "_.property" callback shorthand
+_.pluck(_.reject(users, 'active'), 'user');
+// => ['barney']
-// using "_.pluck" callback shorthand
-_.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
-// => [{ 'x': 1 }, { 'x': 2 }]
+// using the "_.matches" callback shorthand
+_.pluck(_.reject(users, { 'age': 36 }), 'user');
+// => ['fred']
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_withoutarray-value"></a>`_.without(array, [value])`
-<a href="#_withoutarray-value">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5377 "View in source") [Ⓣ][1]
+### <a id="_samplecollection-n"></a>`_.sample(collection, [n])`
+<a href="#_samplecollection-n">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6354 "View in source") [Ⓣ][1]
-Creates an array excluding all provided values using strict equality for comparisons, i.e. `===`.
+Gets a random element or `n` random elements from a collection.
#### Arguments
-1. `array` *(Array)*: The array to filter.
-2. `[value]` *(...*)*: The values to exclude.
+1. `collection` *(Array|Object|string)*: The collection to sample.
+2. `[n]` *(number)*: The number of elements to sample.
#### Returns
-*(Array)*: Returns a new array of filtered values.
+*(*)*: Returns the random sample(s).
#### Example
```js
-_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
-// => [2, 3, 4]
-```
+_.sample([1, 2, 3, 4]);
+// => 2
+_.sample([1, 2, 3, 4], 2);
+// => [3, 1]
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_xorarray"></a>`_.xor([array])`
-<a href="#_xorarray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5398 "View in source") [Ⓣ][1]
+### <a id="_shufflecollection"></a>`_.shuffle(collection)`
+<a href="#_shufflecollection">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6380 "View in source") [Ⓣ][1]
-Creates an array that is the symmetric difference of the provided arrays. See http://en.wikipedia.org/wiki/Symmetric_difference.
+Creates an array of shuffled values, using a version of the Fisher-Yates
+shuffle. See [Wikipedia](http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)
+for more details.
#### Arguments
-1. `[array]` *(...Array)*: The arrays to inspect.
+1. `collection` *(Array|Object|string)*: The collection to shuffle.
#### Returns
-*(Array)*: Returns an array of values.
+*(Array)*: Returns the new shuffled array.
#### Example
```js
-_.xor([1, 2, 3], [5, 2, 1, 4]);
-// => [3, 5, 4]
-
-_.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
-// => [1, 4, 5]
+_.shuffle([1, 2, 3, 4]);
+// => [4, 1, 3, 2]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_ziparray"></a>`_.zip([array])`
-<a href="#_ziparray">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5429 "View in source") [Ⓣ][1]
-
-Creates an array of grouped elements, the first of which contains the first elements of the given arrays, the second of which contains the second elements of the given arrays, and so on.
+### <a id="_sizecollection"></a>`_.size(collection)`
+<a href="#_sizecollection">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6417 "View in source") [Ⓣ][1]
-#### Aliases
-*_.unzip*
+Gets the size of `collection` by returning `collection.length` for
+array-like values or the number of own enumerable properties for objects.
#### Arguments
-1. `[array]` *(...Array)*: Arrays to process.
+1. `collection` *(Array|Object|string)*: The collection to inspect.
#### Returns
-*(Array)*: Returns a new array of grouped elements.
+*(number)*: Returns the size of `collection`.
#### Example
```js
-_.zip(['fred', 'barney'], [30, 40], [true, false]);
-// => [['fred', 30, true], ['barney', 40, false]]
-```
+_.size([1, 2]);
+// => 2
+
+_.size({ 'one': 1, 'two': 2, 'three': 3 });
+// => 3
+_.size('pebbles');
+// => 7
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_zipobjectkeys-values"></a>`_.zipObject(keys, [values=[]])`
-<a href="#_zipobjectkeys-values">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5459 "View in source") [Ⓣ][1]
+### <a id="_somecollection-predicate_identity-thisarg"></a>`_.some(collection, [predicate=_.identity], [thisArg])`
+<a href="#_somecollection-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6464 "View in source") [Ⓣ][1]
-Creates an object composed from arrays of `keys` and `values`. Provide either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]` or two arrays, one of `keys` and one of corresponding `values`.
+Checks if `predicate` returns truthy for **any** element of `collection`.
+The function returns as soon as it finds a passing value and does not iterate
+over the entire collection. The predicate is bound to `thisArg` and invoked
+with three arguments; (value, index|key, collection).
-#### Aliases
-*_.object*
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
#### Arguments
-1. `keys` *(Array)*: The array of keys.
-2. `[values=[]]` *(Array)*: The array of values.
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(Object)*: Returns an object composed of the given keys and corresponding values.
+*(boolean)*: Returns `true` if any element passes the predicate check,
+else `false`.
#### Example
```js
-_.zipObject(['fred', 'barney'], [30, 40]);
-// => { 'fred': 30, 'barney': 40 }
-```
+_.some([null, 0, 'yes', false], Boolean);
+// => true
+
+var users = [
+ { 'user': 'barney', 'age': 36, 'active': false },
+ { 'user': 'fred', 'age': 40, 'active': true }
+];
+
+// using the "_.property" callback shorthand
+_.some(users, 'active');
+// => true
+// using the "_.matches" callback shorthand
+_.some(users, { 'age': 1 });
+// => false
+```
* * *
<!-- /div -->
+<!-- div -->
-<!-- /div -->
+### <a id="_sortbycollection-iteratee_identity-thisarg"></a>`_.sortBy(collection, [iteratee=_.identity], [thisArg])`
+<a href="#_sortbycollection-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6513 "View in source") [Ⓣ][1]
+Creates an array of elements, sorted in ascending order by the results of
+running each element in a collection through `iteratee`. This method performs
+a stable sort, that is, it preserves the original sort order of equal elements.
+The `iteratee` is bound to `thisArg` and invoked with three arguments;
+(value, index|key, collection).
-<!-- div -->
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
-## `“Chaining” Methods`
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
-<!-- div -->
+#### Arguments
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `[iteratee=_.identity]` *(Array|Function|Object|string)*: The function invoked per iteration. If a property name or an object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Array)*: Returns the new sorted array.
-### <a id="_value"></a>`_(value)`
-<a href="#_value">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L647 "View in source") [Ⓣ][1]
+#### Example
+```js
+_.sortBy([1, 2, 3], function(n) { return Math.sin(n); });
+// => [3, 1, 2]
-Creates a `lodash` object which wraps the given value to enable intuitive method chaining.
+_.sortBy([1, 2, 3], function(n) { return this.sin(n); }, Math);
+// => [3, 1, 2]
-In addition to Lo-Dash methods, wrappers also have the following `Array` methods:<br>
-`concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`, and `unshift`
+var users = [
+ { 'user': 'fred' },
+ { 'user': 'pebbles' },
+ { 'user': 'barney' }
+];
-Chaining is supported in custom builds as long as the `value` method is implicitly or explicitly included in the build.
+// using the "_.property" callback shorthand
+_.pluck(_.sortBy(users, 'user'), 'user');
+// => ['barney', 'fred', 'pebbles']
+```
+* * *
-The chainable wrapper functions are:<br>
-`after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `partialRight`, `pick`, ` [...]
+<!-- /div -->
-The non-chainable wrapper functions are:<br>
-`clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`, `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `result`, `shift`, `size [...]
+<!-- div -->
-The wrapper functions `first` and `last` return wrapped values when `n` is provided, otherwise they return unwrapped values.
+### <a id="_sortbyallcollection-props"></a>`_.sortByAll(collection, props)`
+<a href="#_sortbyallcollection-props">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6551 "View in source") [Ⓣ][1]
-Explicit chaining can be enabled by using the `_.chain` method.
+This method is like `_.sortBy` except that it sorts by property names
+instead of an iteratee function.
#### Arguments
-1. `value` *(*)*: The value to wrap in a `lodash` instance.
+1. `collection` *(Array|Object|string)*: The collection to iterate over.
+2. `props` *(...(string|string[])*: The property names to sort by, specified as individual property names or arrays of property names.
#### Returns
-*(Object)*: Returns a `lodash` instance.
+*(Array)*: Returns the new sorted array.
#### Example
```js
-var wrapped = _([1, 2, 3]);
-
-// returns an unwrapped value
-wrapped.reduce(function(sum, num) {
- return sum + num;
-});
-// => 6
-
-// returns a wrapped value
-var squares = wrapped.map(function(num) {
- return num * num;
-});
-
-_.isArray(squares);
-// => false
+var users = [
+ { 'user': 'barney', 'age': 36 },
+ { 'user': 'fred', 'age': 40 },
+ { 'user': 'barney', 'age': 26 },
+ { 'user': 'fred', 'age': 30 }
+];
-_.isArray(squares.value());
-// => true
+_.map(_.sortByAll(users, ['user', 'age']), _.values);
+// => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_chainvalue"></a>`_.chain(value)`
-<a href="#_chainvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6788 "View in source") [Ⓣ][1]
+### <a id="_wherecollection-source"></a>`_.where(collection, source)`
+<a href="#_wherecollection-source">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6600 "View in source") [Ⓣ][1]
-Creates a `lodash` object that wraps the given value with explicit method chaining enabled.
+Performs a deep comparison between each element in `collection` and the
+source object, returning an array of all elements that have equivalent
+property values.
#### Arguments
-1. `value` *(*)*: The value to wrap.
+1. `collection` *(Array|Object|string)*: The collection to search.
+2. `source` *(Object)*: The object of property values to match.
#### Returns
-*(Object)*: Returns the wrapper object.
+*(Array)*: Returns the new filtered array.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 },
- { 'name': 'pebbles', 'age': 1 }
+var users = [
+ { 'user': 'barney', 'age': 36, 'status': 'busy', 'pets': ['hoppy'] },
+ { 'user': 'fred', 'age': 40, 'status': 'busy', 'pets': ['baby puss', 'dino'] }
];
-var youngest = _.chain(characters)
- .sortBy('age')
- .map(function(chr) { return chr.name + ' is ' + chr.age; })
- .first()
- .value();
-// => 'pebbles is 1'
-```
+_.pluck(_.where(users, { 'age': 36 }), 'user');
+// => ['barney']
+_.pluck(_.where(users, { 'pets': ['dino'] }), 'user');
+// => ['fred']
+
+_.pluck(_.where(users, { 'status': 'busy' }), 'user');
+// => ['barney', 'fred']
+```
* * *
<!-- /div -->
+<!-- /div -->
<!-- div -->
-### <a id="_tapvalue-interceptor"></a>`_.tap(value, interceptor)`
-<a href="#_tapvalue-interceptor">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6814 "View in source") [Ⓣ][1]
+## `“Date” Methods`
-Invokes `interceptor` with the `value` as the first argument and then returns `value`. The purpose of this method is to "tap into" a method chain in order to perform operations on intermediate results within the chain.
+<!-- div -->
-#### Arguments
-1. `value` *(*)*: The value to provide to `interceptor`.
-2. `interceptor` *(Function)*: The function to invoke.
+### <a id="_now"></a>`_.now`
+<a href="#_now">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6618 "View in source") [Ⓣ][1]
-#### Returns
-*(*)*: Returns `value`.
+Gets the number of milliseconds that have elapsed since the Unix epoch
+(1 January 1970 00:00:00 UTC).
#### Example
```js
-_([1, 2, 3, 4])
- .tap(function(array) { array.pop(); })
- .reverse()
- .value();
-// => [3, 2, 1]
+_.defer(function(stamp) { console.log(_.now() - stamp); }, _.now());
+// => logs the number of milliseconds it took for the deferred function to be invoked
```
-
* * *
<!-- /div -->
+<!-- /div -->
<!-- div -->
-### <a id="_prototypechain"></a>`_.prototype.chain()`
-<a href="#_prototypechain">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6844 "View in source") [Ⓣ][1]
+## `“Function” Methods`
-Enables explicit method chaining on the wrapper object.
+<!-- div -->
+
+### <a id="_aftern-func"></a>`_.after(n, func)`
+<a href="#_aftern-func">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6647 "View in source") [Ⓣ][1]
+
+The opposite of `_.before`; this method creates a function that invokes
+`func` once it is called `n` or more times.
+
+#### Arguments
+1. `n` *(number)*: The number of calls before `func` is invoked.
+2. `func` *(Function)*: The function to restrict.
#### Returns
-*(*)*: Returns the wrapper object.
+*(Function)*: Returns the new restricted function.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
-];
+var saves = ['profile', 'settings'];
-// without explicit chaining
-_(characters).first();
-// => { 'name': 'barney', 'age': 36 }
+var done = _.after(saves.length, function() {
+ console.log('done saving!');
+});
-// with explicit chaining
-_(characters).chain()
- .first()
- .pick('age')
- .value();
-// => { 'age': 36 }
+_.forEach(saves, function(type) {
+ asyncSave({ 'type': type, 'complete': done });
+});
+// => logs 'done saving!' after the two async saves have completed
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_prototypetostring"></a>`_.prototype.toString()`
-<a href="#_prototypetostring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6861 "View in source") [Ⓣ][1]
+### <a id="_aryfunc"></a>`_.ary(func)`
+<a href="#_aryfunc">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6681 "View in source") [Ⓣ][1]
+
+Creates a function that accepts up to `n` arguments ignoring any
+additional arguments.
-Produces the `toString` result of the wrapped value.
+#### Arguments
+1. `func` *(Function)*: The function to cap arguments for.
+2. `[n=func.length]` *(number)*: The arity cap.
#### Returns
-*(string)*: Returns the string result.
+*(Function)*: Returns the new function.
#### Example
```js
-_([1, 2, 3]).toString();
-// => '1,2,3'
+_.map(['6', '8', '10'], _.ary(parseInt, 1));
+// => [6, 8, 10]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_prototypevalueof"></a>`_.prototype.valueOf()`
-<a href="#_prototypevalueof">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6878 "View in source") [Ⓣ][1]
+### <a id="_beforen-func"></a>`_.before(n, func)`
+<a href="#_beforen-func">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6705 "View in source") [Ⓣ][1]
-Extracts the wrapped value.
+Creates a function that invokes `func`, with the `this` binding and arguments
+of the created function, while it is called less than `n` times. Subsequent
+calls to the created function return the result of the last `func` invocation.
-#### Aliases
-*_.prototype.value*
+#### Arguments
+1. `n` *(number)*: The number of calls at which `func` is no longer invoked.
+2. `func` *(Function)*: The function to restrict.
#### Returns
-*(*)*: Returns the wrapped value.
+*(Function)*: Returns the new restricted function.
#### Example
```js
-_([1, 2, 3]).valueOf();
-// => [1, 2, 3]
+jQuery('#add').on('click', _.before(5, addContactToList));
+// => allows adding up to 4 contacts to the list
```
-
* * *
<!-- /div -->
+<!-- div -->
-<!-- /div -->
+### <a id="_bindfunc-thisarg-args"></a>`_.bind(func, thisArg, [args])`
+<a href="#_bindfunc-thisarg-args">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6761 "View in source") [Ⓣ][1]
+Creates a function that invokes `func` with the `this` binding of `thisArg`
+and prepends any additional `_.bind` arguments to those provided to the
+bound function.
-<!-- div -->
+The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+may be used as a placeholder for partially applied arguments.
+ *Note:** Unlike native `Function#bind` this method does not set the `length`
+property of bound functions.
+
+#### Arguments
+1. `func` *(Function)*: The function to bind.
+2. `thisArg` *(*)*: The `this` binding of `func`.
+3. `[args]` *(...*)*: The arguments to be partially applied.
+
+#### Returns
+*(Function)*: Returns the new bound function.
+
+#### Example
+```js
+var greet = function(greeting, punctuation) {
+ return greeting + ' ' + this.user + punctuation;
+};
+
+var object = { 'user': 'fred' };
+
+var bound = _.bind(greet, object, 'hi');
+bound('!');
+// => 'hi fred!'
+
+// using placeholders
+var bound = _.bind(greet, object, _, '!');
+bound('hi');
+// => 'hi fred!'
+```
+* * *
-## `“Collections” Methods`
+<!-- /div -->
<!-- div -->
-### <a id="_atcollection-index"></a>`_.at(collection, [index])`
-<a href="#_atcollection-index">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3296 "View in source") [Ⓣ][1]
+### <a id="_bindallobject-methodnames"></a>`_.bindAll(object, [methodNames])`
+<a href="#_bindallobject-methodnames">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6798 "View in source") [Ⓣ][1]
-Creates an array of elements from the specified indexes, or keys, of the `collection`. Indexes may be specified as individual arguments or as arrays of indexes.
+Binds methods of an object to the object itself, overwriting the existing
+method. Method names may be specified as individual arguments or as arrays
+of method names. If no method names are provided all enumerable function
+properties, own and inherited, of `object` are bound.
+ *Note:** This method does not set the `length` property of bound functions.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[index]` *(...(number|number[]|string|string[])*: The indexes of `collection` to retrieve, specified as individual indexes or arrays of indexes.
+1. `object` *(Object)*: The object to bind and assign the bound methods to.
+2. `[methodNames]` *(...(string|string[])*: The object method names to bind, specified as individual method names or arrays of method names.
#### Returns
-*(Array)*: Returns a new array of elements corresponding to the provided indexes.
+*(Object)*: Returns `object`.
#### Example
```js
-_.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
-// => ['a', 'c', 'e']
+var view = {
+ 'label': 'docs',
+ 'onClick': function() { console.log('clicked ' + this.label); }
+};
-_.at(['fred', 'barney', 'pebbles'], 0, 2);
-// => ['fred', 'pebbles']
+_.bindAll(view);
+jQuery('#docs').on('click', view.onClick);
+// => logs 'clicked docs' when the element is clicked
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_containscollection-target-fromindex0"></a>`_.contains(collection, target, [fromIndex=0])`
-<a href="#_containscollection-target-fromindex0">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3339 "View in source") [Ⓣ][1]
+### <a id="_bindkeyobject-key-args"></a>`_.bindKey(object, key, [args])`
+<a href="#_bindkeyobject-key-args">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6850 "View in source") [Ⓣ][1]
+
+Creates a function that invokes the method at `object[key]` and prepends
+any additional `_.bindKey` arguments to those provided to the bound function.
-Checks if a given value is present in a collection using strict equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the offset from the end of the collection.
+This method differs from `_.bind` by allowing bound functions to reference
+methods that may be redefined or don't yet exist.
+See [Peter Michaux's article](http://michaux.ca/articles/lazy-function-definition-pattern)
+for more details.
-#### Aliases
-*_.include*
+The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+builds, may be used as a placeholder for partially applied arguments.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `target` *(*)*: The value to check for.
-3. `[fromIndex=0]` *(number)*: The index to search from.
+1. `object` *(Object)*: The object the method belongs to.
+2. `key` *(string)*: The key of the method.
+3. `[args]` *(...*)*: The arguments to be partially applied.
#### Returns
-*(boolean)*: Returns `true` if the `target` element is found, else `false`.
+*(Function)*: Returns the new bound function.
#### Example
```js
-_.contains([1, 2, 3], 1);
-// => true
+var object = {
+ 'user': 'fred',
+ 'greet': function(greeting, punctuation) {
+ return greeting + ' ' + this.user + punctuation;
+ }
+};
-_.contains([1, 2, 3], 1, 2);
-// => false
+var bound = _.bindKey(object, 'greet', 'hi');
+bound('!');
+// => 'hi fred!'
-_.contains({ 'name': 'fred', 'age': 40 }, 'fred');
-// => true
+object.greet = function(greeting, punctuation) {
+ return greeting + 'ya ' + this.user + punctuation;
+};
-_.contains('pebbles', 'eb');
-// => true
-```
+bound('!');
+// => 'hiya fred!'
+// using placeholders
+var bound = _.bindKey(object, 'greet', _, '!');
+bound('hi');
+// => 'hiya fred!'
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_countbycollection-callbackidentity-thisarg"></a>`_.countBy(collection, [callback=identity], [thisArg])`
-<a href="#_countbycollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3394 "View in source") [Ⓣ][1]
-
-Creates an object composed of keys generated from the results of running each element of `collection` through the callback. The corresponding value of each key is the number of times the key was returned by the callback. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
+### <a id="_curryfunc"></a>`_.curry(func)`
+<a href="#_curryfunc">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6901 "View in source") [Ⓣ][1]
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+Creates a function that accepts one or more arguments of `func` that when
+called either invokes `func` returning its result, if all `func` arguments
+have been provided, or returns a function that accepts one or more of the
+remaining `func` arguments, and so on. The arity of `func` may be specified
+if `func.length` is not sufficient.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+may be used as a placeholder for provided arguments.
+ *Note:** This method does not set the `length` property of curried functions.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to curry.
+2. `[arity=func.length]` *(number)*: The arity of `func`.
#### Returns
-*(Object)*: Returns the composed aggregate object.
+*(Function)*: Returns the new curried function.
#### Example
```js
-_.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
-// => { '4': 1, '6': 2 }
+var abc = function(a, b, c) {
+ return [a, b, c];
+};
+
+var curried = _.curry(abc);
+
+curried(1)(2)(3);
+// => [1, 2, 3]
-_.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-// => { '4': 1, '6': 2 }
+curried(1, 2)(3);
+// => [1, 2, 3]
-_.countBy(['one', 'two', 'three'], 'length');
-// => { '3': 2, '5': 1 }
-```
+curried(1, 2, 3);
+// => [1, 2, 3]
+// using placeholders
+curried(1)(_, 3)(2);
+// => [1, 2, 3]
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_everycollection-callbackidentity-thisarg"></a>`_.every(collection, [callback=identity], [thisArg])`
-<a href="#_everycollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3439 "View in source") [Ⓣ][1]
+### <a id="_curryrightfunc"></a>`_.curryRight(func)`
+<a href="#_curryrightfunc">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L6947 "View in source") [Ⓣ][1]
-Checks if the given callback returns truey value for **all** elements of a collection. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
+This method is like `_.curry` except that arguments are applied to `func`
+in the manner of `_.partialRight` instead of `_.partial`.
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
-
-#### Aliases
-*_.all*
+The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+builds, may be used as a placeholder for provided arguments.
+ *Note:** This method does not set the `length` property of curried functions.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to curry.
+2. `[arity=func.length]` *(number)*: The arity of `func`.
#### Returns
-*(boolean)*: Returns `true` if all elements passed the callback check, else `false`.
+*(Function)*: Returns the new curried function.
#### Example
```js
-_.every([true, 1, null, 'yes']);
-// => false
+var abc = function(a, b, c) {
+ return [a, b, c];
+};
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
-];
+var curried = _.curryRight(abc);
-// using "_.pluck" callback shorthand
-_.every(characters, 'age');
-// => true
+curried(3)(2)(1);
+// => [1, 2, 3]
-// using "_.where" callback shorthand
-_.every(characters, { 'age': 36 });
-// => false
-```
+curried(2, 3)(1);
+// => [1, 2, 3]
+
+curried(1, 2, 3);
+// => [1, 2, 3]
+// using placeholders
+curried(3)(1, _)(2);
+// => [1, 2, 3]
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_filtercollection-callbackidentity-thisarg"></a>`_.filter(collection, [callback=identity], [thisArg])`
-<a href="#_filtercollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3500 "View in source") [Ⓣ][1]
+### <a id="_debouncefunc-wait-options-optionsleadingfalse-optionsmaxwait-optionstrailingtrue"></a>`_.debounce(func, wait, [options], [options.leading=false], [options.maxWait], [options.trailing=true])`
+<a href="#_debouncefunc-wait-options-optionsleadingfalse-optionsmaxwait-optionstrailingtrue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7018 "View in source") [Ⓣ][1]
-Iterates over elements of a collection, returning an array of all elements the callback returns truey for. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
+Creates a function that delays invoking `func` until after `wait` milliseconds
+have elapsed since the last time it was invoked. The created function comes
+with a `cancel` method to cancel delayed invocations. Provide an options
+object to indicate that `func` should be invoked on the leading and/or
+trailing edge of the `wait` timeout. Subsequent calls to the debounced
+function return the result of the last `func` invocation.
+ *Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+on the trailing edge of the timeout only if the the debounced function is
+invoked more than once during the `wait` timeout.
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
-
-#### Aliases
-*_.select*
+See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+for details over the differences between `_.debounce` and `_.throttle`.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to debounce.
+2. `wait` *(number)*: The number of milliseconds to delay.
+3. `[options]` *(Object)*: The options object.
+4. `[options.leading=false]` *(boolean)*: Specify invoking on the leading edge of the timeout.
+5. `[options.maxWait]` *(number)*: The maximum time `func` is allowed to be delayed before it is invoked.
+6. `[options.trailing=true]` *(boolean)*: Specify invoking on the trailing edge of the timeout.
#### Returns
-*(Array)*: Returns a new array of elements that passed the callback check.
+*(Function)*: Returns the new debounced function.
#### Example
```js
-var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-// => [2, 4, 6]
+// avoid costly calculations while the window size is in flux
+jQuery(window).on('resize', _.debounce(calculateLayout, 150));
-var characters = [
- { 'name': 'barney', 'age': 36, 'blocked': false },
- { 'name': 'fred', 'age': 40, 'blocked': true }
-];
+// invoke `sendMail` when the click event is fired, debouncing subsequent calls
+jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+ 'leading': true,
+ 'trailing': false
+}));
-// using "_.pluck" callback shorthand
-_.filter(characters, 'blocked');
-// => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
+// ensure `batchLog` is invoked once after 1 second of debounced calls
+var source = new EventSource('/stream');
+jQuery(source).on('message', _.debounce(batchLog, 250, {
+ 'maxWait': 1000
+}));
-// using "_.where" callback shorthand
-_.filter(characters, { 'age': 36 });
-// => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
-```
+// cancel a debounced call
+var todoChanges = _.debounce(batchLog, 1000);
+Object.observe(models.todo, todoChanges);
+Object.observe(models, function(changes) {
+ if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
+ todoChanges.cancel();
+ }
+}, ['delete']);
+
+// ...at some point `models.todo` is changed
+models.todo.completed = true;
+
+// ...before 1 second has passed `models.todo` is deleted
+// which cancels the debounced `todoChanges` call
+delete models.todo;
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_findcollection-callbackidentity-thisarg"></a>`_.find(collection, [callback=identity], [thisArg])`
-<a href="#_findcollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3567 "View in source") [Ⓣ][1]
-
-Iterates over elements of a collection, returning the first element that the callback returns truey for. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
-
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+### <a id="_deferfunc-args"></a>`_.defer(func, [args])`
+<a href="#_deferfunc-args">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7147 "View in source") [Ⓣ][1]
-#### Aliases
-*_.detect, _.findWhere*
+Defers invoking the `func` until the current call stack has cleared. Any
+additional arguments are provided to `func` when it is invoked.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to defer.
+2. `[args]` *(...*)*: The arguments to invoke the function with.
#### Returns
-*(*)*: Returns the found element, else `undefined`.
+*(number)*: Returns the timer id.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36, 'blocked': false },
- { 'name': 'fred', 'age': 40, 'blocked': true },
- { 'name': 'pebbles', 'age': 1, 'blocked': false }
-];
-
-_.find(characters, function(chr) {
- return chr.age < 40;
-});
-// => { 'name': 'barney', 'age': 36, 'blocked': false }
-
-// using "_.where" callback shorthand
-_.find(characters, { 'age': 1 });
-// => { 'name': 'pebbles', 'age': 1, 'blocked': false }
-
-// using "_.pluck" callback shorthand
-_.find(characters, 'blocked');
-// => { 'name': 'fred', 'age': 40, 'blocked': true }
+_.defer(function(text) { console.log(text); }, 'deferred');
+// logs 'deferred' after one or more milliseconds
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_findlastcollection-callbackidentity-thisarg"></a>`_.findLast(collection, [callback=identity], [thisArg])`
-<a href="#_findlastcollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3612 "View in source") [Ⓣ][1]
+### <a id="_delayfunc-wait-args"></a>`_.delay(func, wait, [args])`
+<a href="#_delayfunc-wait-args">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7167 "View in source") [Ⓣ][1]
-This method is like `_.find` except that it iterates over elements of a `collection` from right to left.
+Invokes `func` after `wait` milliseconds. Any additional arguments are
+provided to `func` when it is invoked.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to delay.
+2. `wait` *(number)*: The number of milliseconds to delay invocation.
+3. `[args]` *(...*)*: The arguments to invoke the function with.
#### Returns
-*(*)*: Returns the found element, else `undefined`.
+*(number)*: Returns the timer id.
#### Example
```js
-_.findLast([1, 2, 3, 4], function(num) {
- return num % 2 == 1;
-});
-// => 3
+_.delay(function(text) { console.log(text); }, 1000, 'later');
+// => logs 'later' after one second
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_foreachcollection-callbackidentity-thisarg"></a>`_.forEach(collection, [callback=identity], [thisArg])`
-<a href="#_foreachcollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3650 "View in source") [Ⓣ][1]
-
-Iterates over elements of a collection, executing the callback for each element. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*. Callbacks may exit iteration early by explicitly returning `false`.
+### <a id="_flowfuncs"></a>`_.flow([funcs])`
+<a href="#_flowfuncs">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7195 "View in source") [Ⓣ][1]
-Note: As with other "Collections" methods, objects with a `length` property are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` may be used for object iteration.
-
-#### Aliases
-*_.each*
+Creates a function that returns the result of invoking the provided
+functions with the `this` binding of the created function, where each
+successive invocation is supplied the return value of the previous.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[funcs]` *(...Function)*: Functions to invoke.
#### Returns
-*(Array, Object, string)*: Returns `collection`.
+*(Function)*: Returns the new function.
#### Example
```js
-_([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
-// => logs each number and returns '1,2,3'
+function add(x, y) {
+ return x + y;
+}
-_.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
-// => logs each number and returns the object (property order is not guaranteed across environments)
-```
+function square(n) {
+ return n * n;
+}
+var addSquare = _.flow(add, square);
+addSquare(1, 2);
+// => 9
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_foreachrightcollection-callbackidentity-thisarg"></a>`_.forEachRight(collection, [callback=identity], [thisArg])`
-<a href="#_foreachrightcollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3683 "View in source") [Ⓣ][1]
-
-This method is like `_.forEach` except that it iterates over elements of a `collection` from right to left.
+### <a id="_flowrightfuncs"></a>`_.flowRight([funcs])`
+<a href="#_flowrightfuncs">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7240 "View in source") [Ⓣ][1]
-#### Aliases
-*_.eachRight*
+This method is like `_.flow` except that it creates a function that
+invokes the provided functions from right to left.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[funcs]` *(...Function)*: Functions to invoke.
#### Returns
-*(Array, Object, string)*: Returns `collection`.
+*(Function)*: Returns the new function.
#### Example
```js
-_([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
-// => logs each number from right to left and returns '3,2,1'
-```
+function add(x, y) {
+ return x + y;
+}
+
+function square(n) {
+ return n * n;
+}
+var addSquare = _.flowRight(square, add);
+addSquare(1, 2);
+// => 9
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_groupbycollection-callbackidentity-thisarg"></a>`_.groupBy(collection, [callback=identity], [thisArg])`
-<a href="#_groupbycollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3744 "View in source") [Ⓣ][1]
-
-Creates an object composed of keys generated from the results of running each element of a collection through the callback. The corresponding value of each key is an array of the elements responsible for generating the key. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
-
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`
+### <a id="_memoizefunc-resolver"></a>`_.memoize(func, [resolver])`
+<a href="#_memoizefunc-resolver">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7314 "View in source") [Ⓣ][1]
+
+Creates a function that memoizes the result of `func`. If `resolver` is
+provided it determines the cache key for storing the result based on the
+arguments provided to the memoized function. By default, the first argument
+provided to the memoized function is coerced to a string and used as the
+cache key. The `func` is invoked with the `this` binding of the memoized
+function.
+ *Note:** The cache is exposed as the `cache` property on the memoized
+function. Its creation may be customized by replacing the `_.memoize.Cache`
+constructor with one whose instances implement the ES6 `Map` method interface
+of `get`, `has`, and `set`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object)
+for more details.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to have its output memoized.
+2. `[resolver]` *(Function)*: The function to resolve the cache key.
#### Returns
-*(Object)*: Returns the composed aggregate object.
+*(Function)*: Returns the new memoizing function.
#### Example
```js
-_.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
-// => { '4': [4.2], '6': [6.1, 6.4] }
+var upperCase = _.memoize(function(string) {
+ return string.toUpperCase();
+});
-_.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
-// => { '4': [4.2], '6': [6.1, 6.4] }
+upperCase('fred');
+// => 'FRED'
-// using "_.pluck" callback shorthand
-_.groupBy(['one', 'two', 'three'], 'length');
-// => { '3': ['one', 'two'], '5': ['three'] }
+// modifying the result cache
+upperCase.cache.set('fred, 'BARNEY');
+upperCase('fred');
+// => 'BARNEY'
+
+// replacing `_.memoize.Cache`
+var object = { 'user': 'fred' };
+var other = { 'user': 'barney' };
+var identity = _.memoize(_.identity);
+
+identity(object);
+// => { 'user': 'fred' }
+identity(other);
+// => { 'user': 'fred' }
+
+_.memoize.Cache = WeakMap;
+var identity = _.memoize(_.identity);
+
+identity(object);
+// => { 'user': 'fred' }
+identity(other);
+// => { 'user': 'barney' }
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_indexbycollection-callbackidentity-thisarg"></a>`_.indexBy(collection, [callback=identity], [thisArg])`
-<a href="#_indexbycollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3787 "View in source") [Ⓣ][1]
-
-Creates an object composed of keys generated from the results of running each element of the collection through the given callback. The corresponding value of each key is the last element responsible for generating the key. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
+### <a id="_negatepredicate"></a>`_.negate(predicate)`
+<a href="#_negatepredicate">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7352 "View in source") [Ⓣ][1]
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Creates a function that negates the result of the predicate `func`. The
+`func` predicate is invoked with the `this` binding and arguments of the
+created function.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `predicate` *(Function)*: The predicate to negate.
#### Returns
-*(Object)*: Returns the composed aggregate object.
+*(Function)*: Returns the new function.
#### Example
```js
-var keys = [
- { 'dir': 'left', 'code': 97 },
- { 'dir': 'right', 'code': 100 }
-];
-
-_.indexBy(keys, 'dir');
-// => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
-
-_.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
-// => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+function isEven(n) {
+ return n % 2 == 0;
+}
-_.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
-// => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+_.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+// => [1, 3, 5]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_invokecollection-methodname-arg"></a>`_.invoke(collection, methodName, [arg])`
-<a href="#_invokecollection-methodname-arg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3813 "View in source") [Ⓣ][1]
+### <a id="_oncefunc"></a>`_.once(func)`
+<a href="#_oncefunc">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7379 "View in source") [Ⓣ][1]
-Invokes the method named by `methodName` on each element in the `collection` returning an array of the results of each invoked method. Additional arguments will be provided to each invoked method. If `methodName` is a function it will be invoked for, and `this` bound to, each element in the `collection`.
+Creates a function that is restricted to invoking `func` once. Repeat calls
+to the function return the value of the first call. The `func` is invoked
+with the `this` binding of the created function.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `methodName` *(Function|string)*: The name of the method to invoke or the function invoked per iteration.
-3. `[arg]` *(...*)*: Arguments to invoke the method with.
+1. `func` *(Function)*: The function to restrict.
#### Returns
-*(Array)*: Returns a new array of the results of each invoked method.
+*(Function)*: Returns the new restricted function.
#### Example
```js
-_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
-// => [[1, 5, 7], [1, 2, 3]]
-
-_.invoke([123, 456], String.prototype.split, '');
-// => [['1', '2', '3'], ['4', '5', '6']]
+var initialize = _.once(createApplication);
+initialize();
+initialize();
+// `initialize` invokes `createApplication` once
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_mapcollection-callbackidentity-thisarg"></a>`_.map(collection, [callback=identity], [thisArg])`
-<a href="#_mapcollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3865 "View in source") [Ⓣ][1]
-
-Creates an array of values by running each element in the collection through the callback. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
-
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+### <a id="_partialfunc-args"></a>`_.partial(func, [args])`
+<a href="#_partialfunc-args">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7415 "View in source") [Ⓣ][1]
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Creates a function that invokes `func` with `partial` arguments prepended
+to those provided to the new function. This method is like `_.bind` except
+it does **not** alter the `this` binding.
-#### Aliases
-*_.collect*
+The `_.partial.placeholder` value, which defaults to `_` in monolithic
+builds, may be used as a placeholder for partially applied arguments.
+ *Note:** This method does not set the `length` property of partially
+applied functions.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to partially apply arguments to.
+2. `[args]` *(...*)*: The arguments to be partially applied.
#### Returns
-*(Array)*: Returns a new array of the results of each `callback` execution.
+*(Function)*: Returns the new partially applied function.
#### Example
```js
-_.map([1, 2, 3], function(num) { return num * 3; });
-// => [3, 6, 9]
-
-_.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
-// => [3, 6, 9] (property order is not guaranteed across environments)
+var greet = function(greeting, name) {
+ return greeting + ' ' + name;
+};
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
-];
+var sayHelloTo = _.partial(greet, 'hello');
+sayHelloTo('fred');
+// => 'hello fred'
-// using "_.pluck" callback shorthand
-_.map(characters, 'name');
-// => ['barney', 'fred']
+// using placeholders
+var greetFred = _.partial(greet, _, 'fred');
+greetFred('hi');
+// => 'hi fred'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_maxcollection-callbackidentity-thisarg"></a>`_.max(collection, [callback=identity], [thisArg])`
-<a href="#_maxcollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3923 "View in source") [Ⓣ][1]
-
-Retrieves the maximum value of a collection. If the collection is empty or falsey `-Infinity` is returned. If a callback is provided it will be executed for each value in the collection to generate the criterion by which the value is ranked. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, collection)*.
+### <a id="_partialrightfunc-args"></a>`_.partialRight(func, [args])`
+<a href="#_partialrightfunc-args">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7453 "View in source") [Ⓣ][1]
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+This method is like `_.partial` except that partially applied arguments
+are appended to those provided to the new function.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+builds, may be used as a placeholder for partially applied arguments.
+ *Note:** This method does not set the `length` property of partially
+applied functions.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to partially apply arguments to.
+2. `[args]` *(...*)*: The arguments to be partially applied.
#### Returns
-*(*)*: Returns the maximum value.
+*(Function)*: Returns the new partially applied function.
#### Example
```js
-_.max([4, 2, 8, 6]);
-// => 8
-
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
-];
+var greet = function(greeting, name) {
+ return greeting + ' ' + name;
+};
-_.max(characters, function(chr) { return chr.age; });
-// => { 'name': 'fred', 'age': 40 };
+var greetFred = _.partialRight(greet, 'fred');
+greetFred('hi');
+// => 'hi fred'
-// using "_.pluck" callback shorthand
-_.max(characters, 'age');
-// => { 'name': 'fred', 'age': 40 };
+// using placeholders
+var sayHelloTo = _.partialRight(greet, 'hello', _);
+sayHelloTo('fred');
+// => 'hello fred'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_mincollection-callbackidentity-thisarg"></a>`_.min(collection, [callback=identity], [thisArg])`
-<a href="#_mincollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3998 "View in source") [Ⓣ][1]
-
-Retrieves the minimum value of a collection. If the collection is empty or falsey `Infinity` is returned. If a callback is provided it will be executed for each value in the collection to generate the criterion by which the value is ranked. The callback is bound to `thisArg` and invoked with three arguments; *(value, index, collection)*.
+### <a id="_reargfunc-indexes"></a>`_.rearg(func, indexes)`
+<a href="#_reargfunc-indexes">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7486 "View in source") [Ⓣ][1]
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Creates a function that invokes `func` with arguments arranged according
+to the specified indexes where the argument value at the first index is
+provided as the first argument, the argument value at the second index is
+provided as the second argument, and so on.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `func` *(Function)*: The function to rearrange arguments for.
+2. `indexes` *(...(number|number[])*: The arranged argument indexes, specified as individual indexes or arrays of indexes.
#### Returns
-*(*)*: Returns the minimum value.
+*(Function)*: Returns the new function.
#### Example
```js
-_.min([4, 2, 8, 6]);
-// => 2
+var rearged = _.rearg(function(a, b, c) {
+ return [a, b, c];
+}, 2, 0, 1);
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
-];
-
-_.min(characters, function(chr) { return chr.age; });
-// => { 'name': 'barney', 'age': 36 };
+rearged('b', 'c', 'a')
+// => ['a', 'b', 'c']
-// using "_.pluck" callback shorthand
-_.min(characters, 'age');
-// => { 'name': 'barney', 'age': 36 };
+var map = _.rearg(_.map, [1, 0]);
+map(function(n) { return n * 3; }, [1, 2, 3]);
+// => [3, 6, 9]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_pluckcollection-property"></a>`_.pluck(collection, property)`
-<a href="#_pluckcollection-property">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4053 "View in source") [Ⓣ][1]
+### <a id="_throttlefunc-wait-options-optionsleadingtrue-optionstrailingtrue"></a>`_.throttle(func, wait, [options], [options.leading=true], [options.trailing=true])`
+<a href="#_throttlefunc-wait-options-optionsleadingtrue-optionstrailingtrue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7529 "View in source") [Ⓣ][1]
+
+Creates a function that only invokes `func` at most once per every `wait`
+milliseconds. The created function comes with a `cancel` method to cancel
+delayed invocations. Provide an options object to indicate that `func`
+should be invoked on the leading and/or trailing edge of the `wait` timeout.
+Subsequent calls to the throttled function return the result of the last
+`func` call.
+ *Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+on the trailing edge of the timeout only if the the throttled function is
+invoked more than once during the `wait` timeout.
-Retrieves the value of a specified property from all elements in the collection.
+See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+for details over the differences between `_.throttle` and `_.debounce`.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `property` *(string)*: The name of the property to pluck.
+1. `func` *(Function)*: The function to throttle.
+2. `wait` *(number)*: The number of milliseconds to throttle invocations to.
+3. `[options]` *(Object)*: The options object.
+4. `[options.leading=true]` *(boolean)*: Specify invoking on the leading edge of the timeout.
+5. `[options.trailing=true]` *(boolean)*: Specify invoking on the trailing edge of the timeout.
#### Returns
-*(Array)*: Returns a new array of property values.
+*(Function)*: Returns the new throttled function.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
-];
+// avoid excessively updating the position while scrolling
+jQuery(window).on('scroll', _.throttle(updatePosition, 100));
-_.pluck(characters, 'name');
-// => ['barney', 'fred']
-```
+// invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
+var throttled = _.throttle(renewToken, 300000, { 'trailing': false })
+jQuery('.interactive').on('click', throttled);
+// cancel a trailing throttled call
+jQuery(window).on('popstate', throttled.cancel);
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_reducecollection-callbackidentity-accumulator-thisarg"></a>`_.reduce(collection, [callback=identity], [accumulator], [thisArg])`
-<a href="#_reducecollection-callbackidentity-accumulator-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4085 "View in source") [Ⓣ][1]
-
-Reduces a collection to a value which is the accumulated result of running each element in the collection through the callback, where each successive callback execution consumes the return value of the previous execution. If `accumulator` is not provided the first element of the collection will be used as the initial `accumulator` value. The callback is bound to `thisArg` and invoked with four arguments; *(accumulator, value, index|key, collection)*.
+### <a id="_wrapvalue-wrapper"></a>`_.wrap(value, wrapper)`
+<a href="#_wrapvalue-wrapper">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7569 "View in source") [Ⓣ][1]
-#### Aliases
-*_.foldl, _.inject*
+Creates a function that provides `value` to the wrapper function as its
+first argument. Any additional arguments provided to the function are
+appended to those provided to the wrapper function. The wrapper is invoked
+with the `this` binding of the created function.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[accumulator]` *(*)*: Initial value of the accumulator.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `value` *(*)*: The value to wrap.
+2. `wrapper` *(Function)*: The wrapper function.
#### Returns
-*(*)*: Returns the accumulated value.
+*(Function)*: Returns the new function.
#### Example
```js
-var sum = _.reduce([1, 2, 3], function(sum, num) {
- return sum + num;
+var p = _.wrap(_.escape, function(func, text) {
+ return '<p>' + func(text) + '</p>';
});
-// => 6
-var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
- result[key] = num * 3;
- return result;
-}, {});
-// => { 'a': 3, 'b': 6, 'c': 9 }
+p('fred, barney, & pebbles');
+// => '<p>fred, barney, & pebbles</p>'
```
-
* * *
<!-- /div -->
+<!-- /div -->
<!-- div -->
-### <a id="_reducerightcollection-callbackidentity-accumulator-thisarg"></a>`_.reduceRight(collection, [callback=identity], [accumulator], [thisArg])`
-<a href="#_reducerightcollection-callbackidentity-accumulator-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4128 "View in source") [Ⓣ][1]
+## `“Lang” Methods`
-This method is like `_.reduce` except that it iterates over elements of a `collection` from right to left.
+<!-- div -->
+
+### <a id="_clonevalue-isdeep-customizer-thisarg"></a>`_.clone(value, [isDeep], [customizer], [thisArg])`
+<a href="#_clonevalue-isdeep-customizer-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7625 "View in source") [Ⓣ][1]
-#### Aliases
-*_.foldr*
+Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
+otherwise they are assigned by reference. If `customizer` is provided it is
+invoked to produce the cloned values. If `customizer` returns `undefined`
+cloning is handled by the method instead. The `customizer` is bound to
+`thisArg` and invoked with two argument; (value [, index|key, object]).
+ *Note:** This method is loosely based on the structured clone algorithm.
+The enumerable properties of `arguments` objects and objects created by
+constructors other than `Object` are cloned to plain `Object` objects. An
+empty object is returned for uncloneable values such as functions, DOM nodes,
+Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+for more details.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[accumulator]` *(*)*: Initial value of the accumulator.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `value` *(*)*: The value to clone.
+2. `[isDeep]` *(boolean)*: Specify a deep clone.
+3. `[customizer]` *(Function)*: The function to customize cloning values.
+4. `[thisArg]` *(*)*: The `this` binding of `customizer`.
#### Returns
-*(*)*: Returns the accumulated value.
+*(*)*: Returns the cloned value.
#### Example
```js
-var list = [[0, 1], [2, 3], [4, 5]];
-var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
-// => [4, 5, 2, 3, 0, 1]
-```
+var users = [
+ { 'user': 'barney' },
+ { 'user': 'fred' }
+];
-* * *
+var shallow = _.clone(users);
+shallow[0] === users[0];
+// => true
-<!-- /div -->
+var deep = _.clone(users, true);
+deep[0] === users[0];
+// => false
+// using a customizer callback
+var body = _.clone(document.body, function(value) {
+ return _.isElement(value) ? value.cloneNode(false) : undefined;
+});
-<!-- div -->
+body === document.body
+// => false
+body.nodeName
+// => BODY
+body.childNodes.length;
+// => 0
+```
+* * *
-### <a id="_rejectcollection-callbackidentity-thisarg"></a>`_.reject(collection, [callback=identity], [thisArg])`
-<a href="#_rejectcollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4177 "View in source") [Ⓣ][1]
+<!-- /div -->
-The opposite of `_.filter` this method returns the elements of a collection that the callback does **not** return truey for.
+<!-- div -->
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+### <a id="_clonedeepvalue-customizer-thisarg"></a>`_.cloneDeep(value, [customizer], [thisArg])`
+<a href="#_clonedeepvalue-customizer-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7679 "View in source") [Ⓣ][1]
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Creates a deep clone of `value`. If `customizer` is provided it is invoked
+to produce the cloned values. If `customizer` returns `undefined` cloning
+is handled by the method instead. The `customizer` is bound to `thisArg`
+and invoked with two argument; (value [, index|key, object]).
+ *Note:** This method is loosely based on the structured clone algorithm.
+The enumerable properties of `arguments` objects and objects created by
+constructors other than `Object` are cloned to plain `Object` objects. An
+empty object is returned for uncloneable values such as functions, DOM nodes,
+Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+for more details.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `value` *(*)*: The value to deep clone.
+2. `[customizer]` *(Function)*: The function to customize cloning values.
+3. `[thisArg]` *(*)*: The `this` binding of `customizer`.
#### Returns
-*(Array)*: Returns a new array of elements that failed the callback check.
+*(*)*: Returns the deep cloned value.
#### Example
```js
-var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
-// => [1, 3, 5]
-
-var characters = [
- { 'name': 'barney', 'age': 36, 'blocked': false },
- { 'name': 'fred', 'age': 40, 'blocked': true }
+var users = [
+ { 'user': 'barney' },
+ { 'user': 'fred' }
];
-// using "_.pluck" callback shorthand
-_.reject(characters, 'blocked');
-// => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
+var deep = _.cloneDeep(users);
+deep[0] === users[0];
+// => false
+
+// using a customizer callback
+var el = _.cloneDeep(document.body, function(value) {
+ return _.isElement(value) ? value.cloneNode(true) : undefined;
+});
-// using "_.where" callback shorthand
-_.reject(characters, { 'age': 36 });
-// => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
+body === document.body
+// => false
+body.nodeName
+// => BODY
+body.childNodes.length;
+// => 20
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_samplecollection-n"></a>`_.sample(collection, [n])`
-<a href="#_samplecollection-n">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4203 "View in source") [Ⓣ][1]
+### <a id="_isargumentsvalue"></a>`_.isArguments(value)`
+<a href="#_isargumentsvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7700 "View in source") [Ⓣ][1]
-Retrieves a random element or `n` random elements from a collection.
+Checks if `value` is classified as an `arguments` object.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to sample.
-2. `[n]` *(number)*: The number of elements to sample.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Array)*: Returns the random sample(s) of `collection`.
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
#### Example
```js
-_.sample([1, 2, 3, 4]);
-// => 2
+(function() { return _.isArguments(arguments); })();
+// => true
-_.sample([1, 2, 3, 4], 2);
-// => [3, 1]
+_.isArguments([1, 2, 3]);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_shufflecollection"></a>`_.shuffle(collection)`
-<a href="#_shufflecollection">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4231 "View in source") [Ⓣ][1]
+### <a id="_isarrayvalue"></a>`_.isArray(value)`
+<a href="#_isarrayvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7729 "View in source") [Ⓣ][1]
-Creates an array of shuffled values, using a version of the Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
+Checks if `value` is classified as an `Array` object.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to shuffle.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Array)*: Returns a new shuffled collection.
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
#### Example
```js
-_.shuffle([1, 2, 3, 4, 5, 6]);
-// => [4, 1, 6, 3, 5, 2]
-```
+_.isArray([1, 2, 3]);
+// => true
+(function() { return _.isArray(arguments); })();
+// => false
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_sizecollection"></a>`_.size(collection)`
-<a href="#_sizecollection">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4264 "View in source") [Ⓣ][1]
+### <a id="_isbooleanvalue"></a>`_.isBoolean(value)`
+<a href="#_isbooleanvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7749 "View in source") [Ⓣ][1]
-Gets the size of the `collection` by returning `collection.length` for arrays and array-like objects or the number of own enumerable properties for objects.
+Checks if `value` is classified as a boolean primitive or object.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to inspect.
+1. `value` *(*)*: The value to check.
#### Returns
-*(number)*: Returns `collection.length` or number of own enumerable properties.
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
#### Example
```js
-_.size([1, 2]);
-// => 2
-
-_.size({ 'one': 1, 'two': 2, 'three': 3 });
-// => 3
+_.isBoolean(false);
+// => true
-_.size('pebbles');
-// => 7
+_.isBoolean(null);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_somecollection-callbackidentity-thisarg"></a>`_.some(collection, [callback=identity], [thisArg])`
-<a href="#_somecollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4311 "View in source") [Ⓣ][1]
-
-Checks if the callback returns a truey value for **any** element of a collection. The function returns as soon as it finds a passing value and does not iterate over the entire collection. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
-
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+### <a id="_isdatevalue"></a>`_.isDate(value)`
+<a href="#_isdatevalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7769 "View in source") [Ⓣ][1]
-#### Aliases
-*_.any*
+Checks if `value` is classified as a `Date` object.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `value` *(*)*: The value to check.
#### Returns
-*(boolean)*: Returns `true` if any element passed the callback check, else `false`.
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
#### Example
```js
-_.some([null, 0, 'yes', false], Boolean);
-// => true
-
-var characters = [
- { 'name': 'barney', 'age': 36, 'blocked': false },
- { 'name': 'fred', 'age': 40, 'blocked': true }
-];
-
-// using "_.pluck" callback shorthand
-_.some(characters, 'blocked');
+_.isDate(new Date);
// => true
-// using "_.where" callback shorthand
-_.some(characters, { 'age': 1 });
+_.isDate('Mon April 23 2012');
// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_sortbycollection-callbackidentity-thisarg"></a>`_.sortBy(collection, [callback=identity], [thisArg])`
-<a href="#_sortbycollection-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4381 "View in source") [Ⓣ][1]
-
-Creates an array of elements, sorted in ascending order by the results of running each element in a collection through the callback. This method performs a stable sort, that is, it will preserve the original sort order of equal elements. The callback is bound to `thisArg` and invoked with three arguments; *(value, index|key, collection)*.
-
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an array of property names is provided for `callback` the collection will be sorted by each property value.
+### <a id="_iselementvalue"></a>`_.isElement(value)`
+<a href="#_iselementvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7789 "View in source") [Ⓣ][1]
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Checks if `value` is a DOM element.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `[callback=identity]` *(Array|Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Array)*: Returns a new array of sorted elements.
+*(boolean)*: Returns `true` if `value` is a DOM element, else `false`.
#### Example
```js
-_.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
-// => [3, 1, 2]
-
-_.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
-// => [3, 1, 2]
-
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 },
- { 'name': 'barney', 'age': 26 },
- { 'name': 'fred', 'age': 30 }
-];
-
-// using "_.pluck" callback shorthand
-_.map(_.sortBy(characters, 'age'), _.values);
-// => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
+_.isElement(document.body);
+// => true
-// sorting by multiple properties
-_.map(_.sortBy(characters, ['name', 'age']), _.values);
-// = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
+_.isElement('<body>');
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_toarraycollection"></a>`_.toArray(collection)`
-<a href="#_toarraycollection">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4427 "View in source") [Ⓣ][1]
+### <a id="_isemptyvalue"></a>`_.isEmpty(value)`
+<a href="#_isemptyvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7827 "View in source") [Ⓣ][1]
-Converts the `collection` to an array.
+Checks if a value is empty. A value is considered empty unless it is an
+`arguments` object, array, string, or jQuery-like collection with a length
+greater than `0` or an object with own enumerable properties.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to convert.
+1. `value` *(Array|Object|string)*: The value to inspect.
#### Returns
-*(Array)*: Returns the new converted array.
+*(boolean)*: Returns `true` if `value` is empty, else `false`.
#### Example
```js
-(function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
-// => [2, 3, 4]
-```
+_.isEmpty(null);
+// => true
+
+_.isEmpty(true);
+// => true
+
+_.isEmpty(1);
+// => true
+_.isEmpty([1, 2, 3]);
+// => false
+
+_.isEmpty({ 'a': 1 });
+// => false
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_wherecollection-props"></a>`_.where(collection, props)`
-<a href="#_wherecollection-props">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L4461 "View in source") [Ⓣ][1]
+### <a id="_isequalvalue-other-customizer-thisarg"></a>`_.isEqual(value, other, [customizer], [thisArg])`
+<a href="#_isequalvalue-other-customizer-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7879 "View in source") [Ⓣ][1]
-Performs a deep comparison of each element in a `collection` to the given `properties` object, returning an array of all elements that have equivalent property values.
+Performs a deep comparison between two values to determine if they are
+equivalent. If `customizer` is provided it is invoked to compare values.
+If `customizer` returns `undefined` comparisons are handled by the method
+instead. The `customizer` is bound to `thisArg` and invoked with three
+arguments; (value, other [, index|key]).
+ *Note:** This method supports comparing arrays, booleans, `Date` objects,
+numbers, `Object` objects, regexes, and strings. Functions and DOM nodes
+are **not** supported. Provide a customizer function to extend support
+for comparing other values.
#### Arguments
-1. `collection` *(Array|Object|string)*: The collection to iterate over.
-2. `props` *(Object)*: The object of property values to filter by.
+1. `value` *(*)*: The value to compare.
+2. `other` *(*)*: The other value to compare.
+3. `[customizer]` *(Function)*: The function to customize comparing values.
+4. `[thisArg]` *(*)*: The `this` binding of `customizer`.
#### Returns
-*(Array)*: Returns a new array of elements that have the given properties.
+*(boolean)*: Returns `true` if the values are equivalent, else `false`.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
- { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
-];
+var object = { 'user': 'fred' };
+var other = { 'user': 'fred' };
-_.where(characters, { 'age': 36 });
-// => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
-
-_.where(characters, { 'pets': ['dino'] });
-// => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
-```
+object == other;
+// => false
-* * *
+_.isEqual(object, other);
+// => true
-<!-- /div -->
+// using a customizer callback
+var array = ['hello', 'goodbye'];
+var other = ['hi', 'goodbye'];
+_.isEqual(array, other, function(value, other) {
+ return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+});
+// => true
+```
+* * *
<!-- /div -->
-
-<!-- div -->
-
-## `“Functions” Methods`
-
<!-- div -->
-### <a id="_aftern-func"></a>`_.after(n, func)`
-<a href="#_aftern-func">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5504 "View in source") [Ⓣ][1]
+### <a id="_iserrorvalue"></a>`_.isError(value)`
+<a href="#_iserrorvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7905 "View in source") [Ⓣ][1]
-Creates a function that executes `func`, with the `this` binding and arguments of the created function, only after being called `n` times.
+Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+`SyntaxError`, `TypeError`, or `URIError` object.
#### Arguments
-1. `n` *(number)*: The number of times the function must be called before `func` is executed.
-2. `func` *(Function)*: The function to restrict.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new restricted function.
+*(boolean)*: Returns `true` if `value` is an error object, else `false`.
#### Example
```js
-var saves = ['profile', 'settings'];
-
-var done = _.after(saves.length, function() {
- console.log('Done saving!');
-});
+_.isError(new Error);
+// => true
-_.forEach(saves, function(type) {
- asyncSave({ 'type': type, 'complete': done });
-});
-// => logs 'Done saving!', after all saves have completed
+_.isError(Error);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_bindfunc-thisarg-arg"></a>`_.bind(func, [thisArg], [arg])`
-<a href="#_bindfunc-thisarg-arg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5537 "View in source") [Ⓣ][1]
+### <a id="_isfinitevalue"></a>`_.isFinite(value)`
+<a href="#_isfinitevalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7938 "View in source") [Ⓣ][1]
-Creates a function that, when called, invokes `func` with the `this` binding of `thisArg` and prepends any additional `bind` arguments to those provided to the bound function.
+Checks if `value` is a finite primitive number.
+ *Note:** This method is based on ES6 `Number.isFinite`. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite)
+for more details.
#### Arguments
-1. `func` *(Function)*: The function to bind.
-2. `[thisArg]` *(*)*: The `this` binding of `func`.
-3. `[arg]` *(...*)*: Arguments to be partially applied.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new bound function.
+*(boolean)*: Returns `true` if `value` is a finite number, else `false`.
#### Example
```js
-var func = function(greeting) {
- return greeting + ' ' + this.name;
-};
+_.isFinite(10);
+// => true
-func = _.bind(func, { 'name': 'fred' }, 'hi');
-func();
-// => 'hi fred'
-```
+_.isFinite('10');
+// => false
+
+_.isFinite(true);
+// => false
+
+_.isFinite(Object(10));
+// => false
+_.isFinite(Infinity);
+// => false
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_bindallobject-methodname"></a>`_.bindAll(object, [methodName])`
-<a href="#_bindallobject-methodname">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5567 "View in source") [Ⓣ][1]
+### <a id="_isfunctionvalue"></a>`_.isFunction(value)`
+<a href="#_isfunctionvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7958 "View in source") [Ⓣ][1]
-Binds methods of an object to the object itself, overwriting the existing method. Method names may be specified as individual arguments or as arrays of method names. If no method names are provided all the function properties of `object` will be bound.
+Checks if `value` is classified as a `Function` object.
#### Arguments
-1. `object` *(Object)*: The object to bind and assign the bound methods to.
-2. `[methodName]` *(...string)*: The object method names to bind, specified as individual method names or arrays of method names.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Object)*: Returns `object`.
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
#### Example
```js
-var view = {
- 'label': 'docs',
- 'onClick': function() { console.log('clicked ' + this.label); }
-};
+_.isFunction(_);
+// => true
-_.bindAll(view);
-jQuery('#docs').on('click', view.onClick);
-// => logs 'clicked docs', when the button is clicked
+_.isFunction(/abc/);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_bindkeyobject-key-arg"></a>`_.bindKey(object, key, [arg])`
-<a href="#_bindkeyobject-key-arg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5613 "View in source") [Ⓣ][1]
+### <a id="_ismatchsource-source-customizer-thisarg"></a>`_.isMatch(source, source, [customizer], [thisArg])`
+<a href="#_ismatchsource-source-customizer-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8041 "View in source") [Ⓣ][1]
-Creates a function that, when called, invokes the method at `object[key]` and prepends any additional `bindKey` arguments to those provided to the bound function. This method differs from `_.bind` by allowing bound functions to reference methods that will be redefined or don't yet exist. See http://michaux.ca/articles/lazy-function-definition-pattern.
+Performs a deep comparison between `object` and `source` to determine if
+`object` contains equivalent property values. If `customizer` is provided
+it is invoked to compare values. If `customizer` returns `undefined`
+comparisons are handled by the method instead. The `customizer` is bound
+to `thisArg` and invoked with three arguments; (value, other, index|key).
+ *Note:** This method supports comparing properties of arrays, booleans,
+`Date` objects, numbers, `Object` objects, regexes, and strings. Functions
+and DOM nodes are **not** supported. Provide a customizer function to extend
+support for comparing other values.
#### Arguments
-1. `object` *(Object)*: The object the method belongs to.
-2. `key` *(string)*: The key of the method.
-3. `[arg]` *(...*)*: Arguments to be partially applied.
+1. `source` *(Object)*: The object to inspect.
+2. `source` *(Object)*: The object of property values to match.
+3. `[customizer]` *(Function)*: The function to customize comparing values.
+4. `[thisArg]` *(*)*: The `this` binding of `customizer`.
#### Returns
-*(Function)*: Returns the new bound function.
+*(boolean)*: Returns `true` if `object` is a match, else `false`.
#### Example
```js
-var object = {
- 'name': 'fred',
- 'greet': function(greeting) {
- return greeting + ' ' + this.name;
- }
-};
+var object = { 'user': 'fred', 'age': 40 };
-var func = _.bindKey(object, 'greet', 'hi');
-func();
-// => 'hi fred'
+_.isMatch(object, { 'age': 40 });
+// => true
-object.greet = function(greeting) {
- return greeting + 'ya ' + this.name + '!';
-};
+_.isMatch(object, { 'age': 36 });
+// => false
-func();
-// => 'hiya fred!'
-```
+// using a customizer callback
+var object = { 'greeting': 'hello' };
+var source = { 'greeting': 'hi' };
+_.isMatch(object, source, function(value, other) {
+ return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+});
+// => true
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_composefunc"></a>`_.compose([func])`
-<a href="#_composefunc">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5649 "View in source") [Ⓣ][1]
+### <a id="_isnanvalue"></a>`_.isNaN(value)`
+<a href="#_isnanvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8090 "View in source") [Ⓣ][1]
-Creates a function that is the composition of the provided functions, where each function consumes the return value of the function that follows. For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. Each function is executed with the `this` binding of the composed function.
+Checks if `value` is `NaN`.
+ *Note:** This method is not the same as native `isNaN` which returns `true`
+for `undefined` and other non-numeric values. See the [ES5 spec](http://es5.github.io/#x15.1.2.4)
+for more details.
#### Arguments
-1. `[func]` *(...Function)*: Functions to compose.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new composed function.
+*(boolean)*: Returns `true` if `value` is `NaN`, else `false`.
#### Example
```js
-var realNameMap = {
- 'pebbles': 'penelope'
-};
+_.isNaN(NaN);
+// => true
-var format = function(name) {
- name = realNameMap[name.toLowerCase()] || name;
- return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
-};
+_.isNaN(new Number(NaN));
+// => true
-var greet = function(formatted) {
- return 'Hiya ' + formatted + '!';
-};
+isNaN(undefined);
+// => true
-var welcome = _.compose(greet, format);
-welcome('pebbles');
-// => 'Hiya Penelope!'
+_.isNaN(undefined);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_curryfunc-arityfunclength"></a>`_.curry(func, [arity=func.length])`
-<a href="#_curryfunc-arityfunclength">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5697 "View in source") [Ⓣ][1]
+### <a id="_isnativevalue"></a>`_.isNative(value)`
+<a href="#_isnativevalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8112 "View in source") [Ⓣ][1]
-Creates a function which accepts one or more arguments of `func` that when invoked either executes `func` returning its result, if all `func` arguments have been provided, or returns a function that accepts one or more of the remaining `func` arguments, and so on. The arity of `func` can be specified if `func.length` is not sufficient.
+Checks if `value` is a native function.
#### Arguments
-1. `func` *(Function)*: The function to curry.
-2. `[arity=func.length]` *(number)*: The arity of `func`.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new curried function.
+*(boolean)*: Returns `true` if `value` is a native function, else `false`.
#### Example
```js
-var curried = _.curry(function(a, b, c) {
- console.log(a + b + c);
-});
-
-curried(1)(2)(3);
-// => 6
-
-curried(1, 2)(3);
-// => 6
+_.isNative(Array.prototype.push);
+// => true
-curried(1, 2, 3);
-// => 6
+_.isNative(_);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_debouncefunc-wait-options-optionsmaxwait"></a>`_.debounce(func, wait, [options], [options.maxWait])`
-<a href="#_debouncefunc-wait-options-optionsmaxwait">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5741 "View in source") [Ⓣ][1]
-
-Creates a function that will delay the execution of `func` until after `wait` milliseconds have elapsed since the last time it was invoked. Provide an options object to indicate that `func` should be invoked on the leading and/or trailing edge of the `wait` timeout. Subsequent calls to the debounced function will return the result of the last `func` call.
+### <a id="_isnullvalue"></a>`_.isNull(value)`
+<a href="#_isnullvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8139 "View in source") [Ⓣ][1]
-Note: If `leading` and `trailing` options are `true` `func` will be called on the trailing edge of the timeout only if the the debounced function is invoked more than once during the `wait` timeout.
+Checks if `value` is `null`.
#### Arguments
-1. `func` *(Function)*: The function to debounce.
-2. `wait` *(number)*: The number of milliseconds to delay.
-3. `[options]` *(Object)*: The options object.
-4. `[options.leading=false]` *(boolean)*: Specify execution on the leading edge of the timeout.
-5. `[options.maxWait]` *(number)*: The maximum time `func` is allowed to be delayed before it's called.
-6. `[options.trailing=true]` *(boolean)*: Specify execution on the trailing edge of the timeout.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new debounced function.
+*(boolean)*: Returns `true` if `value` is `null`, else `false`.
#### Example
```js
-// avoid costly calculations while the window size is in flux
-var lazyLayout = _.debounce(calculateLayout, 150);
-jQuery(window).on('resize', lazyLayout);
-
-// execute `sendMail` when the click event is fired, debouncing subsequent calls
-jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
- 'leading': true,
- 'trailing': false
-});
+_.isNull(null);
+// => true
-// ensure `batchLog` is executed once after 1 second of debounced calls
-var source = new EventSource('/stream');
-source.addEventListener('message', _.debounce(batchLog, 250, {
- 'maxWait': 1000
-}, false);
+_.isNull(void 0);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_deferfunc-arg"></a>`_.defer(func, [arg])`
-<a href="#_deferfunc-arg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5857 "View in source") [Ⓣ][1]
+### <a id="_isnumbervalue"></a>`_.isNumber(value)`
+<a href="#_isnumbervalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8165 "View in source") [Ⓣ][1]
-Defers executing the `func` function until the current call stack has cleared. Additional arguments will be provided to `func` when it is invoked.
+Checks if `value` is classified as a `Number` primitive or object.
+ *Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified
+as numbers, use the `_.isFinite` method.
#### Arguments
-1. `func` *(Function)*: The function to defer.
-2. `[arg]` *(...*)*: Arguments to invoke the function with.
+1. `value` *(*)*: The value to check.
#### Returns
-*(number)*: Returns the timer id.
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
#### Example
```js
-_.defer(function(text) { console.log(text); }, 'deferred');
-// logs 'deferred' after one or more milliseconds
-```
+_.isNumber(8.4);
+// => true
+
+_.isNumber(NaN);
+// => true
+_.isNumber('8.4');
+// => false
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_delayfunc-wait-arg"></a>`_.delay(func, wait, [arg])`
-<a href="#_delayfunc-wait-arg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5881 "View in source") [Ⓣ][1]
+### <a id="_isobjectvalue"></a>`_.isObject(value)`
+<a href="#_isobjectvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L7995 "View in source") [Ⓣ][1]
-Executes the `func` function after `wait` milliseconds. Additional arguments will be provided to `func` when it is invoked.
+Checks if `value` is the language type of `Object`.
+(e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *Note:** See the [ES5 spec](http://es5.github.io/#x8) for more details.
#### Arguments
-1. `func` *(Function)*: The function to delay.
-2. `wait` *(number)*: The number of milliseconds to delay execution.
-3. `[arg]` *(...*)*: Arguments to invoke the function with.
+1. `value` *(*)*: The value to check.
#### Returns
-*(number)*: Returns the timer id.
+*(boolean)*: Returns `true` if `value` is an object, else `false`.
#### Example
```js
-_.delay(function(text) { console.log(text); }, 1000, 'later');
-// => logs 'later' after one second
-```
+_.isObject({});
+// => true
+_.isObject([1, 2, 3]);
+// => true
+
+_.isObject(1);
+// => false
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_memoizefunc-resolver"></a>`_.memoize(func, [resolver])`
-<a href="#_memoizefunc-resolver">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5926 "View in source") [Ⓣ][1]
+### <a id="_isplainobjectvalue"></a>`_.isPlainObject(value)`
+<a href="#_isplainobjectvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8199 "View in source") [Ⓣ][1]
-Creates a function that memoizes the result of `func`. If `resolver` is provided it will be used to determine the cache key for storing the result based on the arguments provided to the memoized function. By default, the first argument provided to the memoized function is used as the cache key. The `func` is executed with the `this` binding of the memoized function. The result cache is exposed as the `cache` property on the memoized function.
+Checks if `value` is a plain object, that is, an object created by the
+`Object` constructor or one with a `[[Prototype]]` of `null`.
+ *Note:** This method assumes objects created by the `Object` constructor
+have no inherited enumerable properties.
#### Arguments
-1. `func` *(Function)*: The function to have its output memoized.
-2. `[resolver]` *(Function)*: A function used to resolve the cache key.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new memoizing function.
+*(boolean)*: Returns `true` if `value` is a plain object, else `false`.
#### Example
```js
-var fibonacci = _.memoize(function(n) {
- return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
-});
+function Foo() {
+ this.a = 1;
+}
-fibonacci(9)
-// => 34
+_.isPlainObject(new Foo);
+// => false
-var data = {
- 'fred': { 'name': 'fred', 'age': 40 },
- 'pebbles': { 'name': 'pebbles', 'age': 1 }
-};
+_.isPlainObject([1, 2, 3]);
+// => false
-// modifying the result cache
-var get = _.memoize(function(name) { return data[name]; }, _.identity);
-get('pebbles');
-// => { 'name': 'pebbles', 'age': 1 }
+_.isPlainObject({ 'x': 0, 'y': 0 });
+// => true
-get.cache.pebbles.name = 'penelope';
-get('pebbles');
-// => { 'name': 'penelope', 'age': 1 }
+_.isPlainObject(Object.create(null));
+// => true
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_oncefunc"></a>`_.once(func)`
-<a href="#_oncefunc">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5959 "View in source") [Ⓣ][1]
+### <a id="_isregexpvalue"></a>`_.isRegExp(value)`
+<a href="#_isregexpvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8227 "View in source") [Ⓣ][1]
-Creates a function that is restricted to execute `func` once. Repeat calls to the function will return the value of the first call. The `func` is executed with the `this` binding of the created function.
+Checks if `value` is classified as a `RegExp` object.
#### Arguments
-1. `func` *(Function)*: The function to restrict.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new restricted function.
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
#### Example
```js
-var initialize = _.once(createApplication);
-initialize();
-initialize();
-// `initialize` executes `createApplication` once
-```
+_.isRegExp(/abc/);
+// => true
+_.isRegExp('/abc/');
+// => false
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_partialfunc-arg"></a>`_.partial(func, [arg])`
-<a href="#_partialfunc-arg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L5997 "View in source") [Ⓣ][1]
+### <a id="_isstringvalue"></a>`_.isString(value)`
+<a href="#_isstringvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8247 "View in source") [Ⓣ][1]
-Creates a function that, when called, invokes `func` with any additional `partial` arguments prepended to those provided to the new function. This method is similar to `_.bind` except it does **not** alter the `this` binding.
+Checks if `value` is classified as a `String` primitive or object.
#### Arguments
-1. `func` *(Function)*: The function to partially apply arguments to.
-2. `[arg]` *(...*)*: Arguments to be partially applied.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new partially applied function.
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
#### Example
```js
-var greet = function(greeting, name) { return greeting + ' ' + name; };
-var hi = _.partial(greet, 'hi');
-hi('fred');
-// => 'hi fred'
-```
+_.isString('abc');
+// => true
+_.isString(1);
+// => false
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_partialrightfunc-arg"></a>`_.partialRight(func, [arg])`
-<a href="#_partialrightfunc-arg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6028 "View in source") [Ⓣ][1]
+### <a id="_istypedarrayvalue"></a>`_.isTypedArray(value)`
+<a href="#_istypedarrayvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8267 "View in source") [Ⓣ][1]
-This method is like `_.partial` except that `partial` arguments are appended to those provided to the new function.
+Checks if `value` is classified as a typed array.
#### Arguments
-1. `func` *(Function)*: The function to partially apply arguments to.
-2. `[arg]` *(...*)*: Arguments to be partially applied.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new partially applied function.
-
-#### Example
-```js
-var defaultsDeep = _.partialRight(_.merge, _.defaults);
-
-var options = {
- 'variable': 'data',
- 'imports': { 'jq': $ }
-};
-
-defaultsDeep(options, _.templateSettings);
+*(boolean)*: Returns `true` if `value` is correctly classified, else `false`.
-options.variable
-// => 'data'
+#### Example
+```js
+_.isTypedArray(new Uint8Array);
+// => true
-options.imports
-// => { '_': _, 'jq': $ }
+_.isTypedArray([]);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_throttlefunc-wait-options"></a>`_.throttle(func, wait, [options])`
-<a href="#_throttlefunc-wait-options">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6063 "View in source") [Ⓣ][1]
-
-Creates a function that, when executed, will only call the `func` function at most once per every `wait` milliseconds. Provide an options object to indicate that `func` should be invoked on the leading and/or trailing edge of the `wait` timeout. Subsequent calls to the throttled function will return the result of the last `func` call.
+### <a id="_isundefinedvalue"></a>`_.isUndefined(value)`
+<a href="#_isundefinedvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8287 "View in source") [Ⓣ][1]
-Note: If `leading` and `trailing` options are `true` `func` will be called on the trailing edge of the timeout only if the the throttled function is invoked more than once during the `wait` timeout.
+Checks if `value` is `undefined`.
#### Arguments
-1. `func` *(Function)*: The function to throttle.
-2. `wait` *(number)*: The number of milliseconds to throttle executions to.
-3. `[options]` *(Object)*: The options object.
-4. `[options.leading=true]` *(boolean)*: Specify execution on the leading edge of the timeout.
-5. `[options.trailing=true]` *(boolean)*: Specify execution on the trailing edge of the timeout.
+1. `value` *(*)*: The value to check.
#### Returns
-*(Function)*: Returns the new throttled function.
+*(boolean)*: Returns `true` if `value` is `undefined`, else `false`.
#### Example
```js
-// avoid excessively updating the position while scrolling
-var throttled = _.throttle(updatePosition, 100);
-jQuery(window).on('scroll', throttled);
+_.isUndefined(void 0);
+// => true
-// execute `renewToken` when the click event is fired, but not more than once every 5 minutes
-jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
- 'trailing': false
-}));
+_.isUndefined(null);
+// => false
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_wrapvalue-wrapper"></a>`_.wrap(value, wrapper)`
-<a href="#_wrapvalue-wrapper">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6104 "View in source") [Ⓣ][1]
+### <a id="_toarrayvalue"></a>`_.toArray(value)`
+<a href="#_toarrayvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8304 "View in source") [Ⓣ][1]
-Creates a function that provides `value` to the wrapper function as its first argument. Additional arguments provided to the function are appended to those provided to the wrapper function. The wrapper is executed with the `this` binding of the created function.
+Converts `value` to an array.
#### Arguments
-1. `value` *(*)*: The value to wrap.
-2. `wrapper` *(Function)*: The wrapper function.
+1. `value` *(*)*: The value to convert.
#### Returns
-*(Function)*: Returns the new function.
+*(Array)*: Returns the converted array.
#### Example
```js
-var p = _.wrap(_.escape, function(func, text) {
- return '<p>' + func(text) + '</p>';
-});
-
-p('Fred, Wilma, & Pebbles');
-// => '<p>Fred, Wilma, & Pebbles</p>'
+(function() { return _.toArray(arguments).slice(1); })(1, 2, 3);
+// => [2, 3]
```
-
* * *
<!-- /div -->
-
-<!-- /div -->
-
-
-<!-- div -->
-
-## `“Objects” Methods`
-
<!-- div -->
-### <a id="_assignobject-source-callback-thisarg"></a>`_.assign(object, [source], [callback], [thisArg])`
-<a href="#_assignobject-source-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2084 "View in source") [Ⓣ][1]
+### <a id="_toplainobjectvalue"></a>`_.toPlainObject(value)`
+<a href="#_toplainobjectvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8340 "View in source") [Ⓣ][1]
-Assigns own enumerable properties of source object(s) to the destination object. Subsequent sources will overwrite property assignments of previous sources. If a callback is provided it will be executed to produce the assigned values. The callback is bound to `thisArg` and invoked with two arguments; *(objectValue, sourceValue)*.
-
-#### Aliases
-*_.extend*
+Converts `value` to a plain object flattening inherited enumerable
+properties of `value` to own properties of the plain object.
#### Arguments
-1. `object` *(Object)*: The destination object.
-2. `[source]` *(...Object)*: The source objects.
-3. `[callback]` *(Function)*: The function to customize assigning values.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `value` *(*)*: The value to convert.
#### Returns
-*(Object)*: Returns the destination object.
+*(Object)*: Returns the converted plain object.
#### Example
```js
-_.assign({ 'name': 'fred' }, { 'employer': 'slate' });
-// => { 'name': 'fred', 'employer': 'slate' }
+function Foo() {
+ this.b = 2;
+}
-var defaults = _.partialRight(_.assign, function(a, b) {
- return typeof a == 'undefined' ? b : a;
-});
+Foo.prototype.c = 3;
-var object = { 'name': 'barney' };
-defaults(object, { 'name': 'fred', 'employer': 'slate' });
-// => { 'name': 'barney', 'employer': 'slate' }
-```
+_.assign({ 'a': 1 }, new Foo);
+// => { 'a': 1, 'b': 2 }
+_.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+// => { 'a': 1, 'b': 2, 'c': 3 }
+```
* * *
<!-- /div -->
+<!-- /div -->
+
+<!-- div -->
+
+## `“Number” Methods`
<!-- div -->
-### <a id="_clonevalue-isdeepfalse-callback-thisarg"></a>`_.clone(value, [isDeep=false], [callback], [thisArg])`
-<a href="#_clonevalue-isdeepfalse-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2137 "View in source") [Ⓣ][1]
+### <a id="_randommin0-max1-floating"></a>`_.random([min=0], [max=1], [floating])`
+<a href="#_randommin0-max1-floating">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9227 "View in source") [Ⓣ][1]
-Creates a clone of `value`. If `isDeep` is `true` nested objects will also be cloned, otherwise they will be assigned by reference. If a callback is provided it will be executed to produce the cloned values. If the callback returns `undefined` cloning will be handled by the method instead. The callback is bound to `thisArg` and invoked with one argument; *(value)*.
+Produces a random number between `min` and `max` (inclusive). If only one
+argument is provided a number between `0` and the given number is returned.
+If `floating` is `true`, or either `min` or `max` are floats, a floating-point
+number is returned instead of an integer.
#### Arguments
-1. `value` *(*)*: The value to clone.
-2. `[isDeep=false]` *(boolean)*: Specify a deep clone.
-3. `[callback]` *(Function)*: The function to customize cloning values.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[min=0]` *(number)*: The minimum possible value.
+2. `[max=1]` *(number)*: The maximum possible value.
+3. `[floating]` *(boolean)*: Specify returning a floating-point number.
#### Returns
-*(*)*: Returns the cloned value.
+*(number)*: Returns the random number.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
-];
-
-var shallow = _.clone(characters);
-shallow[0] === characters[0];
-// => true
+_.random(0, 5);
+// => an integer between 0 and 5
-var deep = _.clone(characters, true);
-deep[0] === characters[0];
-// => false
+_.random(5);
+// => also an integer between 0 and 5
-_.mixin({
- 'clone': _.partialRight(_.clone, function(value) {
- return _.isElement(value) ? value.cloneNode(false) : undefined;
- })
-});
+_.random(5, true);
+// => a floating-point number between 0 and 5
-var clone = _.clone(document.body);
-clone.childNodes.length;
-// => 0
+_.random(1.2, 5.2);
+// => a floating-point number between 1.2 and 5.2
```
-
* * *
<!-- /div -->
+<!-- /div -->
<!-- div -->
-### <a id="_clonedeepvalue-callback-thisarg"></a>`_.cloneDeep(value, [callback], [thisArg])`
-<a href="#_clonedeepvalue-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2189 "View in source") [Ⓣ][1]
+## `“Object” Methods`
+
+<!-- div -->
-Creates a deep clone of `value`. If a callback is provided it will be executed to produce the cloned values. If the callback returns `undefined` cloning will be handled by the method instead. The callback is bound to `thisArg` and invoked with one argument; *(value)*.
+### <a id="_assignobject-sources-customizer-thisarg"></a>`_.assign(object, [sources], [customizer], [thisArg])`
+<a href="#_assignobject-sources-customizer-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8375 "View in source") [Ⓣ][1]
-Note: This method is loosely based on the structured clone algorithm. Functions and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and objects created by constructors other than `Object` are cloned to plain `Object` objects. See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
+Assigns own enumerable properties of source object(s) to the destination
+object. Subsequent sources overwrite property assignments of previous sources.
+If `customizer` is provided it is invoked to produce the assigned values.
+The `customizer` is bound to `thisArg` and invoked with five arguments;
+(objectValue, sourceValue, key, object, source).
#### Arguments
-1. `value` *(*)*: The value to deep clone.
-2. `[callback]` *(Function)*: The function to customize cloning values.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `object` *(Object)*: The destination object.
+2. `[sources]` *(...Object)*: The source objects.
+3. `[customizer]` *(Function)*: The function to customize assigning values.
+4. `[thisArg]` *(*)*: The `this` binding of `customizer`.
#### Returns
-*(*)*: Returns the deep cloned value.
+*(Object)*: Returns `object`.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
-];
-
-var deep = _.cloneDeep(characters);
-deep[0] === characters[0];
-// => false
+_.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+// => { 'user': 'fred', 'age': 40 }
-var view = {
- 'label': 'docs',
- 'node': element
-};
-
-var clone = _.cloneDeep(view, function(value) {
- return _.isElement(value) ? value.cloneNode(true) : undefined;
+// using a customizer callback
+var defaults = _.partialRight(_.assign, function(value, other) {
+ return typeof value == 'undefined' ? other : value;
});
-clone.node == view.node;
-// => false
+defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+// => { 'user': 'barney', 'age': 36 }
```
-
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_createprototype-properties"></a>`_.create(prototype, [properties])`
-<a href="#_createprototype-properties">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2224 "View in source") [Ⓣ][1]
+<a href="#_createprototype-properties">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8409 "View in source") [Ⓣ][1]
-Creates an object that inherits from the given `prototype` object. If a `properties` object is provided its own enumerable properties are assigned to the created object.
+Creates an object that inherits from the given `prototype` object. If a
+`properties` object is provided its own enumerable properties are assigned
+to the created object.
#### Arguments
1. `prototype` *(Object)*: The object to inherit from.
2. `[properties]` *(Object)*: The properties to assign to the object.
#### Returns
-*(Object)*: Returns the new object.
+*(Object)*: Returns the new object.
#### Example
```js
@@ -2892,1211 +4521,1528 @@ circle instanceof Circle;
circle instanceof Shape;
// => true
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_defaultsobject-source"></a>`_.defaults(object, [source])`
-<a href="#_defaultsobject-source">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2249 "View in source") [Ⓣ][1]
+### <a id="_defaultsobject-sources"></a>`_.defaults(object, [sources])`
+<a href="#_defaultsobject-sources">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8433 "View in source") [Ⓣ][1]
-Assigns own enumerable properties of source object(s) to the destination object for all destination properties that resolve to `undefined`. Once a property is set, additional defaults of the same property will be ignored.
+Assigns own enumerable properties of source object(s) to the destination
+object for all destination properties that resolve to `undefined`. Once a
+property is set, additional defaults of the same property are ignored.
#### Arguments
1. `object` *(Object)*: The destination object.
-2. `[source]` *(...Object)*: The source objects.
+2. `[sources]` *(...Object)*: The source objects.
#### Returns
-*(Object)*: Returns the destination object.
+*(Object)*: Returns `object`.
#### Example
```js
-var object = { 'name': 'barney' };
-_.defaults(object, { 'name': 'fred', 'employer': 'slate' });
-// => { 'name': 'barney', 'employer': 'slate' }
+_.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+// => { 'user': 'barney', 'age': 36 }
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_findkeyobject-callbackidentity-thisarg"></a>`_.findKey(object, [callback=identity], [thisArg])`
-<a href="#_findkeyobject-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2292 "View in source") [Ⓣ][1]
+### <a id="_findkeyobject-predicate_identity-thisarg"></a>`_.findKey(object, [predicate=_.identity], [thisArg])`
+<a href="#_findkeyobject-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8481 "View in source") [Ⓣ][1]
-This method is like `_.findIndex` except that it returns the key of the first element that passes the callback check, instead of the element itself.
+This method is like `_.findIndex` except that it returns the key of the
+first element `predicate` returns truthy for, instead of the element itself.
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
#### Arguments
1. `object` *(Object)*: The object to search.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(string, undefined)*: Returns the key of the found element, else `undefined`.
+*(string|undefined)*: Returns the key of the matched element, else `undefined`.
#### Example
```js
-var characters = {
- 'barney': { 'age': 36, 'blocked': false },
- 'fred': { 'age': 40, 'blocked': true },
- 'pebbles': { 'age': 1, 'blocked': false }
+var users = {
+ 'barney': { 'age': 36, 'active': true },
+ 'fred': { 'age': 40, 'active': false },
+ 'pebbles': { 'age': 1, 'active': true }
};
-_.findKey(characters, function(chr) {
- return chr.age < 40;
-});
-// => 'barney' (property order is not guaranteed across environments)
+_.findKey(users, function(chr) { return chr.age < 40; });
+// => 'barney' (iteration order is not guaranteed)
-// using "_.where" callback shorthand
-_.findKey(characters, { 'age': 1 });
+// using the "_.matches" callback shorthand
+_.findKey(users, { 'age': 1 });
// => 'pebbles'
-// using "_.pluck" callback shorthand
-_.findKey(characters, 'blocked');
-// => 'fred'
+// using the "_.property" callback shorthand
+_.findKey(users, 'active');
+// => 'barney'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_findlastkeyobject-callbackidentity-thisarg"></a>`_.findLastKey(object, [callback=identity], [thisArg])`
-<a href="#_findlastkeyobject-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2345 "View in source") [Ⓣ][1]
+### <a id="_findlastkeyobject-predicate_identity-thisarg"></a>`_.findLastKey(object, [predicate=_.identity], [thisArg])`
+<a href="#_findlastkeyobject-predicate_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8525 "View in source") [Ⓣ][1]
-This method is like `_.findKey` except that it iterates over elements of a `collection` in the opposite order.
+This method is like `_.findKey` except that it iterates over elements of
+a collection in the opposite order.
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
+If a property name is provided for `predicate` the created "_.property"
+style callback returns the property value of the given element.
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+If an object is provided for `predicate` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
#### Arguments
1. `object` *(Object)*: The object to search.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+2. `[predicate=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(string, undefined)*: Returns the key of the found element, else `undefined`.
+*(string|undefined)*: Returns the key of the matched element, else `undefined`.
#### Example
```js
-var characters = {
- 'barney': { 'age': 36, 'blocked': true },
- 'fred': { 'age': 40, 'blocked': false },
- 'pebbles': { 'age': 1, 'blocked': true }
+var users = {
+ 'barney': { 'age': 36, 'active': true },
+ 'fred': { 'age': 40, 'active': false },
+ 'pebbles': { 'age': 1, 'active': true }
};
-_.findLastKey(characters, function(chr) {
- return chr.age < 40;
-});
-// => returns `pebbles`, assuming `_.findKey` returns `barney`
+_.findLastKey(users, function(chr) { return chr.age < 40; });
+// => returns `pebbles` assuming `_.findKey` returns `barney`
-// using "_.where" callback shorthand
-_.findLastKey(characters, { 'age': 40 });
-// => 'fred'
+// using the "_.matches" callback shorthand
+_.findLastKey(users, { 'age': 36 });
+// => 'barney'
-// using "_.pluck" callback shorthand
-_.findLastKey(characters, 'blocked');
+// using the "_.property" callback shorthand
+_.findLastKey(users, 'active');
// => 'pebbles'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_forinobject-callbackidentity-thisarg"></a>`_.forIn(object, [callback=identity], [thisArg])`
-<a href="#_forinobject-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2388 "View in source") [Ⓣ][1]
+### <a id="_forinobject-iteratee_identity-thisarg"></a>`_.forIn(object, [iteratee=_.identity], [thisArg])`
+<a href="#_forinobject-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8557 "View in source") [Ⓣ][1]
-Iterates over own and inherited enumerable properties of an object, executing the callback for each property. The callback is bound to `thisArg` and invoked with three arguments; *(value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`.
+Iterates over own and inherited enumerable properties of an object invoking
+`iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked
+with three arguments; (value, key, object). Iterator functions may exit
+iteration early by explicitly returning `false`.
#### Arguments
1. `object` *(Object)*: The object to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
#### Returns
-*(Object)*: Returns `object`.
+*(Object)*: Returns `object`.
#### Example
```js
-function Shape() {
- this.x = 0;
- this.y = 0;
+function Foo() {
+ this.a = 1;
+ this.b = 2;
}
-Shape.prototype.move = function(x, y) {
- this.x += x;
- this.y += y;
-};
+Foo.prototype.c = 3;
-_.forIn(new Shape, function(value, key) {
+_.forIn(new Foo, function(value, key) {
console.log(key);
});
-// => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
+// => logs 'a', 'b', and 'c' (iteration order is not guaranteed)
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_forinrightobject-callbackidentity-thisarg"></a>`_.forInRight(object, [callback=identity], [thisArg])`
-<a href="#_forinrightobject-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2420 "View in source") [Ⓣ][1]
+### <a id="_forinrightobject-iteratee_identity-thisarg"></a>`_.forInRight(object, [iteratee=_.identity], [thisArg])`
+<a href="#_forinrightobject-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8589 "View in source") [Ⓣ][1]
-This method is like `_.forIn` except that it iterates over elements of a `collection` in the opposite order.
+This method is like `_.forIn` except that it iterates over properties of
+`object` in the opposite order.
#### Arguments
1. `object` *(Object)*: The object to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
#### Returns
-*(Object)*: Returns `object`.
+*(Object)*: Returns `object`.
#### Example
```js
-function Shape() {
- this.x = 0;
- this.y = 0;
+function Foo() {
+ this.a = 1;
+ this.b = 2;
}
-Shape.prototype.move = function(x, y) {
- this.x += x;
- this.y += y;
-};
+Foo.prototype.c = 3;
-_.forInRight(new Shape, function(value, key) {
+_.forInRight(new Foo, function(value, key) {
console.log(key);
});
-// => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
+// => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_forownobject-callbackidentity-thisarg"></a>`_.forOwn(object, [callback=identity], [thisArg])`
-<a href="#_forownobject-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2458 "View in source") [Ⓣ][1]
+### <a id="_forownobject-iteratee_identity-thisarg"></a>`_.forOwn(object, [iteratee=_.identity], [thisArg])`
+<a href="#_forownobject-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8614 "View in source") [Ⓣ][1]
-Iterates over own enumerable properties of an object, executing the callback for each property. The callback is bound to `thisArg` and invoked with three arguments; *(value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`.
+Iterates over own enumerable properties of an object invoking `iteratee`
+for each property. The `iteratee` is bound to `thisArg` and invoked with
+three arguments; (value, key, object). Iterator functions may exit iteration
+early by explicitly returning `false`.
#### Arguments
1. `object` *(Object)*: The object to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
#### Returns
-*(Object)*: Returns `object`.
+*(Object)*: Returns `object`.
#### Example
```js
-_.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
+_.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
console.log(key);
});
-// => logs '0', '1', and 'length' (property order is not guaranteed across environments)
+// => logs '0', '1', and 'length' (iteration order is not guaranteed)
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_forownrightobject-callbackidentity-thisarg"></a>`_.forOwnRight(object, [callback=identity], [thisArg])`
-<a href="#_forownrightobject-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2478 "View in source") [Ⓣ][1]
+### <a id="_forownrightobject-iteratee_identity-thisarg"></a>`_.forOwnRight(object, [iteratee=_.identity], [thisArg])`
+<a href="#_forownrightobject-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8639 "View in source") [Ⓣ][1]
-This method is like `_.forOwn` except that it iterates over elements of a `collection` in the opposite order.
+This method is like `_.forOwn` except that it iterates over properties of
+`object` in the opposite order.
#### Arguments
1. `object` *(Object)*: The object to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
#### Returns
-*(Object)*: Returns `object`.
+*(Object)*: Returns `object`.
#### Example
```js
-_.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
+_.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
console.log(key);
});
// => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
```
-
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_functionsobject"></a>`_.functions(object)`
-<a href="#_functionsobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2507 "View in source") [Ⓣ][1]
+<a href="#_functionsobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8659 "View in source") [Ⓣ][1]
-Creates a sorted array of property names of all enumerable properties, own and inherited, of `object` that have function values.
-
-#### Aliases
-*_.methods*
+Creates an array of function property names from all enumerable properties,
+own and inherited, of `object`.
#### Arguments
1. `object` *(Object)*: The object to inspect.
#### Returns
-*(Array)*: Returns an array of property names that have function values.
+*(Array)*: Returns the new array of property names.
#### Example
```js
_.functions(_);
-// => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
+// => ['all', 'any', 'bind', ...]
```
-
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_hasobject-key"></a>`_.has(object, key)`
-<a href="#_hasobject-key">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2532 "View in source") [Ⓣ][1]
+<a href="#_hasobject-key">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8678 "View in source") [Ⓣ][1]
-Checks if the specified property name exists as a direct property of `object`, instead of an inherited property.
+Checks if `key` exists as a direct property of `object` instead of an
+inherited property.
#### Arguments
1. `object` *(Object)*: The object to inspect.
-2. `key` *(string)*: The name of the property to check.
+2. `key` *(string)*: The key to check.
#### Returns
-*(boolean)*: Returns `true` if key is a direct property, else `false`.
+*(boolean)*: Returns `true` if `key` is a direct property, else `false`.
#### Example
```js
_.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
// => true
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_invertobject"></a>`_.invert(object)`
-<a href="#_invertobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2549 "View in source") [Ⓣ][1]
+### <a id="_invertobject-multivalue"></a>`_.invert(object, [multiValue])`
+<a href="#_invertobject-multivalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8707 "View in source") [Ⓣ][1]
-Creates an object composed of the inverted keys and values of the given object.
+Creates an object composed of the inverted keys and values of `object`.
+If `object` contains duplicate values, subsequent values overwrite property
+assignments of previous values unless `multiValue` is `true`.
#### Arguments
1. `object` *(Object)*: The object to invert.
+2. `[multiValue]` *(boolean)*: Allow multiple values per key.
#### Returns
-*(Object)*: Returns the created inverted object.
+*(Object)*: Returns the new inverted object.
#### Example
```js
_.invert({ 'first': 'fred', 'second': 'barney' });
// => { 'fred': 'first', 'barney': 'second' }
+
+// without `multiValue`
+_.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' });
+// => { 'fred': 'third', 'barney': 'second' }
+
+// with `multiValue`
+_.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }, true);
+// => { 'fred': ['first', 'third'], 'barney': ['second'] }
+```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_keysobject"></a>`_.keys(object)`
+<a href="#_keysobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8761 "View in source") [Ⓣ][1]
+
+Creates an array of the own enumerable property names of `object`.
+ *Note:** Non-object values are coerced to objects. See the
+[ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
+for more details.
+
+#### Arguments
+1. `object` *(Object)*: The object to inspect.
+
+#### Returns
+*(Array)*: Returns the array of property names.
+
+#### Example
+```js
+function Foo() {
+ this.a = 1;
+ this.b = 2;
+}
+
+Foo.prototype.c = 3;
+
+_.keys(new Foo);
+// => ['a', 'b'] (iteration order is not guaranteed)
+
+_.keys('hi');
+// => ['0', '1']
```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_keysinobject"></a>`_.keysIn(object)`
+<a href="#_keysinobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8795 "View in source") [Ⓣ][1]
+
+Creates an array of the own and inherited enumerable property names of `object`.
+ *Note:** Non-object values are coerced to objects.
+
+#### Arguments
+1. `object` *(Object)*: The object to inspect.
+
+#### Returns
+*(Array)*: Returns the array of property names.
+
+#### Example
+```js
+function Foo() {
+ this.a = 1;
+ this.b = 2;
+}
+Foo.prototype.c = 3;
+
+_.keysIn(new Foo);
+// => ['a', 'b', 'c'] (iteration order is not guaranteed)
+```
* * *
<!-- /div -->
+<!-- div -->
+
+### <a id="_mapvaluesobject-iteratee_identity-thisarg"></a>`_.mapValues(object, [iteratee=_.identity], [thisArg])`
+<a href="#_mapvaluesobject-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8889 "View in source") [Ⓣ][1]
+
+Creates an object with the same keys as `object` and values generated by
+running each own enumerable property of `object` through `iteratee`. The
+iteratee function is bound to `thisArg` and invoked with three arguments;
+(value, key, object).
+
+If a property name is provided for `iteratee` the created "_.property"
+style callback returns the property value of the given element.
+
+If an object is provided for `iteratee` the created "_.matches" style
+callback returns `true` for elements that have the properties of the given
+object, else `false`.
+
+#### Arguments
+1. `object` *(Object)*: The object to iterate over.
+2. `[iteratee=_.identity]` *(Function|Object|string)*: The function invoked per iteration. If a property name or object is provided it is used to create a "_.property" or "_.matches" style callback respectively.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
+
+#### Returns
+*(Object)*: Returns the new mapped object.
+
+#### Example
+```js
+_.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(n) { return n * 3; });
+// => { 'a': 3, 'b': 6, 'c': 9 }
+
+var users = {
+ 'fred': { 'user': 'fred', 'age': 40 },
+ 'pebbles': { 'user': 'pebbles', 'age': 1 }
+};
+
+// using the "_.property" callback shorthand
+_.mapValues(users, 'age');
+// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+```
+* * *
+
+<!-- /div -->
<!-- div -->
-### <a id="_isargumentsvalue"></a>`_.isArguments(value)`
-<a href="#_isargumentsvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L1909 "View in source") [Ⓣ][1]
+### <a id="_mergeobject-sources-customizer-thisarg"></a>`_.merge(object, [sources], [customizer], [thisArg])`
+<a href="#_mergeobject-sources-customizer-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8945 "View in source") [Ⓣ][1]
-Checks if `value` is an `arguments` object.
+Recursively merges own enumerable properties of the source object(s), that
+don't resolve to `undefined` into the destination object. Subsequent sources
+overwrite property assignments of previous sources. If `customizer` is
+provided it is invoked to produce the merged values of the destination and
+source properties. If `customizer` returns `undefined` merging is handled
+by the method instead. The `customizer` is bound to `thisArg` and invoked
+with five arguments; (objectValue, sourceValue, key, object, source).
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `object` *(Object)*: The destination object.
+2. `[sources]` *(...Object)*: The source objects.
+3. `[customizer]` *(Function)*: The function to customize merging properties.
+4. `[thisArg]` *(*)*: The `this` binding of `customizer`.
#### Returns
-*(boolean)*: Returns `true` if the `value` is an `arguments` object, else `false`.
+*(Object)*: Returns `object`.
#### Example
```js
-(function() { return _.isArguments(arguments); })(1, 2, 3);
-// => true
+var users = {
+ 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
+};
-_.isArguments([1, 2, 3]);
-// => false
+var ages = {
+ 'data': [{ 'age': 36 }, { 'age': 40 }]
+};
+
+_.merge(users, ages);
+// => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
+
+// using a customizer callback
+var object = {
+ 'fruits': ['apple'],
+ 'vegetables': ['beet']
+};
+
+var other = {
+ 'fruits': ['banana'],
+ 'vegetables': ['carrot']
+};
+
+_.merge(object, other, function(a, b) {
+ return _.isArray(a) ? a.concat(b) : undefined;
+});
+// => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_omitobject-predicate-thisarg"></a>`_.omit(object, [predicate], [thisArg])`
+<a href="#_omitobject-predicate-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L8975 "View in source") [Ⓣ][1]
+
+The opposite of `_.pick`; this method creates an object composed of the
+own and inherited enumerable properties of `object` that are not omitted.
+Property names may be specified as individual arguments or as arrays of
+property names. If `predicate` is provided it is invoked for each property
+of `object` omitting the properties `predicate` returns truthy for. The
+predicate is bound to `thisArg` and invoked with three arguments;
+(value, key, object).
+
+#### Arguments
+1. `object` *(Object)*: The source object.
+2. `[predicate]` *(Function|...(string|string[])*: The function invoked per iteration or property names to omit, specified as individual property names or arrays of property names.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
+
+#### Returns
+*(Object)*: Returns the new object.
+
+#### Example
+```js
+var object = { 'user': 'fred', 'age': 40 };
+_.omit(object, 'age');
+// => { 'user': 'fred' }
+
+_.omit(object, _.isNumber);
+// => { 'user': 'fred' }
+```
* * *
<!-- /div -->
+<!-- div -->
+
+### <a id="_pairsobject"></a>`_.pairs(object)`
+<a href="#_pairsobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9003 "View in source") [Ⓣ][1]
+
+Creates a two dimensional array of the key-value pairs for `object`,
+e.g. `[[key1, value1], [key2, value2]]`.
+
+#### Arguments
+1. `object` *(Object)*: The object to inspect.
+
+#### Returns
+*(Array)*: Returns the new array of key-value pairs.
+
+#### Example
+```js
+_.pairs({ 'barney': 36, 'fred': 40 });
+// => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
+```
+* * *
+
+<!-- /div -->
<!-- div -->
-### <a id="_isarrayvalue"></a>`_.isArray(value)`
-<a href="#_isarrayvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L1938 "View in source") [Ⓣ][1]
+### <a id="_pickobject-predicate-thisarg"></a>`_.pick(object, [predicate], [thisArg])`
+<a href="#_pickobject-predicate-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9042 "View in source") [Ⓣ][1]
-Checks if `value` is an array.
+Creates an object composed of the picked `object` properties. Property
+names may be specified as individual arguments or as arrays of property
+names. If `predicate` is provided it is invoked for each property of `object`
+picking the properties `predicate` returns truthy for. The predicate is
+bound to `thisArg` and invoked with three arguments; (value, key, object).
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `object` *(Object)*: The source object.
+2. `[predicate]` *(Function|...(string|string[])*: The function invoked per iteration or property names to pick, specified as individual property names or arrays of property names.
+3. `[thisArg]` *(*)*: The `this` binding of `predicate`.
#### Returns
-*(boolean)*: Returns `true` if the `value` is an array, else `false`.
+*(Object)*: Returns the new object.
#### Example
```js
-(function() { return _.isArray(arguments); })();
-// => false
+var object = { 'user': 'fred', 'age': 40 };
-_.isArray([1, 2, 3]);
-// => true
+_.pick(object, 'user');
+// => { 'user': 'fred' }
+
+_.pick(object, _.isString);
+// => { 'user': 'fred' }
```
+* * *
+
+<!-- /div -->
+
+<!-- div -->
+
+### <a id="_resultobject-key-defaultvalue"></a>`_.result(object, key, [defaultValue])`
+<a href="#_resultobject-key-defaultvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9081 "View in source") [Ⓣ][1]
+
+Resolves the value of property `key` on `object`. If the value of `key` is
+a function it is invoked with the `this` binding of `object` and its result
+is returned, else the property value is returned. If the property value is
+`undefined` the `defaultValue` is used in its place.
+
+#### Arguments
+1. `object` *(Object)*: The object to query.
+2. `key` *(string)*: The key of the property to resolve.
+3. `[defaultValue]` *(*)*: The value returned if the property value resolves to `undefined`.
+
+#### Returns
+*(*)*: Returns the resolved value.
+
+#### Example
+```js
+var object = { 'user': 'fred', 'age': _.constant(40) };
+
+_.result(object, 'user');
+// => 'fred'
+
+_.result(object, 'age');
+// => 40
+_.result(object, 'status', 'busy');
+// => 'busy'
+
+_.result(object, 'status', _.constant('busy'));
+// => 'busy'
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isbooleanvalue"></a>`_.isBoolean(value)`
-<a href="#_isbooleanvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2575 "View in source") [Ⓣ][1]
+### <a id="_transformobject-iteratee_identity-accumulator-thisarg"></a>`_.transform(object, [iteratee=_.identity], [accumulator], [thisArg])`
+<a href="#_transformobject-iteratee_identity-accumulator-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9120 "View in source") [Ⓣ][1]
-Checks if `value` is a boolean value.
+An alternative to `_.reduce`; this method transforms `object` to a new
+`accumulator` object which is the result of running each of its own enumerable
+properties through `iteratee`, with each invocation potentially mutating
+the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked
+with four arguments; (accumulator, value, key, object). Iterator functions
+may exit iteration early by explicitly returning `false`.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `object` *(Array|Object)*: The object to iterate over.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[accumulator]` *(*)*: The custom accumulator value.
+4. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
#### Returns
-*(boolean)*: Returns `true` if the `value` is a boolean value, else `false`.
+*(*)*: Returns the accumulated value.
#### Example
```js
-_.isBoolean(null);
-// => false
-```
+var squares = _.transform([1, 2, 3, 4, 5, 6], function(result, n) {
+ n *= n;
+ if (n % 2) {
+ return result.push(n) < 3;
+ }
+});
+// => [1, 9, 25]
+var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ result[key] = n * 3;
+});
+// => { 'a': 3, 'b': 6, 'c': 9 }
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isdatevalue"></a>`_.isDate(value)`
-<a href="#_isdatevalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2593 "View in source") [Ⓣ][1]
+### <a id="_valuesobject"></a>`_.values(object)`
+<a href="#_valuesobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9167 "View in source") [Ⓣ][1]
-Checks if `value` is a date.
+Creates an array of the own enumerable property values of `object`.
+ *Note:** Non-object values are coerced to objects.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `object` *(Object)*: The object to query.
#### Returns
-*(boolean)*: Returns `true` if the `value` is a date, else `false`.
+*(Array)*: Returns the array of property values.
#### Example
```js
-_.isDate(new Date);
-// => true
-```
+function Foo() {
+ this.a = 1;
+ this.b = 2;
+}
+Foo.prototype.c = 3;
+
+_.values(new Foo);
+// => [1, 2] (iteration order is not guaranteed)
+
+_.values('hi');
+// => ['h', 'i']
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_iselementvalue"></a>`_.isElement(value)`
-<a href="#_iselementvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2610 "View in source") [Ⓣ][1]
+### <a id="_valuesinobject"></a>`_.valuesIn(object)`
+<a href="#_valuesinobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9194 "View in source") [Ⓣ][1]
-Checks if `value` is a DOM element.
+Creates an array of the own and inherited enumerable property values
+of `object`.
+ *Note:** Non-object values are coerced to objects.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `object` *(Object)*: The object to query.
#### Returns
-*(boolean)*: Returns `true` if the `value` is a DOM element, else `false`.
+*(Array)*: Returns the array of property values.
#### Example
```js
-_.isElement(document.body);
-// => true
-```
+function Foo() {
+ this.a = 1;
+ this.b = 2;
+}
+
+Foo.prototype.c = 3;
+_.valuesIn(new Foo);
+// => [1, 2, 3] (iteration order is not guaranteed)
+```
* * *
<!-- /div -->
+<!-- /div -->
<!-- div -->
-### <a id="_isemptyvalue"></a>`_.isEmpty(value)`
-<a href="#_isemptyvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2635 "View in source") [Ⓣ][1]
+## `“String” Methods`
+
+<!-- div -->
+
+### <a id="_camelcasestring"></a>`_.camelCase([string=''])`
+<a href="#_camelcasestring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9284 "View in source") [Ⓣ][1]
-Checks if `value` is empty. Arrays, strings, or `arguments` objects with a length of `0` and objects with no own enumerable properties are considered "empty".
+Converts `string` to camel case.
+See [Wikipedia](http://en.wikipedia.org/wiki/CamelCase) for more details.
#### Arguments
-1. `value` *(Array|Object|string)*: The value to inspect.
+1. `[string='']` *(string)*: The string to convert.
#### Returns
-*(boolean)*: Returns `true` if the `value` is empty, else `false`.
+*(string)*: Returns the camel cased string.
#### Example
```js
-_.isEmpty([1, 2, 3]);
-// => false
+_.camelCase('Foo Bar');
+// => 'fooBar'
-_.isEmpty({});
-// => true
+_.camelCase('--foo-bar');
+// => 'fooBar'
-_.isEmpty('');
-// => true
+_.camelCase('__foo_bar__');
+// => 'fooBar'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isequala-b-callback-thisarg"></a>`_.isEqual(a, b, [callback], [thisArg])`
-<a href="#_isequala-b-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2692 "View in source") [Ⓣ][1]
+### <a id="_capitalizestring"></a>`_.capitalize([string=''])`
+<a href="#_capitalizestring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9302 "View in source") [Ⓣ][1]
-Performs a deep comparison between two values to determine if they are equivalent to each other. If a callback is provided it will be executed to compare values. If the callback returns `undefined` comparisons will be handled by the method instead. The callback is bound to `thisArg` and invoked with two arguments; *(a, b)*.
+Capitalizes the first character of `string`.
#### Arguments
-1. `a` *(*)*: The value to compare.
-2. `b` *(*)*: The other value to compare.
-3. `[callback]` *(Function)*: The function to customize comparing values.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[string='']` *(string)*: The string to capitalize.
#### Returns
-*(boolean)*: Returns `true` if the values are equivalent, else `false`.
+*(string)*: Returns the capitalized string.
#### Example
```js
-var object = { 'name': 'fred' };
-var copy = { 'name': 'fred' };
-
-object == copy;
-// => false
-
-_.isEqual(object, copy);
-// => true
-
-var words = ['hello', 'goodbye'];
-var otherWords = ['hi', 'goodbye'];
-
-_.isEqual(words, otherWords, function(a, b) {
- var reGreet = /^(?:hello|hi)$/i,
- aGreet = _.isString(a) && reGreet.test(a),
- bGreet = _.isString(b) && reGreet.test(b);
-
- return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
-});
-// => true
+_.capitalize('fred');
+// => 'Fred'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isfinitevalue"></a>`_.isFinite(value)`
-<a href="#_isfinitevalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2724 "View in source") [Ⓣ][1]
-
-Checks if `value` is, or can be coerced to, a finite number.
+### <a id="_deburrstring"></a>`_.deburr([string=''])`
+<a href="#_deburrstring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9322 "View in source") [Ⓣ][1]
-Note: This is not the same as native `isFinite` which will return true for booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
+Deburrs `string` by converting latin-1 supplementary letters to basic latin letters.
+See [Wikipedia](http://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+for more details.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to deburr.
#### Returns
-*(boolean)*: Returns `true` if the `value` is finite, else `false`.
+*(string)*: Returns the deburred string.
#### Example
```js
-_.isFinite(-101);
-// => true
-
-_.isFinite('10');
-// => true
-
-_.isFinite(true);
-// => false
-
-_.isFinite('');
-// => false
-
-_.isFinite(Infinity);
-// => false
+_.deburr('déjà vu');
+// => 'deja vu'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isfunctionvalue"></a>`_.isFunction(value)`
-<a href="#_isfunctionvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2741 "View in source") [Ⓣ][1]
+### <a id="_endswithstring-target-positionstringlength"></a>`_.endsWith([string=''], [target], [position=string.length])`
+<a href="#_endswithstring-target-positionstringlength">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9348 "View in source") [Ⓣ][1]
-Checks if `value` is a function.
+Checks if `string` ends with the given target string.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to search.
+2. `[target]` *(string)*: The string to search for.
+3. `[position=string.length]` *(number)*: The position to search from.
#### Returns
-*(boolean)*: Returns `true` if the `value` is a function, else `false`.
+*(boolean)*: Returns `true` if `string` ends with `target`, else `false`.
#### Example
```js
-_.isFunction(_);
+_.endsWith('abc', 'c');
// => true
-```
+_.endsWith('abc', 'b');
+// => false
+
+_.endsWith('abc', 'b', 2);
+// => true
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isnanvalue"></a>`_.isNaN(value)`
-<a href="#_isnanvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2804 "View in source") [Ⓣ][1]
+### <a id="_escapestring"></a>`_.escape([string=''])`
+<a href="#_escapestring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9389 "View in source") [Ⓣ][1]
-Checks if `value` is `NaN`.
+Converts the characters "&", "<", ">", '"', "'", and '`', in `string` to
+their corresponding HTML entities.
+ *Note:** No other characters are escaped. To escape additional characters
+use a third-party library like [_he_](http://mths.be/he).
+
+Though the ">" character is escaped for symmetry, characters like
+">" and "/" don't require escaping in HTML and have no special meaning
+unless they're part of a tag or unquoted attribute value.
+See [Mathias Bynens's article](http://mathiasbynens.be/notes/ambiguous-ampersands)
+(under "semi-related fun fact") for more details.
+
+Backticks are escaped because in Internet Explorer < 9, they can break out
+of attribute values or HTML comments. See [#102](http://html5sec.org/#102),
+[#108](http://html5sec.org/#108), and [#133](http://html5sec.org/#133) of
+the [HTML5 Security Cheatsheet](http://html5sec.org/) for more details.
-Note: This is not the same as native `isNaN` which will return `true` for `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
+When working with HTML you should always quote attribute values to reduce
+XSS vectors. See [Ryan Grove's article](http://wonko.com/post/html-escaping)
+for more details.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to escape.
#### Returns
-*(boolean)*: Returns `true` if the `value` is `NaN`, else `false`.
+*(string)*: Returns the escaped string.
#### Example
```js
-_.isNaN(NaN);
-// => true
-
-_.isNaN(new Number(NaN));
-// => true
-
-isNaN(undefined);
-// => true
-
-_.isNaN(undefined);
-// => false
+_.escape('fred, barney, & pebbles');
+// => 'fred, barney, & pebbles'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isnullvalue"></a>`_.isNull(value)`
-<a href="#_isnullvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2826 "View in source") [Ⓣ][1]
+### <a id="_escaperegexpstring"></a>`_.escapeRegExp([string=''])`
+<a href="#_escaperegexpstring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9411 "View in source") [Ⓣ][1]
-Checks if `value` is `null`.
+Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*",
+"+", "(", ")", "[", "]", "{" and "}" in `string`.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to escape.
#### Returns
-*(boolean)*: Returns `true` if the `value` is `null`, else `false`.
+*(string)*: Returns the escaped string.
#### Example
```js
-_.isNull(null);
-// => true
-
-_.isNull(undefined);
-// => false
+_.escapeRegExp('[lodash](https://lodash.com/)');
+// => '\[lodash\]\(https://lodash\.com/\)'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isnumbervalue"></a>`_.isNumber(value)`
-<a href="#_isnumbervalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2845 "View in source") [Ⓣ][1]
-
-Checks if `value` is a number.
+### <a id="_kebabcasestring"></a>`_.kebabCase([string=''])`
+<a href="#_kebabcasestring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9439 "View in source") [Ⓣ][1]
-Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
+Converts `string` to kebab case (a.k.a. spinal case).
+See [Wikipedia](http://en.wikipedia.org/wiki/Letter_case#Computers) for
+more details.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to convert.
#### Returns
-*(boolean)*: Returns `true` if the `value` is a number, else `false`.
+*(string)*: Returns the kebab cased string.
#### Example
```js
-_.isNumber(8.4 * 5);
-// => true
-```
+_.kebabCase('Foo Bar');
+// => 'foo-bar'
+_.kebabCase('fooBar');
+// => 'foo-bar'
+
+_.kebabCase('__foo_bar__');
+// => 'foo-bar'
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isobjectvalue"></a>`_.isObject(value)`
-<a href="#_isobjectvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2771 "View in source") [Ⓣ][1]
+### <a id="_padstring-length0-chars"></a>`_.pad([string=''], [length=0], [chars=' '])`
+<a href="#_padstring-length0-chars">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9466 "View in source") [Ⓣ][1]
-Checks if `value` is the language type of Object. *(e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)*
+Pads `string` on the left and right sides if it is shorter then the given
+padding length. The `chars` string may be truncated if the number of padding
+characters can't be evenly divided by the padding length.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to pad.
+2. `[length=0]` *(number)*: The padding length.
+3. `[chars=' ']` *(string)*: The string used as padding.
#### Returns
-*(boolean)*: Returns `true` if the `value` is an object, else `false`.
+*(string)*: Returns the padded string.
#### Example
```js
-_.isObject({});
-// => true
+_.pad('abc', 8);
+// => ' abc '
-_.isObject([1, 2, 3]);
-// => true
+_.pad('abc', 8, '_-');
+// => '_-abc_-_'
-_.isObject(1);
-// => false
+_.pad('abc', 3);
+// => 'abc'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isplainobjectvalue"></a>`_.isPlainObject(value)`
-<a href="#_isplainobjectvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2874 "View in source") [Ⓣ][1]
+### <a id="_padleftstring-length0-chars"></a>`_.padLeft([string=''], [length=0], [chars=' '])`
+<a href="#_padleftstring-length0-chars">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9505 "View in source") [Ⓣ][1]
-Checks if `value` is an object created by the `Object` constructor.
+Pads `string` on the left side if it is shorter then the given padding
+length. The `chars` string may be truncated if the number of padding
+characters exceeds the padding length.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to pad.
+2. `[length=0]` *(number)*: The padding length.
+3. `[chars=' ']` *(string)*: The string used as padding.
#### Returns
-*(boolean)*: Returns `true` if `value` is a plain object, else `false`.
+*(string)*: Returns the padded string.
#### Example
```js
-function Shape() {
- this.x = 0;
- this.y = 0;
-}
-
-_.isPlainObject(new Shape);
-// => false
+_.padLeft('abc', 6);
+// => ' abc'
-_.isPlainObject([1, 2, 3]);
-// => false
+_.padLeft('abc', 6, '_-');
+// => '_-_abc'
-_.isPlainObject({ 'x': 0, 'y': 0 });
-// => true
+_.padLeft('abc', 3);
+// => 'abc'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isregexpvalue"></a>`_.isRegExp(value)`
-<a href="#_isregexpvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2899 "View in source") [Ⓣ][1]
+### <a id="_padrightstring-length0-chars"></a>`_.padRight([string=''], [length=0], [chars=' '])`
+<a href="#_padrightstring-length0-chars">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9533 "View in source") [Ⓣ][1]
-Checks if `value` is a regular expression.
+Pads `string` on the right side if it is shorter then the given padding
+length. The `chars` string may be truncated if the number of padding
+characters exceeds the padding length.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to pad.
+2. `[length=0]` *(number)*: The padding length.
+3. `[chars=' ']` *(string)*: The string used as padding.
#### Returns
-*(boolean)*: Returns `true` if the `value` is a regular expression, else `false`.
+*(string)*: Returns the padded string.
#### Example
```js
-_.isRegExp(/fred/);
-// => true
-```
+_.padRight('abc', 6);
+// => 'abc '
+
+_.padRight('abc', 6, '_-');
+// => 'abc_-_'
+_.padRight('abc', 3);
+// => 'abc'
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isstringvalue"></a>`_.isString(value)`
-<a href="#_isstringvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2916 "View in source") [Ⓣ][1]
+### <a id="_parseintstring-radix"></a>`_.parseInt(string, [radix])`
+<a href="#_parseintstring-radix">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9561 "View in source") [Ⓣ][1]
-Checks if `value` is a string.
+Converts `string` to an integer of the specified radix. If `radix` is
+`undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal,
+in which case a `radix` of `16` is used.
+ *Note:** This method aligns with the ES5 implementation of `parseInt`.
+See the [ES5 spec](http://es5.github.io/#E) for more details.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `string` *(string)*: The string to convert.
+2. `[radix]` *(number)*: The radix to interpret `value` by.
#### Returns
-*(boolean)*: Returns `true` if the `value` is a string, else `false`.
+*(number)*: Returns the converted integer.
#### Example
```js
-_.isString('fred');
-// => true
-```
+_.parseInt('08');
+// => 8
+_.map(['6', '08', '10'], _.parseInt);
+// => [6, 8, 10]
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_isundefinedvalue"></a>`_.isUndefined(value)`
-<a href="#_isundefinedvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2934 "View in source") [Ⓣ][1]
+### <a id="_repeatstring-n0"></a>`_.repeat([string=''], [n=0])`
+<a href="#_repeatstring-n0">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9603 "View in source") [Ⓣ][1]
-Checks if `value` is `undefined`.
+Repeats the given string `n` times.
#### Arguments
-1. `value` *(*)*: The value to check.
+1. `[string='']` *(string)*: The string to repeat.
+2. `[n=0]` *(number)*: The number of times to repeat the string.
#### Returns
-*(boolean)*: Returns `true` if the `value` is `undefined`, else `false`.
+*(string)*: Returns the repeated string.
#### Example
```js
-_.isUndefined(void 0);
-// => true
-```
+_.repeat('*', 3);
+// => '***'
+_.repeat('abc', 2);
+// => 'abcabc'
+
+_.repeat('abc', 0);
+// => ''
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_keysobject"></a>`_.keys(object)`
-<a href="#_keysobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L1972 "View in source") [Ⓣ][1]
+### <a id="_snakecasestring"></a>`_.snakeCase([string=''])`
+<a href="#_snakecasestring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9643 "View in source") [Ⓣ][1]
-Creates an array composed of the own enumerable property names of an object.
+Converts `string` to snake case.
+See [Wikipedia](http://en.wikipedia.org/wiki/Snake_case) for more details.
#### Arguments
-1. `object` *(Object)*: The object to inspect.
+1. `[string='']` *(string)*: The string to convert.
#### Returns
-*(Array)*: Returns an array of property names.
+*(string)*: Returns the snake cased string.
#### Example
```js
-_.keys({ 'one': 1, 'two': 2, 'three': 3 });
-// => ['one', 'two', 'three'] (property order is not guaranteed across environments)
-```
+_.snakeCase('Foo Bar');
+// => 'foo_bar'
+_.snakeCase('--foo-bar');
+// => 'foo_bar'
+
+_.snakeCase('fooBar');
+// => 'foo_bar'
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_mapvaluesobject-callbackidentity-thisarg"></a>`_.mapValues(object, [callback=identity], [thisArg])`
-<a href="#_mapvaluesobject-callbackidentity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L2974 "View in source") [Ⓣ][1]
-
-Creates an object with the same keys as `object` and values generated by running each own enumerable property of `object` through the callback. The callback is bound to `thisArg` and invoked with three arguments; *(value, key, object)*.
+### <a id="_startswithstring-target-position0"></a>`_.startsWith([string=''], [target], [position=0])`
+<a href="#_startswithstring-target-position0">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9668 "View in source") [Ⓣ][1]
-If a property name is provided for `callback` the created "_.pluck" style callback will return the property value of the given element.
-
-If an object is provided for `callback` the created "_.where" style callback will return `true` for elements that have the properties of the given object, else `false`.
+Checks if `string` starts with the given target string.
#### Arguments
-1. `object` *(Object)*: The object to iterate over.
-2. `[callback=identity]` *(Function|Object|string)*: The function called per iteration. If a property name or object is provided it will be used to create a "_.pluck" or "_.where" style callback, respectively.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[string='']` *(string)*: The string to search.
+2. `[target]` *(string)*: The string to search for.
+3. `[position=0]` *(number)*: The position to search from.
#### Returns
-*(Array)*: Returns a new object with values of the results of each `callback` execution.
+*(boolean)*: Returns `true` if `string` starts with `target`, else `false`.
#### Example
```js
-_.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
-// => { 'a': 3, 'b': 6, 'c': 9 }
+_.startsWith('abc', 'a');
+// => true
-var characters = {
- 'fred': { 'name': 'fred', 'age': 40 },
- 'pebbles': { 'name': 'pebbles', 'age': 1 }
-};
+_.startsWith('abc', 'b');
+// => false
-// using "_.pluck" callback shorthand
-_.mapValues(characters, 'age');
-// => { 'fred': 40, 'pebbles': 1 }
+_.startsWith('abc', 'b', 1);
+// => true
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_mergeobject-source-callback-thisarg"></a>`_.merge(object, [source], [callback], [thisArg])`
-<a href="#_mergeobject-source-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3035 "View in source") [Ⓣ][1]
+### <a id="_templatestring-options-optionsescape-optionsevaluate-optionsimports-optionsinterpolate-optionssourceurl-optionsvariable"></a>`_.template([string=''], [options], [options.escape], [options.evaluate], [options.imports], [options.interpolate], [options.sourceURL], [options.variable])`
+<a href="#_templatestring-options-optionsescape-optionsevaluate-optionsimports-optionsinterpolate-optionssourceurl-optionsvariable">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9770 "View in source") [Ⓣ][1]
+
+Creates a compiled template function that can interpolate data properties
+in "interpolate" delimiters, HTML-escape interpolated data properties in
+"escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+properties may be accessed as free variables in the template. If a setting
+object is provided it takes precedence over `_.templateSettings` values.
+ *Note:** In the development build `_.template` utilizes sourceURLs for easier debugging.
+See the [HTML5 Rocks article on sourcemaps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+for more details.
-Recursively merges own enumerable properties of the source object(s), that don't resolve to `undefined` into the destination object. Subsequent sources will overwrite property assignments of previous sources. If a callback is provided it will be executed to produce the merged values of the destination and source properties. If the callback returns `undefined` merging will be handled by the method instead. The callback is bound to `thisArg` and invoked with two arguments; *(objectValue, s [...]
+For more information on precompiling templates see
+[Lo-Dash's custom builds documentation](https://lodash.com/custom-builds).
+
+For more information on Chrome extension sandboxes see
+[Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
#### Arguments
-1. `object` *(Object)*: The destination object.
-2. `[source]` *(...Object)*: The source objects.
-3. `[callback]` *(Function)*: The function to customize merging properties.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[string='']` *(string)*: The template string.
+2. `[options]` *(Object)*: The options object.
+3. `[options.escape]` *(RegExp)*: The HTML "escape" delimiter.
+4. `[options.evaluate]` *(RegExp)*: The "evaluate" delimiter.
+5. `[options.imports]` *(Object)*: An object to import into the template as free variables.
+6. `[options.interpolate]` *(RegExp)*: The "interpolate" delimiter.
+7. `[options.sourceURL]` *(string)*: The sourceURL of the template's compiled source.
+8. `[options.variable]` *(string)*: The data object variable name.
#### Returns
-*(Object)*: Returns the destination object.
+*(Function)*: Returns the compiled template function.
#### Example
```js
-var names = {
- 'characters': [
- { 'name': 'barney' },
- { 'name': 'fred' }
- ]
-};
+// using the "interpolate" delimiter to create a compiled template
+var compiled = _.template('hello <%= user %>!');
+compiled({ 'user': 'fred' });
+// => 'hello fred!'
-var ages = {
- 'characters': [
- { 'age': 36 },
- { 'age': 40 }
- ]
-};
+// using the HTML "escape" delimiter to escape data property values
+var compiled = _.template('<b><%- value %></b>');
+compiled({ 'value': '<script>' });
+// => '<b><script></b>'
-_.merge(names, ages);
-// => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
+// using the "evaluate" delimiter to execute JavaScript and generate HTML
+var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
+compiled({ 'users': ['fred', 'barney'] });
+// => '<li>fred</li><li>barney</li>'
-var food = {
- 'fruits': ['apple'],
- 'vegetables': ['beet']
-};
+// using the internal `print` function in "evaluate" delimiters
+var compiled = _.template('<% print("hello " + user); %>!');
+compiled({ 'user': 'barney' });
+// => 'hello barney!'
-var otherFood = {
- 'fruits': ['banana'],
- 'vegetables': ['carrot']
-};
+// using the ES6 delimiter as an alternative to the default "interpolate" delimiter
+var compiled = _.template('hello ${ user }!');
+compiled({ 'user': 'pebbles' });
+// => 'hello pebbles!'
+
+// using custom template delimiters
+_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+var compiled = _.template('hello {{ user }}!');
+compiled({ 'user': 'mustache' });
+// => 'hello mustache!'
-_.merge(food, otherFood, function(a, b) {
- return _.isArray(a) ? a.concat(b) : undefined;
-});
-// => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
-```
+// using backslashes to treat delimiters as plain text
+var compiled = _.template('<%= "\\<%- value %\\>" %>');
+compiled({ 'value': 'ignored' });
+// => '<%- value %>'
+
+// using the `imports` option to import `jQuery` as `jq`
+var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
+var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
+compiled({ 'users': ['fred', 'barney'] });
+// => '<li>fred</li><li>barney</li>'
+
+// using the `sourceURL` option to specify a custom sourceURL for the template
+var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
+compiled(data);
+// => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
+
+// using the `variable` option to ensure a with-statement isn't used in the compiled template
+var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
+compiled.source;
+// => function(data) {
+ var __t, __p = '';
+ __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
+ return __p;
+}
+// using the `source` property to inline compiled templates for meaningful
+// line numbers in error messages and a stack trace
+fs.writeFileSync(path.join(cwd, 'jst.js'), '\
+ var JST = {\
+ "main": ' + _.template(mainText).source + '\
+ };\
+');
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_omitobject-callback-thisarg"></a>`_.omit(object, [callback], [thisArg])`
-<a href="#_omitobject-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3091 "View in source") [Ⓣ][1]
+### <a id="_trimstring-charswhitespace"></a>`_.trim([string=''], [chars=whitespace])`
+<a href="#_trimstring-charswhitespace">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9898 "View in source") [Ⓣ][1]
-Creates a shallow clone of `object` excluding the specified properties. Property names may be specified as individual arguments or as arrays of property names. If a callback is provided it will be executed for each property of `object` omitting the properties the callback returns truey for. The callback is bound to `thisArg` and invoked with three arguments; *(value, key, object)*.
+Removes leading and trailing whitespace or specified characters from `string`.
#### Arguments
-1. `object` *(Object)*: The source object.
-2. `[callback]` *(Function|...string|string[])*: The properties to omit or the function called per iteration.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[string='']` *(string)*: The string to trim.
+2. `[chars=whitespace]` *(string)*: The characters to trim.
#### Returns
-*(Object)*: Returns an object without the omitted properties.
+*(string)*: Returns the trimmed string.
#### Example
```js
-_.omit({ 'name': 'fred', 'age': 40 }, 'age');
-// => { 'name': 'fred' }
+_.trim(' abc ');
+// => 'abc'
-_.omit({ 'name': 'fred', 'age': 40 }, function(value) {
- return typeof value == 'number';
-});
-// => { 'name': 'fred' }
-```
+_.trim('-_-abc-_-', '_-');
+// => 'abc'
+_.map([' foo ', ' bar '], _.trim);
+// => ['foo', 'bar]
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_pairsobject"></a>`_.pairs(object)`
-<a href="#_pairsobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3132 "View in source") [Ⓣ][1]
+### <a id="_trimleftstring-charswhitespace"></a>`_.trimLeft([string=''], [chars=whitespace])`
+<a href="#_trimleftstring-charswhitespace">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9929 "View in source") [Ⓣ][1]
-Creates a two dimensional array of an object's key-value pairs, i.e. `[[key1, value1], [key2, value2]]`.
+Removes leading whitespace or specified characters from `string`.
#### Arguments
-1. `object` *(Object)*: The object to inspect.
+1. `[string='']` *(string)*: The string to trim.
+2. `[chars=whitespace]` *(string)*: The characters to trim.
#### Returns
-*(Array)*: Returns new array of key-value pairs.
+*(string)*: Returns the trimmed string.
#### Example
```js
-_.pairs({ 'barney': 36, 'fred': 40 });
-// => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
-```
+_.trimLeft(' abc ');
+// => 'abc '
+_.trimLeft('-_-abc-_-', '_-');
+// => 'abc-_-'
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_pickobject-callback-thisarg"></a>`_.pick(object, [callback], [thisArg])`
-<a href="#_pickobject-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3172 "View in source") [Ⓣ][1]
+### <a id="_trimrightstring-charswhitespace"></a>`_.trimRight([string=''], [chars=whitespace])`
+<a href="#_trimrightstring-charswhitespace">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L9959 "View in source") [Ⓣ][1]
-Creates a shallow clone of `object` composed of the specified properties. Property names may be specified as individual arguments or as arrays of property names. If a callback is provided it will be executed for each property of `object` picking the properties the callback returns truey for. The callback is bound to `thisArg` and invoked with three arguments; *(value, key, object)*.
+Removes trailing whitespace or specified characters from `string`.
#### Arguments
-1. `object` *(Object)*: The source object.
-2. `[callback]` *(Function|...string|string[])*: The function called per iteration or property names to pick, specified as individual property names or arrays of property names.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[string='']` *(string)*: The string to trim.
+2. `[chars=whitespace]` *(string)*: The characters to trim.
#### Returns
-*(Object)*: Returns an object composed of the picked properties.
+*(string)*: Returns the trimmed string.
#### Example
```js
-_.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
-// => { 'name': 'fred' }
+_.trimRight(' abc ');
+// => ' abc'
-_.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
- return key.charAt(0) != '_';
-});
-// => { 'name': 'fred' }
+_.trimRight('-_-abc-_-', '_-');
+// => '-_-abc'
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_transformobject-callbackidentity-accumulator-thisarg"></a>`_.transform(object, [callback=identity], [accumulator], [thisArg])`
-<a href="#_transformobject-callbackidentity-accumulator-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3227 "View in source") [Ⓣ][1]
+### <a id="_truncstring-options-optionslength30-optionsomission-optionsseparator"></a>`_.trunc([string=''], [options], [options.length=30], [options.omission='...'], [options.separator])`
+<a href="#_truncstring-options-optionslength30-optionsomission-optionsseparator">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10003 "View in source") [Ⓣ][1]
-An alternative to `_.reduce` this method transforms `object` to a new `accumulator` object which is the result of running each of its own enumerable properties through a callback, with each callback execution potentially mutating the `accumulator` object. The callback is bound to `thisArg` and invoked with four arguments; *(accumulator, value, key, object)*. Callbacks may exit iteration early by explicitly returning `false`.
+Truncates `string` if it is longer than the given maximum string length.
+The last characters of the truncated string are replaced with the omission
+string which defaults to "...".
#### Arguments
-1. `object` *(Array|Object)*: The object to iterate over.
-2. `[callback=identity]` *(Function)*: The function called per iteration.
-3. `[accumulator]` *(*)*: The custom accumulator value.
-4. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `[string='']` *(string)*: The string to truncate.
+2. `[options]` *(Object|number)*: The options object or maximum string length.
+3. `[options.length=30]` *(number)*: The maximum string length.
+4. `[options.omission='...']` *(string)*: The string to indicate text is omitted.
+5. `[options.separator]` *(RegExp|string)*: The separator pattern to truncate to.
#### Returns
-*(*)*: Returns the accumulated value.
+*(string)*: Returns the truncated string.
#### Example
```js
-var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
- num *= num;
- if (num % 2) {
- return result.push(num) < 3;
- }
-});
-// => [1, 9, 25]
+_.trunc('hi-diddly-ho there, neighborino');
+// => 'hi-diddly-ho there, neighbo...'
-var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
- result[key] = num * 3;
-});
-// => { 'a': 3, 'b': 6, 'c': 9 }
-```
+_.trunc('hi-diddly-ho there, neighborino', 24);
+// => 'hi-diddly-ho there, n...'
+
+_.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': ' ' });
+// => 'hi-diddly-ho there,...'
+_.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': /,? +/ });
+//=> 'hi-diddly-ho there...'
+
+_.trunc('hi-diddly-ho there, neighborino', { 'omission': ' [...]' });
+// => 'hi-diddly-ho there, neig [...]'
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_valuesobject"></a>`_.values(object)`
-<a href="#_valuesobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L3261 "View in source") [Ⓣ][1]
+### <a id="_unescapestring"></a>`_.unescape([string=''])`
+<a href="#_unescapestring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10073 "View in source") [Ⓣ][1]
-Creates an array composed of the own enumerable property values of `object`.
+The inverse of `_.escape`; this method converts the HTML entities
+`&`, `<`, `>`, `"`, `'`, and ``` in `string` to their
+corresponding characters.
+ *Note:** No other HTML entities are unescaped. To unescape additional HTML
+entities use a third-party library like [_he_](http://mths.be/he).
#### Arguments
-1. `object` *(Object)*: The object to inspect.
+1. `[string='']` *(string)*: The string to unescape.
#### Returns
-*(Array)*: Returns an array of property values.
+*(string)*: Returns the unescaped string.
#### Example
```js
-_.values({ 'one': 1, 'two': 2, 'three': 3 });
-// => [1, 2, 3] (property order is not guaranteed across environments)
+_.unescape('fred, barney, & pebbles');
+// => 'fred, barney, & pebbles'
```
-
* * *
<!-- /div -->
-
-<!-- /div -->
-
-
<!-- div -->
-## `“Utilities” Methods`
+### <a id="_wordsstring-pattern"></a>`_.words([string=''], [pattern])`
+<a href="#_wordsstring-pattern">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10098 "View in source") [Ⓣ][1]
-<!-- div -->
+Splits `string` into an array of its words.
-### <a id="_now"></a>`_.now`
-<a href="#_now">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6351 "View in source") [Ⓣ][1]
+#### Arguments
+1. `[string='']` *(string)*: The string to inspect.
+2. `[pattern]` *(RegExp|string)*: The pattern to match words.
-*(unknown)*: Gets the number of milliseconds that have elapsed since the Unix epoch *(1 January `1970 00`:00:00 UTC)*.
+#### Returns
+*(Array)*: Returns the words of `string`.
#### Example
```js
-var stamp = _.now();
-_.defer(function() { console.log(_.now() - stamp); });
-// => logs the number of milliseconds it took for the deferred function to be called
-```
+_.words('fred, barney, & pebbles');
+// => ['fred', 'barney', 'pebbles']
+_.words('fred, barney, & pebbles', /[^, ]+/g);
+// => ['fred', 'barney', '&', 'pebbles']
+```
* * *
<!-- /div -->
+<!-- /div -->
<!-- div -->
-### <a id="_constantvalue"></a>`_.constant(value)`
-<a href="#_constantvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6125 "View in source") [Ⓣ][1]
+## `“Utility” Methods`
-Creates a function that returns `value`.
+<!-- div -->
+
+### <a id="_attemptfunc"></a>`_.attempt(func)`
+<a href="#_attemptfunc">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10128 "View in source") [Ⓣ][1]
+
+Attempts to invoke `func`, returning either the result or the caught
+error object.
#### Arguments
-1. `value` *(*)*: The value to return from the new function.
+1. `func` *(*)*: The function to attempt.
#### Returns
-*(Function)*: Returns the new function.
+*(*)*: Returns the `func` result or error object.
#### Example
```js
-var object = { 'name': 'fred' };
-var getter = _.constant(object);
-getter() === object;
-// => true
-```
+// avoid throwing errors for invalid selectors
+var elements = _.attempt(function() {
+ return document.querySelectorAll(selector);
+});
+if (_.isError(elements)) {
+ elements = [];
+}
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_createcallbackfuncidentity-thisarg-argcount"></a>`_.createCallback([func=identity], [thisArg], [argCount])`
-<a href="#_createcallbackfuncidentity-thisarg-argcount">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6162 "View in source") [Ⓣ][1]
+### <a id="_callbackfunc_identity-thisarg"></a>`_.callback([func=_.identity], [thisArg])`
+<a href="#_callbackfunc_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10171 "View in source") [Ⓣ][1]
-Produces a callback bound to an optional `thisArg`. If `func` is a property name the created callback will return the property value for a given element. If `func` is an object the created callback will return `true` for elements that contain the equivalent object properties, otherwise it will return `false`.
+Creates a function bound to an optional `thisArg`. If `func` is a property
+name the created callback returns the property value for a given element.
+If `func` is an object the created callback returns `true` for elements
+that contain the equivalent object properties, otherwise it returns `false`.
#### Arguments
-1. `[func=identity]` *(*)*: The value to convert to a callback.
-2. `[thisArg]` *(*)*: The `this` binding of the created callback.
-3. `[argCount]` *(number)*: The number of arguments the callback accepts.
+1. `[func=_.identity]` *(*)*: The value to convert to a callback.
+2. `[thisArg]` *(*)*: The `this` binding of `func`.
#### Returns
-*(Function)*: Returns a callback function.
+*(Function)*: Returns the callback.
#### Example
```js
-var characters = [
- { 'name': 'barney', 'age': 36 },
- { 'name': 'fred', 'age': 40 }
+var users = [
+ { 'user': 'barney', 'age': 36 },
+ { 'user': 'fred', 'age': 40 }
];
// wrap to create custom callback shorthands
-_.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
- var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
- return !match ? func(callback, thisArg) : function(object) {
+_.callback = _.wrap(_.callback, function(callback, func, thisArg) {
+ var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
+ if (!match) {
+ return callback(func, thisArg);
+ }
+ return function(object) {
return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
};
});
-_.filter(characters, 'age__gt38');
-// => [{ 'name': 'fred', 'age': 40 }]
+_.filter(users, 'age__gt36');
+// => [{ 'user': 'fred', 'age': 40 }]
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_escapestring"></a>`_.escape(string)`
-<a href="#_escapestring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6211 "View in source") [Ⓣ][1]
+### <a id="_constantvalue"></a>`_.constant(value)`
+<a href="#_constantvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10193 "View in source") [Ⓣ][1]
-Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their corresponding HTML entities.
+Creates a function that returns `value`.
#### Arguments
-1. `string` *(string)*: The string to escape.
+1. `value` *(*)*: The value to return from the new function.
#### Returns
-*(string)*: Returns the escaped string.
+*(Function)*: Returns the new function.
#### Example
```js
-_.escape('Fred, Wilma, & Pebbles');
-// => 'Fred, Wilma, & Pebbles'
+var object = { 'user': 'fred' };
+var getter = _.constant(object);
+getter() === object;
+// => true
```
-
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_identityvalue"></a>`_.identity(value)`
-<a href="#_identityvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6229 "View in source") [Ⓣ][1]
+<a href="#_identityvalue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10213 "View in source") [Ⓣ][1]
This method returns the first argument provided to it.
@@ -4104,406 +6050,318 @@ This method returns the first argument provided to it.
1. `value` *(*)*: Any value.
#### Returns
-*(*)*: Returns `value`.
+*(*)*: Returns `value`.
#### Example
```js
-var object = { 'name': 'fred' };
+var object = { 'user': 'fred' };
_.identity(object) === object;
// => true
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_mixinobjectlodash-source-options"></a>`_.mixin([object=lodash], source, [options])`
-<a href="#_mixinobjectlodash-source-options">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6261 "View in source") [Ⓣ][1]
+### <a id="_matchessource"></a>`_.matches(source)`
+<a href="#_matchessource">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10242 "View in source") [Ⓣ][1]
-Adds function properties of a source object to the destination object. If `object` is a function methods will be added to its prototype as well.
+Creates a function which performs a deep comparison between a given object
+and `source`, returning `true` if the given object has equivalent property
+values, else `false`.
#### Arguments
-1. `[object=lodash]` *(Function|Object)*: object The destination object.
-2. `source` *(Object)*: The object of functions to add.
-3. `[options]` *(Object)*: The options object.
-4. `[options.chain=true]` *(boolean)*: Specify whether the functions added are chainable.
+1. `source` *(Object)*: The object of property values to match.
+
+#### Returns
+*(Function)*: Returns the new function.
#### Example
```js
-function capitalize(string) {
- return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
-}
+var users = [
+ { 'user': 'fred', 'age': 40 },
+ { 'user': 'barney', 'age': 36 }
+];
-_.mixin({ 'capitalize': capitalize });
-_.capitalize('fred');
-// => 'Fred'
+var matchesAge = _.matches({ 'age': 36 });
-_('fred').capitalize().value();
-// => 'Fred'
+_.filter(users, matchesAge);
+// => [{ 'user': 'barney', 'age': 36 }]
-_.mixin({ 'capitalize': capitalize }, { 'chain': false });
-_('fred').capitalize();
-// => 'Fred'
+_.find(users, matchesAge);
+// => { 'user': 'barney', 'age': 36 }
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_noconflict"></a>`_.noConflict()`
-<a href="#_noconflict">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6317 "View in source") [Ⓣ][1]
+### <a id="_mixinobjectthis-source-options-optionschaintrue"></a>`_.mixin([object=this], source, [options], [options.chain=true])`
+<a href="#_mixinobjectthis-source-options-optionschaintrue">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10279 "View in source") [Ⓣ][1]
+
+Adds all own enumerable function properties of a source object to the
+destination object. If `object` is a function then methods are added to
+its prototype as well.
-Reverts the '_' variable to its previous value and returns a reference to the `lodash` function.
+#### Arguments
+1. `[object=this]` *(Function|Object)*: object The destination object.
+2. `source` *(Object)*: The object of functions to add.
+3. `[options]` *(Object)*: The options object.
+4. `[options.chain=true]` *(boolean)*: Specify whether the functions added are chainable.
#### Returns
-*(Function)*: Returns the `lodash` function.
+*(Function|Object)*: Returns `object`.
#### Example
```js
-var lodash = _.noConflict();
-```
+function vowels(string) {
+ return _.filter(string, function(v) {
+ return /[aeiou]/i.test(v);
+ });
+}
+
+_.mixin({ 'vowels': vowels });
+_.vowels('fred');
+// => ['e']
+_('fred').vowels().value();
+// => ['e']
+
+_.mixin({ 'vowels': vowels }, { 'chain': false });
+_('fred').vowels();
+// => ['e']
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_noop"></a>`_.noop()`
-<a href="#_noop">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6334 "View in source") [Ⓣ][1]
+### <a id="_noconflict"></a>`_.noConflict()`
+<a href="#_noconflict">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10342 "View in source") [Ⓣ][1]
-A no-operation function.
+Reverts the `_` variable to its previous value and returns a reference to
+the `lodash` function.
+
+#### Returns
+*(Function)*: Returns the `lodash` function.
#### Example
```js
-var object = { 'name': 'fred' };
-_.noop(object) === undefined;
-// => true
+var lodash = _.noConflict();
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_parseintvalue-radix"></a>`_.parseInt(value, [radix])`
-<a href="#_parseintvalue-radix">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6374 "View in source") [Ⓣ][1]
-
-Converts the given value into an integer of the specified radix. If `radix` is `undefined` or `0` a `radix` of `10` is used unless the `value` is a hexadecimal, in which case a `radix` of `16` is used.
-
-Note: This method avoids differences in native ES3 and ES5 `parseInt` implementations. See http://es5.github.io/#E.
-
-#### Arguments
-1. `value` *(string)*: The value to parse.
-2. `[radix]` *(number)*: The radix used to interpret the value to parse.
+### <a id="_noop"></a>`_.noop()`
+<a href="#_noop">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10359 "View in source") [Ⓣ][1]
-#### Returns
-*(number)*: Returns the new integer value.
+A no-operation function.
#### Example
```js
-_.parseInt('08');
-// => 8
+var object = { 'user': 'fred' };
+_.noop(object) === undefined;
+// => true
```
-
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_propertykey"></a>`_.property(key)`
-<a href="#_propertykey">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6403 "View in source") [Ⓣ][1]
+<a href="#_propertykey">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10386 "View in source") [Ⓣ][1]
-Creates a "_.pluck" style function, which returns the `key` value of a given object.
+Creates a function which returns the property value of `key` on a given object.
#### Arguments
-1. `key` *(string)*: The name of the property to retrieve.
+1. `key` *(string)*: The key of the property to get.
#### Returns
-*(Function)*: Returns the new function.
+*(Function)*: Returns the new function.
#### Example
```js
-var characters = [
- { 'name': 'fred', 'age': 40 },
- { 'name': 'barney', 'age': 36 }
+var users = [
+ { 'user': 'fred' },
+ { 'user': 'barney' }
];
-var getName = _.property('name');
+var getName = _.property('user');
-_.map(characters, getName);
-// => ['barney', 'fred']
+_.map(users, getName);
+// => ['fred', barney']
-_.sortBy(characters, getName);
-// => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }]
+_.pluck(_.sortBy(users, getName), 'user');
+// => ['barney', 'fred']
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_randommin0-max1-floatingfalse"></a>`_.random([min=0], [max=1], [floating=false])`
-<a href="#_randommin0-max1-floatingfalse">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6436 "View in source") [Ⓣ][1]
+### <a id="_propertyofobject"></a>`_.propertyOf(object)`
+<a href="#_propertyofobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10409 "View in source") [Ⓣ][1]
-Produces a random number between `min` and `max` *(inclusive)*. If only one argument is provided a number between `0` and the given number will be returned. If `floating` is truey or either `min` or `max` are floats a floating-point number will be returned instead of an integer.
+The inverse of `_.property`; this method creates a function which returns
+the property value of a given key on `object`.
#### Arguments
-1. `[min=0]` *(number)*: The minimum possible value.
-2. `[max=1]` *(number)*: The maximum possible value.
-3. `[floating=false]` *(boolean)*: Specify returning a floating-point number.
+1. `object` *(Object)*: The object to inspect.
#### Returns
-*(number)*: Returns a random number.
+*(Function)*: Returns the new function.
#### Example
```js
-_.random(0, 5);
-// => an integer between 0 and 5
-
-_.random(5);
-// => also an integer between 0 and 5
+var object = { 'user': 'fred', 'age': 40, 'active': true };
+_.map(['active', 'user'], _.propertyOf(object));
+// => [true, 'fred']
-_.random(5, true);
-// => a floating-point number between 0 and 5
-
-_.random(1.2, 5.2);
-// => a floating-point number between 1.2 and 5.2
+var object = { 'a': 3, 'b': 1, 'c': 2 };
+_.sortBy(['a', 'b', 'c'], _.propertyOf(object));
+// => ['b', 'c', 'a']
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_resultobject-key"></a>`_.result(object, key)`
-<a href="#_resultobject-key">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6494 "View in source") [Ⓣ][1]
+### <a id="_rangestart0-end-step1"></a>`_.range([start=0], end, [step=1])`
+<a href="#_rangestart0-end-step1">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10447 "View in source") [Ⓣ][1]
-Resolves the value of property `key` on `object`. If `key` is a function it will be invoked with the `this` binding of `object` and its result returned, else the property value is returned. If `object` is falsey then `undefined` is returned.
+Creates an array of numbers (positive and/or negative) progressing from
+`start` up to, but not including, `end`. If `start` is less than `end` a
+zero-length range is created unless a negative `step` is specified.
#### Arguments
-1. `object` *(Object)*: The object to inspect.
-2. `key` *(string)*: The name of the property to resolve.
+1. `[start=0]` *(number)*: The start of the range.
+2. `end` *(number)*: The end of the range.
+3. `[step=1]` *(number)*: The value to increment or decrement by.
#### Returns
-*(*)*: Returns the resolved value.
+*(Array)*: Returns the new array of numbers.
#### Example
```js
-var object = {
- 'cheese': 'crumpets',
- 'stuff': function() {
- return 'nonsense';
- }
-};
-
-_.result(object, 'cheese');
-// => 'crumpets'
-
-_.result(object, 'stuff');
-// => 'nonsense'
-```
-
-* * *
-
-<!-- /div -->
-
-
-<!-- div -->
+_.range(4);
+// => [0, 1, 2, 3]
-### <a id="_runincontextcontextroot"></a>`_.runInContext([context=root])`
-<a href="#_runincontextcontextroot">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L469 "View in source") [Ⓣ][1]
+_.range(1, 5);
+// => [1, 2, 3, 4]
-Create a new `lodash` function using the given context object.
+_.range(0, 20, 5);
+// => [0, 5, 10, 15]
-#### Arguments
-1. `[context=root]` *(Object)*: The context object.
+_.range(0, -4, -1);
+// => [0, -1, -2, -3]
-#### Returns
-*(Function)*: Returns the `lodash` function.
+_.range(1, 4, 0);
+// => [1, 1, 1]
+_.range(0);
+// => []
+```
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_templatetext-data-options-optionsescape-optionsevaluate-optionsimports-optionsinterpolate-sourceurl-variable"></a>`_.template(text, data, [options], [options.escape], [options.evaluate], [options.imports], [options.interpolate], [sourceURL], [variable])`
-<a href="#_templatetext-data-options-optionsescape-optionsevaluate-optionsimports-optionsinterpolate-sourceurl-variable">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6587 "View in source") [Ⓣ][1]
-
-A micro-templating method that handles arbitrary delimiters, preserves whitespace, and correctly escapes quotes within interpolated code.
-
-Note: In the development build, `_.template` utilizes sourceURLs for easier debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
-
-For more information on precompiling templates see:<br>
-http://lodash.com/custom-builds
+### <a id="_runincontextcontextroot"></a>`_.runInContext([context=root])`
+<a href="#_runincontextcontextroot">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L688 "View in source") [Ⓣ][1]
-For more information on Chrome extension sandboxes see:<br>
-http://developer.chrome.com/stable/extensions/sandboxingEval.html
+Create a new pristine `lodash` function using the given `context` object.
#### Arguments
-1. `text` *(string)*: The template text.
-2. `data` *(Object)*: The data object used to populate the text.
-3. `[options]` *(Object)*: The options object.
-4. `[options.escape]` *(RegExp)*: The "escape" delimiter.
-5. `[options.evaluate]` *(RegExp)*: The "evaluate" delimiter.
-6. `[options.imports]` *(Object)*: An object to import into the template as local variables.
-7. `[options.interpolate]` *(RegExp)*: The "interpolate" delimiter.
-8. `[sourceURL]` *(string)*: The sourceURL of the template's compiled source.
-9. `[variable]` *(string)*: The data object variable name.
+1. `[context=root]` *(Object)*: The context object.
#### Returns
-*(Function, string)*: Returns a compiled function when no `data` object is given, else it returns the interpolated text.
+*(Function)*: Returns a new `lodash` function.
#### Example
```js
-// using the "interpolate" delimiter to create a compiled template
-var compiled = _.template('hello <%= name %>');
-compiled({ 'name': 'fred' });
-// => 'hello fred'
-
-// using the "escape" delimiter to escape HTML in data property values
-_.template('<b><%- value %></b>', { 'value': '<script>' });
-// => '<b><script></b>'
-
-// using the "evaluate" delimiter to generate HTML
-var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
-_.template(list, { 'people': ['fred', 'barney'] });
-// => '<li>fred</li><li>barney</li>'
-
-// using the ES6 delimiter as an alternative to the default "interpolate" delimiter
-_.template('hello ${ name }', { 'name': 'pebbles' });
-// => 'hello pebbles'
-
-// using the internal `print` function in "evaluate" delimiters
-_.template('<% print("hello " + name); %>!', { 'name': 'barney' });
-// => 'hello barney!'
+_.mixin({ 'add': function(a, b) { return a + b; } });
-// using a custom template delimiters
-_.templateSettings = {
- 'interpolate': /{{([\s\S]+?)}}/g
-};
-
-_.template('hello {{ name }}!', { 'name': 'mustache' });
-// => 'hello mustache!'
+var lodash = _.runInContext();
+lodash.mixin({ 'sub': function(a, b) { return a - b; } });
-// using the `imports` option to import jQuery
-var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
-_.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
-// => '<li>fred</li><li>barney</li>'
+_.isFunction(_.add);
+// => true
+_.isFunction(_.sub);
+// => false
-// using the `sourceURL` option to specify a custom sourceURL for the template
-var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
-compiled(data);
-// => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
+lodash.isFunction(lodash.add);
+// => false
+lodash.isFunction(lodash.sub);
+// => true
-// using the `variable` option to ensure a with-statement isn't used in the compiled template
-var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
-compiled.source;
-// => function(data) {
- var __t, __p = '', __e = _.escape;
- __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
- return __p;
-}
+// using `context` to mock `Date#getTime` use in `_.now`
+var mock = _.runInContext({
+ 'Date': function() {
+ return { 'getTime': getTimeMock };
+ }
+});
-// using the `source` property to inline compiled templates for meaningful
-// line numbers in error messages and a stack trace
-fs.writeFileSync(path.join(cwd, 'jst.js'), '\
- var JST = {\
- "main": ' + _.template(mainText).source + '\
- };\
-');
+// or creating a suped-up `defer` in Node.js
+var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
```
-
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_timesn-callback-thisarg"></a>`_.times(n, callback, [thisArg])`
-<a href="#_timesn-callback-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6710 "View in source") [Ⓣ][1]
+### <a id="_timesn-iteratee_identity-thisarg"></a>`_.times(n, [iteratee=_.identity], [thisArg])`
+<a href="#_timesn-iteratee_identity-thisarg">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10496 "View in source") [Ⓣ][1]
-Executes the callback `n` times, returning an array of the results of each callback execution. The callback is bound to `thisArg` and invoked with one argument; *(index)*.
+Invokes the iteratee function `n` times, returning an array of the results
+of each invocation. The `iteratee` is bound to `thisArg` and invoked with
+one argument; (index).
#### Arguments
-1. `n` *(number)*: The number of times to execute the callback.
-2. `callback` *(Function)*: The function called per iteration.
-3. `[thisArg]` *(*)*: The `this` binding of `callback`.
+1. `n` *(number)*: The number of times to invoke `iteratee`.
+2. `[iteratee=_.identity]` *(Function)*: The function invoked per iteration.
+3. `[thisArg]` *(*)*: The `this` binding of `iteratee`.
#### Returns
-*(Array)*: Returns an array of the results of each `callback` execution.
+*(Array)*: Returns the array of results.
#### Example
```js
-var diceRolls = _.times(3, _.partial(_.random, 1, 6));
+var diceRolls = _.times(3, _.partial(_.random, 1, 6, false));
// => [3, 6, 4]
_.times(3, function(n) { mage.castSpell(n); });
-// => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
+// => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2` respectively
_.times(3, function(n) { this.cast(n); }, mage);
-// => also calls `mage.castSpell(n)` three times
-```
-
-* * *
-
-<!-- /div -->
-
-
-<!-- div -->
-
-### <a id="_unescapestring"></a>`_.unescape(string)`
-<a href="#_unescapestring">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6737 "View in source") [Ⓣ][1]
-
-The inverse of `_.escape` this method converts the HTML entities `&`, `<`, `>`, `"`, and `'` in `string` to their corresponding characters.
-
-#### Arguments
-1. `string` *(string)*: The string to unescape.
-
-#### Returns
-*(string)*: Returns the unescaped string.
-
-#### Example
-```js
-_.unescape('Fred, Barney & Pebbles');
-// => 'Fred, Barney & Pebbles'
+// => also invokes `mage.castSpell(n)` three times
```
-
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_uniqueidprefix"></a>`_.uniqueId([prefix])`
-<a href="#_uniqueidprefix">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L6757 "View in source") [Ⓣ][1]
+<a href="#_uniqueidprefix">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10534 "View in source") [Ⓣ][1]
-Generates a unique ID. If `prefix` is provided the ID will be appended to it.
+Generates a unique ID. If `prefix` is provided the ID is appended to it.
#### Arguments
1. `[prefix]` *(string)*: The value to prefix the ID with.
#### Returns
-*(string)*: Returns the unique ID.
+*(string)*: Returns the unique ID.
#### Example
```js
@@ -4513,15 +6371,12 @@ _.uniqueId('contact_');
_.uniqueId();
// => '105'
```
-
* * *
<!-- /div -->
-
<!-- /div -->
-
<!-- div -->
## `Methods`
@@ -4529,7 +6384,7 @@ _.uniqueId();
<!-- div -->
### <a id="_templatesettingsimports_"></a>`_.templateSettings.imports._`
-<a href="#_templatesettingsimports_">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L867 "View in source") [Ⓣ][1]
+<a href="#_templatesettingsimports_">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1162 "View in source") [Ⓣ][1]
A reference to the `lodash` function.
@@ -4537,10 +6392,8 @@ A reference to the `lodash` function.
<!-- /div -->
-
<!-- /div -->
-
<!-- div -->
## `Properties`
@@ -4548,243 +6401,240 @@ A reference to the `lodash` function.
<!-- div -->
### <a id="_version"></a>`_.VERSION`
-<a href="#_version">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L7078 "View in source") [Ⓣ][1]
+<a href="#_version">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L10794 "View in source") [Ⓣ][1]
-*(string)*: The semantic version number.
+(string): The semantic version number.
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_support"></a>`_.support`
-<a href="#_support">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L676 "View in source") [Ⓣ][1]
-
-*(Object)*: An object used to flag environments features.
-
-* * *
-
-<!-- /div -->
-
-
-<!-- div -->
+<a href="#_support">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L951 "View in source") [Ⓣ][1]
-### <a id="_supportargsclass"></a>`_.support.argsClass`
-<a href="#_supportargsclass">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L693 "View in source") [Ⓣ][1]
-
-*(boolean)*: Detect if an `arguments` object's [[Class]] is resolvable *(all but Firefox < `4`, IE < `9`)*.
+(Object): An object environment feature flags.
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_supportargsobject"></a>`_.support.argsObject`
-<a href="#_supportargsobject">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L701 "View in source") [Ⓣ][1]
+### <a id="_supportargstag"></a>`_.support.argsTag`
+<a href="#_supportargstag">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L968 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if `arguments` objects are `Object` objects *(all but Narwhal and Opera < `10.5`)*.
+(boolean): Detect if the `toStringTag` of `arguments` objects is resolvable
+(all but Firefox < 4, IE < 9).
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_supportenumerrorprops"></a>`_.support.enumErrorProps`
-<a href="#_supportenumerrorprops">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L710 "View in source") [Ⓣ][1]
+<a href="#_supportenumerrorprops">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L977 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if `name` or `message` properties of `Error.prototype` are enumerable by default. *(IE < `9`, Safari < `5.1`)*
+(boolean): Detect if `name` or `message` properties of `Error.prototype` are
+enumerable by default (IE < 9, Safari < 5.1).
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_supportenumprototypes"></a>`_.support.enumPrototypes`
-<a href="#_supportenumprototypes">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L723 "View in source") [Ⓣ][1]
+<a href="#_supportenumprototypes">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L991 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if `prototype` properties are enumerable by default.
+(boolean): Detect if `prototype` properties are enumerable by default.
-Firefox < `3.6`, Opera > `9.50` - Opera < `11.60`, and Safari < `5.1` *(if the prototype or a property on the prototype has been set)* incorrectly sets a function's `prototype` property [[Enumerable]] value to `true`.
+Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
+(if the prototype or a property on the prototype has been set)
+incorrectly set the `[[Enumerable]]` value of a function's `prototype`
+property to `true`.
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_supportfuncdecomp"></a>`_.support.funcDecomp`
-<a href="#_supportfuncdecomp">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L732 "View in source") [Ⓣ][1]
+<a href="#_supportfuncdecomp">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1001 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if functions can be decompiled by `Function#toString` *(all but PS3 and older Opera mobile browsers & avoided in Windows `8` apps)*.
+(boolean): Detect if functions can be decompiled by `Function#toString`
+(all but Firefox OS certified apps, older Opera mobile browsers, and
+the PlayStation 3; forced `false` for Windows 8 apps).
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_supportfuncnames"></a>`_.support.funcNames`
-<a href="#_supportfuncnames">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L740 "View in source") [Ⓣ][1]
+<a href="#_supportfuncnames">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1009 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if `Function#name` is supported *(all but IE)*.
+(boolean): Detect if `Function#name` is supported (all but IE).
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_supportnonenumargs"></a>`_.support.nonEnumArgs`
-<a href="#_supportnonenumargs">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L749 "View in source") [Ⓣ][1]
+### <a id="_supportnodetag"></a>`_.support.nodeTag`
+<a href="#_supportnodetag">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1017 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if `arguments` object indexes are non-enumerable *(Firefox < `4`, IE < `9`, PhantomJS, Safari < `5.1`)*.
+(boolean): Detect if the `toStringTag` of DOM nodes is resolvable (all but IE < 9).
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_supportnonenumshadows"></a>`_.support.nonEnumShadows`
-<a href="#_supportnonenumshadows">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L760 "View in source") [Ⓣ][1]
+<a href="#_supportnonenumshadows">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1038 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if properties shadowing those on `Object.prototype` are non-enumerable.
+(boolean): Detect if properties shadowing those on `Object.prototype` are
+non-enumerable.
-In IE < `9` an objects own properties, shadowing non-enumerable ones, are made non-enumerable as well *(a.k.a the JScript [[DontEnum]] bug)*.
+In IE < 9 an object's own properties, shadowing non-enumerable ones,
+are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug).
* * *
<!-- /div -->
+<!-- div -->
+
+### <a id="_supportnonenumstrings"></a>`_.support.nonEnumStrings`
+<a href="#_supportnonenumstrings">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1026 "View in source") [Ⓣ][1]
+
+(boolean): Detect if string indexes are non-enumerable
+(IE < 9, RingoJS, Rhino, Narwhal).
+
+* * *
+
+<!-- /div -->
<!-- div -->
### <a id="_supportownlast"></a>`_.support.ownLast`
-<a href="#_supportownlast">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L768 "View in source") [Ⓣ][1]
+<a href="#_supportownlast">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1046 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if own properties are iterated after inherited properties *(all but IE < `9`)*.
+(boolean): Detect if own properties are iterated after inherited properties (IE < 9).
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_supportspliceobjects"></a>`_.support.spliceObjects`
-<a href="#_supportspliceobjects">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L782 "View in source") [Ⓣ][1]
+<a href="#_supportspliceobjects">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1061 "View in source") [Ⓣ][1]
-*(boolean)*: Detect if `Array#shift` and `Array#splice` augment array-like objects correctly.
+(boolean): Detect if `Array#shift` and `Array#splice` augment array-like objects
+correctly.
-Firefox < `10`, IE compatibility mode, and IE < `9` have buggy Array `shift()` and `splice()` functions that fail to remove the last element, `value[0]`, of array-like objects even though the `length` property is set to `0`. The `shift()` method is buggy in IE `8` compatibility mode, while `splice()` is buggy regardless of mode in IE < `9` and buggy in compatibility mode in IE `9`.
+Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array `shift()`
+and `splice()` functions that fail to remove the last element, `value[0]`,
+of array-like objects even though the `length` property is set to `0`.
+The `shift()` method is buggy in compatibility modes of IE 8, while `splice()`
+is buggy regardless of mode in IE < 9.
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_supportunindexedchars"></a>`_.support.unindexedChars`
-<a href="#_supportunindexedchars">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L793 "View in source") [Ⓣ][1]
+<a href="#_supportunindexedchars">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1072 "View in source") [Ⓣ][1]
-*(boolean)*: Detect lack of support for accessing string characters by index.
+(boolean): Detect lack of support for accessing string characters by index.
-IE < `8` can't access characters by index and IE `8` can only access characters by index on string literals.
+IE < 8 can't access characters by index. IE 8 can only access characters
+by index on string literals, not string objects.
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_templatesettings"></a>`_.templateSettings`
-<a href="#_templatesettings">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L819 "View in source") [Ⓣ][1]
+<a href="#_templatesettings">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1114 "View in source") [Ⓣ][1]
-*(Object)*: By default, the template delimiters used by Lo-Dash are similar to those in embedded Ruby *(ERB)*. Change the following template settings to use alternative delimiters.
+(Object): By default, the template delimiters used by Lo-Dash are like those in
+embedded Ruby (ERB). Change the following template settings to use
+alternative delimiters.
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_templatesettingsescape"></a>`_.templateSettings.escape`
-<a href="#_templatesettingsescape">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L827 "View in source") [Ⓣ][1]
+<a href="#_templatesettingsescape">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1122 "View in source") [Ⓣ][1]
-*(RegExp)*: Used to detect `data` property values to be HTML-escaped.
+(RegExp): Used to detect `data` property values to be HTML-escaped.
* * *
<!-- /div -->
-
<!-- div -->
### <a id="_templatesettingsevaluate"></a>`_.templateSettings.evaluate`
-<a href="#_templatesettingsevaluate">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L835 "View in source") [Ⓣ][1]
+<a href="#_templatesettingsevaluate">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1130 "View in source") [Ⓣ][1]
-*(RegExp)*: Used to detect code to be evaluated.
+(RegExp): Used to detect code to be evaluated.
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_templatesettingsinterpolate"></a>`_.templateSettings.interpolate`
-<a href="#_templatesettingsinterpolate">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L843 "View in source") [Ⓣ][1]
+### <a id="_templatesettingsimports"></a>`_.templateSettings.imports`
+<a href="#_templatesettingsimports">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1154 "View in source") [Ⓣ][1]
-*(RegExp)*: Used to detect `data` property values to inject.
+(Object): Used to import variables into the compiled template.
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_templatesettingsvariable"></a>`_.templateSettings.variable`
-<a href="#_templatesettingsvariable">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L851 "View in source") [Ⓣ][1]
+### <a id="_templatesettingsinterpolate"></a>`_.templateSettings.interpolate`
+<a href="#_templatesettingsinterpolate">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1138 "View in source") [Ⓣ][1]
-*(string)*: Used to reference the data object in the template text.
+(RegExp): Used to detect `data` property values to inject.
* * *
<!-- /div -->
-
<!-- div -->
-### <a id="_templatesettingsimports"></a>`_.templateSettings.imports`
-<a href="#_templatesettingsimports">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/master/lodash.js#L859 "View in source") [Ⓣ][1]
+### <a id="_templatesettingsvariable"></a>`_.templateSettings.variable`
+<a href="#_templatesettingsvariable">#</a> [Ⓢ](https://github.com/lodash/lodash/blob/3.0.0/lodash.src.js#L1146 "View in source") [Ⓣ][1]
-*(Object)*: Used to import variables into the compiled template.
+(string): Used to reference the data object in the template text.
* * *
<!-- /div -->
-
<!-- /div -->
-
<!-- /div -->
-
- [1]: #arrays "Jump back to the TOC."
\ No newline at end of file
+ [1]: #array "Jump back to the TOC."
diff --git a/lodash.js b/lodash.js
index 5b37903..4ecebb5 100644
--- a/lodash.js
+++ b/lodash.js
@@ -1,199 +1,322 @@
/**
* @license
- * Lo-Dash 2.4.1 <http://lodash.com/>
- * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <http://lodash.com/license>
+ * Lo-Dash 3.0.0 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modern -o ./lodash.js`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
*/
;(function() {
- /** Used as a safe reference for `undefined` in pre ES5 environments */
+ /** Used as a safe reference for `undefined` in pre ES5 environments. */
var undefined;
- /** Used to pool arrays and objects used internally */
- var arrayPool = [],
- objectPool = [];
+ /** Used as the semantic version number. */
+ var VERSION = '3.0.0';
+
+ /** Used to compose bitmasks for wrapper metadata. */
+ var BIND_FLAG = 1,
+ BIND_KEY_FLAG = 2,
+ CURRY_BOUND_FLAG = 4,
+ CURRY_FLAG = 8,
+ CURRY_RIGHT_FLAG = 16,
+ PARTIAL_FLAG = 32,
+ PARTIAL_RIGHT_FLAG = 64,
+ REARG_FLAG = 128,
+ ARY_FLAG = 256;
+
+ /** Used as default options for `_.trunc`. */
+ var DEFAULT_TRUNC_LENGTH = 30,
+ DEFAULT_TRUNC_OMISSION = '...';
+
+ /** Used to detect when a function becomes hot. */
+ var HOT_COUNT = 150,
+ HOT_SPAN = 16;
+
+ /** Used to indicate the type of lazy iteratees. */
+ var LAZY_FILTER_FLAG = 0,
+ LAZY_MAP_FLAG = 1,
+ LAZY_WHILE_FLAG = 2;
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used as the internal argument placeholder. */
+ var PLACEHOLDER = '__lodash_placeholder__';
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /** Used to match empty string literals in compiled template source. */
+ var reEmptyStringLeading = /\b__p \+= '';/g,
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
- /** Used to generate unique IDs */
- var idCounter = 0;
+ /** Used to match HTML entities and HTML characters. */
+ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g,
+ reUnescapedHtml = /[&<>"'`]/g,
+ reHasEscapedHtml = RegExp(reEscapedHtml.source),
+ reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
- /** Used internally to indicate various things */
- var indicatorObject = {};
+ /** Used to match template delimiters. */
+ var reEscape = /<%-([\s\S]+?)%>/g,
+ reEvaluate = /<%([\s\S]+?)%>/g,
+ reInterpolate = /<%=([\s\S]+?)%>/g;
- /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
- var keyPrefix = +new Date + '';
+ /**
+ * Used to match ES6 template delimiters.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literal-lexical-components)
+ * for more details.
+ */
+ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
- /** Used as the size when optimizations are enabled for large arrays */
- var largeArraySize = 75;
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
- /** Used as the max size of the `arrayPool` and `objectPool` */
- var maxPoolSize = 40;
+ /** Used to detect named functions. */
+ var reFuncName = /^\s*function[ \n\r\t]+\w/;
- /** Used to detect and test whitespace */
- var whitespace = (
- // whitespace
- ' \t\x0B\f\xA0\ufeff' +
+ /** Used to detect hexadecimal string values. */
+ var reHexPrefix = /^0[xX]/;
- // line terminators
- '\n\r\u2028\u2029' +
+ /** Used to detect host constructors (Safari > 5). */
+ var reHostCtor = /^\[object .+?Constructor\]$/;
- // unicode category "Zs" space separators
- '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
- );
+ /** Used to match latin-1 supplementary letters (excluding mathematical operators). */
+ var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g;
- /** Used to match empty string literals in compiled template source */
- var reEmptyStringLeading = /\b__p \+= '';/g,
- reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
- reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+ /** Used to ensure capturing order of template delimiters. */
+ var reNoMatch = /($^)/;
/**
- * Used to match ES6 template delimiters
- * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
+ * Used to match `RegExp` special characters.
+ * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
+ * for more details.
*/
- var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+ var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
+ reHasRegExpChars = RegExp(reRegExpChars.source);
- /** Used to match regexp flags from their coerced string values */
- var reFlags = /\w*$/;
+ /** Used to detect functions containing a `this` reference. */
+ var reThis = /\bthis\b/;
- /** Used to detected named functions */
- var reFuncName = /^\s*function[ \n\r\t]+\w/;
+ /** Used to match unescaped characters in compiled string literals. */
+ var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
- /** Used to match "interpolate" template delimiters */
- var reInterpolate = /<%=([\s\S]+?)%>/g;
+ /** Used to match words to create compound words. */
+ var reWords = (function() {
+ var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]',
+ lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+';
- /** Used to match leading whitespace and zeros to be removed */
- var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
+ return RegExp(upper + '{2,}(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g');
+ }());
- /** Used to ensure capturing order of template delimiters */
- var reNoMatch = /($^)/;
+ /** Used to detect and test for whitespace. */
+ var whitespace = (
+ // Basic whitespace characters.
+ ' \t\x0b\f\xa0\ufeff' +
- /** Used to detect functions containing a `this` reference */
- var reThis = /\bthis\b/;
+ // Line terminators.
+ '\n\r\u2028\u2029' +
- /** Used to match unescaped characters in compiled string literals */
- var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
+ // Unicode category "Zs" space separators.
+ '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
+ );
- /** Used to assign default `context` object properties */
+ /** Used to assign default `context` object properties. */
var contextProps = [
- 'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object',
- 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
- 'parseInt', 'setTimeout'
- ];
-
- /** Used to fix the JScript [[DontEnum]] bug */
- var shadowedProps = [
- 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
- 'toLocaleString', 'toString', 'valueOf'
+ 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array',
+ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number',
+ 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document',
+ 'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array',
+ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
+ 'window', 'WinRTError'
];
- /** Used to make template sourceURLs easier to identify */
- var templateCounter = 0;
-
- /** `Object#toString` result shortcuts */
- var argsClass = '[object Arguments]',
- arrayClass = '[object Array]',
- boolClass = '[object Boolean]',
- dateClass = '[object Date]',
- errorClass = '[object Error]',
- funcClass = '[object Function]',
- numberClass = '[object Number]',
- objectClass = '[object Object]',
- regexpClass = '[object RegExp]',
- stringClass = '[object String]';
-
- /** Used to identify object classifications that `_.clone` supports */
- var cloneableClasses = {};
- cloneableClasses[funcClass] = false;
- cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
- cloneableClasses[boolClass] = cloneableClasses[dateClass] =
- cloneableClasses[numberClass] = cloneableClasses[objectClass] =
- cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
-
- /** Used as an internal `_.debounce` options object */
+ /** Used to make template sourceURLs easier to identify. */
+ var templateCounter = -1;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dateTag] = typedArrayTags[errorTag] =
+ typedArrayTags[funcTag] = typedArrayTags[mapTag] =
+ typedArrayTags[numberTag] = typedArrayTags[objectTag] =
+ typedArrayTags[regexpTag] = typedArrayTags[setTag] =
+ typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag] = cloneableTags[arrayTag] =
+ cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
+ cloneableTags[dateTag] = cloneableTags[float32Tag] =
+ cloneableTags[float64Tag] = cloneableTags[int8Tag] =
+ cloneableTags[int16Tag] = cloneableTags[int32Tag] =
+ cloneableTags[numberTag] = cloneableTags[objectTag] =
+ cloneableTags[regexpTag] = cloneableTags[stringTag] =
+ cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+ cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+ cloneableTags[errorTag] = cloneableTags[funcTag] =
+ cloneableTags[mapTag] = cloneableTags[setTag] =
+ cloneableTags[weakMapTag] = false;
+
+ /** Used as an internal `_.debounce` options object by `_.throttle`. */
var debounceOptions = {
'leading': false,
'maxWait': 0,
'trailing': false
};
- /** Used as the property descriptor for `__bindData__` */
- var descriptor = {
- 'configurable': false,
- 'enumerable': false,
- 'value': null,
- 'writable': false
+ /** Used to map latin-1 supplementary letters to basic latin letters. */
+ var deburredLetters = {
+ '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+ '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+ '\xc7': 'C', '\xe7': 'c',
+ '\xd0': 'D', '\xf0': 'd',
+ '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+ '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+ '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+ '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
+ '\xd1': 'N', '\xf1': 'n',
+ '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+ '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+ '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+ '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
+ '\xc6': 'Ae', '\xe6': 'ae',
+ '\xde': 'Th', '\xfe': 'th',
+ '\xdf': 'ss'
};
- /** Used as the data object for `iteratorTemplate` */
- var iteratorData = {
- 'args': '',
- 'array': null,
- 'bottom': '',
- 'firstArg': '',
- 'init': '',
- 'keys': null,
- 'loop': '',
- 'shadowedProps': null,
- 'support': null,
- 'top': '',
- 'useHas': false
+ /** Used to map characters to HTML entities. */
+ var htmlEscapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
};
- /** Used to determine if values are of the language type Object */
+ /** Used to map HTML entities to characters. */
+ var htmlUnescapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ ''': "'",
+ '`': '`'
+ };
+
+ /** Used to determine if values are of the language type `Object`. */
var objectTypes = {
- 'boolean': false,
'function': true,
- 'object': true,
- 'number': false,
- 'string': false,
- 'undefined': false
+ 'object': true
};
- /** Used to escape characters for inclusion in compiled string literals */
+ /** Used to escape characters for inclusion in compiled string literals. */
var stringEscapes = {
'\\': '\\',
"'": "'",
'\n': 'n',
'\r': 'r',
- '\t': 't',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
- /** Used as a reference to the global object */
- var root = (objectTypes[typeof window] && window) || this;
+ /**
+ * Used as a reference to the global object.
+ *
+ * The `this` value is used if it is the global object to avoid Greasemonkey's
+ * restricted `window` object, otherwise the `window` object is used.
+ */
+ var root = (objectTypes[typeof window] && window !== (this && this.window)) ? window : this;
- /** Detect free variable `exports` */
+ /** Detect free variable `exports`. */
var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
- /** Detect free variable `module` */
+ /** Detect free variable `module`. */
var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
- /** Detect the popular CommonJS extension `module.exports` */
- var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
-
- /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
- var freeGlobal = objectTypes[typeof global] && global;
- if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */
+ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
root = freeGlobal;
}
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
+
/*--------------------------------------------------------------------------*/
/**
- * The base implementation of `_.indexOf` without support for binary searches
- * or `fromIndex` constraints.
+ * The base implementation of `compareAscending` which compares values and
+ * sorts them in ascending order without guaranteeing a stable sort.
+ *
+ * @private
+ * @param {*} value The value to compare to `other`.
+ * @param {*} other The value to compare to `value`.
+ * @returns {number} Returns the sort order indicator for `value`.
+ */
+ function baseCompareAscending(value, other) {
+ if (value !== other) {
+ var valIsReflexive = value === value,
+ othIsReflexive = other === other;
+
+ if (value > other || !valIsReflexive || (typeof value == 'undefined' && othIsReflexive)) {
+ return 1;
+ }
+ if (value < other || !othIsReflexive || (typeof other == 'undefined' && valIsReflexive)) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * The base implementation of `_.indexOf` without support for binary searches.
*
* @private
* @param {Array} array The array to search.
* @param {*} value The value to search for.
* @param {number} [fromIndex=0] The index to search from.
- * @returns {number} Returns the index of the matched value or `-1`.
+ * @returns {number} Returns the index of the matched value, else `-1`.
*/
function baseIndexOf(array, value, fromIndex) {
+ if (value !== value) {
+ return indexOfNaN(array, fromIndex);
+ }
var index = (fromIndex || 0) - 1,
- length = array ? array.length : 0;
+ length = array.length;
while (++index < length) {
if (array[index] === value) {
@@ -204,267 +327,338 @@
}
/**
- * An implementation of `_.contains` for cache objects that mimics the return
- * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
+ * The base implementation of `_.sortBy` and `_.sortByAll` which uses `comparer`
+ * to define the sort order of `array` and replaces criteria objects with their
+ * corresponding values.
*
* @private
- * @param {Object} cache The cache object to inspect.
- * @param {*} value The value to search for.
- * @returns {number} Returns `0` if `value` is found, else `-1`.
+ * @param {Array} array The array to sort.
+ * @param {Function} comparer The function to define sort order.
+ * @returns {Array} Returns `array`.
*/
- function cacheIndexOf(cache, value) {
- var type = typeof value;
- cache = cache.cache;
+ function baseSortBy(array, comparer) {
+ var length = array.length;
- if (type == 'boolean' || value == null) {
- return cache[value] ? 0 : -1;
+ array.sort(comparer);
+ while (length--) {
+ array[length] = array[length].value;
}
- if (type != 'number' && type != 'string') {
- type = 'object';
+ return array;
+ }
+
+ /**
+ * Converts `value` to a string if it is not one. An empty string is returned
+ * for `null` or `undefined` values.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ if (typeof value == 'string') {
+ return value;
}
- var key = type == 'number' ? value : keyPrefix + value;
- cache = (cache = cache[type]) && cache[key];
+ return value == null ? '' : (value + '');
+ }
- return type == 'object'
- ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
- : (cache ? 0 : -1);
+ /**
+ * Used by `_.max` and `_.min` as the default callback for string values.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the code unit of the first character of the string.
+ */
+ function charAtCallback(string) {
+ return string.charCodeAt(0);
}
/**
- * Adds a given value to the corresponding cache object.
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first character
+ * of `string` that is not found in `chars`.
*
* @private
- * @param {*} value The value to add to the cache.
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the first character not found in `chars`.
*/
- function cachePush(value) {
- var cache = this.cache,
- type = typeof value;
+ function charsLeftIndex(string, chars) {
+ var index = -1,
+ length = string.length;
- if (type == 'boolean' || value == null) {
- cache[value] = true;
- } else {
- if (type != 'number' && type != 'string') {
- type = 'object';
- }
- var key = type == 'number' ? value : keyPrefix + value,
- typeCache = cache[type] || (cache[type] = {});
+ while (++index < length && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
- if (type == 'object') {
- (typeCache[key] || (typeCache[key] = [])).push(value);
- } else {
- typeCache[key] = true;
- }
- }
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the last character not found in `chars`.
+ */
+ function charsRightIndex(string, chars) {
+ var index = string.length;
+
+ while (index-- && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
}
/**
- * Used by `_.max` and `_.min` as the default callback when a given
- * collection is a string value.
+ * Used by `_.sortBy` to compare transformed elements of a collection and stable
+ * sort them in ascending order.
*
* @private
- * @param {string} value The character to inspect.
- * @returns {number} Returns the code unit of given character.
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
*/
- function charAtCallback(value) {
- return value.charCodeAt(0);
+ function compareAscending(object, other) {
+ return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index);
}
/**
- * Used by `sortBy` to compare transformed `collection` elements, stable sorting
- * them in ascending order.
+ * Used by `_.sortByAll` to compare multiple properties of each element
+ * in a collection and stable sort them in ascending order.
*
* @private
- * @param {Object} a The object to compare to `b`.
- * @param {Object} b The object to compare to `a`.
- * @returns {number} Returns the sort order indicator of `1` or `-1`.
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
*/
- function compareAscending(a, b) {
- var ac = a.criteria,
- bc = b.criteria,
- index = -1,
- length = ac.length;
+ function compareMultipleAscending(object, other) {
+ var index = -1,
+ objCriteria = object.criteria,
+ othCriteria = other.criteria,
+ length = objCriteria.length;
while (++index < length) {
- var value = ac[index],
- other = bc[index];
-
- if (value !== other) {
- if (value > other || typeof value == 'undefined') {
- return 1;
- }
- if (value < other || typeof other == 'undefined') {
- return -1;
- }
+ var result = baseCompareAscending(objCriteria[index], othCriteria[index]);
+ if (result) {
+ return result;
}
}
// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
- // that causes it, under certain circumstances, to return the same value for
- // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
+ // that causes it, under certain circumstances, to provide the same value
+ // for `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247.
//
// This also ensures a stable sort in V8 and other engines.
- // See http://code.google.com/p/v8/issues/detail?id=90
- return a.index - b.index;
+ // See https://code.google.com/p/v8/issues/detail?id=90.
+ return object.index - other.index;
}
/**
- * Creates a cache object to optimize linear searches of large arrays.
+ * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
*
* @private
- * @param {Array} [array=[]] The array to search.
- * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
+ * @param {string} letter The matched letter to deburr.
+ * @returns {string} Returns the deburred letter.
*/
- function createCache(array) {
- var index = -1,
- length = array.length,
- first = array[0],
- mid = array[(length / 2) | 0],
- last = array[length - 1];
-
- if (first && typeof first == 'object' &&
- mid && typeof mid == 'object' && last && typeof last == 'object') {
- return false;
- }
- var cache = getObject();
- cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
-
- var result = getObject();
- result.array = array;
- result.cache = cache;
- result.push = cachePush;
-
- while (++index < length) {
- result.push(array[index]);
- }
- return result;
+ function deburrLetter(letter) {
+ return deburredLetters[letter];
}
/**
- * Used by `template` to escape characters for inclusion in compiled
- * string literals.
+ * Used by `_.escape` to convert characters to HTML entities.
*
* @private
- * @param {string} match The matched character to escape.
+ * @param {string} chr The matched character to escape.
* @returns {string} Returns the escaped character.
*/
- function escapeStringChar(match) {
- return '\\' + stringEscapes[match];
+ function escapeHtmlChar(chr) {
+ return htmlEscapes[chr];
}
/**
- * Gets an array from the array pool or creates a new one if the pool is empty.
+ * Used by `_.template` to escape characters for inclusion in compiled
+ * string literals.
*
* @private
- * @returns {Array} The array from the pool.
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
*/
- function getArray() {
- return arrayPool.pop() || [];
+ function escapeStringChar(chr) {
+ return '\\' + stringEscapes[chr];
}
/**
- * Gets an object from the object pool or creates a new one if the pool is empty.
+ * Gets the index at which the first occurrence of `NaN` is found in `array`.
+ * If `fromRight` is provided elements of `array` are iterated from right to left.
*
* @private
- * @returns {Object} The object from the pool.
+ * @param {Array} array The array to search.
+ * @param {number} [fromIndex] The index to search from.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched `NaN`, else `-1`.
*/
- function getObject() {
- return objectPool.pop() || {
- 'array': null,
- 'cache': null,
- 'criteria': null,
- 'false': false,
- 'index': 0,
- 'null': false,
- 'number': null,
- 'object': null,
- 'push': null,
- 'string': null,
- 'true': false,
- 'undefined': false,
- 'value': null
- };
+ function indexOfNaN(array, fromIndex, fromRight) {
+ var length = array.length,
+ index = fromRight ? (fromIndex || length) : ((fromIndex || 0) - 1);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var other = array[index];
+ if (other !== other) {
+ return index;
+ }
+ }
+ return -1;
}
/**
- * Checks if `value` is a DOM node in IE < 9.
+ * Checks if `value` is object-like.
*
* @private
* @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a DOM node, else `false`.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
*/
- function isNode(value) {
- // IE < 9 presents DOM nodes as `Object` objects except they have `toString`
- // methods that are `typeof` "string" and still can coerce nodes to strings
- return typeof value.toString != 'function' && typeof (value + '') == 'string';
+ function isObjectLike(value) {
+ return (value && typeof value == 'object') || false;
}
/**
- * Releases the given array back to the array pool.
+ * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a
+ * character code is whitespace.
*
* @private
- * @param {Array} [array] The array to release.
+ * @param {number} charCode The character code to inspect.
+ * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`.
*/
- function releaseArray(array) {
- array.length = 0;
- if (arrayPool.length < maxPoolSize) {
- arrayPool.push(array);
- }
+ function isSpace(charCode) {
+ return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 ||
+ (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279)));
}
/**
- * Releases the given object back to the object pool.
+ * Replaces all `placeholder` elements in `array` with an internal placeholder
+ * and returns an array of their indexes.
*
* @private
- * @param {Object} [object] The object to release.
+ * @param {Array} array The array to modify.
+ * @param {*} placeholder The placeholder to replace.
+ * @returns {Array} Returns the new array of placeholder indexes.
*/
- function releaseObject(object) {
- var cache = object.cache;
- if (cache) {
- releaseObject(cache);
- }
- object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
- if (objectPool.length < maxPoolSize) {
- objectPool.push(object);
+ function replaceHolders(array, placeholder) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ if (array[index] === placeholder) {
+ array[index] = PLACEHOLDER;
+ result[++resIndex] = index;
+ }
}
+ return result;
}
/**
- * Slices the `collection` from the `start` index up to, but not including,
- * the `end` index.
- *
- * Note: This function is used instead of `Array#slice` to support node lists
- * in IE < 9 and to ensure dense arrays are returned.
+ * An implementation of `_.uniq` optimized for sorted arrays without support
+ * for callback shorthands and `this` binding.
*
* @private
- * @param {Array|Object|string} collection The collection to slice.
- * @param {number} start The start index.
- * @param {number} end The end index.
- * @returns {Array} Returns the new array.
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
*/
- function slice(array, start, end) {
- start || (start = 0);
- if (typeof end == 'undefined') {
- end = array ? array.length : 0;
- }
- var index = -1,
- length = end - start || 0,
- result = Array(length < 0 ? 0 : length);
+ function sortedUniq(array, iteratee) {
+ var seen,
+ index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
while (++index < length) {
- result[index] = array[start + index];
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (!index || seen !== computed) {
+ seen = computed;
+ result[++resIndex] = value;
+ }
}
return result;
}
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the first non-whitespace character.
+ */
+ function trimmedLeftIndex(string) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the last non-whitespace character.
+ */
+ function trimmedRightIndex(string) {
+ var index = string.length;
+
+ while (index-- && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} chr The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ function unescapeHtmlChar(chr) {
+ return htmlUnescapes[chr];
+ }
+
/*--------------------------------------------------------------------------*/
/**
- * Create a new `lodash` function using the given context object.
+ * Create a new pristine `lodash` function using the given `context` object.
*
* @static
* @memberOf _
- * @category Utilities
+ * @category Utility
* @param {Object} [context=root] The context object.
- * @returns {Function} Returns the `lodash` function.
+ * @returns {Function} Returns a new `lodash` function.
+ * @example
+ *
+ * _.mixin({ 'add': function(a, b) { return a + b; } });
+ *
+ * var lodash = _.runInContext();
+ * lodash.mixin({ 'sub': function(a, b) { return a - b; } });
+ *
+ * _.isFunction(_.add);
+ * // => true
+ * _.isFunction(_.sub);
+ * // => false
+ *
+ * lodash.isFunction(lodash.add);
+ * // => false
+ * lodash.isFunction(lodash.sub);
+ * // => true
+ *
+ * // using `context` to mock `Date#getTime` use in `_.now`
+ * var mock = _.runInContext({
+ * 'Date': function() {
+ * return { 'getTime': getTimeMock };
+ * }
+ * });
+ *
+ * // or creating a suped-up `defer` in Node.js
+ * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
*/
function runInContext(context) {
// Avoid issues with some ES3 environments that attempt to use values, named
@@ -473,9 +667,8 @@
// See http://es5.github.io/#x11.1.5.
context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
- /** Native constructor references */
+ /** Native constructor references. */
var Array = context.Array,
- Boolean = context.Boolean,
Date = context.Date,
Error = context.Error,
Function = context.Function,
@@ -486,141 +679,168 @@
String = context.String,
TypeError = context.TypeError;
+ /** Used for native method references. */
+ var arrayProto = Array.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect DOM support. */
+ var document = (document = context.window) && document.document;
+
+ /** Used to resolve the decompiled source of functions. */
+ var fnToString = Function.prototype.toString;
+
+ /** Used to the length of n-tuples for `_.unzip`. */
+ var getLength = baseProperty('length');
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to generate unique IDs. */
+ var idCounter = 0;
+
/**
- * Used for `Array` method references.
- *
- * Normally `Array.prototype` would suffice, however, using an array literal
- * avoids issues in Narwhal.
+ * Used to resolve the `toStringTag` of values.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
+ * for more details.
*/
- var arrayRef = [];
-
- /** Used for native method references */
- var errorProto = Error.prototype,
- objectProto = Object.prototype,
- stringProto = String.prototype;
+ var objToString = objectProto.toString;
- /** Used to restore the original `_` reference in `noConflict` */
+ /** Used to restore the original `_` reference in `_.noConflict`. */
var oldDash = context._;
- /** Used to resolve the internal [[Class]] of values */
- var toString = objectProto.toString;
-
- /** Used to detect if a method is native */
+ /** Used to detect if a method is native. */
var reNative = RegExp('^' +
- String(toString)
- .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
- .replace(/toString| for [^\]]+/g, '.*?') + '$'
+ escapeRegExp(objToString)
+ .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
- /** Native method shortcuts */
- var ceil = Math.ceil,
+ /** Native method references. */
+ var ArrayBuffer = isNative(ArrayBuffer = context.ArrayBuffer) && ArrayBuffer,
+ bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice,
+ ceil = Math.ceil,
clearTimeout = context.clearTimeout,
floor = Math.floor,
- fnToString = Function.prototype.toString,
getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
- hasOwnProperty = objectProto.hasOwnProperty,
- push = arrayRef.push,
+ push = arrayProto.push,
propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ Set = isNative(Set = context.Set) && Set,
setTimeout = context.setTimeout,
- splice = arrayRef.splice,
- unshift = arrayRef.unshift;
-
- /** Used to set meta data on functions */
- var defineProperty = (function() {
- // IE 8 only accepts DOM elements
+ splice = arrayProto.splice,
+ Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array,
+ unshift = arrayProto.unshift,
+ WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap;
+
+ /** Used to clone array buffers. */
+ var Float64Array = (function() {
+ // Safari 5 errors when using an array buffer to initialize a typed array
+ // where the array buffer's `byteLength` is not a multiple of the typed
+ // array's `BYTES_PER_ELEMENT`.
try {
- var o = {},
- func = isNative(func = Object.defineProperty) && func,
- result = func(o, o, o) && func;
- } catch(e) { }
+ var func = isNative(func = context.Float64Array) && func,
+ result = new func(new ArrayBuffer(10), 0, 1) && func;
+ } catch(e) {}
return result;
}());
- /* Native method shortcuts for methods with the same name as other `lodash` methods */
- var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
- nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
+ /* Native method references for those with the same name as other `lodash` methods. */
+ var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
+ nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
nativeIsFinite = context.isFinite,
- nativeIsNaN = context.isNaN,
nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
nativeMax = Math.max,
nativeMin = Math.min,
+ nativeNow = isNative(nativeNow = Date.now) && nativeNow,
+ nativeNumIsFinite = isNative(nativeNumIsFinite = Number.isFinite) && nativeNumIsFinite,
nativeParseInt = context.parseInt,
nativeRandom = Math.random;
- /** Used to lookup a built-in constructor by [[Class]] */
- var ctorByClass = {};
- ctorByClass[arrayClass] = Array;
- ctorByClass[boolClass] = Boolean;
- ctorByClass[dateClass] = Date;
- ctorByClass[funcClass] = Function;
- ctorByClass[objectClass] = Object;
- ctorByClass[numberClass] = Number;
- ctorByClass[regexpClass] = RegExp;
- ctorByClass[stringClass] = String;
-
- /** Used to avoid iterating non-enumerable properties in IE < 9 */
- var nonEnumProps = {};
- nonEnumProps[arrayClass] = nonEnumProps[dateClass] = nonEnumProps[numberClass] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
- nonEnumProps[boolClass] = nonEnumProps[stringClass] = { 'constructor': true, 'toString': true, 'valueOf': true };
- nonEnumProps[errorClass] = nonEnumProps[funcClass] = nonEnumProps[regexpClass] = { 'constructor': true, 'toString': true };
- nonEnumProps[objectClass] = { 'constructor': true };
-
- (function() {
- var length = shadowedProps.length;
- while (length--) {
- var key = shadowedProps[length];
- for (var className in nonEnumProps) {
- if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], key)) {
- nonEnumProps[className][key] = false;
- }
- }
- }
- }());
+ /** Used as references for `-Infinity` and `Infinity`. */
+ var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY,
+ POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
+
+ /** Used as references for the maximum length and index of an array. */
+ var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1,
+ MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+ HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+ /** Used as the size, in bytes, of each `Float64Array` element. */
+ var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;
+
+ /**
+ * Used as the maximum length of an array-like value.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
+ * for more details.
+ */
+ var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
- /*--------------------------------------------------------------------------*/
+ /** Used to store function metadata. */
+ var metaMap = WeakMap && new WeakMap;
+
+ /*------------------------------------------------------------------------*/
/**
- * Creates a `lodash` object which wraps the given value to enable intuitive
- * method chaining.
+ * Creates a `lodash` object which wraps `value` to enable intuitive chaining.
+ * Methods that operate on and return arrays, collections, and functions can
+ * be chained together. Methods that return a boolean or single value will
+ * automatically end the chain returning the unwrapped value. Explicit chaining
+ * may be enabled using `_.chain`. The execution of chained methods is lazy,
+ * that is, execution is deferred until `_#value` is implicitly or explicitly
+ * called.
+ *
+ * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
+ * fusion is an optimization that merges iteratees to avoid creating intermediate
+ * arrays and reduce the number of iteratee executions.
+ *
+ * Chaining is supported in custom builds as long as the `_#value` method is
+ * directly or indirectly included in the build.
*
* In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
* `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
* and `unshift`
*
- * Chaining is supported in custom builds as long as the `value` method is
- * implicitly or explicitly included in the build.
+ * The wrapper functions that support shortcut fusion are:
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `first`,
+ * `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, `slice`,
+ * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `where`
*
* The chainable wrapper functions are:
- * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
- * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
- * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
- * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
- * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
- * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
- * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
- * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
- * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
- * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
- * and `zip`
- *
- * The non-chainable wrapper functions are:
- * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
- * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
- * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
- * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
- * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
- * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
- * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
- * `template`, `unescape`, `uniqueId`, and `value`
- *
- * The wrapper functions `first` and `last` return wrapped values when `n` is
- * provided, otherwise they return unwrapped values.
- *
- * Explicit chaining can be enabled by using the `_.chain` method.
+ * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
+ * `callback`, `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`,
+ * `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`,
+ * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`,
+ * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`,
+ * `initial`, `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`,
+ * `mapValues`, `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`,
+ * `omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`,
+ * `pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`,
+ * `rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
+ * `sortBy`, `sortByAll`, `splice`, `take`, `takeRight`, `takeRightWhile`,
+ * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
+ * `transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`,
+ * `where`, `without`, `wrap`, `xor`, `zip`, and `zipObject`
+ *
+ * The wrapper functions that are **not** chainable by default are:
+ * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
+ * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`,
+ * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`,
+ * `identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`,
+ * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`,
+ * `isFunction`, `isMatch` , `isNative`, `isNaN`, `isNull`, `isNumber`,
+ * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`,
+ * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`,
+ * `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`,
+ * `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`,
+ * `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`,
+ * `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
+ * `unescape`, `uniqueId`, `value`, and `words`
+ *
+ * The wrapper function `sample` will return a wrapped value when `n` is provided,
+ * otherwise an unwrapped value is returned.
*
* @name _
* @constructor
- * @category Chaining
+ * @category Chain
* @param {*} value The value to wrap in a `lodash` instance.
* @returns {Object} Returns a `lodash` instance.
* @example
@@ -628,15 +848,11 @@
* var wrapped = _([1, 2, 3]);
*
* // returns an unwrapped value
- * wrapped.reduce(function(sum, num) {
- * return sum + num;
- * });
+ * wrapped.reduce(function(sum, n) { return sum + n; });
* // => 6
*
* // returns a wrapped value
- * var squares = wrapped.map(function(num) {
- * return num * num;
- * });
+ * var squares = wrapped.map(function(n) { return n * n; });
*
* _.isArray(squares);
* // => false
@@ -645,29 +861,33 @@
* // => true
*/
function lodash(value) {
- // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
- return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
- ? value
- : new lodashWrapper(value);
+ if (isObjectLike(value) && !isArray(value)) {
+ if (value instanceof LodashWrapper) {
+ return value;
+ }
+ if (hasOwnProperty.call(value, '__wrapped__')) {
+ return new LodashWrapper(value.__wrapped__, value.__chain__, arrayCopy(value.__actions__));
+ }
+ }
+ return new LodashWrapper(value);
}
/**
- * A fast path for creating `lodash` wrapper objects.
+ * The base constructor for creating `lodash` wrapper objects.
*
* @private
- * @param {*} value The value to wrap in a `lodash` instance.
- * @param {boolean} chainAll A flag to enable chaining for all methods
- * @returns {Object} Returns a `lodash` instance.
+ * @param {*} value The value to wrap.
+ * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
+ * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
*/
- function lodashWrapper(value, chainAll) {
+ function LodashWrapper(value, chainAll, actions) {
+ this.__actions__ = actions || [];
this.__chain__ = !!chainAll;
this.__wrapped__ = value;
}
- // ensure `new lodashWrapper` is an instance of `lodash`
- lodashWrapper.prototype = lodash.prototype;
/**
- * An object used to flag environments features.
+ * An object environment feature flags.
*
* @static
* @memberOf _
@@ -675,56 +895,12 @@
*/
var support = lodash.support = {};
- (function() {
- var ctor = function() { this.x = 1; },
- object = { '0': 1, 'length': 1 },
- props = [];
-
- ctor.prototype = { 'valueOf': 1, 'y': 1 };
- for (var key in new ctor) { props.push(key); }
- for (key in arguments) { }
-
- /**
- * Detect if an `arguments` object's [[Class]] is resolvable (all but Firefox < 4, IE < 9).
- *
- * @memberOf _.support
- * @type boolean
- */
- support.argsClass = toString.call(arguments) == argsClass;
-
- /**
- * Detect if `arguments` objects are `Object` objects (all but Narwhal and Opera < 10.5).
- *
- * @memberOf _.support
- * @type boolean
- */
- support.argsObject = arguments.constructor == Object && !(arguments instanceof Array);
-
- /**
- * Detect if `name` or `message` properties of `Error.prototype` are
- * enumerable by default. (IE < 9, Safari < 5.1)
- *
- * @memberOf _.support
- * @type boolean
- */
- support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name');
-
- /**
- * Detect if `prototype` properties are enumerable by default.
- *
- * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
- * (if the prototype or a property on the prototype has been set)
- * incorrectly sets a function's `prototype` property [[Enumerable]]
- * value to `true`.
- *
- * @memberOf _.support
- * @type boolean
- */
- support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype');
+ (function(x) {
/**
* Detect if functions can be decompiled by `Function#toString`
- * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
+ * (all but Firefox OS certified apps, older Opera mobile browsers, and
+ * the PlayStation 3; forced `false` for Windows 8 apps).
*
* @memberOf _.support
* @type boolean
@@ -740,77 +916,40 @@
support.funcNames = typeof Function.name == 'string';
/**
- * Detect if `arguments` object indexes are non-enumerable
- * (Firefox < 4, IE < 9, PhantomJS, Safari < 5.1).
- *
- * @memberOf _.support
- * @type boolean
- */
- support.nonEnumArgs = key != 0;
-
- /**
- * Detect if properties shadowing those on `Object.prototype` are non-enumerable.
- *
- * In IE < 9 an objects own properties, shadowing non-enumerable ones, are
- * made non-enumerable as well (a.k.a the JScript [[DontEnum]] bug).
- *
- * @memberOf _.support
- * @type boolean
- */
- support.nonEnumShadows = !/valueOf/.test(props);
-
- /**
- * Detect if own properties are iterated after inherited properties (all but IE < 9).
- *
- * @memberOf _.support
- * @type boolean
- */
- support.ownLast = props[0] != 'x';
-
- /**
- * Detect if `Array#shift` and `Array#splice` augment array-like objects correctly.
- *
- * Firefox < 10, IE compatibility mode, and IE < 9 have buggy Array `shift()`
- * and `splice()` functions that fail to remove the last element, `value[0]`,
- * of array-like objects even though the `length` property is set to `0`.
- * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
- * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
+ * Detect if the DOM is supported.
*
* @memberOf _.support
* @type boolean
*/
- support.spliceObjects = (arrayRef.splice.call(object, 0, 1), !object[0]);
+ try {
+ support.dom = document.createDocumentFragment().nodeType === 11;
+ } catch(e) {
+ support.dom = false;
+ }
/**
- * Detect lack of support for accessing string characters by index.
- *
- * IE < 8 can't access characters by index and IE 8 can only access
- * characters by index on string literals.
+ * Detect if `arguments` object indexes are non-enumerable.
*
- * @memberOf _.support
- * @type boolean
- */
- support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx';
-
- /**
- * Detect if a DOM node's [[Class]] is resolvable (all but IE < 9)
- * and that the JS engine errors when attempting to coerce an object to
- * a string without a `toString` function.
+ * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object
+ * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat
+ * `arguments` object indexes as non-enumerable and fail `hasOwnProperty`
+ * checks for indexes that exceed their function's formal parameters with
+ * associated values of `0`.
*
* @memberOf _.support
* @type boolean
*/
try {
- support.nodeClass = !(toString.call(document) == objectClass && !({ 'toString': 0 } + ''));
+ support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1);
} catch(e) {
- support.nodeClass = true;
+ support.nonEnumArgs = true;
}
- }(1));
+ }(0, 0));
/**
- * By default, the template delimiters used by Lo-Dash are similar to those in
- * embedded Ruby (ERB). Change the following template settings to use alternative
- * delimiters.
+ * By default, the template delimiters used by Lo-Dash are like those in
+ * embedded Ruby (ERB). Change the following template settings to use
+ * alternative delimiters.
*
* @static
* @memberOf _
@@ -824,7 +963,7 @@
* @memberOf _.templateSettings
* @type RegExp
*/
- 'escape': /<%-([\s\S]+?)%>/g,
+ 'escape': reEscape,
/**
* Used to detect code to be evaluated.
@@ -832,7 +971,7 @@
* @memberOf _.templateSettings
* @type RegExp
*/
- 'evaluate': /<%([\s\S]+?)%>/g,
+ 'evaluate': reEvaluate,
/**
* Used to detect `data` property values to inject.
@@ -868,1486 +1007,901 @@
}
};
- /*--------------------------------------------------------------------------*/
+ /*------------------------------------------------------------------------*/
/**
- * The template used to create iterator functions.
+ * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
*
* @private
- * @param {Object} data The data object used to populate the text.
- * @returns {string} Returns the interpolated text.
- */
- var iteratorTemplate = template(
- // the `iterable` may be reassigned by the `top` snippet
- 'var index, iterable = <%= firstArg %>, ' +
- // assign the `result` variable an initial value
- 'result = <%= init %>;\n' +
- // exit early if the first argument is falsey
- 'if (!iterable) return result;\n' +
- // add code before the iteration branches
- '<%= top %>;' +
-
- // array-like iteration:
- '<% if (array) { %>\n' +
- 'var length = iterable.length; index = -1;\n' +
- 'if (<%= array %>) {' +
-
- // add support for accessing string characters by index if needed
- ' <% if (support.unindexedChars) { %>\n' +
- ' if (isString(iterable)) {\n' +
- " iterable = iterable.split('')\n" +
- ' }' +
- ' <% } %>\n' +
-
- // iterate over the array-like value
- ' while (++index < length) {\n' +
- ' <%= loop %>;\n' +
- ' }\n' +
- '}\n' +
- 'else {' +
-
- // object iteration:
- // add support for iterating over `arguments` objects if needed
- ' <% } else if (support.nonEnumArgs) { %>\n' +
- ' var length = iterable.length; index = -1;\n' +
- ' if (length && isArguments(iterable)) {\n' +
- ' while (++index < length) {\n' +
- " index += '';\n" +
- ' <%= loop %>;\n' +
- ' }\n' +
- ' } else {' +
- ' <% } %>' +
-
- // avoid iterating over `prototype` properties in older Firefox, Opera, and Safari
- ' <% if (support.enumPrototypes) { %>\n' +
- " var skipProto = typeof iterable == 'function';\n" +
- ' <% } %>' +
-
- // avoid iterating over `Error.prototype` properties in older IE and Safari
- ' <% if (support.enumErrorProps) { %>\n' +
- ' var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n' +
- ' <% } %>' +
-
- // define conditions used in the loop
- ' <%' +
- ' var conditions = [];' +
- ' if (support.enumPrototypes) { conditions.push(\'!(skipProto && index == "prototype")\'); }' +
- ' if (support.enumErrorProps) { conditions.push(\'!(skipErrorProps && (index == "message" || index == "name"))\'); }' +
- ' %>' +
-
- // iterate own properties using `Object.keys`
- ' <% if (useHas && keys) { %>\n' +
- ' var ownIndex = -1,\n' +
- ' ownProps = objectTypes[typeof iterable] && keys(iterable),\n' +
- ' length = ownProps ? ownProps.length : 0;\n\n' +
- ' while (++ownIndex < length) {\n' +
- ' index = ownProps[ownIndex];\n<%' +
- " if (conditions.length) { %> if (<%= conditions.join(' && ') %>) {\n <% } %>" +
- ' <%= loop %>;' +
- ' <% if (conditions.length) { %>\n }<% } %>\n' +
- ' }' +
-
- // else using a for-in loop
- ' <% } else { %>\n' +
- ' for (index in iterable) {\n<%' +
- ' if (useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); }' +
- " if (conditions.length) { %> if (<%= conditions.join(' && ') %>) {\n <% } %>" +
- ' <%= loop %>;' +
- ' <% if (conditions.length) { %>\n }<% } %>\n' +
- ' }' +
-
- // Because IE < 9 can't set the `[[Enumerable]]` attribute of an
- // existing property and the `constructor` property of a prototype
- // defaults to non-enumerable, Lo-Dash skips the `constructor`
- // property when it infers it's iterating over a `prototype` object.
- ' <% if (support.nonEnumShadows) { %>\n\n' +
- ' if (iterable !== objectProto) {\n' +
- " var ctor = iterable.constructor,\n" +
- ' isProto = iterable === (ctor && ctor.prototype),\n' +
- ' className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n' +
- ' nonEnum = nonEnumProps[className];\n' +
- ' <% for (k = 0; k < 7; k++) { %>\n' +
- " index = '<%= shadowedProps[k] %>';\n" +
- ' if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))<%' +
- ' if (!useHas) { %> || (!nonEnum[index] && iterable[index] !== objectProto[index])<% }' +
- ' %>) {\n' +
- ' <%= loop %>;\n' +
- ' }' +
- ' <% } %>\n' +
- ' }' +
- ' <% } %>' +
- ' <% } %>' +
- ' <% if (array || support.nonEnumArgs) { %>\n}<% } %>\n' +
-
- // add code to the bottom of the iteration function
- '<%= bottom %>;\n' +
- // finally, return the `result`
- 'return result'
- );
+ * @param {*} value The value to wrap.
+ */
+ function LazyWrapper(value) {
+ this.actions = null;
+ this.dir = 1;
+ this.dropCount = 0;
+ this.filtered = false;
+ this.iteratees = null;
+ this.takeCount = POSITIVE_INFINITY;
+ this.views = null;
+ this.wrapped = value;
+ }
- /*--------------------------------------------------------------------------*/
+ /**
+ * Creates a clone of the lazy wrapper object.
+ *
+ * @private
+ * @name clone
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the cloned `LazyWrapper` object.
+ */
+ function lazyClone() {
+ var actions = this.actions,
+ iteratees = this.iteratees,
+ views = this.views,
+ result = new LazyWrapper(this.wrapped);
+
+ result.actions = actions ? arrayCopy(actions) : null;
+ result.dir = this.dir;
+ result.dropCount = this.dropCount;
+ result.filtered = this.filtered;
+ result.iteratees = iteratees ? arrayCopy(iteratees) : null;
+ result.takeCount = this.takeCount;
+ result.views = views ? arrayCopy(views) : null;
+ return result;
+ }
/**
- * The base implementation of `_.bind` that creates the bound function and
- * sets its meta data.
+ * Reverses the direction of lazy iteration.
*
* @private
- * @param {Array} bindData The bind data array.
- * @returns {Function} Returns the new bound function.
+ * @name reverse
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the new reversed `LazyWrapper` object.
*/
- function baseBind(bindData) {
- var func = bindData[0],
- partialArgs = bindData[2],
- thisArg = bindData[4];
+ function lazyReverse() {
+ var filtered = this.filtered,
+ result = filtered ? new LazyWrapper(this) : this.clone();
+
+ result.dir = this.dir * -1;
+ result.filtered = filtered;
+ return result;
+ }
- function bound() {
- // `Function#bind` spec
- // http://es5.github.io/#x15.3.4.5
- if (partialArgs) {
- // avoid `arguments` object deoptimizations by using `slice` instead
- // of `Array.prototype.slice.call` and not assigning `arguments` to a
- // variable as a ternary expression
- var args = slice(partialArgs);
- push.apply(args, arguments);
+ /**
+ * Extracts the unwrapped value from its lazy wrapper.
+ *
+ * @private
+ * @name value
+ * @memberOf LazyWrapper
+ * @returns {*} Returns the unwrapped value.
+ */
+ function lazyValue() {
+ var array = this.wrapped.value();
+ if (!isArray(array)) {
+ return baseWrapperValue(array, this.actions);
+ }
+ var dir = this.dir,
+ isRight = dir < 0,
+ length = array.length,
+ view = getView(0, length, this.views),
+ start = view.start,
+ end = view.end,
+ dropCount = this.dropCount,
+ takeCount = nativeMin(end - start, this.takeCount - dropCount),
+ index = isRight ? end : start - 1,
+ iteratees = this.iteratees,
+ iterLength = iteratees ? iteratees.length : 0,
+ resIndex = 0,
+ result = [];
+
+ outer:
+ while (length-- && resIndex < takeCount) {
+ index += dir;
+
+ var iterIndex = -1,
+ value = array[index];
+
+ while (++iterIndex < iterLength) {
+ var data = iteratees[iterIndex],
+ iteratee = data.iteratee,
+ computed = iteratee(value, index, array),
+ type = data.type;
+
+ if (type == LAZY_MAP_FLAG) {
+ value = computed;
+ } else if (!computed) {
+ if (type == LAZY_FILTER_FLAG) {
+ continue outer;
+ } else {
+ break outer;
+ }
+ }
}
- // mimic the constructor's `return` behavior
- // http://es5.github.io/#x13.2.2
- if (this instanceof bound) {
- // ensure `new bound` is an instance of `func`
- var thisBinding = baseCreate(func.prototype),
- result = func.apply(thisBinding, args || arguments);
- return isObject(result) ? result : thisBinding;
+ if (dropCount) {
+ dropCount--;
+ } else {
+ result[resIndex++] = value;
}
- return func.apply(thisArg, args || arguments);
}
- setBindData(bound, bindData);
- return bound;
+ return isRight ? result.reverse() : result;
}
+ /*------------------------------------------------------------------------*/
+
/**
- * The base implementation of `_.clone` without argument juggling or support
- * for `thisArg` binding.
+ * Creates a cache object to store key/value pairs.
*
* @private
- * @param {*} value The value to clone.
- * @param {boolean} [isDeep=false] Specify a deep clone.
- * @param {Function} [callback] The function to customize cloning values.
- * @param {Array} [stackA=[]] Tracks traversed source objects.
- * @param {Array} [stackB=[]] Associates clones with source counterparts.
- * @returns {*} Returns the cloned value.
+ * @static
+ * @name Cache
+ * @memberOf _.memoize
*/
- function baseClone(value, isDeep, callback, stackA, stackB) {
- if (callback) {
- var result = callback(value);
- if (typeof result != 'undefined') {
- return result;
- }
- }
- // inspect [[Class]]
- var isObj = isObject(value);
- if (isObj) {
- var className = toString.call(value);
- if (!cloneableClasses[className] || (!support.nodeClass && isNode(value))) {
- return value;
- }
- var ctor = ctorByClass[className];
- switch (className) {
- case boolClass:
- case dateClass:
- return new ctor(+value);
-
- case numberClass:
- case stringClass:
- return new ctor(value);
-
- case regexpClass:
- result = ctor(value.source, reFlags.exec(value));
- result.lastIndex = value.lastIndex;
- return result;
- }
- } else {
- return value;
- }
- var isArr = isArray(value);
- if (isDeep) {
- // check for circular references and return corresponding clone
- var initedStack = !stackA;
- stackA || (stackA = getArray());
- stackB || (stackB = getArray());
-
- var length = stackA.length;
- while (length--) {
- if (stackA[length] == value) {
- return stackB[length];
- }
- }
- result = isArr ? ctor(value.length) : {};
- }
- else {
- result = isArr ? slice(value) : assign({}, value);
- }
- // add array properties assigned by `RegExp#exec`
- if (isArr) {
- if (hasOwnProperty.call(value, 'index')) {
- result.index = value.index;
- }
- if (hasOwnProperty.call(value, 'input')) {
- result.input = value.input;
- }
- }
- // exit for shallow clone
- if (!isDeep) {
- return result;
- }
- // add the source value to the stack of traversed objects
- // and associate it with its clone
- stackA.push(value);
- stackB.push(result);
+ function MapCache() {
+ this.__data__ = {};
+ }
- // recursively populate clone (susceptible to call stack limits)
- (isArr ? baseEach : forOwn)(value, function(objValue, key) {
- result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
- });
+ /**
+ * Removes `key` and its value from the cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`.
+ */
+ function mapDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
- if (initedStack) {
- releaseArray(stackA);
- releaseArray(stackB);
- }
- return result;
+ /**
+ * Gets the cached value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the cached value.
+ */
+ function mapGet(key) {
+ return key == '__proto__' ? undefined : this.__data__[key];
}
/**
- * The base implementation of `_.create` without support for assigning
- * properties to the created object.
+ * Checks if a cached value for `key` exists.
*
* @private
- * @param {Object} prototype The object to inherit from.
- * @returns {Object} Returns the new object.
+ * @name has
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
- function baseCreate(prototype, properties) {
- return isObject(prototype) ? nativeCreate(prototype) : {};
- }
- // fallback for browsers without `Object.create`
- if (!nativeCreate) {
- baseCreate = (function() {
- function Object() {}
- return function(prototype) {
- if (isObject(prototype)) {
- Object.prototype = prototype;
- var result = new Object;
- Object.prototype = null;
- }
- return result || context.Object();
- };
- }());
+ function mapHas(key) {
+ return key != '__proto__' && hasOwnProperty.call(this.__data__, key);
}
/**
- * The base implementation of `_.createCallback` without support for creating
- * "_.pluck" or "_.where" style callbacks.
+ * Adds `value` to `key` of the cache.
*
* @private
- * @param {*} [func=identity] The value to convert to a callback.
- * @param {*} [thisArg] The `this` binding of the created callback.
- * @param {number} [argCount] The number of arguments the callback accepts.
- * @returns {Function} Returns a callback function.
+ * @name set
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to cache.
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache object.
*/
- function baseCreateCallback(func, thisArg, argCount) {
- if (typeof func != 'function') {
- return identity;
- }
- // exit early for no `thisArg` or already bound by `Function#bind`
- if (typeof thisArg == 'undefined' || !('prototype' in func)) {
- return func;
- }
- var bindData = func.__bindData__;
- if (typeof bindData == 'undefined') {
- if (support.funcNames) {
- bindData = !func.name;
- }
- bindData = bindData || !support.funcDecomp;
- if (!bindData) {
- var source = fnToString.call(func);
- if (!support.funcNames) {
- bindData = !reFuncName.test(source);
- }
- if (!bindData) {
- // checks if `func` references the `this` keyword and stores the result
- bindData = reThis.test(source);
- setBindData(func, bindData);
- }
- }
- }
- // exit early if there are no `this` references or `func` is bound
- if (bindData === false || (bindData !== true && bindData[1] & 1)) {
- return func;
+ function mapSet(key, value) {
+ if (key != '__proto__') {
+ this.__data__[key] = value;
}
- switch (argCount) {
- case 1: return function(value) {
- return func.call(thisArg, value);
- };
- case 2: return function(a, b) {
- return func.call(thisArg, a, b);
- };
- case 3: return function(value, index, collection) {
- return func.call(thisArg, value, index, collection);
- };
- case 4: return function(accumulator, value, index, collection) {
- return func.call(thisArg, accumulator, value, index, collection);
- };
+ return this;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ *
+ * Creates a cache object to store unique values.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var length = values ? values.length : 0;
+
+ this.data = { 'hash': nativeCreate(null), 'set': new Set };
+ while (length--) {
+ this.push(values[length]);
}
- return bind(func, thisArg);
}
/**
- * The base implementation of `createWrapper` that creates the wrapper and
- * sets its meta data.
+ * Checks if `value` is in `cache` mimicking the return signature of
+ * `_.indexOf` by returning `0` if the value is found, else `-1`.
*
* @private
- * @param {Array} bindData The bind data array.
- * @returns {Function} Returns the new function.
+ * @param {Object} cache The cache to search.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `0` if `value` is found, else `-1`.
*/
- function baseCreateWrapper(bindData) {
- var func = bindData[0],
- bitmask = bindData[1],
- partialArgs = bindData[2],
- partialRightArgs = bindData[3],
- thisArg = bindData[4],
- arity = bindData[5];
-
- var isBind = bitmask & 1,
- isBindKey = bitmask & 2,
- isCurry = bitmask & 4,
- isCurryBound = bitmask & 8,
- key = func;
+ function cacheIndexOf(cache, value) {
+ var data = cache.data,
+ result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
- function bound() {
- var thisBinding = isBind ? thisArg : this;
- if (partialArgs) {
- var args = slice(partialArgs);
- push.apply(args, arguments);
- }
- if (partialRightArgs || isCurry) {
- args || (args = slice(arguments));
- if (partialRightArgs) {
- push.apply(args, partialRightArgs);
- }
- if (isCurry && args.length < arity) {
- bitmask |= 16 & ~32;
- return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
- }
- }
- args || (args = arguments);
- if (isBindKey) {
- func = thisBinding[key];
- }
- if (this instanceof bound) {
- thisBinding = baseCreate(func.prototype);
- var result = func.apply(thisBinding, args);
- return isObject(result) ? result : thisBinding;
- }
- return func.apply(thisBinding, args);
+ return result ? 0 : -1;
+ }
+
+ /**
+ * Adds `value` to the cache.
+ *
+ * @private
+ * @name push
+ * @memberOf SetCache
+ * @param {*} value The value to cache.
+ */
+ function cachePush(value) {
+ var data = this.data;
+ if (typeof value == 'string' || isObject(value)) {
+ data.set.add(value);
+ } else {
+ data.hash[value] = true;
}
- setBindData(bound, bindData);
- return bound;
}
+ /*------------------------------------------------------------------------*/
+
/**
- * The base implementation of `_.difference` that accepts a single array
- * of values to exclude.
+ * Copies the values of `source` to `array`.
*
* @private
- * @param {Array} array The array to process.
- * @param {Array} [values] The array of values to exclude.
- * @returns {Array} Returns a new array of filtered values.
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
*/
- function baseDifference(array, values) {
+ function arrayCopy(source, array) {
var index = -1,
- indexOf = getIndexOf(),
- length = array ? array.length : 0,
- isLarge = length >= largeArraySize && indexOf === baseIndexOf,
- result = [];
+ length = source.length;
- if (isLarge) {
- var cache = createCache(values);
- if (cache) {
- indexOf = cacheIndexOf;
- values = cache;
- } else {
- isLarge = false;
- }
- }
+ array || (array = Array(length));
while (++index < length) {
- var value = array[index];
- if (indexOf(values, value) < 0) {
- result.push(value);
- }
- }
- if (isLarge) {
- releaseObject(values);
+ array[index] = source[index];
}
- return result;
+ return array;
}
/**
- * The base implementation of `_.flatten` without support for callback
- * shorthands or `thisArg` binding.
+ * A specialized version of `_.forEach` for arrays without support for callback
+ * shorthands or `this` binding.
*
* @private
- * @param {Array} array The array to flatten.
- * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
- * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
- * @param {number} [fromIndex=0] The index to start from.
- * @returns {Array} Returns a new flattened array.
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
*/
- function baseFlatten(array, isShallow, isStrict, fromIndex) {
- var index = (fromIndex || 0) - 1,
- length = array ? array.length : 0,
- result = [];
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array.length;
while (++index < length) {
- var value = array[index];
-
- if (value && typeof value == 'object' && typeof value.length == 'number'
- && (isArray(value) || isArguments(value))) {
- // recursively flatten arrays (susceptible to call stack limits)
- if (!isShallow) {
- value = baseFlatten(value, isShallow, isStrict);
- }
- var valIndex = -1,
- valLength = value.length,
- resIndex = result.length;
-
- result.length += valLength;
- while (++valIndex < valLength) {
- result[resIndex++] = value[valIndex];
- }
- } else if (!isStrict) {
- result.push(value);
+ if (iteratee(array[index], index, array) === false) {
+ break;
}
}
- return result;
+ return array;
}
/**
- * The base implementation of `_.isEqual`, without support for `thisArg` binding,
- * that allows partial "_.where" style comparisons.
+ * A specialized version of `_.forEachRight` for arrays without support for
+ * callback shorthands or `this` binding.
*
* @private
- * @param {*} a The value to compare.
- * @param {*} b The other value to compare.
- * @param {Function} [callback] The function to customize comparing values.
- * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
- * @param {Array} [stackA=[]] Tracks traversed `a` objects.
- * @param {Array} [stackB=[]] Tracks traversed `b` objects.
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
*/
- function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
- // used to indicate that when comparing objects, `a` has at least the properties of `b`
- if (callback) {
- var result = callback(a, b);
- if (typeof result != 'undefined') {
- return !!result;
- }
- }
- // exit early for identical values
- if (a === b) {
- // treat `+0` vs. `-0` as not equal
- return a !== 0 || (1 / a == 1 / b);
- }
- var type = typeof a,
- otherType = typeof b;
-
- // exit early for unlike primitive values
- if (a === a &&
- !(a && objectTypes[type]) &&
- !(b && objectTypes[otherType])) {
- return false;
- }
- // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
- // http://es5.github.io/#x15.3.4.4
- if (a == null || b == null) {
- return a === b;
- }
- // compare [[Class]] names
- var className = toString.call(a),
- otherClass = toString.call(b);
-
- if (className == argsClass) {
- className = objectClass;
- }
- if (otherClass == argsClass) {
- otherClass = objectClass;
- }
- if (className != otherClass) {
- return false;
- }
- switch (className) {
- case boolClass:
- case dateClass:
- // coerce dates and booleans to numbers, dates to milliseconds and booleans
- // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
- return +a == +b;
-
- case numberClass:
- // treat `NaN` vs. `NaN` as equal
- return (a != +a)
- ? b != +b
- // but treat `+0` vs. `-0` as not equal
- : (a == 0 ? (1 / a == 1 / b) : a == +b);
-
- case regexpClass:
- case stringClass:
- // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
- // treat string primitives and their corresponding object instances as equal
- return a == String(b);
- }
- var isArr = className == arrayClass;
- if (!isArr) {
- // unwrap any `lodash` wrapped values
- var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
- bWrapped = hasOwnProperty.call(b, '__wrapped__');
-
- if (aWrapped || bWrapped) {
- return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
- }
- // exit for functions and DOM nodes
- if (className != objectClass || (!support.nodeClass && (isNode(a) || isNode(b)))) {
- return false;
- }
- // in older versions of Opera, `arguments` objects have `Array` constructors
- var ctorA = !support.argsObject && isArguments(a) ? Object : a.constructor,
- ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor;
-
- // non `Object` object instances with different constructors are not equal
- if (ctorA != ctorB &&
- !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
- ('constructor' in a && 'constructor' in b)
- ) {
- return false;
- }
- }
- // assume cyclic structures are equal
- // the algorithm for detecting cyclic structures is adapted from ES 5.1
- // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
- var initedStack = !stackA;
- stackA || (stackA = getArray());
- stackB || (stackB = getArray());
+ function arrayEachRight(array, iteratee) {
+ var length = array.length;
- var length = stackA.length;
while (length--) {
- if (stackA[length] == a) {
- return stackB[length] == b;
+ if (iteratee(array[length], length, array) === false) {
+ break;
}
}
- var size = 0;
- result = true;
-
- // add `a` and `b` to the stack of traversed objects
- stackA.push(a);
- stackB.push(b);
+ return array;
+ }
- // recursively compare objects and arrays (susceptible to call stack limits)
- if (isArr) {
- // compare lengths to determine if a deep comparison is necessary
- length = a.length;
- size = b.length;
- result = size == length;
-
- if (result || isWhere) {
- // deep compare the contents, ignoring non-numeric properties
- while (size--) {
- var index = length,
- value = b[size];
-
- if (isWhere) {
- while (index--) {
- if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
- break;
- }
- }
- } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
- break;
- }
- }
- }
- }
- else {
- // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
- // which, in this case, is more costly
- forIn(b, function(value, key, b) {
- if (hasOwnProperty.call(b, key)) {
- // count the number of properties.
- size++;
- // deep compare each property value.
- return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
- }
- });
+ /**
+ * A specialized version of `_.every` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ */
+ function arrayEvery(array, predicate) {
+ var index = -1,
+ length = array.length;
- if (result && !isWhere) {
- // ensure both objects have the same number of properties
- forIn(a, function(value, key, a) {
- if (hasOwnProperty.call(a, key)) {
- // `size` will be `-1` if `a` has more properties than `b`
- return (result = --size > -1);
- }
- });
+ while (++index < length) {
+ if (!predicate(array[index], index, array)) {
+ return false;
}
}
- stackA.pop();
- stackB.pop();
-
- if (initedStack) {
- releaseArray(stackA);
- releaseArray(stackB);
- }
- return result;
+ return true;
}
/**
- * The base implementation of `_.merge` without argument juggling or support
- * for `thisArg` binding.
+ * A specialized version of `_.filter` for arrays without support for callback
+ * shorthands or `this` binding.
*
* @private
- * @param {Object} object The destination object.
- * @param {Object} source The source object.
- * @param {Function} [callback] The function to customize merging properties.
- * @param {Array} [stackA=[]] Tracks traversed source objects.
- * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
*/
- function baseMerge(object, source, callback, stackA, stackB) {
- (isArray(source) ? forEach : forOwn)(source, function(source, key) {
- var found,
- isArr,
- result = source,
- value = object[key];
-
- if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
- // avoid merging previously merged cyclic sources
- var stackLength = stackA.length;
- while (stackLength--) {
- if ((found = stackA[stackLength] == source)) {
- value = stackB[stackLength];
- break;
- }
- }
- if (!found) {
- var isShallow;
- if (callback) {
- result = callback(value, source);
- if ((isShallow = typeof result != 'undefined')) {
- value = result;
- }
- }
- if (!isShallow) {
- value = isArr
- ? (isArray(value) ? value : [])
- : (isPlainObject(value) ? value : {});
- }
- // add `source` and associated `value` to the stack of traversed objects
- stackA.push(source);
- stackB.push(value);
+ function arrayFilter(array, predicate) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
- // recursively merge objects and arrays (susceptible to call stack limits)
- if (!isShallow) {
- baseMerge(value, source, callback, stackA, stackB);
- }
- }
- }
- else {
- if (callback) {
- result = callback(value, source);
- if (typeof result == 'undefined') {
- result = source;
- }
- }
- if (typeof result != 'undefined') {
- value = result;
- }
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result[++resIndex] = value;
}
- object[key] = value;
- });
+ }
+ return result;
}
/**
- * The base implementation of `_.random` without argument juggling or support
- * for returning floating-point numbers.
+ * A specialized version of `_.map` for arrays without support for callback
+ * shorthands or `this` binding.
*
* @private
- * @param {number} min The minimum possible value.
- * @param {number} max The maximum possible value.
- * @returns {number} Returns a random number.
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
*/
- function baseRandom(min, max) {
- return min + floor(nativeRandom() * (max - min + 1));
+ function arrayMap(array, iteratee) {
+ var index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = iteratee(array[index], index, array);
+ }
+ return result;
}
/**
- * The base implementation of `_.uniq` without support for callback shorthands
- * or `thisArg` binding.
+ * A specialized version of `_.max` for arrays without support for iteratees.
*
* @private
- * @param {Array} array The array to process.
- * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
- * @param {Function} [callback] The function called per iteration.
- * @returns {Array} Returns a duplicate-value-free array.
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the maximum value.
*/
- function baseUniq(array, isSorted, callback) {
+ function arrayMax(array) {
var index = -1,
- indexOf = getIndexOf(),
- length = array ? array.length : 0,
- result = [];
+ length = array.length,
+ result = NEGATIVE_INFINITY;
- var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
- seen = (callback || isLarge) ? getArray() : result;
-
- if (isLarge) {
- var cache = createCache(seen);
- indexOf = cacheIndexOf;
- seen = cache;
- }
while (++index < length) {
- var value = array[index],
- computed = callback ? callback(value, index, array) : value;
-
- if (isSorted
- ? !index || seen[seen.length - 1] !== computed
- : indexOf(seen, computed) < 0
- ) {
- if (callback || isLarge) {
- seen.push(computed);
- }
- result.push(value);
+ var value = array[index];
+ if (value > result) {
+ result = value;
}
}
- if (isLarge) {
- releaseArray(seen.array);
- releaseObject(seen);
- } else if (callback) {
- releaseArray(seen);
- }
return result;
}
/**
- * Creates a function that aggregates a collection, creating an object composed
- * of keys generated from the results of running each element of the collection
- * through a callback. The given `setter` function sets the keys and values
- * of the composed object.
+ * A specialized version of `_.min` for arrays without support for iteratees.
*
* @private
- * @param {Function} setter The setter function.
- * @returns {Function} Returns the new aggregator function.
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the minimum value.
*/
- function createAggregator(setter) {
- return function(collection, callback, thisArg) {
- var result = {};
- callback = lodash.createCallback(callback, thisArg, 3);
-
- if (isArray(collection)) {
- var index = -1,
- length = collection.length;
+ function arrayMin(array) {
+ var index = -1,
+ length = array.length,
+ result = POSITIVE_INFINITY;
- while (++index < length) {
- var value = collection[index];
- setter(result, value, callback(value, index, collection), collection);
- }
- } else {
- baseEach(collection, function(value, key, collection) {
- setter(result, value, callback(value, key, collection), collection);
- });
+ while (++index < length) {
+ var value = array[index];
+ if (value < result) {
+ result = value;
}
- return result;
- };
+ }
+ return result;
}
/**
- * Creates a function that, when called, either curries or invokes `func`
- * with an optional `this` binding and partially applied arguments.
+ * A specialized version of `_.reduce` for arrays without support for callback
+ * shorthands or `this` binding.
*
* @private
- * @param {Function|string} func The function or method name to reference.
- * @param {number} bitmask The bitmask of method flags to compose.
- * The bitmask may be composed of the following flags:
- * 1 - `_.bind`
- * 2 - `_.bindKey`
- * 4 - `_.curry`
- * 8 - `_.curry` (bound)
- * 16 - `_.partial`
- * 32 - `_.partialRight`
- * @param {Array} [partialArgs] An array of arguments to prepend to those
- * provided to the new function.
- * @param {Array} [partialRightArgs] An array of arguments to append to those
- * provided to the new function.
- * @param {*} [thisArg] The `this` binding of `func`.
- * @param {number} [arity] The arity of `func`.
- * @returns {Function} Returns the new function.
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the first element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
*/
- function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
- var isBind = bitmask & 1,
- isBindKey = bitmask & 2,
- isCurry = bitmask & 4,
- isCurryBound = bitmask & 8,
- isPartial = bitmask & 16,
- isPartialRight = bitmask & 32;
+ function arrayReduce(array, iteratee, accumulator, initFromArray) {
+ var index = -1,
+ length = array.length;
- if (!isBindKey && !isFunction(func)) {
- throw new TypeError;
+ if (initFromArray && length) {
+ accumulator = array[++index];
}
- if (isPartial && !partialArgs.length) {
- bitmask &= ~16;
- isPartial = partialArgs = false;
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
}
- if (isPartialRight && !partialRightArgs.length) {
- bitmask &= ~32;
- isPartialRight = partialRightArgs = false;
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.reduceRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the last element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduceRight(array, iteratee, accumulator, initFromArray) {
+ var length = array.length;
+ if (initFromArray && length) {
+ accumulator = array[--length];
}
- var bindData = func && func.__bindData__;
- if (bindData && bindData !== true) {
- // clone `bindData`
- bindData = slice(bindData);
- if (bindData[2]) {
- bindData[2] = slice(bindData[2]);
- }
- if (bindData[3]) {
- bindData[3] = slice(bindData[3]);
- }
- // set `thisBinding` is not previously bound
- if (isBind && !(bindData[1] & 1)) {
- bindData[4] = thisArg;
- }
- // set if previously bound but not currently (subsequent curried functions)
- if (!isBind && bindData[1] & 1) {
- bitmask |= 8;
- }
- // set curried arity if not yet set
- if (isCurry && !(bindData[1] & 4)) {
- bindData[5] = arity;
- }
- // append partial left arguments
- if (isPartial) {
- push.apply(bindData[2] || (bindData[2] = []), partialArgs);
- }
- // append partial right arguments
- if (isPartialRight) {
- unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
- }
- // merge flags
- bindData[1] |= bitmask;
- return createWrapper.apply(null, bindData);
+ while (length--) {
+ accumulator = iteratee(accumulator, array[length], length, array);
}
- // fast path for `_.bind`
- var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
- return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
+ return accumulator;
}
/**
- * Creates compiled iteration functions.
+ * A specialized version of `_.some` for arrays without support for callback
+ * shorthands or `this` binding.
*
* @private
- * @param {...Object} [options] The compile options object(s).
- * @param {string} [options.array] Code to determine if the iterable is an array or array-like.
- * @param {boolean} [options.useHas] Specify using `hasOwnProperty` checks in the object loop.
- * @param {Function} [options.keys] A reference to `_.keys` for use in own property iteration.
- * @param {string} [options.args] A comma separated string of iteration function arguments.
- * @param {string} [options.top] Code to execute before the iteration branches.
- * @param {string} [options.loop] Code to execute in the object loop.
- * @param {string} [options.bottom] Code to execute after the iteration branches.
- * @returns {Function} Returns the compiled function.
- */
- function createIterator() {
- // data properties
- iteratorData.shadowedProps = shadowedProps;
- iteratorData.support = support;
-
- // iterator options
- iteratorData.array = iteratorData.bottom = iteratorData.loop = iteratorData.top = '';
- iteratorData.init = 'iterable';
- iteratorData.useHas = true;
-
- // merge options into a template data object
- for (var object, index = 0; object = arguments[index]; index++) {
- for (var key in object) {
- iteratorData[key] = object[key];
- }
- }
- var args = iteratorData.args;
- iteratorData.firstArg = /^[^,]+/.exec(args)[0];
-
- // create the function factory
- var factory = Function(
- 'baseCreateCallback, errorClass, errorProto, hasOwnProperty, ' +
- 'indicatorObject, isArguments, isArray, isString, keys, objectProto, ' +
- 'objectTypes, nonEnumProps, stringClass, stringProto, toString',
- 'return function(' + args + ') {\n' + iteratorTemplate(iteratorData) + '\n}'
- );
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array.length;
- // return the compiled function
- return factory(
- baseCreateCallback, errorClass, errorProto, hasOwnProperty,
- indicatorObject, isArguments, isArray, isString, iteratorData.keys, objectProto,
- objectTypes, nonEnumProps, stringClass, stringProto, toString
- );
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
}
/**
- * Used by `escape` to convert characters to HTML entities.
+ * Used by `_.defaults` to customize its `_.assign` use.
*
* @private
- * @param {string} match The matched character to escape.
- * @returns {string} Returns the escaped character.
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @returns {*} Returns the value to assign to the destination object.
*/
- function escapeHtmlChar(match) {
- return htmlEscapes[match];
+ function assignDefaults(objectValue, sourceValue) {
+ return typeof objectValue == 'undefined' ? sourceValue : objectValue;
}
/**
- * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
- * customized, this method returns the custom method, otherwise it returns
- * the `baseIndexOf` function.
+ * Used by `_.template` to customize its `_.assign` use.
+ *
+ * **Note:** This method is like `assignDefaults` except that it ignores
+ * inherited property values when checking if a property is `undefined`.
*
* @private
- * @returns {Function} Returns the "indexOf" function.
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @param {string} key The key associated with the object and source values.
+ * @param {Object} object The destination object.
+ * @returns {*} Returns the value to assign to the destination object.
*/
- function getIndexOf() {
- var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
- return result;
+ function assignOwnDefaults(objectValue, sourceValue, key, object) {
+ return (typeof objectValue == 'undefined' || !hasOwnProperty.call(object, key))
+ ? sourceValue
+ : objectValue;
}
/**
- * Checks if `value` is a native function.
+ * The base implementation of `_.assign` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
*
* @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @returns {Object} Returns the destination object.
*/
- function isNative(value) {
- return typeof value == 'function' && reNative.test(value);
+ function baseAssign(object, source, customizer) {
+ var props = keys(source);
+ if (!customizer) {
+ return baseCopy(source, object, props);
+ }
+ var index = -1,
+ length = props.length
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key],
+ result = customizer(value, source[key], key, object, source);
+
+ if ((result === result ? result !== value : value === value) ||
+ (typeof value == 'undefined' && !(key in object))) {
+ object[key] = result;
+ }
+ }
+ return object;
}
/**
- * Sets `this` binding data on a given function.
+ * The base implementation of `_.at` without support for strings and individual
+ * key arguments.
*
* @private
- * @param {Function} func The function to set data on.
- * @param {Array} value The data array to set.
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {number[]|string[]} [props] The property names or indexes of elements to pick.
+ * @returns {Array} Returns the new array of picked elements.
*/
- var setBindData = !defineProperty ? noop : function(func, value) {
- descriptor.value = value;
- defineProperty(func, '__bindData__', descriptor);
- };
+ function baseAt(collection, props) {
+ var index = -1,
+ length = collection.length,
+ isArr = isLength(length),
+ propsLength = props.length,
+ result = Array(propsLength);
+
+ while(++index < propsLength) {
+ var key = props[index];
+ if (isArr) {
+ key = parseFloat(key);
+ result[index] = isIndex(key, length) ? collection[key] : undefined;
+ } else {
+ result[index] = collection[key];
+ }
+ }
+ return result;
+ }
/**
- * A fallback implementation of `isPlainObject` which checks if a given value
- * is an object created by the `Object` constructor, assuming objects created
- * by the `Object` constructor have no inherited enumerable properties and that
- * there are no `Object.prototype` extensions.
+ * Copies the properties of `source` to `object`.
*
* @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @param {Object} source The object to copy properties from.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Array} props The property names to copy.
+ * @returns {Object} Returns `object`.
*/
- function shimIsPlainObject(value) {
- var ctor,
- result;
-
- // avoid non Object objects, `arguments` objects, and DOM elements
- if (!(value && toString.call(value) == objectClass) ||
- (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) ||
- (!support.argsClass && isArguments(value)) ||
- (!support.nodeClass && isNode(value))) {
- return false;
+ function baseCopy(source, object, props) {
+ if (!props) {
+ props = object;
+ object = {};
}
- // IE < 9 iterates inherited properties before own properties. If the first
- // iterated property is an object's own property then there are no inherited
- // enumerable properties.
- if (support.ownLast) {
- forIn(value, function(value, key, object) {
- result = hasOwnProperty.call(object, key);
- return false;
- });
- return result !== false;
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ object[key] = source[key];
}
- // In most environments an object's own properties are iterated before
- // its inherited properties. If the last iterated property is an object's
- // own property then there are no inherited enumerable properties.
- forIn(value, function(value, key) {
- result = key;
- });
- return typeof result == 'undefined' || hasOwnProperty.call(value, result);
+ return object;
}
/**
- * Used by `unescape` to convert HTML entities to characters.
+ * The base implementation of `_.bindAll` without support for individual
+ * method name arguments.
*
* @private
- * @param {string} match The matched character to unescape.
- * @returns {string} Returns the unescaped character.
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {string[]} methodNames The object method names to bind.
+ * @returns {Object} Returns `object`.
*/
- function unescapeHtmlChar(match) {
- return htmlUnescapes[match];
- }
+ function baseBindAll(object, methodNames) {
+ var index = -1,
+ length = methodNames.length;
- /*--------------------------------------------------------------------------*/
+ while (++index < length) {
+ var key = methodNames[index];
+ object[key] = createWrapper(object[key], BIND_FLAG, object);
+ }
+ return object;
+ }
/**
- * Checks if `value` is an `arguments` object.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
- * @example
+ * The base implementation of `_.callback` which supports specifying the
+ * number of arguments to provide to `func`.
*
- * (function() { return _.isArguments(arguments); })(1, 2, 3);
- * // => true
- *
- * _.isArguments([1, 2, 3]);
- * // => false
+ * @private
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
*/
- function isArguments(value) {
- return value && typeof value == 'object' && typeof value.length == 'number' &&
- toString.call(value) == argsClass || false;
- }
- // fallback for browsers that can't detect `arguments` objects by [[Class]]
- if (!support.argsClass) {
- isArguments = function(value) {
- return value && typeof value == 'object' && typeof value.length == 'number' &&
- hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee') || false;
- };
+ function baseCallback(func, thisArg, argCount) {
+ var type = typeof func;
+ if (type == 'function') {
+ return (typeof thisArg != 'undefined' && isBindable(func))
+ ? bindCallback(func, thisArg, argCount)
+ : func;
+ }
+ if (func == null) {
+ return identity;
+ }
+ // Handle "_.property" and "_.matches" style callback shorthands.
+ return type == 'object'
+ ? baseMatches(func, !argCount)
+ : baseProperty(argCount ? baseToString(func) : func);
}
/**
- * Checks if `value` is an array.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
- * @example
- *
- * (function() { return _.isArray(arguments); })();
- * // => false
+ * The base implementation of `_.clone` without support for argument juggling
+ * and `this` binding `customizer` functions.
*
- * _.isArray([1, 2, 3]);
- * // => true
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The object `value` belongs to.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates clones with source counterparts.
+ * @returns {*} Returns the cloned value.
*/
- var isArray = nativeIsArray || function(value) {
- return value && typeof value == 'object' && typeof value.length == 'number' &&
- toString.call(value) == arrayClass || false;
- };
+ function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
+ var result;
+ if (customizer) {
+ result = object ? customizer(value, key, object) : customizer(value);
+ }
+ if (typeof result != 'undefined') {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return arrayCopy(value, result);
+ }
+ } else {
+ var tag = objToString.call(value),
+ isFunc = tag == funcTag;
+
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ result = initCloneObject(isFunc ? {} : value);
+ if (!isDeep) {
+ return baseCopy(value, result, keys(value));
+ }
+ } else {
+ return cloneableTags[tag]
+ ? initCloneByTag(value, tag, isDeep)
+ : (object ? value : {});
+ }
+ }
+ // Check for circular references and return corresponding clone.
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == value) {
+ return stackB[length];
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate it with its clone.
+ stackA.push(value);
+ stackB.push(result);
+
+ // Recursively populate clone (susceptible to call stack limits).
+ (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
+ result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
+ });
+ return result;
+ }
/**
- * A fallback implementation of `Object.keys` which produces an array of the
- * given object's own enumerable property names.
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
*
* @private
- * @type Function
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns an array of property names.
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
*/
- var shimKeys = createIterator({
- 'args': 'object',
- 'init': '[]',
- 'top': 'if (!(objectTypes[typeof object])) return result',
- 'loop': 'result.push(index)'
- });
+ var baseCreate = (function() {
+ function Object() {}
+ return function(prototype) {
+ if (isObject(prototype)) {
+ Object.prototype = prototype;
+ var result = new Object;
+ Object.prototype = null;
+ }
+ return result || context.Object();
+ };
+ }());
/**
- * Creates an array composed of the own enumerable property names of an object.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns an array of property names.
- * @example
+ * The base implementation of `_.delay` and `_.defer` which accepts an index
+ * of where to slice the arguments to provide to `func`.
*
- * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
- * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
+ * @private
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {Object} args The `arguments` object to slice and provide to `func`.
+ * @returns {number} Returns the timer id.
*/
- var keys = !nativeKeys ? shimKeys : function(object) {
- if (!isObject(object)) {
- return [];
- }
- if ((support.enumPrototypes && typeof object == 'function') ||
- (support.nonEnumArgs && object.length && isArguments(object))) {
- return shimKeys(object);
+ function baseDelay(func, wait, args, fromIndex) {
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
}
- return nativeKeys(object);
- };
-
- /** Reusable iterator options shared by `each`, `forIn`, and `forOwn` */
- var eachIteratorOptions = {
- 'args': 'collection, callback, thisArg',
- 'top': "callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3)",
- 'array': "typeof length == 'number'",
- 'keys': keys,
- 'loop': 'if (callback(iterable[index], index, collection) === false) return result'
- };
-
- /** Reusable iterator options for `assign` and `defaults` */
- var defaultsIteratorOptions = {
- 'args': 'object, source, guard',
- 'top':
- 'var args = arguments,\n' +
- ' argsIndex = 0,\n' +
- " argsLength = typeof guard == 'number' ? 2 : args.length;\n" +
- 'while (++argsIndex < argsLength) {\n' +
- ' iterable = args[argsIndex];\n' +
- ' if (iterable && objectTypes[typeof iterable]) {',
- 'keys': keys,
- 'loop': "if (typeof result[index] == 'undefined') result[index] = iterable[index]",
- 'bottom': ' }\n}'
- };
-
- /** Reusable iterator options for `forIn` and `forOwn` */
- var forOwnIteratorOptions = {
- 'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top,
- 'array': false
- };
+ return setTimeout(function() { func.apply(undefined, baseSlice(args, fromIndex)); }, wait);
+ }
/**
- * Used to convert characters to HTML entities:
+ * The base implementation of `_.difference` which accepts a single array
+ * of values to exclude.
*
- * Though the `>` character is escaped for symmetry, characters like `>` and `/`
- * don't require escaping in HTML and have no special meaning unless they're part
- * of a tag or an unquoted attribute value.
- * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Array} values The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
*/
- var htmlEscapes = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": '''
- };
+ function baseDifference(array, values) {
+ var length = array ? array.length : 0,
+ result = [];
+
+ if (!length) {
+ return result;
+ }
+ var index = -1,
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf,
+ cache = isCommon && values.length >= 200 && createCache(values),
+ valuesLength = values.length;
- /** Used to convert HTML entities to characters */
- var htmlUnescapes = invert(htmlEscapes);
+ if (cache) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ values = cache;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index];
- /** Used to match HTML entities and HTML characters */
- var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
- reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
+ if (isCommon && value === value) {
+ var valuesIndex = valuesLength;
+ while (valuesIndex--) {
+ if (values[valuesIndex] === value) {
+ continue outer;
+ }
+ }
+ result.push(value);
+ }
+ else if (indexOf(values, value) < 0) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
/**
- * A function compiled to iterate `arguments` objects, arrays, objects, and
- * strings consistenly across environments, executing the callback for each
- * element in the collection. The callback is bound to `thisArg` and invoked
- * with three arguments; (value, index|key, collection). Callbacks may exit
- * iteration early by explicitly returning `false`.
+ * The base implementation of `_.forEach` without support for callback
+ * shorthands and `this` binding.
*
* @private
- * @type Function
* @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
+ * @param {Function} iteratee The function invoked per iteration.
* @returns {Array|Object|string} Returns `collection`.
*/
- var baseEach = createIterator(eachIteratorOptions);
+ function baseEach(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwn(collection, iteratee);
+ }
+ var index = -1,
+ iterable = toObject(collection);
- /*--------------------------------------------------------------------------*/
+ while (++index < length) {
+ if (iteratee(iterable[index], index, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
/**
- * Assigns own enumerable properties of source object(s) to the destination
- * object. Subsequent sources will overwrite property assignments of previous
- * sources. If a callback is provided it will be executed to produce the
- * assigned values. The callback is bound to `thisArg` and invoked with two
- * arguments; (objectValue, sourceValue).
- *
- * @static
- * @memberOf _
- * @type Function
- * @alias extend
- * @category Objects
- * @param {Object} object The destination object.
- * @param {...Object} [source] The source objects.
- * @param {Function} [callback] The function to customize assigning values.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the destination object.
- * @example
+ * The base implementation of `_.forEachRight` without support for callback
+ * shorthands and `this` binding.
*
- * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
- * // => { 'name': 'fred', 'employer': 'slate' }
- *
- * var defaults = _.partialRight(_.assign, function(a, b) {
- * return typeof a == 'undefined' ? b : a;
- * });
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEachRight(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwnRight(collection, iteratee);
+ }
+ var iterable = toObject(collection);
+ while (length--) {
+ if (iteratee(iterable[length], length, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.every` without support for callback
+ * shorthands or `this` binding.
*
- * var object = { 'name': 'barney' };
- * defaults(object, { 'name': 'fred', 'employer': 'slate' });
- * // => { 'name': 'barney', 'employer': 'slate' }
- */
- var assign = createIterator(defaultsIteratorOptions, {
- 'top':
- defaultsIteratorOptions.top.replace(';',
- ';\n' +
- "if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" +
- ' var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);\n' +
- "} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" +
- ' callback = args[--argsLength];\n' +
- '}'
- ),
- 'loop': 'result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]'
- });
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`
+ */
+ function baseEvery(collection, predicate) {
+ var result = true;
+ baseEach(collection, function(value, index, collection) {
+ result = !!predicate(value, index, collection);
+ return result;
+ });
+ return result;
+ }
/**
- * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
- * be cloned, otherwise they will be assigned by reference. If a callback
- * is provided it will be executed to produce the cloned values. If the
- * callback returns `undefined` cloning will be handled by the method instead.
- * The callback is bound to `thisArg` and invoked with one argument; (value).
+ * The base implementation of `_.filter` without support for callback
+ * shorthands or `this` binding.
*
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to clone.
- * @param {boolean} [isDeep=false] Specify a deep clone.
- * @param {Function} [callback] The function to customize cloning values.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the cloned value.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * var shallow = _.clone(characters);
- * shallow[0] === characters[0];
- * // => true
- *
- * var deep = _.clone(characters, true);
- * deep[0] === characters[0];
- * // => false
- *
- * _.mixin({
- * 'clone': _.partialRight(_.clone, function(value) {
- * return _.isElement(value) ? value.cloneNode(false) : undefined;
- * })
- * });
- *
- * var clone = _.clone(document.body);
- * clone.childNodes.length;
- * // => 0
- */
- function clone(value, isDeep, callback, thisArg) {
- // allows working with "Collections" methods without using their `index`
- // and `collection` arguments for `isDeep` and `callback`
- if (typeof isDeep != 'boolean' && isDeep != null) {
- thisArg = callback;
- callback = isDeep;
- isDeep = false;
- }
- return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
- }
-
- /**
- * Creates a deep clone of `value`. If a callback is provided it will be
- * executed to produce the cloned values. If the callback returns `undefined`
- * cloning will be handled by the method instead. The callback is bound to
- * `thisArg` and invoked with one argument; (value).
- *
- * Note: This method is loosely based on the structured clone algorithm. Functions
- * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
- * objects created by constructors other than `Object` are cloned to plain `Object` objects.
- * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {*} value The value to deep clone.
- * @param {Function} [callback] The function to customize cloning values.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the deep cloned value.
- * @example
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
- *
- * var deep = _.cloneDeep(characters);
- * deep[0] === characters[0];
- * // => false
- *
- * var view = {
- * 'label': 'docs',
- * 'node': element
- * };
- *
- * var clone = _.cloneDeep(view, function(value) {
- * return _.isElement(value) ? value.cloneNode(true) : undefined;
- * });
- *
- * clone.node == view.node;
- * // => false
- */
- function cloneDeep(value, callback, thisArg) {
- return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
- }
-
- /**
- * Creates an object that inherits from the given `prototype` object. If a
- * `properties` object is provided its own enumerable properties are assigned
- * to the created object.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} prototype The object to inherit from.
- * @param {Object} [properties] The properties to assign to the object.
- * @returns {Object} Returns the new object.
- * @example
- *
- * function Shape() {
- * this.x = 0;
- * this.y = 0;
- * }
- *
- * function Circle() {
- * Shape.call(this);
- * }
- *
- * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
- *
- * var circle = new Circle;
- * circle instanceof Circle;
- * // => true
- *
- * circle instanceof Shape;
- * // => true
- */
- function create(prototype, properties) {
- var result = baseCreate(prototype);
- return properties ? assign(result, properties) : result;
- }
-
- /**
- * Assigns own enumerable properties of source object(s) to the destination
- * object for all destination properties that resolve to `undefined`. Once a
- * property is set, additional defaults of the same property will be ignored.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Objects
- * @param {Object} object The destination object.
- * @param {...Object} [source] The source objects.
- * @param- {Object} [guard] Allows working with `_.reduce` without using its
- * `key` and `object` arguments as sources.
- * @returns {Object} Returns the destination object.
- * @example
- *
- * var object = { 'name': 'barney' };
- * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
- * // => { 'name': 'barney', 'employer': 'slate' }
- */
- var defaults = createIterator(defaultsIteratorOptions);
-
- /**
- * This method is like `_.findIndex` except that it returns the key of the
- * first element that passes the callback check, instead of the element itself.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to search.
- * @param {Function|Object|string} [callback=identity] The function called per
- * iteration. If a property name or object is provided it will be used to
- * create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {string|undefined} Returns the key of the found element, else `undefined`.
- * @example
- *
- * var characters = {
- * 'barney': { 'age': 36, 'blocked': false },
- * 'fred': { 'age': 40, 'blocked': true },
- * 'pebbles': { 'age': 1, 'blocked': false }
- * };
- *
- * _.findKey(characters, function(chr) {
- * return chr.age < 40;
- * });
- * // => 'barney' (property order is not guaranteed across environments)
- *
- * // using "_.where" callback shorthand
- * _.findKey(characters, { 'age': 1 });
- * // => 'pebbles'
- *
- * // using "_.pluck" callback shorthand
- * _.findKey(characters, 'blocked');
- * // => 'fred'
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
*/
- function findKey(object, callback, thisArg) {
- var result;
- callback = lodash.createCallback(callback, thisArg, 3);
- forOwn(object, function(value, key, object) {
- if (callback(value, key, object)) {
- result = key;
- return false;
+ function baseFilter(collection, predicate) {
+ var result = [];
+ baseEach(collection, function(value, index, collection) {
+ if (predicate(value, index, collection)) {
+ result.push(value);
}
});
return result;
}
/**
- * This method is like `_.findKey` except that it iterates over elements
- * of a `collection` in the opposite order.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to search.
- * @param {Function|Object|string} [callback=identity] The function called per
- * iteration. If a property name or object is provided it will be used to
- * create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {string|undefined} Returns the key of the found element, else `undefined`.
- * @example
+ * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
+ * without support for callback shorthands and `this` binding, which iterates
+ * over `collection` using the provided `eachFunc`.
*
- * var characters = {
- * 'barney': { 'age': 36, 'blocked': true },
- * 'fred': { 'age': 40, 'blocked': false },
- * 'pebbles': { 'age': 1, 'blocked': true }
- * };
- *
- * _.findLastKey(characters, function(chr) {
- * return chr.age < 40;
- * });
- * // => returns `pebbles`, assuming `_.findKey` returns `barney`
- *
- * // using "_.where" callback shorthand
- * _.findLastKey(characters, { 'age': 40 });
- * // => 'fred'
- *
- * // using "_.pluck" callback shorthand
- * _.findLastKey(characters, 'blocked');
- * // => 'pebbles'
- */
- function findLastKey(object, callback, thisArg) {
+ * @private
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @param {boolean} [retKey] Specify returning the key of the found element
+ * instead of the element itself.
+ * @returns {*} Returns the found element or its key, else `undefined`.
+ */
+ function baseFind(collection, predicate, eachFunc, retKey) {
var result;
- callback = lodash.createCallback(callback, thisArg, 3);
- forOwnRight(object, function(value, key, object) {
- if (callback(value, key, object)) {
- result = key;
+ eachFunc(collection, function(value, key, collection) {
+ if (predicate(value, key, collection)) {
+ result = retKey ? key : value;
return false;
}
});
@@ -2355,134 +1909,89 @@
}
/**
- * Iterates over own and inherited enumerable properties of an object,
- * executing the callback for each property. The callback is bound to `thisArg`
- * and invoked with three arguments; (value, key, object). Callbacks may exit
- * iteration early by explicitly returning `false`.
- *
- * @static
- * @memberOf _
- * @type Function
- * @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns `object`.
- * @example
- *
- * function Shape() {
- * this.x = 0;
- * this.y = 0;
- * }
- *
- * Shape.prototype.move = function(x, y) {
- * this.x += x;
- * this.y += y;
- * };
+ * The base implementation of `_.flatten` with added support for restricting
+ * flattening and specifying the start index.
*
- * _.forIn(new Shape, function(value, key) {
- * console.log(key);
- * });
- * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
+ * @private
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param {boolean} [isStrict] Restrict flattening to arrays and `arguments` objects.
+ * @param {number} [fromIndex=0] The index to start from.
+ * @returns {Array} Returns the new flattened array.
*/
- var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, {
- 'useHas': false
- });
+ function baseFlatten(array, isDeep, isStrict, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
- /**
- * This method is like `_.forIn` except that it iterates over elements
- * of a `collection` in the opposite order.
- *
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns `object`.
- * @example
- *
- * function Shape() {
- * this.x = 0;
- * this.y = 0;
- * }
- *
- * Shape.prototype.move = function(x, y) {
- * this.x += x;
- * this.y += y;
- * };
- *
- * _.forInRight(new Shape, function(value, key) {
- * console.log(key);
- * });
- * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
- */
- function forInRight(object, callback, thisArg) {
- var pairs = [];
+ while (++index < length) {
+ var value = array[index];
- forIn(object, function(value, key) {
- pairs.push(key, value);
- });
+ if (isObjectLike(value) && isLength(value.length) && (isArray(value) || isArguments(value))) {
+ if (isDeep) {
+ // Recursively flatten arrays (susceptible to call stack limits).
+ value = baseFlatten(value, isDeep, isStrict);
+ }
+ var valIndex = -1,
+ valLength = value.length;
- var length = pairs.length;
- callback = baseCreateCallback(callback, thisArg, 3);
- while (length--) {
- if (callback(pairs[length--], pairs[length], object) === false) {
- break;
+ result.length += valLength;
+ while (++valIndex < valLength) {
+ result[++resIndex] = value[valIndex];
+ }
+ } else if (!isStrict) {
+ result[++resIndex] = value;
}
}
- return object;
+ return result;
}
/**
- * Iterates over own enumerable properties of an object, executing the callback
- * for each property. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, key, object). Callbacks may exit iteration early by
- * explicitly returning `false`.
+ * The base implementation of `baseForIn` and `baseForOwn` which iterates
+ * over `object` properties returned by `keysFunc` invoking `iteratee` for
+ * each property. Iterator functions may exit iteration early by explicitly
+ * returning `false`.
*
- * @static
- * @memberOf _
- * @type Function
- * @category Objects
+ * @private
* @param {Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
* @returns {Object} Returns `object`.
- * @example
- *
- * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
- * console.log(key);
- * });
- * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
*/
- var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions);
+ function baseFor(object, iteratee, keysFunc) {
+ var index = -1,
+ iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
/**
- * This method is like `_.forOwn` except that it iterates over elements
- * of a `collection` in the opposite order.
+ * This function is like `baseFor` except that it iterates over properties
+ * in the opposite order.
*
- * @static
- * @memberOf _
- * @category Objects
+ * @private
* @param {Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
* @returns {Object} Returns `object`.
- * @example
- *
- * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
- * console.log(key);
- * });
- * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
*/
- function forOwnRight(object, callback, thisArg) {
- var props = keys(object),
+ function baseForRight(object, iteratee, keysFunc) {
+ var iterable = toObject(object),
+ props = keysFunc(object),
length = props.length;
- callback = baseCreateCallback(callback, thisArg, 3);
while (length--) {
var key = props[length];
- if (callback(object[key], key, object) === false) {
+ if (iteratee(iterable[key], key, iterable) === false) {
break;
}
}
@@ -2490,4089 +1999,7538 @@
}
/**
- * Creates a sorted array of property names of all enumerable properties,
- * own and inherited, of `object` that have function values.
- *
- * @static
- * @memberOf _
- * @alias methods
- * @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns an array of property names that have function values.
- * @example
+ * The base implementation of `_.forIn` without support for callback
+ * shorthands and `this` binding.
*
- * _.functions(_);
- * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
*/
- function functions(object) {
- var result = [];
- forIn(object, function(value, key) {
- if (isFunction(value)) {
- result.push(key);
- }
- });
- return result.sort();
+ function baseForIn(object, iteratee) {
+ return baseFor(object, iteratee, keysIn);
}
/**
- * Checks if the specified property name exists as a direct property of `object`,
- * instead of an inherited property.
+ * The base implementation of `_.forOwn` without support for callback
+ * shorthands and `this` binding.
*
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to inspect.
- * @param {string} key The name of the property to check.
- * @returns {boolean} Returns `true` if key is a direct property, else `false`.
- * @example
- *
- * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
- * // => true
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
*/
- function has(object, key) {
- return object ? hasOwnProperty.call(object, key) : false;
+ function baseForOwn(object, iteratee) {
+ return baseFor(object, iteratee, keys);
}
/**
- * Creates an object composed of the inverted keys and values of the given object.
+ * The base implementation of `_.forOwnRight` without support for callback
+ * shorthands and `this` binding.
*
- * @static
- * @memberOf _
- * @category Objects
- * @param {Object} object The object to invert.
- * @returns {Object} Returns the created inverted object.
- * @example
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwnRight(object, iteratee) {
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.functions` which creates an array of
+ * `object` function property names filtered from those provided.
*
- * _.invert({ 'first': 'fred', 'second': 'barney' });
- * // => { 'fred': 'first', 'barney': 'second' }
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Array} props The property names to filter.
+ * @returns {Array} Returns the new array of filtered property names.
*/
- function invert(object) {
+ function baseFunctions(object, props) {
var index = -1,
- props = keys(object),
length = props.length,
- result = {};
+ resIndex = -1,
+ result = [];
while (++index < length) {
var key = props[index];
- result[object[key]] = key;
+ if (isFunction(object[key])) {
+ result[++resIndex] = key;
+ }
}
return result;
}
/**
- * Checks if `value` is a boolean value.
+ * The base implementation of `_.invoke` which requires additional arguments
+ * to be provided as an array of arguments rather than individually.
*
- * @static
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {Array} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseInvoke(collection, methodName, args) {
+ var index = -1,
+ isFunc = typeof methodName == 'function',
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value) {
+ var func = isFunc ? methodName : (value != null && value[methodName]);
+ result[++index] = func ? func.apply(value, args) : undefined;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isEqual` without support for `this` binding
+ * `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, customizer, isWhere, stackA, stackB) {
+ // Exit early for identical values.
+ if (value === other) {
+ // Treat `+0` vs. `-0` as not equal.
+ return value !== 0 || (1 / value == 1 / other);
+ }
+ var valType = typeof value,
+ othType = typeof other;
+
+ // Exit early for unlike primitive values.
+ if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') ||
+ value == null || other == null) {
+ // Return `false` unless both values are `NaN`.
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, baseIsEqual, customizer, isWhere, stackA, stackB);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA=[]] Tracks traversed `value` objects.
+ * @param {Array} [stackB=[]] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = arrayTag,
+ othTag = arrayTag;
+
+ if (!objIsArr) {
+ objTag = objToString.call(object);
+ if (objTag == argsTag) {
+ objTag = objectTag;
+ } else if (objTag != objectTag) {
+ objIsArr = isTypedArray(object);
+ }
+ }
+ if (!othIsArr) {
+ othTag = objToString.call(other);
+ if (othTag == argsTag) {
+ othTag = objectTag;
+ } else if (othTag != objectTag) {
+ othIsArr = isTypedArray(other);
+ }
+ }
+ var objIsObj = objTag == objectTag,
+ othIsObj = othTag == objectTag,
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && !(objIsArr || objIsObj)) {
+ return equalByTag(object, other, objTag);
+ }
+ var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (valWrapped || othWrapped) {
+ return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isWhere, stackA, stackB);
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ // Assume cyclic structures are equal.
+ // The algorithm for detecting cyclic structures is adapted from ES 5.1
+ // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3).
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == object) {
+ return stackB[length] == other;
+ }
+ }
+ // Add `object` and `other` to the stack of traversed objects.
+ stackA.push(object);
+ stackB.push(other);
+
+ var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isWhere, stackA, stackB);
+
+ stackA.pop();
+ stackB.pop();
+
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isMatch` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Object} source The object to inspect.
+ * @param {Array} props The source property names to match.
+ * @param {Array} values The source values to match.
+ * @param {Array} strictCompareFlags Strict comparison flags for source values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ */
+ function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
+ var length = props.length;
+ if (object == null) {
+ return !length;
+ }
+ var index = -1,
+ noCustomizer = !customizer;
+
+ while (++index < length) {
+ if ((noCustomizer && strictCompareFlags[index])
+ ? values[index] !== object[props[index]]
+ : !hasOwnProperty.call(object, props[index])
+ ) {
+ return false;
+ }
+ }
+ index = -1;
+ while (++index < length) {
+ var key = props[index];
+ if (noCustomizer && strictCompareFlags[index]) {
+ var result = hasOwnProperty.call(object, key);
+ } else {
+ var objValue = object[key],
+ srcValue = values[index];
+
+ result = customizer ? customizer(objValue, srcValue, key) : undefined;
+ if (typeof result == 'undefined') {
+ result = baseIsEqual(srcValue, objValue, customizer, true);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.map` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function baseMap(collection, iteratee) {
+ var result = [];
+ baseEach(collection, function(value, key, collection) {
+ result.push(iteratee(value, key, collection));
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.matches` which supports specifying whether
+ * `source` should be cloned.
+ *
+ * @private
+ * @param {Object} source The object of property values to match.
+ * @param {boolean} [isCloned] Specify cloning the source object.
+ * @returns {Function} Returns the new function.
+ */
+ function baseMatches(source, isCloned) {
+ var props = keys(source),
+ length = props.length;
+
+ if (length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return function(object) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ };
+ }
+ }
+ if (isCloned) {
+ source = baseClone(source, true);
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = source[props[length]];
+ values[length] = value;
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return function(object) {
+ return baseIsMatch(object, props, values, strictCompareFlags);
+ };
+ }
+
+ /**
+ * The base implementation of `_.merge` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseMerge(object, source, customizer, stackA, stackB) {
+ var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
+
+ (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
+ if (isObjectLike(srcValue)) {
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+ return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ }
+ if ((isSrcArr || typeof result != 'undefined') &&
+ (isCommon || (result === result ? result !== value : value === value))) {
+ object[key] = result;
+ }
+ });
+ return object;
+ }
+
+ /**
+ * A specialized version of `baseMerge` for arrays and objects which performs
+ * deep merges and tracks traversed objects enabling objects with circular
+ * references to be merged.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {string} key The key of the value to merge.
+ * @param {Function} mergeFunc The function to merge values.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
+ var length = stackA.length,
+ srcValue = source[key];
+
+ while (length--) {
+ if (stackA[length] == srcValue) {
+ object[key] = stackB[length];
+ return;
+ }
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) {
+ result = isArray(value)
+ ? value
+ : (value ? arrayCopy(value) : []);
+ }
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+ result = isArguments(value)
+ ? toPlainObject(value)
+ : (isPlainObject(value) ? value : {});
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate
+ // it with its merged value.
+ stackA.push(srcValue);
+ stackB.push(result);
+
+ if (isCommon) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
+ } else if (result === result ? result !== value : value === value) {
+ object[key] = result;
+ }
+ }
+
+ /**
+ * The base implementation of `_.property` which does not coerce `key` to a string.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * The base implementation of `_.pullAt` without support for individual
+ * index arguments.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {number[]} indexes The indexes of elements to remove.
+ * @returns {Array} Returns the new array of removed elements.
+ */
+ function basePullAt(array, indexes) {
+ var length = indexes.length,
+ result = baseAt(array, indexes);
+
+ indexes.sort(baseCompareAscending);
+ while (length--) {
+ var index = parseFloat(indexes[length]);
+ if (index != previous && isIndex(index)) {
+ var previous = index;
+ splice.call(array, index, 1);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.random` without support for argument juggling
+ * and returning floating-point numbers.
+ *
+ * @private
+ * @param {number} min The minimum possible value.
+ * @param {number} max The maximum possible value.
+ * @returns {number} Returns the random number.
+ */
+ function baseRandom(min, max) {
+ return min + floor(nativeRandom() * (max - min + 1));
+ }
+
+ /**
+ * The base implementation of `_.reduce` and `_.reduceRight` without support
+ * for callback shorthands or `this` binding, which iterates over `collection`
+ * using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} accumulator The initial value.
+ * @param {boolean} initFromCollection Specify using the first or last element
+ * of `collection` as the initial value.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @returns {*} Returns the accumulated value.
+ */
+ function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
+ eachFunc(collection, function(value, index, collection) {
+ accumulator = initFromCollection
+ ? (initFromCollection = false, value)
+ : iteratee(accumulator, value, index, collection)
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `setData` without support for hot loop detection.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var baseSetData = !metaMap ? identity : function(func, data) {
+ metaMap.set(func, data);
+ return func;
+ };
+
+ /**
+ * The base implementation of `_.slice` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseSlice(array, start, end) {
+ var index = -1,
+ length = array.length;
+
+ start = start == null ? 0 : (+start || 0);
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = (typeof end == 'undefined' || end > length) ? length : (+end || 0);
+ if (end < 0) {
+ end += length;
+ }
+ length = start > end ? 0 : (end - start);
+
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = array[index + start];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.some` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function baseSome(collection, predicate) {
+ var result;
+
+ baseEach(collection, function(value, index, collection) {
+ result = predicate(value, index, collection);
+ return !result;
+ });
+ return !!result;
+ }
+
+ /**
+ * The base implementation of `_.uniq` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function baseUniq(array, iteratee) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = array.length,
+ isCommon = indexOf == baseIndexOf,
+ isLarge = isCommon && length >= 200,
+ seen = isLarge && createCache(),
+ result = [];
+
+ if (seen) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ } else {
+ isLarge = false;
+ seen = iteratee ? [] : result;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (isCommon && value === value) {
+ var seenIndex = seen.length;
+ while (seenIndex--) {
+ if (seen[seenIndex] === computed) {
+ continue outer;
+ }
+ }
+ if (iteratee) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ else if (indexOf(seen, computed) < 0) {
+ if (iteratee || isLarge) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.values` and `_.valuesIn` which creates an
+ * array of `object` property values corresponding to the property names
+ * returned by `keysFunc`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} props The property names to get values for.
+ * @returns {Object} Returns the array of property values.
+ */
+ function baseValues(object, props) {
+ var index = -1,
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = object[props[index]];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `wrapperValue` which returns the result of
+ * performing a sequence of actions on the unwrapped `value`, where each
+ * successive action is supplied the return value of the previous.
+ *
+ * @private
+ * @param {*} value The unwrapped value.
+ * @param {Array} actions Actions to peform to resolve the unwrapped value.
+ * @returns {*} Returns the resolved unwrapped value.
+ */
+ function baseWrapperValue(value, actions) {
+ var result = value;
+ if (result instanceof LazyWrapper) {
+ result = result.value();
+ }
+ var index = -1,
+ length = actions.length;
+
+ while (++index < length) {
+ var args = [result],
+ action = actions[index];
+
+ push.apply(args, action.args);
+ result = action.func.apply(action.thisArg, args);
+ }
+ return result;
+ }
+
+ /**
+ * Performs a binary search of `array` to determine the index at which `value`
+ * should be inserted into `array` in order to maintain its sort order.
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndex(array, value, retHighest) {
+ var low = 0,
+ high = array ? array.length : low;
+
+ if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+ while (low < high) {
+ var mid = (low + high) >>> 1,
+ computed = array[mid];
+
+ if (retHighest ? (computed <= value) : (computed < value)) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return high;
+ }
+ return binaryIndexBy(array, value, identity, retHighest);
+ }
+
+ /**
+ * This function is like `binaryIndex` except that it invokes `iteratee` for
+ * `value` and each element of `array` to compute their sort ranking. The
+ * iteratee is invoked with one argument; (value).
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndexBy(array, value, iteratee, retHighest) {
+ value = iteratee(value);
+
+ var low = 0,
+ high = array ? array.length : 0,
+ valIsNaN = value !== value,
+ valIsUndef = typeof value == 'undefined';
+
+ while (low < high) {
+ var mid = floor((low + high) / 2),
+ computed = iteratee(array[mid]),
+ isReflexive = computed === computed;
+
+ if (valIsNaN) {
+ var setLow = isReflexive || retHighest;
+ } else if (valIsUndef) {
+ setLow = isReflexive && (retHighest || typeof computed != 'undefined');
+ } else {
+ setLow = retHighest ? (computed <= value) : (computed < value);
+ }
+ if (setLow) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return nativeMin(high, MAX_ARRAY_INDEX);
+ }
+
+ /**
+ * A specialized version of `baseCallback` which only supports `this` binding
+ * and specifying the number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function bindCallback(func, thisArg, argCount) {
+ if (typeof func != 'function') {
+ return identity;
+ }
+ if (typeof thisArg == 'undefined') {
+ return func;
+ }
+ switch (argCount) {
+ case 1: return function(value) {
+ return func.call(thisArg, value);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ case 5: return function(value, other, key, object, source) {
+ return func.call(thisArg, value, other, key, object, source);
+ };
+ }
+ return function() {
+ return func.apply(thisArg, arguments);
+ };
+ }
+
+ /**
+ * Creates a clone of the given array buffer.
+ *
+ * @private
+ * @param {ArrayBuffer} buffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+ function bufferClone(buffer) {
+ return bufferSlice.call(buffer, 0);
+ }
+ if (!bufferSlice) {
+ // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`.
+ bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) {
+ var byteLength = buffer.byteLength,
+ floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
+ offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
+ result = new ArrayBuffer(byteLength);
+
+ if (floatLength) {
+ var view = new Float64Array(result, 0, floatLength);
+ view.set(new Float64Array(buffer, 0, floatLength));
+ }
+ if (byteLength != offset) {
+ view = new Uint8Array(result, offset);
+ view.set(new Uint8Array(buffer, offset));
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates an array that is the composition of partially applied arguments,
+ * placeholders, and provided arguments into a single array of arguments.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to prepend to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgs(args, partials, holders) {
+ var holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ leftIndex = -1,
+ leftLength = partials.length,
+ result = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ result[leftIndex] = partials[leftIndex];
+ }
+ while (++argsIndex < holdersLength) {
+ result[holders[argsIndex]] = args[argsIndex];
+ }
+ while (argsLength--) {
+ result[leftIndex++] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * This function is like `composeArgs` except that the arguments composition
+ * is tailored for `_.partialRight`.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to append to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgsRight(args, partials, holders) {
+ var holdersIndex = -1,
+ holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ rightIndex = -1,
+ rightLength = partials.length,
+ result = Array(argsLength + rightLength);
+
+ while (++argsIndex < argsLength) {
+ result[argsIndex] = args[argsIndex];
+ }
+ var pad = argsIndex;
+ while (++rightIndex < rightLength) {
+ result[pad + rightIndex] = partials[rightIndex];
+ }
+ while (++holdersIndex < holdersLength) {
+ result[pad + holders[holdersIndex]] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * Creates a function that aggregates a collection, creating an accumulator
+ * object composed from the results of running each element in the collection
+ * through an iteratee. The `setter` sets the keys and values of the accumulator
+ * object. If `initializer` is provided initializes the accumulator object.
+ *
+ * @private
+ * @param {Function} setter The function to set keys and values of the accumulator object.
+ * @param {Function} [initializer] The function to initialize the accumulator object.
+ * @returns {Function} Returns the new aggregator function.
+ */
+ function createAggregator(setter, initializer) {
+ return function(collection, iteratee, thisArg) {
+ var result = initializer ? initializer() : {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ setter(result, value, iteratee(value, index, collection), collection);
+ }
+ } else {
+ baseEach(collection, function(value, key, collection) {
+ setter(result, value, iteratee(value, key, collection), collection);
+ });
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that assigns properties of source object(s) to a given
+ * destination object.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return function() {
+ var length = arguments.length,
+ object = arguments[0];
+
+ if (length < 2 || object == null) {
+ return object;
+ }
+ if (length > 3 && isIterateeCall(arguments[1], arguments[2], arguments[3])) {
+ length = 2;
+ }
+ // Juggle arguments.
+ if (length > 3 && typeof arguments[length - 2] == 'function') {
+ var customizer = bindCallback(arguments[--length - 1], arguments[length--], 5);
+ } else if (length > 2 && typeof arguments[length - 1] == 'function') {
+ customizer = arguments[--length];
+ }
+ var index = 0;
+ while (++index < length) {
+ var source = arguments[index];
+ if (source) {
+ assigner(object, source, customizer);
+ }
+ }
+ return object;
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the `this`
+ * binding of `thisArg`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createBindWrapper(func, thisArg) {
+ var Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ return (this instanceof wrapper ? Ctor : func).apply(thisArg, arguments);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `Set` cache object to optimize linear searches of large arrays.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
+ */
+ var createCache = !(nativeCreate && Set) ? constant(null) : function(values) {
+ return new SetCache(values);
+ };
+
+ /**
+ * Creates a function that produces compound words out of the words in a
+ * given string.
+ *
+ * @private
+ * @param {Function} callback The function to combine each word.
+ * @returns {Function} Returns the new compounder function.
+ */
+ function createCompounder(callback) {
+ return function(string) {
+ var index = -1,
+ array = words(deburr(string)),
+ length = array.length,
+ result = '';
+
+ while (++index < length) {
+ result = callback(result, array[index], index);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that produces an instance of `Ctor` regardless of
+ * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+ *
+ * @private
+ * @param {Function} Ctor The constructor to wrap.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createCtorWrapper(Ctor) {
+ return function() {
+ var thisBinding = baseCreate(Ctor.prototype),
+ result = Ctor.apply(thisBinding, arguments);
+
+ // Mimic the constructor's `return` behavior.
+ // See http://es5.github.io/#x13.2.2.
+ return isObject(result) ? result : thisBinding;
+ };
+ }
+
+ /**
+ * Creates a function that gets the extremum value of a collection.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to get the extremum value from an array.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the maximum,
+ * extremum value.
+ * @returns {Function} Returns the new extremum function.
+ */
+ function createExtremum(arrayFunc, isMin) {
+ return function(collection, iteratee, thisArg) {
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ var func = getCallback(),
+ noIteratee = iteratee == null;
+
+ if (!(func === baseCallback && noIteratee)) {
+ noIteratee = false;
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ if (noIteratee) {
+ var isArr = isArray(collection);
+ if (!isArr && isString(collection)) {
+ iteratee = charAtCallback;
+ } else {
+ return arrayFunc(isArr ? collection : toIterable(collection));
+ }
+ }
+ return extremumBy(collection, iteratee, isMin);
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with optional `this`
+ * binding of, partial application, and currying.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
+ * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+ var isAry = bitmask & ARY_FLAG,
+ isBind = bitmask & BIND_FLAG,
+ isBindKey = bitmask & BIND_KEY_FLAG,
+ isCurry = bitmask & CURRY_FLAG,
+ isCurryBound = bitmask & CURRY_BOUND_FLAG,
+ isCurryRight = bitmask & CURRY_RIGHT_FLAG;
+
+ var Ctor = !isBindKey && createCtorWrapper(func),
+ key = func;
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it to other functions.
+ var length = arguments.length,
+ index = length,
+ args = Array(length);
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ if (partials) {
+ args = composeArgs(args, partials, holders);
+ }
+ if (partialsRight) {
+ args = composeArgsRight(args, partialsRight, holdersRight);
+ }
+ if (isCurry || isCurryRight) {
+ var placeholder = wrapper.placeholder,
+ argsHolders = replaceHolders(args, placeholder);
+
+ length -= argsHolders.length;
+ if (length < arity) {
+ var newArgPos = argPos ? arrayCopy(argPos) : null,
+ newArity = nativeMax(arity - length, 0),
+ newsHolders = isCurry ? argsHolders : null,
+ newHoldersRight = isCurry ? null : argsHolders,
+ newPartials = isCurry ? args : null,
+ newPartialsRight = isCurry ? null : args;
+
+ bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
+ bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
+
+ if (!isCurryBound) {
+ bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
+ }
+ var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity);
+ result.placeholder = placeholder;
+ return result;
+ }
+ }
+ var thisBinding = isBind ? thisArg : this;
+ if (isBindKey) {
+ func = thisBinding[key];
+ }
+ if (argPos) {
+ args = reorder(args, argPos);
+ }
+ if (isAry && ary < args.length) {
+ args.length = ary;
+ }
+ return (this instanceof wrapper ? (Ctor || createCtorWrapper(func)) : func).apply(thisBinding, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates the pad required for `string` based on the given padding length.
+ * The `chars` string may be truncated if the number of padding characters
+ * exceeds the padding length.
+ *
+ * @private
+ * @param {string} string The string to create padding for.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the pad for `string`.
+ */
+ function createPad(string, length, chars) {
+ var strLength = string.length;
+ length = +length;
+
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return '';
+ }
+ var padLength = length - strLength;
+ chars = chars == null ? ' ' : baseToString(chars);
+ return repeat(chars, ceil(padLength / chars.length)).slice(0, padLength);
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the optional `this`
+ * binding of `thisArg` and the `partials` prepended to those provided to
+ * the wrapper.
+ *
+ * @private
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} partials The arguments to prepend to those provided to the new function.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createPartialWrapper(func, bitmask, thisArg, partials) {
+ var isBind = bitmask & BIND_FLAG,
+ Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it `func`.
+ var argsIndex = -1,
+ argsLength = arguments.length,
+ leftIndex = -1,
+ leftLength = partials.length,
+ args = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ args[leftIndex] = partials[leftIndex];
+ }
+ while (argsLength--) {
+ args[leftIndex++] = arguments[++argsIndex];
+ }
+ return (this instanceof wrapper ? Ctor : func).apply(isBind ? thisArg : this, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a function that either curries or invokes `func` with optional
+ * `this` binding and partially applied arguments.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags.
+ * The bitmask may be composed of the following flags:
+ * 1 - `_.bind`
+ * 2 - `_.bindKey`
+ * 4 - `_.curry` or `_.curryRight` of a bound function
+ * 8 - `_.curry`
+ * 16 - `_.curryRight`
+ * 32 - `_.partial`
+ * 64 - `_.partialRight`
+ * 128 - `_.rearg`
+ * 256 - `_.ary`
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to be partially applied.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
+ var isBindKey = bitmask & BIND_KEY_FLAG;
+ if (!isBindKey && !isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var length = partials ? partials.length : 0;
+ if (!length) {
+ bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
+ partials = holders = null;
+ }
+ length -= (holders ? holders.length : 0);
+ if (bitmask & PARTIAL_RIGHT_FLAG) {
+ var partialsRight = partials,
+ holdersRight = holders;
+
+ partials = holders = null;
+ }
+ var data = !isBindKey && getData(func),
+ newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
+
+ if (data && data !== true) {
+ mergeData(newData, data);
+ bitmask = newData[1];
+ arity = newData[9];
+ }
+ newData[9] = arity == null
+ ? (isBindKey ? 0 : func.length)
+ : (nativeMax(arity - length, 0) || 0);
+
+ if (bitmask == BIND_FLAG) {
+ var result = createBindWrapper(newData[0], newData[2]);
+ } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
+ result = createPartialWrapper.apply(null, newData);
+ } else {
+ result = createHybridWrapper.apply(null, newData);
+ }
+ var setter = data ? baseSetData : setData;
+ return setter(result, newData);
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing arrays.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var index = -1,
+ arrLength = array.length,
+ othLength = other.length,
+ result = true;
+
+ if (arrLength != othLength && !(isWhere && othLength > arrLength)) {
+ return false;
+ }
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (result && ++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, arrValue, index)
+ : customizer(arrValue, othValue, index);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (isWhere) {
+ var othIndex = othLength;
+ while (othIndex--) {
+ othValue = other[othIndex];
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ if (result) {
+ break;
+ }
+ }
+ } else {
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ }
+ return !!result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} value The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag) {
+ switch (tag) {
+ case boolTag:
+ case dateTag:
+ // Coerce dates and booleans to numbers, dates to milliseconds and booleans
+ // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
+ return +object == +other;
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case numberTag:
+ // Treat `NaN` vs. `NaN` as equal.
+ return (object != +object)
+ ? other != +other
+ // But, treat `-0` vs. `+0` as not equal.
+ : (object == 0 ? ((1 / object) == (1 / other)) : object == +other);
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings (http://es5.github.io/#x15.10.6.4) and
+ // treat strings primitives and string objects as equal.
+ return object == baseToString(other);
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objProps = keys(object),
+ objLength = objProps.length,
+ othProps = keys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isWhere) {
+ return false;
+ }
+ var hasCtor,
+ index = -1;
+
+ while (++index < objLength) {
+ var key = objProps[index],
+ result = hasOwnProperty.call(other, key);
+
+ if (result) {
+ var objValue = object[key],
+ othValue = other[key];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, objValue, key)
+ : customizer(objValue, othValue, key);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare objects (susceptible to call stack limits).
+ result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ hasCtor || (hasCtor = key == 'constructor');
+ }
+ if (!hasCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Gets the extremum value of `collection` invoking `iteratee` for each value
+ * in `collection` to generate the criterion by which the value is ranked.
+ * The `iteratee` is invoked with three arguments; (value, index, collection).
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the
+ * maximum, extremum value.
+ * @returns {*} Returns the extremum value.
+ */
+ function extremumBy(collection, iteratee, isMin) {
+ var exValue = isMin ? POSITIVE_INFINITY : NEGATIVE_INFINITY,
+ computed = exValue,
+ result = computed;
+
+ baseEach(collection, function(value, index, collection) {
+ var current = iteratee(value, index, collection);
+ if ((isMin ? current < computed : current > computed) || (current === exValue && current === result)) {
+ computed = current;
+ result = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Gets the appropriate "callback" function. If the `_.callback` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseCallback` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function} Returns the chosen function or its result.
+ */
+ function getCallback(func, thisArg, argCount) {
+ var result = lodash.callback || callback;
+ result = result === callback ? baseCallback : result;
+ return argCount ? result(func, thisArg, argCount) : result;
+ }
+
+ /**
+ * Gets metadata for `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {*} Returns the metadata for `func`.
+ */
+ var getData = !metaMap ? noop : function(func) {
+ return metaMap.get(func);
+ };
+
+ /**
+ * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseIndexOf` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function|number} Returns the chosen function or its result.
+ */
+ function getIndexOf(collection, target, fromIndex) {
+ var result = lodash.indexOf || indexOf;
+ result = result === indexOf ? baseIndexOf : result;
+ return collection ? result(collection, target, fromIndex) : result;
+ }
+
+ /**
+ * Gets the view, applying any `transforms` to the `start` and `end` positions.
+ *
+ * @private
+ * @param {number} start The start of the view.
+ * @param {number} end The end of the view.
+ * @param {Array} [transforms] The transformations to apply to the view.
+ * @returns {Object} Returns an object containing the `start` and `end`
+ * positions of the view.
+ */
+ function getView(start, end, transforms) {
+ var index = -1,
+ length = transforms ? transforms.length : 0;
+
+ while (++index < length) {
+ var data = transforms[index],
+ size = data.size;
+
+ switch (data.type) {
+ case 'drop': start += size; break;
+ case 'dropRight': end -= size; break;
+ case 'take': end = nativeMin(end, start + size); break;
+ case 'takeRight': start = nativeMax(start, end - size); break;
+ }
+ }
+ return { 'start': start, 'end': end };
+ }
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = new array.constructor(length);
+
+ // Add array properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ /**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneObject(object) {
+ var Ctor = object.constructor;
+ if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
+ Ctor = Object;
+ }
+ return new Ctor;
+ }
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return bufferClone(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ var buffer = object.buffer;
+ return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ var result = new Ctor(object.source, reFlags.exec(object));
+ result.lastIndex = object.lastIndex;
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `func` is eligible for `this` binding.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is eligible, else `false`.
+ */
+ function isBindable(func) {
+ var support = lodash.support,
+ result = !(support.funcNames ? func.name : support.funcDecomp);
+
+ if (!result) {
+ var source = fnToString.call(func);
+ if (!support.funcNames) {
+ result = !reFuncName.test(source);
+ }
+ if (!result) {
+ // Check if `func` references the `this` keyword and store the result.
+ result = reThis.test(source) || isNative(func);
+ baseSetData(func, result);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ value = +value;
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return value > -1 && value % 1 == 0 && value < length;
+ }
+
+ /**
+ * Checks if the provided arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number') {
+ var length = object.length,
+ prereq = isLength(length) && isIndex(index, length);
+ } else {
+ prereq = type == 'string' && index in value;
+ }
+ return prereq && object[index] === value;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+ function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` if suitable for strict
+ * equality comparisons, else `false`.
+ */
+ function isStrictComparable(value) {
+ return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value));
+ }
+
+ /**
+ * Merges the function metadata of `source` into `data`.
+ *
+ * Merging metadata reduces the number of wrappers required to invoke a function.
+ * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+ * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
+ * augment function arguments, making the order in which they are executed important,
+ * preventing the merging of metadata. However, we make an exception for a safe
+ * common case where curried functions have `_.ary` and or `_.rearg` applied.
+ *
+ * @private
+ * @param {Array} data The destination metadata.
+ * @param {Array} source The source metadata.
+ * @returns {Array} Returns `data`.
+ */
+ function mergeData(data, source) {
+ var bitmask = data[1],
+ srcBitmask = source[1],
+ newBitmask = bitmask | srcBitmask;
+
+ var arityFlags = ARY_FLAG | REARG_FLAG,
+ bindFlags = BIND_FLAG | BIND_KEY_FLAG,
+ comboFlags = arityFlags | bindFlags | CURRY_BOUND_FLAG | CURRY_RIGHT_FLAG;
+
+ var isAry = bitmask & ARY_FLAG && !(srcBitmask & ARY_FLAG),
+ isRearg = bitmask & REARG_FLAG && !(srcBitmask & REARG_FLAG),
+ argPos = (isRearg ? data : source)[7],
+ ary = (isAry ? data : source)[8];
+
+ var isCommon = !(bitmask >= REARG_FLAG && srcBitmask > bindFlags) &&
+ !(bitmask > bindFlags && srcBitmask >= REARG_FLAG);
+
+ var isCombo = (newBitmask >= arityFlags && newBitmask <= comboFlags) &&
+ (bitmask < REARG_FLAG || ((isRearg || isAry) && argPos.length <= ary));
+
+ // Exit early if metadata can't be merged.
+ if (!(isCommon || isCombo)) {
+ return data;
+ }
+ // Use source `thisArg` if available.
+ if (srcBitmask & BIND_FLAG) {
+ data[2] = source[2];
+ // Set when currying a bound function.
+ newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
+ }
+ // Compose partial arguments.
+ var value = source[3];
+ if (value) {
+ var partials = data[3];
+ data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
+ data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
+ }
+ // Compose partial right arguments.
+ value = source[5];
+ if (value) {
+ partials = data[5];
+ data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
+ data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
+ }
+ // Use source `argPos` if available.
+ value = source[7];
+ if (value) {
+ data[7] = arrayCopy(value);
+ }
+ // Use source `ary` if it's smaller.
+ if (srcBitmask & ARY_FLAG) {
+ data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
+ }
+ // Use source `arity` if one is not provided.
+ if (data[9] == null) {
+ data[9] = source[9];
+ }
+ // Use source `func` and merge bitmasks.
+ data[0] = source[0];
+ data[1] = newBitmask;
+
+ return data;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties specified
+ * by the `props` array.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {string[]} props The property names to pick.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByArray(object, props) {
+ object = toObject(object);
+
+ var index = -1,
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index];
+ if (key in object) {
+ result[key] = object[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties `predicate`
+ * returns truthy for.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByCallback(object, predicate) {
+ var result = {};
+ baseForIn(object, function(value, key, object) {
+ if (predicate(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Reorder `array` according to the specified indexes where the element at
+ * the first index is assigned as the first element, the element at
+ * the second index is assigned as the second element, and so on.
+ *
+ * @private
+ * @param {Array} array The array to reorder.
+ * @param {Array} indexes The arranged array indexes.
+ * @returns {Array} Returns `array`.
+ */
+ function reorder(array, indexes) {
+ var arrLength = array.length,
+ length = nativeMin(indexes.length, arrLength),
+ oldArray = arrayCopy(array);
+
+ while (length--) {
+ var index = indexes[length];
+ array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
+ }
+ return array;
+ }
+
+ /**
+ * Sets metadata for `func`.
+ *
+ * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+ * period of time, it will trip its breaker and transition to an identity function
+ * to avoid garbage collection pauses in V8. See https://code.google.com/p/v8/issues/detail?id=2070.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var setData = (function() {
+ var count = 0,
+ lastCalled = 0;
+
+ return function(key, value) {
+ var stamp = now(),
+ remaining = HOT_SPAN - (stamp - lastCalled);
+
+ lastCalled = stamp;
+ if (remaining > 0) {
+ if (++count >= HOT_COUNT) {
+ return key;
+ }
+ } else {
+ count = 0;
+ }
+ return baseSetData(key, value);
+ };
+ }());
+
+ /**
+ * A fallback implementation of `_.isPlainObject` which checks if `value`
+ * is an object created by the `Object` constructor or has a `[[Prototype]]`
+ * of `null`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ */
+ function shimIsPlainObject(value) {
+ var Ctor,
+ support = lodash.support;
+
+ // Exit early for non `Object` objects.
+ if (!(isObjectLike(value) && objToString.call(value) == objectTag) ||
+ (!hasOwnProperty.call(value, 'constructor') &&
+ (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
+ return false;
+ }
+ // IE < 9 iterates inherited properties before own properties. If the first
+ // iterated property is an object's own property then there are no inherited
+ // enumerable properties.
+ var result;
+ // In most environments an object's own properties are iterated before
+ // its inherited properties. If the last iterated property is an object's
+ // own property then there are no inherited enumerable properties.
+ baseForIn(value, function(subValue, key) {
+ result = key;
+ });
+ return typeof result == 'undefined' || hasOwnProperty.call(value, result);
+ }
+
+ /**
+ * A fallback implementation of `Object.keys` which creates an array of the
+ * own enumerable property names of `object`.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ */
+ function shimKeys(object) {
+ var props = keysIn(object),
+ propsLength = props.length,
+ length = propsLength && object.length,
+ support = lodash.support;
+
+ var allowIndexes = length && isLength(length) &&
+ (isArray(object) || (support.nonEnumArgs && isArguments(object)));
+
+ var index = -1,
+ result = [];
+
+ while (++index < propsLength) {
+ var key = props[index];
+ if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `value` to an array-like object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Array|Object} Returns the array-like object.
+ */
+ function toIterable(value) {
+ if (value == null) {
+ return [];
+ }
+ if (!isLength(value.length)) {
+ return values(value);
+ }
+ return isObject(value) ? value : Object(value);
+ }
+
+ /**
+ * Converts `value` to an object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Object} Returns the object.
+ */
+ function toObject(value) {
+ return isObject(value) ? value : Object(value);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements split into groups the length of `size`.
+ * If `collection` can't be split evenly, the final chunk will be the remaining
+ * elements.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to process.
+ * @param {numer} [size=1] The length of each chunk.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new array containing chunks.
+ * @example
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 2);
+ * // => [['a', 'b'], ['c', 'd']]
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 3);
+ * // => [['a', 'b', 'c'], ['d']]
+ */
+ function chunk(array, size, guard) {
+ if (guard ? isIterateeCall(array, size, guard) : size == null) {
+ size = 1;
+ } else {
+ size = nativeMax(+size || 1, 1);
+ }
+ var index = 0,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = Array(ceil(length / size));
+
+ while (index < length) {
+ result[++resIndex] = baseSlice(array, index, (index += size));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array with all falsey values removed. The values `false`, `null`,
+ * `0`, `""`, `undefined`, and `NaN` are falsey.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to compact.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.compact([0, 1, false, 2, '', 3]);
+ * // => [1, 2, 3]
+ */
+ function compact(array) {
+ var index = -1,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all values of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The arrays of values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.difference([1, 2, 3], [5, 2, 10]);
+ * // => [1, 3]
+ */
+ function difference() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var value = arguments[index];
+ if (isArray(value) || isArguments(value)) {
+ break;
+ }
+ }
+ return baseDifference(value, baseFlatten(arguments, false, true, ++index));
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.drop([1, 2, 3]);
+ * // => [2, 3]
+ *
+ * _.drop([1, 2, 3], 2);
+ * // => [3]
+ *
+ * _.drop([1, 2, 3], 5);
+ * // => []
+ *
+ * _.drop([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function drop(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRight([1, 2, 3]);
+ * // => [1, 2]
+ *
+ * _.dropRight([1, 2, 3], 2);
+ * // => [1]
+ *
+ * _.dropRight([1, 2, 3], 5);
+ * // => []
+ *
+ * _.dropRight([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function dropRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the end.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [1]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropRightWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function dropRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, 0, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the beginning.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['pebbles']
+ */
+ function dropWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, index);
+ }
+
+ /**
+ * This method is like `_.find` except that it returns the index of the first
+ * element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findIndex(users, function(chr) { return chr.age < 40; });
+ * // => 0
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findIndex(users, { 'age': 1 });
+ * // => 2
+ *
+ * // using the "_.property" callback shorthand
+ * _.findIndex(users, 'active');
+ * // => 1
+ */
+ function findIndex(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it iterates over elements
+ * of `collection` from right to left.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findLastIndex(users, function(chr) { return chr.age < 40; });
+ * // => 2
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastIndex(users, { 'age': 40 });
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastIndex(users, 'active');
+ * // => 0
+ */
+ function findLastIndex(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length--) {
+ if (predicate(array[length], length, array)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Gets the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias head
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the first element of `array`.
+ * @example
+ *
+ * _.first([1, 2, 3]);
+ * // => 1
+ *
+ * _.first([]);
+ * // => undefined
+ */
+ function first(array) {
+ return array ? array[0] : undefined;
+ }
+
+ /**
+ * Flattens a nested array. If `isDeep` is `true` the array is recursively
+ * flattened, otherwise it is only flattened a single level.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flatten([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, [[4]]];
+ *
+ * // using `isDeep`
+ * _.flatten([1, [2], [3, [[4]]]], true);
+ * // => [1, 2, 3, 4];
+ */
+ function flatten(array, isDeep, guard) {
+ var length = array ? array.length : 0;
+ if (guard && isIterateeCall(array, isDeep, guard)) {
+ isDeep = false;
+ }
+ return length ? baseFlatten(array, isDeep) : [];
+ }
+
+ /**
+ * Recursively flattens a nested array.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to recursively flatten.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flattenDeep([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, 4];
+ */
+ function flattenDeep(array) {
+ var length = array ? array.length : 0;
+ return length ? baseFlatten(array, true) : [];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found in `array`
+ * using `SameValueZero` for equality comparisons. If `fromIndex` is negative,
+ * it is used as the offset from the end of `array`. If `array` is sorted
+ * providing `true` for `fromIndex` performs a faster binary search.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=0] The index to search from or `true`
+ * to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 1
+ *
+ * // using `fromIndex`
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 4
+ *
+ * // performing a binary search
+ * _.indexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 2
+ */
+ function indexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else if (fromIndex) {
+ var index = binaryIndex(array, value),
+ other = array[index];
+
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ return baseIndexOf(array, value, fromIndex);
+ }
+
+ /**
+ * Gets all but the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.initial([1, 2, 3]);
+ * // => [1, 2]
+ */
+ function initial(array) {
+ return dropRight(array, 1);
+ }
+
+ /**
+ * Creates an array of unique values in all provided arrays using `SameValueZero`
+ * for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of shared values.
+ * @example
+ *
+ * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2]
+ */
+ function intersection() {
+ var args = [],
+ argsIndex = -1,
+ argsLength = arguments.length,
+ caches = [],
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf;
+
+ while (++argsIndex < argsLength) {
+ var value = arguments[argsIndex];
+ if (isArray(value) || isArguments(value)) {
+ args.push(value);
+ caches.push(isCommon && value.length >= 120 && createCache(argsIndex && value));
+ }
+ }
+ argsLength = args.length;
+ var array = args[0],
+ index = -1,
+ length = array ? array.length : 0,
+ result = [],
+ seen = caches[0];
+
+ outer:
+ while (++index < length) {
+ value = array[index];
+ if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value)) < 0) {
+ argsIndex = argsLength;
+ while (--argsIndex) {
+ var cache = caches[argsIndex];
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
+ continue outer;
+ }
+ }
+ if (seen) {
+ seen.push(value);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the last element of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ */
+ function last(array) {
+ var length = array ? array.length : 0;
+ return length ? array[length - 1] : undefined;
+ }
+
+ /**
+ * This method is like `_.indexOf` except that it iterates over elements of
+ * `array` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=array.length-1] The index to search from
+ * or `true` to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 4
+ *
+ * // using `fromIndex`
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 1
+ *
+ * // performing a binary search
+ * _.lastIndexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 3
+ */
+ function lastIndexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ var index = length;
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1;
+ } else if (fromIndex) {
+ index = binaryIndex(array, value, true) - 1;
+ var other = array[index];
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ if (value !== value) {
+ return indexOfNaN(array, index, true);
+ }
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all provided values from `array` using `SameValueZero` for equality
+ * comparisons.
+ *
+ * **Notes:**
+ * - Unlike `_.without`, this method mutates `array`.
+ * - `SameValueZero` comparisons are like strict equality comparisons, e.g. `===`,
+ * except that `NaN` matches `NaN`. See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...*} [values] The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3, 1, 2, 3];
+ * _.pull(array, 2, 3);
+ * console.log(array);
+ * // => [1, 1]
+ */
+ function pull() {
+ var array = arguments[0];
+ if (!(array && array.length)) {
+ return array;
+ }
+ var index = 0,
+ indexOf = getIndexOf(),
+ length = arguments.length;
+
+ while (++index < length) {
+ var fromIndex = 0,
+ value = arguments[index];
+
+ while ((fromIndex = indexOf(array, value, fromIndex)) > -1) {
+ splice.call(array, fromIndex, 1);
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Removes elements from `array` corresponding to the given indexes and returns
+ * an array of the removed elements. Indexes may be specified as an array of
+ * indexes or as individual arguments.
+ *
+ * **Note:** Unlike `_.at`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...(number|number[])} [indexes] The indexes of elements to remove,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [5, 10, 15, 20];
+ * var evens = _.pullAt(array, [1, 3]);
+ *
+ * console.log(array);
+ * // => [5, 15]
+ *
+ * console.log(evens);
+ * // => [10, 20]
+ */
+ function pullAt(array) {
+ return basePullAt(array || [], baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Removes all elements from `array` that `predicate` returns truthy for
+ * and returns an array of the removed elements. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** Unlike `_.filter`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [1, 2, 3, 4];
+ * var evens = _.remove(array, function(n) { return n % 2 == 0; });
+ *
+ * console.log(array);
+ * // => [1, 3]
+ *
+ * console.log(evens);
+ * // => [2, 4]
+ */
+ function remove(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0,
+ result = [];
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result.push(value);
+ splice.call(array, index--, 1);
+ length--;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets all but the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias tail
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.rest([1, 2, 3]);
+ * // => [2, 3]
+ */
+ function rest(array) {
+ return drop(array, 1);
+ }
+
+ /**
+ * Creates a slice of `array` from `start` up to, but not including, `end`.
+ *
+ * **Note:** This function is used instead of `Array#slice` to support node
+ * lists in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function slice(array, start, end) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
+ start = 0;
+ end = length;
+ }
+ return baseSlice(array, start, end);
+ }
+
+ /**
+ * Uses a binary search to determine the lowest index at which `value` should
+ * be inserted into `array` in order to maintain its sort order. If an iteratee
+ * function is provided it is invoked for `value` and each element of `array`
+ * to compute their sort ranking. The iteratee is bound to `thisArg` and
+ * invoked with one argument; (value).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([30, 50], 40);
+ * // => 1
+ *
+ * _.sortedIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 2
+ *
+ * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } };
+ *
+ * // using an iteratee function
+ * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) {
+ * return this.data[word];
+ * }, dict);
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
+ * // => 1
+ */
+ function sortedIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1));
+ }
+
+ /**
+ * This method is like `_.sortedIndex` except that it returns the highest
+ * index at which `value` should be inserted into `array` in order to
+ * maintain its sort order.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedLastIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 4
+ */
+ function sortedLastIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value, true)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1), true);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.take([1, 2, 3]);
+ * // => [1]
+ *
+ * _.take([1, 2, 3], 2);
+ * // => [1, 2]
+ *
+ * _.take([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.take([1, 2, 3], 0);
+ * // => []
+ */
+ function take(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRight([1, 2, 3]);
+ * // => [3]
+ *
+ * _.takeRight([1, 2, 3], 2);
+ * // => [2, 3]
+ *
+ * _.takeRight([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.takeRight([1, 2, 3], 0);
+ * // => []
+ */
+ function takeRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the end. Elements are
+ * taken until `predicate` returns falsey. The predicate is bound to `thisArg`
+ * and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [2, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeRightWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['pebbles']
+ */
+ function takeRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the beginning. Elements
+ * are taken until `predicate` returns falsey. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [1, 2]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function takeWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, 0, index);
+ }
+
+ /**
+ * Creates an array of unique values, in order, of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2, 3, 5, 4]
+ */
+ function union() {
+ return baseUniq(baseFlatten(arguments, false, true));
+ }
+
+ /**
+ * Creates a duplicate-value-free version of an array using `SameValueZero`
+ * for equality comparisons. Providing `true` for `isSorted` performs a faster
+ * search algorithm for sorted arrays. If an iteratee function is provided it
+ * is invoked for each value in the array to generate the criterion by which
+ * uniqueness is computed. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias unique
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {boolean} [isSorted] Specify the array is sorted.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ * @example
+ *
+ * _.uniq([1, 2, 1]);
+ * // => [1, 2]
+ *
+ * // using `isSorted`
+ * _.uniq([1, 1, 2], true);
+ * // => [1, 2]
+ *
+ * // using an iteratee function
+ * _.uniq([1, 2.5, 1.5, 2], function(n) { return this.floor(n); }, Math);
+ * // => [1, 2.5]
+ *
+ * // using the "_.property" callback shorthand
+ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniq(array, isSorted, iteratee, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ // Juggle arguments.
+ if (typeof isSorted != 'boolean' && isSorted != null) {
+ thisArg = iteratee;
+ iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted;
+ isSorted = false;
+ }
+ var func = getCallback();
+ if (!(func === baseCallback && iteratee == null)) {
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ return (isSorted && getIndexOf() == baseIndexOf)
+ ? sortedUniq(array, iteratee)
+ : baseUniq(array, iteratee);
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts an array of grouped
+ * elements and creates an array regrouping the elements to their pre `_.zip`
+ * configuration.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ *
+ * _.unzip(zipped);
+ * // => [['fred', 'barney'], [30, 40], [true, false]]
+ */
+ function unzip(array) {
+ var index = -1,
+ length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = arrayMap(array, baseProperty(index));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all provided values using `SameValueZero` for
+ * equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to filter.
+ * @param {...*} [values] The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+ * // => [2, 3, 4]
+ */
+ function without(array) {
+ return baseDifference(array, baseSlice(arguments, 1));
+ }
+
+ /**
+ * Creates an array that is the symmetric difference of the provided arrays.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Symmetric_difference) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of values.
+ * @example
+ *
+ * _.xor([1, 2, 3], [5, 2, 1, 4]);
+ * // => [3, 5, 4]
+ *
+ * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+ * // => [1, 4, 5]
+ */
+ function xor() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var array = arguments[index];
+ if (isArray(array) || isArguments(array)) {
+ var result = result
+ ? baseDifference(result, array).concat(baseDifference(array, result))
+ : array;
+ }
+ }
+ return result ? baseUniq(result) : [];
+ }
+
+ /**
+ * Creates an array of grouped elements, the first of which contains the first
+ * elements of the given arrays, the second of which contains the second elements
+ * of the given arrays, and so on.
+ *
+ * @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ */
+ function zip() {
+ var length = arguments.length,
+ array = Array(length);
+
+ while (length--) {
+ array[length] = arguments[length];
+ }
+ return unzip(array);
+ }
+
+ /**
+ * Creates an object composed from arrays of property names and values. Provide
+ * either a single two dimensional array, e.g. `[[key1, value1], [key2, value2]]`
+ * or two arrays, one of property names and one of corresponding values.
+ *
+ * @static
+ * @memberOf _
+ * @alias object
+ * @category Array
+ * @param {Array} props The property names.
+ * @param {Array} [values=[]] The property values.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.zipObject(['fred', 'barney'], [30, 40]);
+ * // => { 'fred': 30, 'barney': 40 }
+ */
+ function zipObject(props, values) {
+ var index = -1,
+ length = props ? props.length : 0,
+ result = {};
+
+ if (length && !values && !isArray(props[0])) {
+ values = [];
+ }
+ while (++index < length) {
+ var key = props[index];
+ if (values) {
+ result[key] = values[index];
+ } else if (key) {
+ result[key[0]] = key[1];
+ }
+ }
+ return result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object that wraps `value` with explicit method
+ * chaining enabled.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to wrap.
+ * @returns {Object} Returns the new `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'pebbles', 'age': 1 }
+ * ];
+ *
+ * var youngest = _.chain(users)
+ * .sortBy('age')
+ * .map(function(chr) { return chr.user + ' is ' + chr.age; })
+ * .first()
+ * .value();
+ * // => 'pebbles is 1'
+ */
+ function chain(value) {
+ var result = lodash(value);
+ result.__chain__ = true;
+ return result;
+ }
+
+ /**
+ * This method invokes `interceptor` and returns `value`. The interceptor is
+ * bound to `thisArg` and invoked with one argument; (value). The purpose of
+ * this method is to "tap into" a method chain in order to perform operations
+ * on intermediate results within the chain.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .tap(function(array) { array.pop(); })
+ * .reverse()
+ * .value();
+ * // => [2, 1]
+ */
+ function tap(value, interceptor, thisArg) {
+ interceptor.call(thisArg, value);
+ return value;
+ }
+
+ /**
+ * This method is like `_.tap` except that it returns the result of `interceptor`.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns the result of `interceptor`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .last()
+ * .thru(function(value) { return [value]; })
+ * .value();
+ * // => [3]
+ */
+ function thru(value, interceptor, thisArg) {
+ return interceptor.call(thisArg, value);
+ }
+
+ /**
+ * Enables explicit method chaining on the wrapper object.
+ *
+ * @name chain
+ * @memberOf _
+ * @category Chain
+ * @returns {*} Returns the `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // without explicit chaining
+ * _(users).first();
+ * // => { 'user': 'barney', 'age': 36 }
+ *
+ * // with explicit chaining
+ * _(users).chain()
+ * .first()
+ * .pick('user')
+ * .value();
+ * // => { 'user': 'barney' }
+ */
+ function wrapperChain() {
+ return chain(this);
+ }
+
+ /**
+ * Reverses the wrapped array so the first element becomes the last, the
+ * second element becomes the second to last, and so on.
+ *
+ * **Note:** This method mutates the wrapped array.
+ *
+ * @name reverse
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new reversed `lodash` object.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _(array).reverse().value()
+ * // => [3, 2, 1]
+ *
+ * console.log(array);
+ * // => [3, 2, 1]
+ */
+ function wrapperReverse() {
+ var value = this.__wrapped__;
+ if (value instanceof LazyWrapper) {
+ return new LodashWrapper(value.reverse());
+ }
+ return this.thru(function(value) {
+ return value.reverse();
+ });
+ }
+
+ /**
+ * Produces the result of coercing the unwrapped value to a string.
+ *
+ * @name toString
+ * @memberOf _
+ * @category Chain
+ * @returns {string} Returns the coerced string value.
+ * @example
+ *
+ * _([1, 2, 3]).toString();
+ * // => '1,2,3'
+ */
+ function wrapperToString() {
+ return (this.value() + '');
+ }
+
+ /**
+ * Executes the chained sequence to extract the unwrapped value.
+ *
+ * @name value
+ * @memberOf _
+ * @alias toJSON, valueOf
+ * @category Chain
+ * @returns {*} Returns the resolved unwrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperValue() {
+ return baseWrapperValue(this.__wrapped__, this.__actions__);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements corresponding to the given keys, or indexes,
+ * of `collection`. Keys may be specified as individual arguments or as arrays
+ * of keys.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(number|number[]|string|string[])} [props] The property names
+ * or indexes of elements to pick, specified individually or in arrays.
+ * @returns {Array} Returns the new array of picked elements.
+ * @example
+ *
+ * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
+ * // => ['a', 'c', 'e']
+ *
+ * _.at(['fred', 'barney', 'pebbles'], 0, 2);
+ * // => ['fred', 'pebbles']
+ */
+ function at(collection) {
+ var length = collection ? collection.length : 0;
+ if (isLength(length)) {
+ collection = toIterable(collection);
+ }
+ return baseAt(collection, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Checks if `value` is in `collection` using `SameValueZero` for equality
+ * comparisons. If `fromIndex` is negative, it is used as the offset from
+ * the end of `collection`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias contains, include
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {*} target The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {boolean} Returns `true` if a matching element is found, else `false`.
+ * @example
+ *
+ * _.includes([1, 2, 3], 1);
+ * // => true
+ *
+ * _.includes([1, 2, 3], 1, 2);
+ * // => false
+ *
+ * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
+ * // => true
+ *
+ * _.includes('pebbles', 'eb');
+ * // => true
+ */
+ function includes(collection, target, fromIndex) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ collection = values(collection);
+ length = collection.length;
+ }
+ if (!length) {
+ return false;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else {
+ fromIndex = 0;
+ }
+ return (typeof collection == 'string' || !isArray(collection) && isString(collection))
+ ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
+ : (getIndexOf(collection, target, fromIndex) > -1);
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the number of times the key was returned by `iteratee`.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy(['one', 'two', 'three'], 'length');
+ * // => { '3': 2, '5': 1 }
+ */
+ var countBy = createAggregator(function(result, value, key) {
+ hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1);
+ });
+
+ /**
+ * Checks if `predicate` returns truthy for **all** elements of `collection`.
+ * The predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias all
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes']);
+ * // => false
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.every(users, 'age');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.every(users, { 'age': 36 });
+ * // => false
+ */
+ function every(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayEvery : baseEvery;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning an array of all elements
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias select
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
* @example
*
- * _.isBoolean(null);
- * // => false
+ * var evens = _.filter([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [2, 4]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.filter(users, 'active'), 'user');
+ * // => ['fred']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.filter(users, { 'age': 36 }), 'user');
+ * // => ['barney']
*/
- function isBoolean(value) {
- return value === true || value === false ||
- value && typeof value == 'object' && toString.call(value) == boolClass || false;
+ function filter(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, predicate);
}
/**
- * Checks if `value` is a date.
+ * Iterates over elements of `collection`, returning the first element
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
+ * @alias detect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
* @example
*
- * _.isDate(new Date);
- * // => true
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.result(_.find(users, function(chr) { return chr.age < 40; }), 'user');
+ * // => 'barney'
+ *
+ * // using the "_.matches" callback shorthand
+ * _.result(_.find(users, { 'age': 1 }), 'user');
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.result(_.find(users, 'active'), 'user');
+ * // => 'fred'
*/
- function isDate(value) {
- return value && typeof value == 'object' && toString.call(value) == dateClass || false;
+ function find(collection, predicate, thisArg) {
+ if (isArray(collection)) {
+ var index = findIndex(collection, predicate, thisArg);
+ return index > -1 ? collection[index] : undefined;
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEach);
}
/**
- * Checks if `value` is a DOM element.
+ * This method is like `_.find` except that it iterates over elements of
+ * `collection` from right to left.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
* @example
*
- * _.isElement(document.body);
- * // => true
+ * _.findLast([1, 2, 3, 4], function(n) { return n % 2 == 1; });
+ * // => 3
*/
- function isElement(value) {
- return value && value.nodeType === 1 || false;
+ function findLast(collection, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEachRight);
}
/**
- * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
- * length of `0` and objects with no own enumerable properties are considered
- * "empty".
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning the first element that has equivalent property
+ * values.
*
* @static
* @memberOf _
- * @category Objects
- * @param {Array|Object|string} value The value to inspect.
- * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {*} Returns the matched element, else `undefined`.
* @example
*
- * _.isEmpty([1, 2, 3]);
- * // => false
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy' },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy' }
+ * ];
*
- * _.isEmpty({});
- * // => true
+ * _.result(_.findWhere(users, { 'status': 'busy' }), 'user');
+ * // => 'barney'
*
- * _.isEmpty('');
- * // => true
+ * _.result(_.findWhere(users, { 'age': 40 }), 'user');
+ * // => 'fred'
*/
- function isEmpty(value) {
- var result = true;
- if (!value) {
- return result;
- }
- var className = toString.call(value),
- length = value.length;
+ function findWhere(collection, source) {
+ return find(collection, matches(source));
+ }
- if ((className == arrayClass || className == stringClass ||
- (support.argsClass ? className == argsClass : isArguments(value))) ||
- (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
- return !length;
- }
- forOwn(value, function() {
- return (result = false);
- });
- return result;
+ /**
+ * Iterates over elements of `collection` invoking `iteratee` for each element.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection). Iterator functions may exit iteration early
+ * by explicitly returning `false`.
+ *
+ * **Note:** As with other "Collections" methods, objects with a `length` property
+ * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+ * may be used for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEach(function(n) { console.log(n); });
+ * // => logs each value from left to right and returns the array
+ *
+ * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(n, key) { console.log(n, key); });
+ * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
+ */
+ function forEach(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEach(collection, iteratee)
+ : baseEach(collection, bindCallback(iteratee, thisArg, 3));
}
/**
- * Performs a deep comparison between two values to determine if they are
- * equivalent to each other. If a callback is provided it will be executed
- * to compare values. If the callback returns `undefined` comparisons will
- * be handled by the method instead. The callback is bound to `thisArg` and
- * invoked with two arguments; (a, b).
+ * This method is like `_.forEach` except that it iterates over elements of
+ * `collection` from right to left.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} a The value to compare.
- * @param {*} b The other value to compare.
- * @param {Function} [callback] The function to customize comparing values.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @alias eachRight
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
* @example
*
- * var object = { 'name': 'fred' };
- * var copy = { 'name': 'fred' };
+ * _([1, 2, 3]).forEachRight(function(n) { console.log(n); }).join(',');
+ * // => logs each value from right to left and returns the array
+ */
+ function forEachRight(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEachRight(collection, iteratee)
+ : baseEachRight(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is an array of the elements responsible for generating the key.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
*
- * object == copy;
- * // => false
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
*
- * _.isEqual(object, copy);
- * // => true
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
- * var words = ['hello', 'goodbye'];
- * var otherWords = ['hi', 'goodbye'];
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
*
- * _.isEqual(words, otherWords, function(a, b) {
- * var reGreet = /^(?:hello|hi)$/i,
- * aGreet = _.isString(a) && reGreet.test(a),
- * bGreet = _.isString(b) && reGreet.test(b);
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
*
- * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
- * });
- * // => true
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * // using the "_.property" callback shorthand
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
*/
- function isEqual(a, b, callback, thisArg) {
- return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
- }
+ var groupBy = createAggregator(function(result, value, key) {
+ if (hasOwnProperty.call(result, key)) {
+ result[key].push(value);
+ } else {
+ result[key] = [value];
+ }
+ });
/**
- * Checks if `value` is, or can be coerced to, a finite number.
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the last element responsible for generating the key. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
*
- * Note: This is not the same as native `isFinite` which will return true for
- * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
* @example
*
- * _.isFinite(-101);
- * // => true
+ * var keyData = [
+ * { 'dir': 'left', 'code': 97 },
+ * { 'dir': 'right', 'code': 100 }
+ * ];
*
- * _.isFinite('10');
- * // => true
+ * _.indexBy(keyData, 'dir');
+ * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
*
- * _.isFinite(true);
- * // => false
+ * _.indexBy(keyData, function(object) { return String.fromCharCode(object.code); });
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
*
- * _.isFinite('');
- * // => false
+ * _.indexBy(keyData, function(object) { return this.fromCharCode(object.code); }, String);
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ */
+ var indexBy = createAggregator(function(result, value, key) {
+ result[key] = value;
+ });
+
+ /**
+ * Invokes the method named by `methodName` on each element in `collection`,
+ * returning an array of the results of each invoked method. Any additional
+ * arguments are provided to each invoked method. If `methodName` is a function
+ * it is invoked for, and `this` bound to, each element in `collection`.
*
- * _.isFinite(Infinity);
- * // => false
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {...*} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+ * // => [[1, 5, 7], [1, 2, 3]]
+ *
+ * _.invoke([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
*/
- function isFinite(value) {
- return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
+ function invoke(collection, methodName) {
+ return baseInvoke(collection, methodName, baseSlice(arguments, 2));
}
/**
- * Checks if `value` is a function.
+ * Creates an array of values by running each element in `collection` through
+ * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
+ * @alias collect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new mapped array.
* @example
*
- * _.isFunction(_);
- * // => true
+ * _.map([1, 2, 3], function(n) { return n * 3; });
+ * // => [3, 6, 9]
+ *
+ * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(n) { return n * 3; });
+ * // => [3, 6, 9] (iteration order is not guaranteed)
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(users, 'user');
+ * // => ['barney', 'fred']
*/
- function isFunction(value) {
- return typeof value == 'function';
- }
- // fallback for older versions of Chrome and Safari
- if (isFunction(/x/)) {
- isFunction = function(value) {
- return typeof value == 'function' && toString.call(value) == funcClass;
- };
+ function map(collection, iteratee, thisArg) {
+ var func = isArray(collection) ? arrayMap : baseMap;
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return func(collection, iteratee);
}
/**
- * Checks if `value` is the language type of Object.
- * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ * Gets the maximum value of `collection`. If `collection` is empty or falsey
+ * `-Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the maximum value.
* @example
*
- * _.isObject({});
- * // => true
+ * _.max([4, 2, 8, 6]);
+ * // => 8
*
- * _.isObject([1, 2, 3]);
- * // => true
+ * _.max([]);
+ * // => -Infinity
*
- * _.isObject(1);
- * // => false
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.max(users, function(chr) { return chr.age; });
+ * // => { 'user': 'fred', 'age': 40 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.max(users, 'age');
+ * // => { 'user': 'fred', 'age': 40 };
*/
- function isObject(value) {
- // check if the value is the ECMAScript language type of Object
- // http://es5.github.io/#x8
- // and avoid a V8 bug
- // http://code.google.com/p/v8/issues/detail?id=2291
- return !!(value && objectTypes[typeof value]);
- }
+ var max = createExtremum(arrayMax);
/**
- * Checks if `value` is `NaN`.
+ * Gets the minimum value of `collection`. If `collection` is empty or falsey
+ * `Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
*
- * Note: This is not the same as native `isNaN` which will return `true` for
- * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the minimum value.
* @example
*
- * _.isNaN(NaN);
- * // => true
+ * _.min([4, 2, 8, 6]);
+ * // => 2
*
- * _.isNaN(new Number(NaN));
- * // => true
+ * _.min([]);
+ * // => Infinity
*
- * isNaN(undefined);
- * // => true
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
*
- * _.isNaN(undefined);
- * // => false
+ * _.min(users, function(chr) { return chr.age; });
+ * // => { 'user': 'barney', 'age': 36 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.min(users, 'age');
+ * // => { 'user': 'barney', 'age': 36 };
*/
- function isNaN(value) {
- // `NaN` as a primitive is the only value that is not equal to itself
- // (perform the [[Class]] check first to avoid errors with some host objects in IE)
- return isNumber(value) && value != +value;
+ var min = createExtremum(arrayMin, true);
+
+ /**
+ * Creates an array of elements split into two groups, the first of which
+ * contains elements `predicate` returns truthy for, while the second of which
+ * contains elements `predicate` returns falsey for. The predicate is bound
+ * to `thisArg` and invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the array of grouped elements.
+ * @example
+ *
+ * _.partition([1, 2, 3], function(n) { return n % 2; });
+ * // => [[1, 3], [2]]
+ *
+ * _.partition([1.2, 2.3, 3.4], function(n) { return this.floor(n) % 2; }, Math);
+ * // => [[1, 3], [2]]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * // using the "_.matches" callback shorthand
+ * _.map(_.partition(users, { 'age': 1 }), function(array) { return _.pluck(array, 'user'); });
+ * // => [['pebbles'], ['barney', 'fred']]
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(_.partition(users, 'active'), function(array) { return _.pluck(array, 'user'); });
+ * // => [['fred'], ['barney', 'pebbles']]
+ */
+ var partition = createAggregator(function(result, value, key) {
+ result[key ? 0 : 1].push(value);
+ }, function() { return [[], []]; });
+
+ /**
+ * Gets the value of `key` from all elements in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {string} key The key of the property to pluck.
+ * @returns {Array} Returns the property values.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.pluck(users, 'user');
+ * // => ['barney', 'fred']
+ *
+ * var userIndex = _.indexBy(users, 'user');
+ * _.pluck(userIndex, 'age');
+ * // => [36, 40] (iteration order is not guaranteed)
+ */
+ function pluck(collection, key) {
+ return map(collection, property(key));
}
/**
- * Checks if `value` is `null`.
+ * Reduces `collection` to a value which is the accumulated result of running
+ * each element in `collection` through `iteratee`, where each successive
+ * invocation is supplied the return value of the previous. If `accumulator`
+ * is not provided the first element of `collection` is used as the initial
+ * value. The `iteratee` is bound to `thisArg`and invoked with four arguments;
+ * (accumulator, value, index|key, collection).
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
+ * @alias foldl, inject
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
* @example
*
- * _.isNull(null);
- * // => true
+ * var sum = _.reduce([1, 2, 3], function(sum, n) { return sum + n; });
+ * // => 6
*
- * _.isNull(undefined);
- * // => false
+ * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * return result;
+ * }, {});
+ * // => { 'a': 3, 'b': 6, 'c': 9 } (iteration order is not guaranteed)
+ */
+ function reduce(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduce : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEach);
+ }
+
+ /**
+ * This method is like `_.reduce` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias foldr
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var array = [[0, 1], [2, 3], [4, 5]];
+ * _.reduceRight(array, function(flattened, other) { return flattened.concat(other); }, []);
+ * // => [4, 5, 2, 3, 0, 1]
+ */
+ function reduceRight(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduceRight : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEachRight);
+ }
+
+ /**
+ * The opposite of `_.filter`; this method returns the elements of `collection`
+ * that `predicate` does **not** return truthy for.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var odds = _.reject([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [1, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.reject(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.reject(users, { 'age': 36 }), 'user');
+ * // => ['fred']
*/
- function isNull(value) {
- return value === null;
+ function reject(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, function(value, index, collection) {
+ return !predicate(value, index, collection);
+ });
}
/**
- * Checks if `value` is a number.
- *
- * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
+ * Gets a random element or `n` random elements from a collection.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to sample.
+ * @param {number} [n] The number of elements to sample.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {*} Returns the random sample(s).
* @example
*
- * _.isNumber(8.4 * 5);
- * // => true
+ * _.sample([1, 2, 3, 4]);
+ * // => 2
+ *
+ * _.sample([1, 2, 3, 4], 2);
+ * // => [3, 1]
*/
- function isNumber(value) {
- return typeof value == 'number' ||
- value && typeof value == 'object' && toString.call(value) == numberClass || false;
+ function sample(collection, n, guard) {
+ if (guard ? isIterateeCall(collection, n, guard) : n == null) {
+ collection = toIterable(collection);
+ var length = collection.length;
+ return length > 0 ? collection[baseRandom(0, length - 1)] : undefined;
+ }
+ var result = shuffle(collection);
+ result.length = nativeMin(n < 0 ? 0 : (+n || 0), result.length);
+ return result;
}
/**
- * Checks if `value` is an object created by the `Object` constructor.
+ * Creates an array of shuffled values, using a version of the Fisher-Yates
+ * shuffle. See [Wikipedia](http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)
+ * for more details.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to shuffle.
+ * @returns {Array} Returns the new shuffled array.
* @example
*
- * function Shape() {
- * this.x = 0;
- * this.y = 0;
- * }
- *
- * _.isPlainObject(new Shape);
- * // => false
- *
- * _.isPlainObject([1, 2, 3]);
- * // => false
- *
- * _.isPlainObject({ 'x': 0, 'y': 0 });
- * // => true
+ * _.shuffle([1, 2, 3, 4]);
+ * // => [4, 1, 3, 2]
*/
- var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
- if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) {
- return false;
- }
- var valueOf = value.valueOf,
- objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
+ function shuffle(collection) {
+ collection = toIterable(collection);
- return objProto
- ? (value == objProto || getPrototypeOf(value) == objProto)
- : shimIsPlainObject(value);
- };
+ var index = -1,
+ length = collection.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var rand = baseRandom(0, index);
+ if (index != rand) {
+ result[index] = result[rand];
+ }
+ result[rand] = collection[index];
+ }
+ return result;
+ }
/**
- * Checks if `value` is a regular expression.
+ * Gets the size of `collection` by returning `collection.length` for
+ * array-like values or the number of own enumerable properties for objects.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @returns {number} Returns the size of `collection`.
* @example
*
- * _.isRegExp(/fred/);
- * // => true
+ * _.size([1, 2]);
+ * // => 2
+ *
+ * _.size({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => 3
+ *
+ * _.size('pebbles');
+ * // => 7
*/
- function isRegExp(value) {
- return value && objectTypes[typeof value] && toString.call(value) == regexpClass || false;
+ function size(collection) {
+ var length = collection ? collection.length : 0;
+ return isLength(length) ? length : keys(collection).length;
}
/**
- * Checks if `value` is a string.
+ * Checks if `predicate` returns truthy for **any** element of `collection`.
+ * The function returns as soon as it finds a passing value and does not iterate
+ * over the entire collection. The predicate is bound to `thisArg` and invoked
+ * with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
+ * @alias any
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
* @example
*
- * _.isString('fred');
+ * _.some([null, 0, 'yes', false], Boolean);
+ * // => true
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.some(users, 'active');
* // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.some(users, { 'age': 1 });
+ * // => false
*/
- function isString(value) {
- return typeof value == 'string' ||
- value && typeof value == 'object' && toString.call(value) == stringClass || false;
+ function some(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arraySome : baseSome;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
}
/**
- * Checks if `value` is `undefined`.
+ * Creates an array of elements, sorted in ascending order by the results of
+ * running each element in a collection through `iteratee`. This method performs
+ * a stable sort, that is, it preserves the original sort order of equal elements.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Objects
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Array|Function|Object|string} [iteratee=_.identity] The function
+ * invoked per iteration. If a property name or an object is provided it is
+ * used to create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new sorted array.
* @example
*
- * _.isUndefined(void 0);
- * // => true
+ * _.sortBy([1, 2, 3], function(n) { return Math.sin(n); });
+ * // => [3, 1, 2]
+ *
+ * _.sortBy([1, 2, 3], function(n) { return this.sin(n); }, Math);
+ * // => [3, 1, 2]
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'pebbles' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.sortBy(users, 'user'), 'user');
+ * // => ['barney', 'fred', 'pebbles']
*/
- function isUndefined(value) {
- return typeof value == 'undefined';
+ function sortBy(collection, iteratee, thisArg) {
+ var index = -1,
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ iteratee = getCallback(iteratee, thisArg, 3);
+ baseEach(collection, function(value, key, collection) {
+ result[++index] = { 'criteria': iteratee(value, key, collection), 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareAscending);
}
/**
- * Creates an object with the same keys as `object` and values generated by
- * running each own enumerable property of `object` through the callback.
- * The callback is bound to `thisArg` and invoked with three arguments;
- * (value, key, object).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * This method is like `_.sortBy` except that it sorts by property names
+ * instead of an iteratee function.
*
* @static
* @memberOf _
- * @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new object with values of the results of each `callback` execution.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(string|string[])} props The property names to sort by,
+ * specified as individual property names or arrays of property names.
+ * @returns {Array} Returns the new sorted array.
* @example
*
- * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
- * // => { 'a': 3, 'b': 6, 'c': 9 }
- *
- * var characters = {
- * 'fred': { 'name': 'fred', 'age': 40 },
- * 'pebbles': { 'name': 'pebbles', 'age': 1 }
- * };
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 26 },
+ * { 'user': 'fred', 'age': 30 }
+ * ];
*
- * // using "_.pluck" callback shorthand
- * _.mapValues(characters, 'age');
- * // => { 'fred': 40, 'pebbles': 1 }
+ * _.map(_.sortByAll(users, ['user', 'age']), _.values);
+ * // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
*/
- function mapValues(object, callback, thisArg) {
- var result = {};
- callback = lodash.createCallback(callback, thisArg, 3);
+ function sortByAll(collection) {
+ var args = arguments;
+ if (args.length > 3 && isIterateeCall(args[1], args[2], args[3])) {
+ args = [collection, args[1]];
+ }
+ var index = -1,
+ length = collection ? collection.length : 0,
+ props = baseFlatten(args, false, false, 1),
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value, key, collection) {
+ var length = props.length,
+ criteria = Array(length);
- forOwn(object, function(value, key, object) {
- result[key] = callback(value, key, object);
+ while (length--) {
+ criteria[length] = value == null ? undefined : value[props[length]];
+ }
+ result[++index] = { 'criteria': criteria, 'index': index, 'value': value };
});
- return result;
+ return baseSortBy(result, compareMultipleAscending);
}
/**
- * Recursively merges own enumerable properties of the source object(s), that
- * don't resolve to `undefined` into the destination object. Subsequent sources
- * will overwrite property assignments of previous sources. If a callback is
- * provided it will be executed to produce the merged values of the destination
- * and source properties. If the callback returns `undefined` merging will
- * be handled by the method instead. The callback is bound to `thisArg` and
- * invoked with two arguments; (objectValue, sourceValue).
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning an array of all elements that have equivalent
+ * property values.
*
* @static
* @memberOf _
- * @category Objects
- * @param {Object} object The destination object.
- * @param {...Object} [source] The source objects.
- * @param {Function} [callback] The function to customize merging properties.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the destination object.
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {Array} Returns the new filtered array.
* @example
*
- * var names = {
- * 'characters': [
- * { 'name': 'barney' },
- * { 'name': 'fred' }
- * ]
- * };
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy', 'pets': ['hoppy'] },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy', 'pets': ['baby puss', 'dino'] }
+ * ];
*
- * var ages = {
- * 'characters': [
- * { 'age': 36 },
- * { 'age': 40 }
- * ]
- * };
+ * _.pluck(_.where(users, { 'age': 36 }), 'user');
+ * // => ['barney']
*
- * _.merge(names, ages);
- * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
+ * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user');
+ * // => ['fred']
*
- * var food = {
- * 'fruits': ['apple'],
- * 'vegetables': ['beet']
- * };
+ * _.pluck(_.where(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function where(collection, source) {
+ return filter(collection, matches(source));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Gets the number of milliseconds that have elapsed since the Unix epoch
+ * (1 January 1970 00:00:00 UTC).
*
- * var otherFood = {
- * 'fruits': ['banana'],
- * 'vegetables': ['carrot']
- * };
+ * @static
+ * @memberOf _
+ * @category Date
+ * @example
*
- * _.merge(food, otherFood, function(a, b) {
- * return _.isArray(a) ? a.concat(b) : undefined;
- * });
- * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
+ * _.defer(function(stamp) { console.log(_.now() - stamp); }, _.now());
+ * // => logs the number of milliseconds it took for the deferred function to be invoked
*/
- function merge(object) {
- var args = arguments,
- length = 2;
-
- if (!isObject(object)) {
- return object;
- }
- // allows working with `_.reduce` and `_.reduceRight` without using
- // their `index` and `collection` arguments
- if (typeof args[2] != 'number') {
- length = args.length;
- }
- if (length > 3 && typeof args[length - 2] == 'function') {
- var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
- } else if (length > 2 && typeof args[length - 1] == 'function') {
- callback = args[--length];
- }
- var sources = slice(arguments, 1, length),
- index = -1,
- stackA = getArray(),
- stackB = getArray();
+ var now = nativeNow || function() {
+ return new Date().getTime();
+ };
- while (++index < length) {
- baseMerge(object, sources[index], callback, stackA, stackB);
- }
- releaseArray(stackA);
- releaseArray(stackB);
- return object;
- }
+ /*------------------------------------------------------------------------*/
/**
- * Creates a shallow clone of `object` excluding the specified properties.
- * Property names may be specified as individual arguments or as arrays of
- * property names. If a callback is provided it will be executed for each
- * property of `object` omitting the properties the callback returns truey
- * for. The callback is bound to `thisArg` and invoked with three arguments;
- * (value, key, object).
+ * The opposite of `_.before`; this method creates a function that invokes
+ * `func` once it is called `n` or more times.
*
* @static
* @memberOf _
- * @category Objects
- * @param {Object} object The source object.
- * @param {Function|...string|string[]} [callback] The properties to omit or the
- * function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns an object without the omitted properties.
+ * @category Function
+ * @param {number} n The number of calls before `func` is invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
* @example
*
- * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
- * // => { 'name': 'fred' }
+ * var saves = ['profile', 'settings'];
+ *
+ * var done = _.after(saves.length, function() {
+ * console.log('done saving!');
+ * });
*
- * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
- * return typeof value == 'number';
+ * _.forEach(saves, function(type) {
+ * asyncSave({ 'type': type, 'complete': done });
* });
- * // => { 'name': 'fred' }
+ * // => logs 'done saving!' after the two async saves have completed
*/
- function omit(object, callback, thisArg) {
- var result = {};
- if (typeof callback != 'function') {
- var props = [];
- forIn(object, function(value, key) {
- props.push(key);
- });
- props = baseDifference(props, baseFlatten(arguments, true, false, 1));
-
- var index = -1,
- length = props.length;
-
- while (++index < length) {
- var key = props[index];
- result[key] = object[key];
+ function after(n, func) {
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
}
- } else {
- callback = lodash.createCallback(callback, thisArg, 3);
- forIn(object, function(value, key, object) {
- if (!callback(value, key, object)) {
- result[key] = value;
- }
- });
}
- return result;
+ n = nativeIsFinite(n = +n) ? n : 0;
+ return function() {
+ if (--n < 1) {
+ return func.apply(this, arguments);
+ }
+ };
}
/**
- * Creates a two dimensional array of an object's key-value pairs,
- * i.e. `[[key1, value1], [key2, value2]]`.
+ * Creates a function that accepts up to `n` arguments ignoring any
+ * additional arguments.
*
* @static
* @memberOf _
- * @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns new array of key-value pairs.
+ * @category Function
+ * @param {Function} func The function to cap arguments for.
+ * @param {number} [n=func.length] The arity cap.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new function.
* @example
*
- * _.pairs({ 'barney': 36, 'fred': 40 });
- * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
+ * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+ * // => [6, 8, 10]
*/
- function pairs(object) {
- var index = -1,
- props = keys(object),
- length = props.length,
- result = Array(length);
-
- while (++index < length) {
- var key = props[index];
- result[index] = [key, object[key]];
+ function ary(func, n, guard) {
+ if (guard && isIterateeCall(func, n, guard)) {
+ n = null;
}
- return result;
+ n = n == null ? func.length : (+n || 0);
+ return createWrapper(func, ARY_FLAG, null, null, null, null, n);
}
/**
- * Creates a shallow clone of `object` composed of the specified properties.
- * Property names may be specified as individual arguments or as arrays of
- * property names. If a callback is provided it will be executed for each
- * property of `object` picking the properties the callback returns truey
- * for. The callback is bound to `thisArg` and invoked with three arguments;
- * (value, key, object).
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it is called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
*
* @static
* @memberOf _
- * @category Objects
- * @param {Object} object The source object.
- * @param {Function|...string|string[]} [callback] The function called per
- * iteration or property names to pick, specified as individual property
- * names or arrays of property names.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns an object composed of the picked properties.
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
* @example
*
- * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
- * // => { 'name': 'fred' }
- *
- * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
- * return key.charAt(0) != '_';
- * });
- * // => { 'name': 'fred' }
+ * jQuery('#add').on('click', _.before(5, addContactToList));
+ * // => allows adding up to 4 contacts to the list
*/
- function pick(object, callback, thisArg) {
- var result = {};
- if (typeof callback != 'function') {
- var index = -1,
- props = baseFlatten(arguments, true, false, 1),
- length = isObject(object) ? props.length : 0;
-
- while (++index < length) {
- var key = props[index];
- if (key in object) {
- result[key] = object[key];
- }
+ function before(n, func) {
+ var result;
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
}
- } else {
- callback = lodash.createCallback(callback, thisArg, 3);
- forIn(object, function(value, key, object) {
- if (callback(value, key, object)) {
- result[key] = value;
- }
- });
}
- return result;
+ return function() {
+ if (--n > 0) {
+ result = func.apply(this, arguments);
+ } else {
+ func = null;
+ }
+ return result;
+ };
}
/**
- * An alternative to `_.reduce` this method transforms `object` to a new
- * `accumulator` object which is the result of running each of its own
- * enumerable properties through a callback, with each callback execution
- * potentially mutating the `accumulator` object. The callback is bound to
- * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
- * Callbacks may exit iteration early by explicitly returning `false`.
+ * Creates a function that invokes `func` with the `this` binding of `thisArg`
+ * and prepends any additional `_.bind` arguments to those provided to the
+ * bound function.
+ *
+ * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** Unlike native `Function#bind` this method does not set the `length`
+ * property of bound functions.
*
* @static
* @memberOf _
- * @category Objects
- * @param {Array|Object} object The object to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [accumulator] The custom accumulator value.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the accumulated value.
+ * @category Function
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
* @example
*
- * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
- * num *= num;
- * if (num % 2) {
- * return result.push(num) < 3;
- * }
- * });
- * // => [1, 9, 25]
+ * var greet = function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * };
*
- * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
- * result[key] = num * 3;
- * });
- * // => { 'a': 3, 'b': 6, 'c': 9 }
+ * var object = { 'user': 'fred' };
+ *
+ * var bound = _.bind(greet, object, 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * // using placeholders
+ * var bound = _.bind(greet, object, _, '!');
+ * bound('hi');
+ * // => 'hi fred!'
*/
- function transform(object, callback, accumulator, thisArg) {
- var isArr = isArray(object);
- if (accumulator == null) {
- if (isArr) {
- accumulator = [];
- } else {
- var ctor = object && object.constructor,
- proto = ctor && ctor.prototype;
-
- accumulator = baseCreate(proto);
- }
- }
- if (callback) {
- callback = lodash.createCallback(callback, thisArg, 4);
- (isArr ? baseEach : forOwn)(object, function(value, index, object) {
- return callback(accumulator, value, index, object);
- });
+ function bind(func, thisArg) {
+ var bitmask = BIND_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bind.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
}
- return accumulator;
+ return createWrapper(func, bitmask, thisArg, partials, holders);
}
/**
- * Creates an array composed of the own enumerable property values of `object`.
+ * Binds methods of an object to the object itself, overwriting the existing
+ * method. Method names may be specified as individual arguments or as arrays
+ * of method names. If no method names are provided all enumerable function
+ * properties, own and inherited, of `object` are bound.
+ *
+ * **Note:** This method does not set the `length` property of bound functions.
*
* @static
* @memberOf _
- * @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns an array of property values.
+ * @category Function
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {...(string|string[])} [methodNames] The object method names to bind,
+ * specified as individual method names or arrays of method names.
+ * @returns {Object} Returns `object`.
* @example
*
- * _.values({ 'one': 1, 'two': 2, 'three': 3 });
- * // => [1, 2, 3] (property order is not guaranteed across environments)
+ * var view = {
+ * 'label': 'docs',
+ * 'onClick': function() { console.log('clicked ' + this.label); }
+ * };
+ *
+ * _.bindAll(view);
+ * jQuery('#docs').on('click', view.onClick);
+ * // => logs 'clicked docs' when the element is clicked
*/
- function values(object) {
- var index = -1,
- props = keys(object),
- length = props.length,
- result = Array(length);
-
- while (++index < length) {
- result[index] = object[props[index]];
- }
- return result;
+ function bindAll(object) {
+ return baseBindAll(object,
+ arguments.length > 1
+ ? baseFlatten(arguments, false, false, 1)
+ : functions(object)
+ );
}
- /*--------------------------------------------------------------------------*/
-
/**
- * Creates an array of elements from the specified indexes, or keys, of the
- * `collection`. Indexes may be specified as individual arguments or as arrays
- * of indexes.
+ * Creates a function that invokes the method at `object[key]` and prepends
+ * any additional `_.bindKey` arguments to those provided to the bound function.
+ *
+ * This method differs from `_.bind` by allowing bound functions to reference
+ * methods that may be redefined or don't yet exist.
+ * See [Peter Michaux's article](http://michaux.ca/articles/lazy-function-definition-pattern)
+ * for more details.
+ *
+ * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
- * to retrieve, specified as individual indexes or arrays of indexes.
- * @returns {Array} Returns a new array of elements corresponding to the
- * provided indexes.
+ * @category Function
+ * @param {Object} object The object the method belongs to.
+ * @param {string} key The key of the method.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
* @example
*
- * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
- * // => ['a', 'c', 'e']
+ * var object = {
+ * 'user': 'fred',
+ * 'greet': function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * }
+ * };
*
- * _.at(['fred', 'barney', 'pebbles'], 0, 2);
- * // => ['fred', 'pebbles']
+ * var bound = _.bindKey(object, 'greet', 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * object.greet = function(greeting, punctuation) {
+ * return greeting + 'ya ' + this.user + punctuation;
+ * };
+ *
+ * bound('!');
+ * // => 'hiya fred!'
+ *
+ * // using placeholders
+ * var bound = _.bindKey(object, 'greet', _, '!');
+ * bound('hi');
+ * // => 'hiya fred!'
*/
- function at(collection) {
- var args = arguments,
- index = -1,
- props = baseFlatten(args, true, false, 1),
- length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
- result = Array(length);
+ function bindKey(object, key) {
+ var bitmask = BIND_FLAG | BIND_KEY_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bindKey.placeholder);
- if (support.unindexedChars && isString(collection)) {
- collection = collection.split('');
- }
- while(++index < length) {
- result[index] = collection[props[index]];
+ bitmask |= PARTIAL_FLAG;
}
- return result;
+ return createWrapper(key, bitmask, object, partials, holders);
}
/**
- * Checks if a given value is present in a collection using strict equality
- * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
- * offset from the end of the collection.
+ * Creates a function that accepts one or more arguments of `func` that when
+ * called either invokes `func` returning its result, if all `func` arguments
+ * have been provided, or returns a function that accepts one or more of the
+ * remaining `func` arguments, and so on. The arity of `func` may be specified
+ * if `func.length` is not sufficient.
+ *
+ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
*
* @static
* @memberOf _
- * @alias include
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {*} target The value to check for.
- * @param {number} [fromIndex=0] The index to search from.
- * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
* @example
*
- * _.contains([1, 2, 3], 1);
- * // => true
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
*
- * _.contains([1, 2, 3], 1, 2);
- * // => false
+ * var curried = _.curry(abc);
*
- * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
- * // => true
+ * curried(1)(2)(3);
+ * // => [1, 2, 3]
*
- * _.contains('pebbles', 'eb');
- * // => true
+ * curried(1, 2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(1)(_, 3)(2);
+ * // => [1, 2, 3]
*/
- function contains(collection, target, fromIndex) {
- var index = -1,
- indexOf = getIndexOf(),
- length = collection ? collection.length : 0,
- result = false;
-
- fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
- if (isArray(collection)) {
- result = indexOf(collection, target, fromIndex) > -1;
- } else if (typeof length == 'number') {
- result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
- } else {
- baseEach(collection, function(value) {
- if (++index >= fromIndex) {
- return !(result = value === target);
- }
- });
+ function curry(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
}
+ var result = createWrapper(func, CURRY_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curry.placeholder;
return result;
}
/**
- * Creates an object composed of keys generated from the results of running
- * each element of `collection` through the callback. The corresponding value
- * of each key is the number of times the key was returned by the callback.
- * The callback is bound to `thisArg` and invoked with three arguments;
- * (value, index|key, collection).
+ * This method is like `_.curry` except that arguments are applied to `func`
+ * in the manner of `_.partialRight` instead of `_.partial`.
*
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for provided arguments.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * **Note:** This method does not set the `length` property of curried functions.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the composed aggregate object.
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
* @example
*
- * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
- * // => { '4': 1, '6': 2 }
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
*
- * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
- * // => { '4': 1, '6': 2 }
+ * var curried = _.curryRight(abc);
*
- * _.countBy(['one', 'two', 'three'], 'length');
- * // => { '3': 2, '5': 1 }
+ * curried(3)(2)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(2, 3)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(3)(1, _)(2);
+ * // => [1, 2, 3]
*/
- var countBy = createAggregator(function(result, value, key) {
- (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
- });
+ function curryRight(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_RIGHT_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curryRight.placeholder;
+ return result;
+ }
/**
- * Checks if the given callback returns truey value for **all** elements of
- * a collection. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index|key, collection).
+ * Creates a function that delays invoking `func` until after `wait` milliseconds
+ * have elapsed since the last time it was invoked. The created function comes
+ * with a `cancel` method to cancel delayed invocations. Provide an options
+ * object to indicate that `func` should be invoked on the leading and/or
+ * trailing edge of the `wait` timeout. Subsequent calls to the debounced
+ * function return the result of the last `func` invocation.
*
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the debounced function is
+ * invoked more than once during the `wait` timeout.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.debounce` and `_.throttle`.
*
* @static
* @memberOf _
- * @alias all
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {boolean} Returns `true` if all elements passed the callback check,
- * else `false`.
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} wait The number of milliseconds to delay.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=false] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {number} [options.maxWait] The maximum time `func` is allowed to be
+ * delayed before it is invoked.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
* @example
*
- * _.every([true, 1, null, 'yes']);
- * // => false
+ * // avoid costly calculations while the window size is in flux
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
*
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
+ * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
+ * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
*
- * // using "_.pluck" callback shorthand
- * _.every(characters, 'age');
- * // => true
+ * // ensure `batchLog` is invoked once after 1 second of debounced calls
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', _.debounce(batchLog, 250, {
+ * 'maxWait': 1000
+ * }));
*
- * // using "_.where" callback shorthand
- * _.every(characters, { 'age': 36 });
- * // => false
+ * // cancel a debounced call
+ * var todoChanges = _.debounce(batchLog, 1000);
+ * Object.observe(models.todo, todoChanges);
+ *
+ * Object.observe(models, function(changes) {
+ * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
+ * todoChanges.cancel();
+ * }
+ * }, ['delete']);
+ *
+ * // ...at some point `models.todo` is changed
+ * models.todo.completed = true;
+ *
+ * // ...before 1 second has passed `models.todo` is deleted
+ * // which cancels the debounced `todoChanges` call
+ * delete models.todo;
*/
- function every(collection, callback, thisArg) {
- var result = true;
- callback = lodash.createCallback(callback, thisArg, 3);
+ function debounce(func, wait, options) {
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
- if (isArray(collection)) {
- var index = -1,
- length = collection.length;
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = wait < 0 ? 0 : wait;
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (isObject(options)) {
+ leading = options.leading;
+ maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
- while (++index < length) {
- if (!(result = !!callback(collection[index], index, collection))) {
- break;
+ function cancel() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ }
+
+ function delayed() {
+ var remaining = wait - (now() - stamp);
+ if (remaining <= 0 || remaining > wait) {
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ var isCalled = trailingCall;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
}
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
}
- } else {
- baseEach(collection, function(value, index, collection) {
- return (result = !!callback(value, index, collection));
- });
}
- return result;
+
+ function maxDelayed() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ }
+
+ function debounced() {
+ args = arguments;
+ stamp = now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0 || remaining > maxWait;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ return debounced;
+ }
+
+ /**
+ * Defers invoking the `func` until the current call stack has cleared. Any
+ * additional arguments are provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to defer.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.defer(function(text) { console.log(text); }, 'deferred');
+ * // logs 'deferred' after one or more milliseconds
+ */
+ function defer(func) {
+ return baseDelay(func, 1, arguments, 1);
+ }
+
+ /**
+ * Invokes `func` after `wait` milliseconds. Any additional arguments are
+ * provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.delay(function(text) { console.log(text); }, 1000, 'later');
+ * // => logs 'later' after one second
+ */
+ function delay(func, wait) {
+ return baseDelay(func, wait, arguments, 2);
}
/**
- * Iterates over elements of a collection, returning an array of all elements
- * the callback returns truey for. The callback is bound to `thisArg` and
- * invoked with three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Creates a function that returns the result of invoking the provided
+ * functions with the `this` binding of the created function, where each
+ * successive invocation is supplied the return value of the previous.
*
* @static
* @memberOf _
- * @alias select
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of elements that passed the callback check.
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
* @example
*
- * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
- * // => [2, 4, 6]
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true }
- * ];
+ * function add(x, y) {
+ * return x + y;
+ * }
*
- * // using "_.pluck" callback shorthand
- * _.filter(characters, 'blocked');
- * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
+ * function square(n) {
+ * return n * n;
+ * }
*
- * // using "_.where" callback shorthand
- * _.filter(characters, { 'age': 36 });
- * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
+ * var addSquare = _.flow(add, square);
+ * addSquare(1, 2);
+ * // => 9
*/
- function filter(collection, callback, thisArg) {
- var result = [];
- callback = lodash.createCallback(callback, thisArg, 3);
+ function flow() {
+ var funcs = arguments,
+ length = funcs.length;
- if (isArray(collection)) {
- var index = -1,
- length = collection.length;
+ if (!length) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = 0,
+ result = funcs[index].apply(this, arguments);
while (++index < length) {
- var value = collection[index];
- if (callback(value, index, collection)) {
- result.push(value);
- }
+ result = funcs[index].call(this, result);
}
- } else {
- baseEach(collection, function(value, index, collection) {
- if (callback(value, index, collection)) {
- result.push(value);
- }
- });
- }
- return result;
+ return result;
+ };
}
/**
- * Iterates over elements of a collection, returning the first element that
- * the callback returns truey for. The callback is bound to `thisArg` and
- * invoked with three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * This method is like `_.flow` except that it creates a function that
+ * invokes the provided functions from right to left.
*
* @static
* @memberOf _
- * @alias detect, findWhere
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the found element, else `undefined`.
+ * @alias backflow, compose
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
* @example
*
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true },
- * { 'name': 'pebbles', 'age': 1, 'blocked': false }
- * ];
- *
- * _.find(characters, function(chr) {
- * return chr.age < 40;
- * });
- * // => { 'name': 'barney', 'age': 36, 'blocked': false }
+ * function add(x, y) {
+ * return x + y;
+ * }
*
- * // using "_.where" callback shorthand
- * _.find(characters, { 'age': 1 });
- * // => { 'name': 'pebbles', 'age': 1, 'blocked': false }
+ * function square(n) {
+ * return n * n;
+ * }
*
- * // using "_.pluck" callback shorthand
- * _.find(characters, 'blocked');
- * // => { 'name': 'fred', 'age': 40, 'blocked': true }
+ * var addSquare = _.flowRight(square, add);
+ * addSquare(1, 2);
+ * // => 9
*/
- function find(collection, callback, thisArg) {
- callback = lodash.createCallback(callback, thisArg, 3);
+ function flowRight() {
+ var funcs = arguments,
+ fromIndex = funcs.length - 1;
- if (isArray(collection)) {
- var index = -1,
- length = collection.length;
+ if (fromIndex < 0) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = fromIndex,
+ result = funcs[index].apply(this, arguments);
- while (++index < length) {
- var value = collection[index];
- if (callback(value, index, collection)) {
- return value;
- }
+ while (index--) {
+ result = funcs[index].call(this, result);
}
- } else {
- var result;
- baseEach(collection, function(value, index, collection) {
- if (callback(value, index, collection)) {
- result = value;
- return false;
- }
- });
return result;
- }
+ };
}
/**
- * This method is like `_.find` except that it iterates over elements
- * of a `collection` from right to left.
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is coerced to a string and used as the
+ * cache key. The `func` is invoked with the `this` binding of the memoized
+ * function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the ES6 `Map` method interface
+ * of `get`, `has`, and `set`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object)
+ * for more details.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the found element, else `undefined`.
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoizing function.
* @example
*
- * _.findLast([1, 2, 3, 4], function(num) {
- * return num % 2 == 1;
+ * var upperCase = _.memoize(function(string) {
+ * return string.toUpperCase();
* });
- * // => 3
- */
- function findLast(collection, callback, thisArg) {
- var result;
- callback = lodash.createCallback(callback, thisArg, 3);
- forEachRight(collection, function(value, index, collection) {
- if (callback(value, index, collection)) {
- result = value;
- return false;
- }
- });
- return result;
- }
-
- /**
- * Iterates over elements of a collection, executing the callback for each
- * element. The callback is bound to `thisArg` and invoked with three arguments;
- * (value, index|key, collection). Callbacks may exit iteration early by
- * explicitly returning `false`.
*
- * Note: As with other "Collections" methods, objects with a `length` property
- * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
- * may be used for object iteration.
+ * upperCase('fred');
+ * // => 'FRED'
*
- * @static
- * @memberOf _
- * @alias each
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array|Object|string} Returns `collection`.
- * @example
+ * // modifying the result cache
+ * upperCase.cache.set('fred, 'BARNEY');
+ * upperCase('fred');
+ * // => 'BARNEY'
+ *
+ * // replacing `_.memoize.Cache`
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'barney' };
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'fred' }
*
- * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
- * // => logs each number and returns '1,2,3'
+ * _.memoize.Cache = WeakMap;
+ * var identity = _.memoize(_.identity);
*
- * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
- * // => logs each number and returns the object (property order is not guaranteed across environments)
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'barney' }
*/
- function forEach(collection, callback, thisArg) {
- if (callback && typeof thisArg == 'undefined' && isArray(collection)) {
- var index = -1,
- length = collection.length;
+ function memoize(func, resolver) {
+ if (!isFunction(func) || (resolver && !isFunction(resolver))) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var cache = memoized.cache,
+ key = resolver ? resolver.apply(this, arguments) : arguments[0];
- while (++index < length) {
- if (callback(collection[index], index, collection) === false) {
- break;
- }
+ if (cache.has(key)) {
+ return cache.get(key);
}
- } else {
- baseEach(collection, callback, thisArg);
- }
- return collection;
+ var result = func.apply(this, arguments);
+ cache.set(key, result);
+ return result;
+ };
+ memoized.cache = new memoize.Cache;
+ return memoized;
}
/**
- * This method is like `_.forEach` except that it iterates over elements
- * of a `collection` from right to left.
+ * Creates a function that negates the result of the predicate `func`. The
+ * `func` predicate is invoked with the `this` binding and arguments of the
+ * created function.
*
* @static
* @memberOf _
- * @alias eachRight
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array|Object|string} Returns `collection`.
+ * @category Function
+ * @param {Function} predicate The predicate to negate.
+ * @returns {Function} Returns the new function.
* @example
*
- * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
- * // => logs each number from right to left and returns '3,2,1'
+ * function isEven(n) {
+ * return n % 2 == 0;
+ * }
+ *
+ * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+ * // => [1, 3, 5]
*/
- function forEachRight(collection, callback, thisArg) {
- var iterable = collection,
- length = collection ? collection.length : 0;
-
- callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
- if (isArray(collection)) {
- while (length--) {
- if (callback(collection[length], length, collection) === false) {
- break;
- }
- }
- } else {
- if (typeof length != 'number') {
- var props = keys(collection);
- length = props.length;
- } else if (support.unindexedChars && isString(collection)) {
- iterable = collection.split('');
- }
- baseEach(collection, function(value, key, collection) {
- key = props ? props[--length] : --length;
- return callback(iterable[key], key, collection);
- });
+ function negate(predicate) {
+ if (!isFunction(predicate)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
}
- return collection;
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
}
/**
- * Creates an object composed of keys generated from the results of running
- * each element of a collection through the callback. The corresponding value
- * of each key is an array of the elements responsible for generating the key.
- * The callback is bound to `thisArg` and invoked with three arguments;
- * (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first call. The `func` is invoked
+ * with the `this` binding of the created function.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the composed aggregate object.
+ * @type Function
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
* @example
*
- * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
- * // => { '4': [4.2], '6': [6.1, 6.4] }
- *
- * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
- * // => { '4': [4.2], '6': [6.1, 6.4] }
- *
- * // using "_.pluck" callback shorthand
- * _.groupBy(['one', 'two', 'three'], 'length');
- * // => { '3': ['one', 'two'], '5': ['three'] }
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // `initialize` invokes `createApplication` once
*/
- var groupBy = createAggregator(function(result, value, key) {
- (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
- });
+ function once(func) {
+ return before(func, 2);
+ }
/**
- * Creates an object composed of keys generated from the results of running
- * each element of the collection through the given callback. The corresponding
- * value of each key is the last element responsible for generating the key.
- * The callback is bound to `thisArg` and invoked with three arguments;
- * (value, index|key, collection).
+ * Creates a function that invokes `func` with `partial` arguments prepended
+ * to those provided to the new function. This method is like `_.bind` except
+ * it does **not** alter the `this` binding.
*
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns the composed aggregate object.
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
* @example
*
- * var keys = [
- * { 'dir': 'left', 'code': 97 },
- * { 'dir': 'right', 'code': 100 }
- * ];
- *
- * _.indexBy(keys, 'dir');
- * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
- *
- * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
- * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
- *
- * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
- * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
- */
- var indexBy = createAggregator(function(result, value, key) {
- result[key] = value;
- });
-
- /**
- * Invokes the method named by `methodName` on each element in the `collection`
- * returning an array of the results of each invoked method. Additional arguments
- * will be provided to each invoked method. If `methodName` is a function it
- * will be invoked for, and `this` bound to, each element in the `collection`.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|string} methodName The name of the method to invoke or
- * the function invoked per iteration.
- * @param {...*} [arg] Arguments to invoke the method with.
- * @returns {Array} Returns a new array of the results of each invoked method.
- * @example
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
*
- * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
- * // => [[1, 5, 7], [1, 2, 3]]
+ * var sayHelloTo = _.partial(greet, 'hello');
+ * sayHelloTo('fred');
+ * // => 'hello fred'
*
- * _.invoke([123, 456], String.prototype.split, '');
- * // => [['1', '2', '3'], ['4', '5', '6']]
+ * // using placeholders
+ * var greetFred = _.partial(greet, _, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
*/
- function invoke(collection, methodName) {
- var args = slice(arguments, 2),
- index = -1,
- isFunc = typeof methodName == 'function',
- length = collection ? collection.length : 0,
- result = Array(typeof length == 'number' ? length : 0);
+ function partial(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partial.placeholder);
- forEach(collection, function(value) {
- result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
- });
- return result;
+ return createWrapper(func, PARTIAL_FLAG, null, partials, holders);
}
/**
- * Creates an array of values by running each element in the collection
- * through the callback. The callback is bound to `thisArg` and invoked with
- * three arguments; (value, index|key, collection).
+ * This method is like `_.partial` except that partially applied arguments
+ * are appended to those provided to the new function.
*
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
*
* @static
* @memberOf _
- * @alias collect
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of the results of each `callback` execution.
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
* @example
*
- * _.map([1, 2, 3], function(num) { return num * 3; });
- * // => [3, 6, 9]
- *
- * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
- * // => [3, 6, 9] (property order is not guaranteed across environments)
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
*
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
+ * var greetFred = _.partialRight(greet, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
*
- * // using "_.pluck" callback shorthand
- * _.map(characters, 'name');
- * // => ['barney', 'fred']
+ * // using placeholders
+ * var sayHelloTo = _.partialRight(greet, 'hello', _);
+ * sayHelloTo('fred');
+ * // => 'hello fred'
*/
- function map(collection, callback, thisArg) {
- var index = -1,
- length = collection ? collection.length : 0,
- result = Array(typeof length == 'number' ? length : 0);
+ function partialRight(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partialRight.placeholder);
- callback = lodash.createCallback(callback, thisArg, 3);
- if (isArray(collection)) {
- while (++index < length) {
- result[index] = callback(collection[index], index, collection);
- }
- } else {
- baseEach(collection, function(value, key, collection) {
- result[++index] = callback(value, key, collection);
- });
- }
- return result;
+ return createWrapper(func, PARTIAL_RIGHT_FLAG, null, partials, holders);
}
/**
- * Retrieves the maximum value of a collection. If the collection is empty or
- * falsey `-Infinity` is returned. If a callback is provided it will be executed
- * for each value in the collection to generate the criterion by which the value
- * is ranked. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Creates a function that invokes `func` with arguments arranged according
+ * to the specified indexes where the argument value at the first index is
+ * provided as the first argument, the argument value at the second index is
+ * provided as the second argument, and so on.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the maximum value.
+ * @category Function
+ * @param {Function} func The function to rearrange arguments for.
+ * @param {...(number|number[])} indexes The arranged argument indexes,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Function} Returns the new function.
* @example
*
- * _.max([4, 2, 8, 6]);
- * // => 8
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
+ * var rearged = _.rearg(function(a, b, c) {
+ * return [a, b, c];
+ * }, 2, 0, 1);
*
- * _.max(characters, function(chr) { return chr.age; });
- * // => { 'name': 'fred', 'age': 40 };
+ * rearged('b', 'c', 'a')
+ * // => ['a', 'b', 'c']
*
- * // using "_.pluck" callback shorthand
- * _.max(characters, 'age');
- * // => { 'name': 'fred', 'age': 40 };
+ * var map = _.rearg(_.map, [1, 0]);
+ * map(function(n) { return n * 3; }, [1, 2, 3]);
+ * // => [3, 6, 9]
*/
- function max(collection, callback, thisArg) {
- var computed = -Infinity,
- result = computed;
-
- // allows working with functions like `_.map` without using
- // their `index` argument as a callback
- if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
- callback = null;
- }
- if (callback == null && isArray(collection)) {
- var index = -1,
- length = collection.length;
-
- while (++index < length) {
- var value = collection[index];
- if (value > result) {
- result = value;
- }
- }
- } else {
- callback = (callback == null && isString(collection))
- ? charAtCallback
- : lodash.createCallback(callback, thisArg, 3);
-
- baseEach(collection, function(value, index, collection) {
- var current = callback(value, index, collection);
- if (current > computed) {
- computed = current;
- result = value;
- }
- });
- }
- return result;
+ function rearg(func) {
+ var indexes = baseFlatten(arguments, false, false, 1);
+ return createWrapper(func, REARG_FLAG, null, null, null, indexes);
}
/**
- * Retrieves the minimum value of a collection. If the collection is empty or
- * falsey `Infinity` is returned. If a callback is provided it will be executed
- * for each value in the collection to generate the criterion by which the value
- * is ranked. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index, collection).
+ * Creates a function that only invokes `func` at most once per every `wait`
+ * milliseconds. The created function comes with a `cancel` method to cancel
+ * delayed invocations. Provide an options object to indicate that `func`
+ * should be invoked on the leading and/or trailing edge of the `wait` timeout.
+ * Subsequent calls to the throttled function return the result of the last
+ * `func` call.
*
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the throttled function is
+ * invoked more than once during the `wait` timeout.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.throttle` and `_.debounce`.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the minimum value.
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} wait The number of milliseconds to throttle invocations to.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=true] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
* @example
*
- * _.min([4, 2, 8, 6]);
- * // => 2
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
+ * // avoid excessively updating the position while scrolling
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
*
- * _.min(characters, function(chr) { return chr.age; });
- * // => { 'name': 'barney', 'age': 36 };
+ * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false })
+ * jQuery('.interactive').on('click', throttled);
*
- * // using "_.pluck" callback shorthand
- * _.min(characters, 'age');
- * // => { 'name': 'barney', 'age': 36 };
+ * // cancel a trailing throttled call
+ * jQuery(window).on('popstate', throttled.cancel);
*/
- function min(collection, callback, thisArg) {
- var computed = Infinity,
- result = computed;
+ function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
- // allows working with functions like `_.map` without using
- // their `index` argument as a callback
- if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
- callback = null;
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
}
- if (callback == null && isArray(collection)) {
- var index = -1,
- length = collection.length;
-
- while (++index < length) {
- var value = collection[index];
- if (value < result) {
- result = value;
- }
- }
- } else {
- callback = (callback == null && isString(collection))
- ? charAtCallback
- : lodash.createCallback(callback, thisArg, 3);
-
- baseEach(collection, function(value, index, collection) {
- var current = callback(value, index, collection);
- if (current < computed) {
- computed = current;
- result = value;
- }
- });
+ if (options === false) {
+ leading = false;
+ } else if (isObject(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
}
- return result;
+ debounceOptions.leading = leading;
+ debounceOptions.maxWait = +wait;
+ debounceOptions.trailing = trailing;
+ return debounce(func, wait, debounceOptions);
}
/**
- * Retrieves the value of a specified property from all elements in the collection.
+ * Creates a function that provides `value` to the wrapper function as its
+ * first argument. Any additional arguments provided to the function are
+ * appended to those provided to the wrapper function. The wrapper is invoked
+ * with the `this` binding of the created function.
*
* @static
* @memberOf _
- * @type Function
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {string} property The name of the property to pluck.
- * @returns {Array} Returns a new array of property values.
+ * @category Function
+ * @param {*} value The value to wrap.
+ * @param {Function} wrapper The wrapper function.
+ * @returns {Function} Returns the new function.
* @example
*
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
+ * var p = _.wrap(_.escape, function(func, text) {
+ * return '<p>' + func(text) + '</p>';
+ * });
*
- * _.pluck(characters, 'name');
- * // => ['barney', 'fred']
+ * p('fred, barney, & pebbles');
+ * // => '<p>fred, barney, & pebbles</p>'
*/
- var pluck = map;
+ function wrap(value, wrapper) {
+ wrapper = wrapper == null ? identity : wrapper;
+ return createWrapper(wrapper, PARTIAL_FLAG, null, [value], []);
+ }
+
+ /*------------------------------------------------------------------------*/
/**
- * Reduces a collection to a value which is the accumulated result of running
- * each element in the collection through the callback, where each successive
- * callback execution consumes the return value of the previous execution. If
- * `accumulator` is not provided the first element of the collection will be
- * used as the initial `accumulator` value. The callback is bound to `thisArg`
- * and invoked with four arguments; (accumulator, value, index|key, collection).
+ * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
+ * otherwise they are assigned by reference. If `customizer` is provided it is
+ * invoked to produce the cloned values. If `customizer` returns `undefined`
+ * cloning is handled by the method instead. The `customizer` is bound to
+ * `thisArg` and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
*
* @static
* @memberOf _
- * @alias foldl, inject
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [accumulator] Initial value of the accumulator.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the accumulated value.
+ * @category Lang
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the cloned value.
* @example
*
- * var sum = _.reduce([1, 2, 3], function(sum, num) {
- * return sum + num;
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var shallow = _.clone(users);
+ * shallow[0] === users[0];
+ * // => true
+ *
+ * var deep = _.clone(users, true);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var body = _.clone(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(false) : undefined;
* });
- * // => 6
*
- * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
- * result[key] = num * 3;
- * return result;
- * }, {});
- * // => { 'a': 3, 'b': 6, 'c': 9 }
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 0
*/
- function reduce(collection, callback, accumulator, thisArg) {
- var noaccum = arguments.length < 3;
- callback = lodash.createCallback(callback, thisArg, 4);
-
- if (isArray(collection)) {
- var index = -1,
- length = collection.length;
-
- if (noaccum) {
- accumulator = collection[++index];
- }
- while (++index < length) {
- accumulator = callback(accumulator, collection[index], index, collection);
- }
- } else {
- baseEach(collection, function(value, index, collection) {
- accumulator = noaccum
- ? (noaccum = false, value)
- : callback(accumulator, value, index, collection)
- });
+ function clone(value, isDeep, customizer, thisArg) {
+ // Juggle arguments.
+ if (typeof isDeep != 'boolean' && isDeep != null) {
+ thisArg = customizer;
+ customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep;
+ isDeep = false;
}
- return accumulator;
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, isDeep, customizer);
}
/**
- * This method is like `_.reduce` except that it iterates over elements
- * of a `collection` from right to left.
+ * Creates a deep clone of `value`. If `customizer` is provided it is invoked
+ * to produce the cloned values. If `customizer` returns `undefined` cloning
+ * is handled by the method instead. The `customizer` is bound to `thisArg`
+ * and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
*
* @static
* @memberOf _
- * @alias foldr
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function} [callback=identity] The function called per iteration.
- * @param {*} [accumulator] Initial value of the accumulator.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the accumulated value.
+ * @category Lang
+ * @param {*} value The value to deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the deep cloned value.
* @example
*
- * var list = [[0, 1], [2, 3], [4, 5]];
- * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
- * // => [4, 5, 2, 3, 0, 1]
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var deep = _.cloneDeep(users);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var el = _.cloneDeep(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(true) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 20
*/
- function reduceRight(collection, callback, accumulator, thisArg) {
- var noaccum = arguments.length < 3;
- callback = lodash.createCallback(callback, thisArg, 4);
- forEachRight(collection, function(value, index, collection) {
- accumulator = noaccum
- ? (noaccum = false, value)
- : callback(accumulator, value, index, collection);
- });
- return accumulator;
+ function cloneDeep(value, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, true, customizer);
}
/**
- * The opposite of `_.filter` this method returns the elements of a
- * collection that the callback does **not** return truey for.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Checks if `value` is classified as an `arguments` object.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of elements that failed the callback check.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
- * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
- * // => [1, 3, 5]
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.reject(characters, 'blocked');
- * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
+ * (function() { return _.isArguments(arguments); })();
+ * // => true
*
- * // using "_.where" callback shorthand
- * _.reject(characters, { 'age': 36 });
- * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
+ * _.isArguments([1, 2, 3]);
+ * // => false
*/
- function reject(collection, callback, thisArg) {
- callback = lodash.createCallback(callback, thisArg, 3);
- return filter(collection, function(value, index, collection) {
- return !callback(value, index, collection);
- });
+ function isArguments(value) {
+ var length = isObjectLike(value) ? value.length : undefined;
+ return (isLength(length) && objToString.call(value) == argsTag) || false;
}
/**
- * Retrieves a random element or `n` random elements from a collection.
+ * Checks if `value` is classified as an `Array` object.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to sample.
- * @param {number} [n] The number of elements to sample.
- * @param- {Object} [guard] Allows working with functions like `_.map`
- * without using their `index` arguments as `n`.
- * @returns {Array} Returns the random sample(s) of `collection`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
- * _.sample([1, 2, 3, 4]);
- * // => 2
+ * _.isArray([1, 2, 3]);
+ * // => true
*
- * _.sample([1, 2, 3, 4], 2);
- * // => [3, 1]
+ * (function() { return _.isArray(arguments); })();
+ * // => false
*/
- function sample(collection, n, guard) {
- if (collection && typeof collection.length != 'number') {
- collection = values(collection);
- } else if (support.unindexedChars && isString(collection)) {
- collection = collection.split('');
- }
- if (n == null || guard) {
- return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
- }
- var result = shuffle(collection);
- result.length = nativeMin(nativeMax(0, n), result.length);
- return result;
- }
+ var isArray = nativeIsArray || function(value) {
+ return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false;
+ };
/**
- * Creates an array of shuffled values, using a version of the Fisher-Yates
- * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
+ * Checks if `value` is classified as a boolean primitive or object.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to shuffle.
- * @returns {Array} Returns a new shuffled collection.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
- * _.shuffle([1, 2, 3, 4, 5, 6]);
- * // => [4, 1, 6, 3, 5, 2]
+ * _.isBoolean(false);
+ * // => true
+ *
+ * _.isBoolean(null);
+ * // => false
*/
- function shuffle(collection) {
- var index = -1,
- length = collection ? collection.length : 0,
- result = Array(typeof length == 'number' ? length : 0);
-
- forEach(collection, function(value) {
- var rand = baseRandom(0, ++index);
- result[index] = result[rand];
- result[rand] = value;
- });
- return result;
+ function isBoolean(value) {
+ return (value === true || value === false || isObjectLike(value) && objToString.call(value) == boolTag) || false;
}
/**
- * Gets the size of the `collection` by returning `collection.length` for arrays
- * and array-like objects or the number of own enumerable properties for objects.
+ * Checks if `value` is classified as a `Date` object.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to inspect.
- * @returns {number} Returns `collection.length` or number of own enumerable properties.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
- * _.size([1, 2]);
- * // => 2
- *
- * _.size({ 'one': 1, 'two': 2, 'three': 3 });
- * // => 3
+ * _.isDate(new Date);
+ * // => true
*
- * _.size('pebbles');
- * // => 7
+ * _.isDate('Mon April 23 2012');
+ * // => false
*/
- function size(collection) {
- var length = collection ? collection.length : 0;
- return typeof length == 'number' ? length : keys(collection).length;
+ function isDate(value) {
+ return (isObjectLike(value) && objToString.call(value) == dateTag) || false;
}
/**
- * Checks if the callback returns a truey value for **any** element of a
- * collection. The function returns as soon as it finds a passing value and
- * does not iterate over the entire collection. The callback is bound to
- * `thisArg` and invoked with three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Checks if `value` is a DOM element.
*
* @static
* @memberOf _
- * @alias any
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {boolean} Returns `true` if any element passed the callback check,
- * else `false`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
* @example
*
- * _.some([null, 0, 'yes', false], Boolean);
- * // => true
- *
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.some(characters, 'blocked');
+ * _.isElement(document.body);
* // => true
*
- * // using "_.where" callback shorthand
- * _.some(characters, { 'age': 1 });
+ * _.isElement('<body>');
* // => false
*/
- function some(collection, callback, thisArg) {
- var result;
- callback = lodash.createCallback(callback, thisArg, 3);
-
- if (isArray(collection)) {
- var index = -1,
- length = collection.length;
-
- while (++index < length) {
- if ((result = callback(collection[index], index, collection))) {
- break;
- }
- }
- } else {
- baseEach(collection, function(value, index, collection) {
- return !(result = callback(value, index, collection));
- });
- }
- return !!result;
+ function isElement(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) &&
+ objToString.call(value).indexOf('Element') > -1) || false;
+ }
+ // Fallback for environments without DOM support.
+ if (!support.dom) {
+ isElement = function(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value)) || false;
+ };
}
/**
- * Creates an array of elements, sorted in ascending order by the results of
- * running each element in a collection through the callback. This method
- * performs a stable sort, that is, it will preserve the original sort order
- * of equal elements. The callback is bound to `thisArg` and invoked with
- * three arguments; (value, index|key, collection).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an array of property names is provided for `callback` the collection
- * will be sorted by each property value.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Checks if a value is empty. A value is considered empty unless it is an
+ * `arguments` object, array, string, or jQuery-like collection with a length
+ * greater than `0` or an object with own enumerable properties.
*
* @static
* @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Array|Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of sorted elements.
+ * @category Lang
+ * @param {Array|Object|string} value The value to inspect.
+ * @returns {boolean} Returns `true` if `value` is empty, else `false`.
* @example
*
- * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
- * // => [3, 1, 2]
+ * _.isEmpty(null);
+ * // => true
*
- * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
- * // => [3, 1, 2]
+ * _.isEmpty(true);
+ * // => true
*
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 },
- * { 'name': 'barney', 'age': 26 },
- * { 'name': 'fred', 'age': 30 }
- * ];
+ * _.isEmpty(1);
+ * // => true
*
- * // using "_.pluck" callback shorthand
- * _.map(_.sortBy(characters, 'age'), _.values);
- * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
+ * _.isEmpty([1, 2, 3]);
+ * // => false
*
- * // sorting by multiple properties
- * _.map(_.sortBy(characters, ['name', 'age']), _.values);
- * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
+ * _.isEmpty({ 'a': 1 });
+ * // => false
*/
- function sortBy(collection, callback, thisArg) {
- var index = -1,
- isArr = isArray(callback),
- length = collection ? collection.length : 0,
- result = Array(typeof length == 'number' ? length : 0);
-
- if (!isArr) {
- callback = lodash.createCallback(callback, thisArg, 3);
+ function isEmpty(value) {
+ if (value == null) {
+ return true;
}
- forEach(collection, function(value, key, collection) {
- var object = result[++index] = getObject();
- if (isArr) {
- object.criteria = map(callback, function(key) { return value[key]; });
- } else {
- (object.criteria = getArray())[0] = callback(value, key, collection);
- }
- object.index = index;
- object.value = value;
- });
-
- length = result.length;
- result.sort(compareAscending);
- while (length--) {
- var object = result[length];
- result[length] = object.value;
- if (!isArr) {
- releaseArray(object.criteria);
- }
- releaseObject(object);
+ var length = value.length;
+ if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) ||
+ (isObjectLike(value) && isFunction(value.splice)))) {
+ return !length;
}
- return result;
+ return !keys(value).length;
}
/**
- * Converts the `collection` to an array.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to convert.
- * @returns {Array} Returns the new converted array.
- * @example
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent. If `customizer` is provided it is invoked to compare values.
+ * If `customizer` returns `undefined` comparisons are handled by the method
+ * instead. The `customizer` is bound to `thisArg` and invoked with three
+ * arguments; (value, other [, index|key]).
*
- * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
- * // => [2, 3, 4]
- */
- function toArray(collection) {
- if (collection && typeof collection.length == 'number') {
- return (support.unindexedChars && isString(collection))
- ? collection.split('')
- : slice(collection);
- }
- return values(collection);
- }
-
- /**
- * Performs a deep comparison of each element in a `collection` to the given
- * `properties` object, returning an array of all elements that have equivalent
- * property values.
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Functions and DOM nodes
+ * are **not** supported. Provide a customizer function to extend support
+ * for comparing other values.
*
* @static
* @memberOf _
- * @type Function
- * @category Collections
- * @param {Array|Object|string} collection The collection to iterate over.
- * @param {Object} props The object of property values to filter by.
- * @returns {Array} Returns a new array of elements that have the given properties.
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
* @example
*
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
- * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
- * ];
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'fred' };
*
- * _.where(characters, { 'age': 36 });
- * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
+ * object == other;
+ * // => false
*
- * _.where(characters, { 'pets': ['dino'] });
- * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
- */
- var where = filter;
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Creates an array with all falsey values removed. The values `false`, `null`,
- * `0`, `""`, `undefined`, and `NaN` are all falsey.
+ * _.isEqual(object, other);
+ * // => true
*
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to compact.
- * @returns {Array} Returns a new array of filtered values.
- * @example
+ * // using a customizer callback
+ * var array = ['hello', 'goodbye'];
+ * var other = ['hi', 'goodbye'];
*
- * _.compact([0, 1, false, 2, '', 3]);
- * // => [1, 2, 3]
+ * _.isEqual(array, other, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
*/
- function compact(array) {
- var index = -1,
- length = array ? array.length : 0,
- result = [];
-
- while (++index < length) {
- var value = array[index];
- if (value) {
- result.push(value);
- }
+ function isEqual(value, other, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && isStrictComparable(value) && isStrictComparable(other)) {
+ return value === other;
}
- return result;
+ var result = customizer ? customizer(value, other) : undefined;
+ return typeof result == 'undefined' ? baseIsEqual(value, other, customizer) : !!result;
}
/**
- * Creates an array excluding all values of the provided arrays using strict
- * equality for comparisons, i.e. `===`.
+ * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+ * `SyntaxError`, `TypeError`, or `URIError` object.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to process.
- * @param {...Array} [values] The arrays of values to exclude.
- * @returns {Array} Returns a new array of filtered values.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
* @example
*
- * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
- * // => [1, 3, 4]
+ * _.isError(new Error);
+ * // => true
+ *
+ * _.isError(Error);
+ * // => false
*/
- function difference(array) {
- return baseDifference(array, baseFlatten(arguments, true, true, 1));
+ function isError(value) {
+ return (isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag) || false;
}
/**
- * This method is like `_.find` except that it returns the index of the first
- * element that passes the callback check, instead of the element itself.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * Checks if `value` is a finite primitive number.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * **Note:** This method is based on ES6 `Number.isFinite`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite)
+ * for more details.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to search.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {number} Returns the index of the found element, else `-1`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
* @example
*
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': false },
- * { 'name': 'fred', 'age': 40, 'blocked': true },
- * { 'name': 'pebbles', 'age': 1, 'blocked': false }
- * ];
+ * _.isFinite(10);
+ * // => true
*
- * _.findIndex(characters, function(chr) {
- * return chr.age < 20;
- * });
- * // => 2
+ * _.isFinite('10');
+ * // => false
+ *
+ * _.isFinite(true);
+ * // => false
+ *
+ * _.isFinite(Object(10));
+ * // => false
+ *
+ * _.isFinite(Infinity);
+ * // => false
+ */
+ var isFinite = nativeNumIsFinite || function(value) {
+ return typeof value == 'number' && nativeIsFinite(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
*
- * // using "_.where" callback shorthand
- * _.findIndex(characters, { 'age': 36 });
- * // => 0
+ * _.isFunction(_);
+ * // => true
*
- * // using "_.pluck" callback shorthand
- * _.findIndex(characters, 'blocked');
- * // => 1
+ * _.isFunction(/abc/);
+ * // => false
*/
- function findIndex(array, callback, thisArg) {
- var index = -1,
- length = array ? array.length : 0;
-
- callback = lodash.createCallback(callback, thisArg, 3);
- while (++index < length) {
- if (callback(array[index], index, array)) {
- return index;
- }
- }
- return -1;
+ function isFunction(value) {
+ // Avoid a Chakra JIT bug in compatibility modes of IE 11.
+ // See https://github.com/jashkenas/underscore/issues/1621.
+ return typeof value == 'function' || false;
+ }
+ // Fallback for environments that return incorrect `typeof` operator results.
+ if (isFunction(/x/) || (Uint8Array && !isFunction(Uint8Array))) {
+ isFunction = function(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in older versions of Chrome and Safari which return 'function' for regexes
+ // and Safari 8 equivalents which return 'object' for typed array constructors.
+ return objToString.call(value) == funcTag;
+ };
}
/**
- * This method is like `_.findIndex` except that it iterates over elements
- * of a `collection` from right to left.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * Checks if `value` is the language type of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * **Note:** See the [ES5 spec](http://es5.github.io/#x8) for more details.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to search.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {number} Returns the index of the found element, else `-1`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
- * var characters = [
- * { 'name': 'barney', 'age': 36, 'blocked': true },
- * { 'name': 'fred', 'age': 40, 'blocked': false },
- * { 'name': 'pebbles', 'age': 1, 'blocked': true }
- * ];
- *
- * _.findLastIndex(characters, function(chr) {
- * return chr.age > 30;
- * });
- * // => 1
+ * _.isObject({});
+ * // => true
*
- * // using "_.where" callback shorthand
- * _.findLastIndex(characters, { 'age': 36 });
- * // => 0
+ * _.isObject([1, 2, 3]);
+ * // => true
*
- * // using "_.pluck" callback shorthand
- * _.findLastIndex(characters, 'blocked');
- * // => 2
+ * _.isObject(1);
+ * // => false
*/
- function findLastIndex(array, callback, thisArg) {
- var length = array ? array.length : 0;
- callback = lodash.createCallback(callback, thisArg, 3);
- while (length--) {
- if (callback(array[length], length, array)) {
- return length;
- }
- }
- return -1;
+ function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291.
+ var type = typeof value;
+ return type == 'function' || (value && type == 'object') || false;
}
/**
- * Gets the first element or first `n` elements of an array. If a callback
- * is provided elements at the beginning of the array are returned as long
- * as the callback returns truey. The callback is bound to `thisArg` and
- * invoked with three arguments; (value, index, array).
+ * Performs a deep comparison between `object` and `source` to determine if
+ * `object` contains equivalent property values. If `customizer` is provided
+ * it is invoked to compare values. If `customizer` returns `undefined`
+ * comparisons are handled by the method instead. The `customizer` is bound
+ * to `thisArg` and invoked with three arguments; (value, other, index|key).
*
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * **Note:** This method supports comparing properties of arrays, booleans,
+ * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions
+ * and DOM nodes are **not** supported. Provide a customizer function to extend
+ * support for comparing other values.
*
* @static
* @memberOf _
- * @alias head, take
- * @category Arrays
- * @param {Array} array The array to query.
- * @param {Function|Object|number|string} [callback] The function called
- * per element or the number of elements to return. If a property name or
- * object is provided it will be used to create a "_.pluck" or "_.where"
- * style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the first element(s) of `array`.
+ * @category Lang
+ * @param {Object} source The object to inspect.
+ * @param {Object} source The object of property values to match.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
* @example
*
- * _.first([1, 2, 3]);
- * // => 1
- *
- * _.first([1, 2, 3], 2);
- * // => [1, 2]
+ * var object = { 'user': 'fred', 'age': 40 };
*
- * _.first([1, 2, 3], function(num) {
- * return num < 3;
- * });
- * // => [1, 2]
+ * _.isMatch(object, { 'age': 40 });
+ * // => true
*
- * var characters = [
- * { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
- * { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
- * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
- * ];
+ * _.isMatch(object, { 'age': 36 });
+ * // => false
*
- * // using "_.pluck" callback shorthand
- * _.first(characters, 'blocked');
- * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
+ * // using a customizer callback
+ * var object = { 'greeting': 'hello' };
+ * var source = { 'greeting': 'hi' };
*
- * // using "_.where" callback shorthand
- * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
- * // => ['barney', 'fred']
+ * _.isMatch(object, source, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
*/
- function first(array, callback, thisArg) {
- var n = 0,
- length = array ? array.length : 0;
+ function isMatch(object, source, customizer, thisArg) {
+ var props = keys(source),
+ length = props.length;
- if (typeof callback != 'number' && callback != null) {
- var index = -1;
- callback = lodash.createCallback(callback, thisArg, 3);
- while (++index < length && callback(array[index], index, array)) {
- n++;
- }
- } else {
- n = callback;
- if (n == null || thisArg) {
- return array ? array[0] : undefined;
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
}
}
- return slice(array, 0, nativeMin(nativeMax(0, n), length));
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = values[length] = source[props[length]];
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return baseIsMatch(object, props, values, strictCompareFlags, customizer);
}
/**
- * Flattens a nested array (the nesting can be to any depth). If `isShallow`
- * is truey, the array will only be flattened a single level. If a callback
- * is provided each element of the array is passed through the callback before
- * flattening. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * Checks if `value` is `NaN`.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * **Note:** This method is not the same as native `isNaN` which returns `true`
+ * for `undefined` and other non-numeric values. See the [ES5 spec](http://es5.github.io/#x15.1.2.4)
+ * for more details.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to flatten.
- * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new flattened array.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
* @example
*
- * _.flatten([1, [2], [3, [[4]]]]);
- * // => [1, 2, 3, 4];
+ * _.isNaN(NaN);
+ * // => true
*
- * _.flatten([1, [2], [3, [[4]]]], true);
- * // => [1, 2, 3, [[4]]];
+ * _.isNaN(new Number(NaN));
+ * // => true
*
- * var characters = [
- * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
- * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
- * ];
+ * isNaN(undefined);
+ * // => true
*
- * // using "_.pluck" callback shorthand
- * _.flatten(characters, 'pets');
- * // => ['hoppy', 'baby puss', 'dino']
+ * _.isNaN(undefined);
+ * // => false
*/
- function flatten(array, isShallow, callback, thisArg) {
- // juggle arguments
- if (typeof isShallow != 'boolean' && isShallow != null) {
- thisArg = callback;
- callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
- isShallow = false;
- }
- if (callback != null) {
- array = map(array, callback, thisArg);
- }
- return baseFlatten(array, isShallow);
+ function isNaN(value) {
+ // An `NaN` primitive is the only value that is not equal to itself.
+ // Perform the `toStringTag` check first to avoid errors with some host objects in IE.
+ return isNumber(value) && value != +value;
}
/**
- * Gets the index at which the first occurrence of `value` is found using
- * strict equality for comparisons, i.e. `===`. If the array is already sorted
- * providing `true` for `fromIndex` will run a faster binary search.
+ * Checks if `value` is a native function.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to search.
- * @param {*} value The value to search for.
- * @param {boolean|number} [fromIndex=0] The index to search from or `true`
- * to perform a binary search on a sorted array.
- * @returns {number} Returns the index of the matched value or `-1`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
* @example
*
- * _.indexOf([1, 2, 3, 1, 2, 3], 2);
- * // => 1
- *
- * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
- * // => 4
+ * _.isNative(Array.prototype.push);
+ * // => true
*
- * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
- * // => 2
+ * _.isNative(_);
+ * // => false
*/
- function indexOf(array, value, fromIndex) {
- if (typeof fromIndex == 'number') {
- var length = array ? array.length : 0;
- fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
- } else if (fromIndex) {
- var index = sortedIndex(array, value);
- return array[index] === value ? index : -1;
+ function isNative(value) {
+ if (value == null) {
+ return false;
}
- return baseIndexOf(array, value, fromIndex);
+ if (objToString.call(value) == funcTag) {
+ return reNative.test(fnToString.call(value));
+ }
+ return (isObjectLike(value) && reHostCtor.test(value)) || false;
}
/**
- * Gets all but the last element or last `n` elements of an array. If a
- * callback is provided elements at the end of the array are excluded from
- * the result as long as the callback returns truey. The callback is bound
- * to `thisArg` and invoked with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Checks if `value` is `null`.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to query.
- * @param {Function|Object|number|string} [callback=1] The function called
- * per element or the number of elements to exclude. If a property name or
- * object is provided it will be used to create a "_.pluck" or "_.where"
- * style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a slice of `array`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
* @example
*
- * _.initial([1, 2, 3]);
- * // => [1, 2]
- *
- * _.initial([1, 2, 3], 2);
- * // => [1]
- *
- * _.initial([1, 2, 3], function(num) {
- * return num > 1;
- * });
- * // => [1]
- *
- * var characters = [
- * { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
- * { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
- * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.initial(characters, 'blocked');
- * // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }]
+ * _.isNull(null);
+ * // => true
*
- * // using "_.where" callback shorthand
- * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
- * // => ['barney', 'fred']
+ * _.isNull(void 0);
+ * // => false
*/
- function initial(array, callback, thisArg) {
- var n = 0,
- length = array ? array.length : 0;
-
- if (typeof callback != 'number' && callback != null) {
- var index = length;
- callback = lodash.createCallback(callback, thisArg, 3);
- while (index-- && callback(array[index], index, array)) {
- n++;
- }
- } else {
- n = (callback == null || thisArg) ? 1 : callback || n;
- }
- return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
+ function isNull(value) {
+ return value === null;
}
/**
- * Creates an array of unique values present in all provided arrays using
- * strict equality for comparisons, i.e. `===`.
+ * Checks if `value` is classified as a `Number` primitive or object.
+ *
+ * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified
+ * as numbers, use the `_.isFinite` method.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {...Array} [array] The arrays to inspect.
- * @returns {Array} Returns an array of shared values.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
- * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
- * // => [1, 2]
+ * _.isNumber(8.4);
+ * // => true
+ *
+ * _.isNumber(NaN);
+ * // => true
+ *
+ * _.isNumber('8.4');
+ * // => false
*/
- function intersection() {
- var args = [],
- argsIndex = -1,
- argsLength = arguments.length,
- caches = getArray(),
- indexOf = getIndexOf(),
- trustIndexOf = indexOf === baseIndexOf,
- seen = getArray();
-
- while (++argsIndex < argsLength) {
- var value = arguments[argsIndex];
- if (isArray(value) || isArguments(value)) {
- args.push(value);
- caches.push(trustIndexOf && value.length >= largeArraySize &&
- createCache(argsIndex ? args[argsIndex] : seen));
- }
- }
- var array = args[0],
- index = -1,
- length = array ? array.length : 0,
- result = [];
-
- outer:
- while (++index < length) {
- var cache = caches[0];
- value = array[index];
-
- if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
- argsIndex = argsLength;
- (cache || seen).push(value);
- while (--argsIndex) {
- cache = caches[argsIndex];
- if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
- continue outer;
- }
- }
- result.push(value);
- }
- }
- while (argsLength--) {
- cache = caches[argsLength];
- if (cache) {
- releaseObject(cache);
- }
- }
- releaseArray(caches);
- releaseArray(seen);
- return result;
+ function isNumber(value) {
+ return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag) || false;
}
/**
- * Gets the last element or last `n` elements of an array. If a callback is
- * provided elements at the end of the array are returned as long as the
- * callback returns truey. The callback is bound to `thisArg` and invoked
- * with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * **Note:** This method assumes objects created by the `Object` constructor
+ * have no inherited enumerable properties.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to query.
- * @param {Function|Object|number|string} [callback] The function called
- * per element or the number of elements to return. If a property name or
- * object is provided it will be used to create a "_.pluck" or "_.where"
- * style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {*} Returns the last element(s) of `array`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
* @example
*
- * _.last([1, 2, 3]);
- * // => 3
- *
- * _.last([1, 2, 3], 2);
- * // => [2, 3]
+ * function Foo() {
+ * this.a = 1;
+ * }
*
- * _.last([1, 2, 3], function(num) {
- * return num > 1;
- * });
- * // => [2, 3]
+ * _.isPlainObject(new Foo);
+ * // => false
*
- * var characters = [
- * { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
- * { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
- * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
- * ];
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
*
- * // using "_.pluck" callback shorthand
- * _.pluck(_.last(characters, 'blocked'), 'name');
- * // => ['fred', 'pebbles']
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
*
- * // using "_.where" callback shorthand
- * _.last(characters, { 'employer': 'na' });
- * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
+ * _.isPlainObject(Object.create(null));
+ * // => true
*/
- function last(array, callback, thisArg) {
- var n = 0,
- length = array ? array.length : 0;
-
- if (typeof callback != 'number' && callback != null) {
- var index = length;
- callback = lodash.createCallback(callback, thisArg, 3);
- while (index-- && callback(array[index], index, array)) {
- n++;
- }
- } else {
- n = callback;
- if (n == null || thisArg) {
- return array ? array[length - 1] : undefined;
- }
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
+ if (!(value && objToString.call(value) == objectTag)) {
+ return false;
}
- return slice(array, nativeMax(0, length - n));
- }
+ var valueOf = value.valueOf,
+ objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
+
+ return objProto
+ ? (value == objProto || getPrototypeOf(value) == objProto)
+ : shimIsPlainObject(value);
+ };
/**
- * Gets the index at which the last occurrence of `value` is found using strict
- * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
- * as the offset from the end of the collection.
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Checks if `value` is classified as a `RegExp` object.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to search.
- * @param {*} value The value to search for.
- * @param {number} [fromIndex=array.length-1] The index to search from.
- * @returns {number} Returns the index of the matched value or `-1`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
- * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
- * // => 4
+ * _.isRegExp(/abc/);
+ * // => true
*
- * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
- * // => 1
+ * _.isRegExp('/abc/');
+ * // => false
*/
- function lastIndexOf(array, value, fromIndex) {
- var index = array ? array.length : 0;
- if (typeof fromIndex == 'number') {
- index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
- }
- while (index--) {
- if (array[index] === value) {
- return index;
- }
- }
- return -1;
+ function isRegExp(value) {
+ return (isObjectLike(value) && objToString.call(value) == regexpTag) || false;
}
/**
- * Removes all provided values from the given array using strict equality for
- * comparisons, i.e. `===`.
+ * Checks if `value` is classified as a `String` primitive or object.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to modify.
- * @param {...*} [value] The values to remove.
- * @returns {Array} Returns `array`.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
- * var array = [1, 2, 3, 1, 2, 3];
- * _.pull(array, 2, 3);
- * console.log(array);
- * // => [1, 1]
+ * _.isString('abc');
+ * // => true
+ *
+ * _.isString(1);
+ * // => false
*/
- function pull(array) {
- var args = arguments,
- argsIndex = 0,
- argsLength = args.length,
- length = array ? array.length : 0;
-
- while (++argsIndex < argsLength) {
- var index = -1,
- value = args[argsIndex];
- while (++index < length) {
- if (array[index] === value) {
- splice.call(array, index--, 1);
- length--;
- }
- }
- }
- return array;
+ function isString(value) {
+ return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag) || false;
}
/**
- * Creates an array of numbers (positive and/or negative) progressing from
- * `start` up to but not including `end`. If `start` is less than `stop` a
- * zero-length range is created unless a negative `step` is specified.
+ * Checks if `value` is classified as a typed array.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {number} [start=0] The start of the range.
- * @param {number} end The end of the range.
- * @param {number} [step=1] The value to increment or decrement by.
- * @returns {Array} Returns a new range array.
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
- * _.range(4);
- * // => [0, 1, 2, 3]
- *
- * _.range(1, 5);
- * // => [1, 2, 3, 4]
+ * _.isTypedArray(new Uint8Array);
+ * // => true
*
- * _.range(0, 20, 5);
- * // => [0, 5, 10, 15]
+ * _.isTypedArray([]);
+ * // => false
+ */
+ function isTypedArray(value) {
+ return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false;
+ }
+
+ /**
+ * Checks if `value` is `undefined`.
*
- * _.range(0, -4, -1);
- * // => [0, -1, -2, -3]
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+ * @example
*
- * _.range(1, 4, 0);
- * // => [1, 1, 1]
+ * _.isUndefined(void 0);
+ * // => true
*
- * _.range(0);
- * // => []
+ * _.isUndefined(null);
+ * // => false
*/
- function range(start, end, step) {
- start = +start || 0;
- step = typeof step == 'number' ? step : (+step || 1);
+ function isUndefined(value) {
+ return typeof value == 'undefined';
+ }
- if (end == null) {
- end = start;
- start = 0;
+ /**
+ * Converts `value` to an array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Array} Returns the converted array.
+ * @example
+ *
+ * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3);
+ * // => [2, 3]
+ */
+ function toArray(value) {
+ var length = value ? value.length : 0;
+ if (!isLength(length)) {
+ return values(value);
}
- // use `Array(length)` so engines like Chakra and V8 avoid slower modes
- // http://youtu.be/XAqIpGU8ZZk#t=17m25s
- var index = -1,
- length = nativeMax(0, ceil((end - start) / (step || 1))),
- result = Array(length);
-
- while (++index < length) {
- result[index] = start;
- start += step;
+ if (!length) {
+ return [];
}
- return result;
+ return arrayCopy(value);
}
/**
- * Removes all elements from an array that the callback returns truey for
- * and returns an array of removed elements. The callback is bound to `thisArg`
- * and invoked with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Converts `value` to a plain object flattening inherited enumerable
+ * properties of `value` to own properties of the plain object.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to modify.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a new array of removed elements.
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Object} Returns the converted plain object.
* @example
*
- * var array = [1, 2, 3, 4, 5, 6];
- * var evens = _.remove(array, function(num) { return num % 2 == 0; });
+ * function Foo() {
+ * this.b = 2;
+ * }
*
- * console.log(array);
- * // => [1, 3, 5]
+ * Foo.prototype.c = 3;
*
- * console.log(evens);
- * // => [2, 4, 6]
+ * _.assign({ 'a': 1 }, new Foo);
+ * // => { 'a': 1, 'b': 2 }
+ *
+ * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+ * // => { 'a': 1, 'b': 2, 'c': 3 }
*/
- function remove(array, callback, thisArg) {
- var index = -1,
- length = array ? array.length : 0,
- result = [];
-
- callback = lodash.createCallback(callback, thisArg, 3);
- while (++index < length) {
- var value = array[index];
- if (callback(value, index, array)) {
- result.push(value);
- splice.call(array, index--, 1);
- length--;
- }
- }
- return result;
+ function toPlainObject(value) {
+ return baseCopy(value, keysIn(value));
}
+ /*------------------------------------------------------------------------*/
+
/**
- * The opposite of `_.initial` this method gets all but the first element or
- * first `n` elements of an array. If a callback function is provided elements
- * at the beginning of the array are excluded from the result as long as the
- * callback returns truey. The callback is bound to `thisArg` and invoked
- * with three arguments; (value, index, array).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources overwrite property assignments of previous sources.
+ * If `customizer` is provided it is invoked to produce the assigned values.
+ * The `customizer` is bound to `thisArg` and invoked with five arguments;
+ * (objectValue, sourceValue, key, object, source).
*
* @static
* @memberOf _
- * @alias drop, tail
- * @category Arrays
- * @param {Array} array The array to query.
- * @param {Function|Object|number|string} [callback=1] The function called
- * per element or the number of elements to exclude. If a property name or
- * object is provided it will be used to create a "_.pluck" or "_.where"
- * style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a slice of `array`.
+ * @alias extend
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
* @example
*
- * _.rest([1, 2, 3]);
- * // => [2, 3]
- *
- * _.rest([1, 2, 3], 2);
- * // => [3]
+ * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+ * // => { 'user': 'fred', 'age': 40 }
*
- * _.rest([1, 2, 3], function(num) {
- * return num < 3;
+ * // using a customizer callback
+ * var defaults = _.partialRight(_.assign, function(value, other) {
+ * return typeof value == 'undefined' ? other : value;
* });
- * // => [3]
- *
- * var characters = [
- * { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
- * { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
- * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
- * ];
- *
- * // using "_.pluck" callback shorthand
- * _.pluck(_.rest(characters, 'blocked'), 'name');
- * // => ['fred', 'pebbles']
*
- * // using "_.where" callback shorthand
- * _.rest(characters, { 'employer': 'slate' });
- * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
+ * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
*/
- function rest(array, callback, thisArg) {
- if (typeof callback != 'number' && callback != null) {
- var n = 0,
- index = -1,
- length = array ? array.length : 0;
-
- callback = lodash.createCallback(callback, thisArg, 3);
- while (++index < length && callback(array[index], index, array)) {
- n++;
- }
- } else {
- n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
- }
- return slice(array, n);
- }
+ var assign = createAssigner(baseAssign);
/**
- * Uses a binary search to determine the smallest index at which a value
- * should be inserted into a given sorted array in order to maintain the sort
- * order of the array. If a callback is provided it will be executed for
- * `value` and each element of `array` to compute their sort ranking. The
- * callback is bound to `thisArg` and invoked with one argument; (value).
- *
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
- *
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * Creates an object that inherits from the given `prototype` object. If a
+ * `properties` object is provided its own enumerable properties are assigned
+ * to the created object.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to inspect.
- * @param {*} value The value to evaluate.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {number} Returns the index at which `value` should be inserted
- * into `array`.
+ * @category Object
+ * @param {Object} prototype The object to inherit from.
+ * @param {Object} [properties] The properties to assign to the object.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new object.
* @example
*
- * _.sortedIndex([20, 30, 50], 40);
- * // => 2
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
*
- * // using "_.pluck" callback shorthand
- * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
- * // => 2
+ * function Circle() {
+ * Shape.call(this);
+ * }
*
- * var dict = {
- * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
- * };
+ * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
*
- * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
- * return dict.wordToNumber[word];
- * });
- * // => 2
+ * var circle = new Circle;
+ * circle instanceof Circle;
+ * // => true
*
- * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
- * return this.wordToNumber[word];
- * }, dict);
- * // => 2
+ * circle instanceof Shape;
+ * // => true
*/
- function sortedIndex(array, value, callback, thisArg) {
- var low = 0,
- high = array ? array.length : low;
-
- // explicitly reference `identity` for better inlining in Firefox
- callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
- value = callback(value);
-
- while (low < high) {
- var mid = (low + high) >>> 1;
- (callback(array[mid]) < value)
- ? low = mid + 1
- : high = mid;
+ function create(prototype, properties, guard) {
+ var result = baseCreate(prototype);
+ if (guard && isIterateeCall(prototype, properties, guard)) {
+ properties = null;
}
- return low;
+ return properties ? baseCopy(properties, result, keys(properties)) : result;
}
/**
- * Creates an array of unique values, in order, of the provided arrays using
- * strict equality for comparisons, i.e. `===`.
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object for all destination properties that resolve to `undefined`. Once a
+ * property is set, additional defaults of the same property are ignored.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {...Array} [array] The arrays to inspect.
- * @returns {Array} Returns an array of combined values.
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
* @example
*
- * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
- * // => [1, 2, 3, 5, 4]
+ * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
*/
- function union() {
- return baseUniq(baseFlatten(arguments, true, true));
+ function defaults(object) {
+ if (object == null) {
+ return object;
+ }
+ var args = arrayCopy(arguments);
+ args.push(assignDefaults);
+ return assign.apply(undefined, args);
}
/**
- * Creates a duplicate-value-free version of an array using strict equality
- * for comparisons, i.e. `===`. If the array is sorted, providing
- * `true` for `isSorted` will use a faster algorithm. If a callback is provided
- * each element of `array` is passed through the callback before uniqueness
- * is computed. The callback is bound to `thisArg` and invoked with three
- * arguments; (value, index, array).
+ * This method is like `_.findIndex` except that it returns the key of the
+ * first element `predicate` returns truthy for, instead of the element itself.
*
- * If a property name is provided for `callback` the created "_.pluck" style
- * callback will return the property value of the given element.
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
*
- * If an object is provided for `callback` the created "_.where" style callback
- * will return `true` for elements that have the properties of the given object,
- * else `false`.
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @alias unique
- * @category Arrays
- * @param {Array} array The array to process.
- * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
- * @param {Function|Object|string} [callback=identity] The function called
- * per iteration. If a property name or object is provided it will be used
- * to create a "_.pluck" or "_.where" style callback, respectively.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns a duplicate-value-free array.
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
* @example
*
- * _.uniq([1, 2, 1, 3, 1]);
- * // => [1, 2, 3]
- *
- * _.uniq([1, 1, 2, 2, 3], true);
- * // => [1, 2, 3]
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
*
- * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
- * // => ['A', 'b', 'C']
+ * _.findKey(users, function(chr) { return chr.age < 40; });
+ * // => 'barney' (iteration order is not guaranteed)
*
- * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
- * // => [1, 2.5, 3]
+ * // using the "_.matches" callback shorthand
+ * _.findKey(users, { 'age': 1 });
+ * // => 'pebbles'
*
- * // using "_.pluck" callback shorthand
- * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
- * // => [{ 'x': 1 }, { 'x': 2 }]
+ * // using the "_.property" callback shorthand
+ * _.findKey(users, 'active');
+ * // => 'barney'
*/
- function uniq(array, isSorted, callback, thisArg) {
- // juggle arguments
- if (typeof isSorted != 'boolean' && isSorted != null) {
- thisArg = callback;
- callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
- isSorted = false;
- }
- if (callback != null) {
- callback = lodash.createCallback(callback, thisArg, 3);
- }
- return baseUniq(array, isSorted, callback);
+ function findKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwn, true);
}
/**
- * Creates an array excluding all provided values using strict equality for
- * comparisons, i.e. `===`.
+ * This method is like `_.findKey` except that it iterates over elements of
+ * a collection in the opposite order.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {Array} array The array to filter.
- * @param {...*} [value] The values to exclude.
- * @returns {Array} Returns a new array of filtered values.
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
* @example
*
- * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
- * // => [2, 3, 4]
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findLastKey(users, function(chr) { return chr.age < 40; });
+ * // => returns `pebbles` assuming `_.findKey` returns `barney`
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastKey(users, { 'age': 36 });
+ * // => 'barney'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastKey(users, 'active');
+ * // => 'pebbles'
*/
- function without(array) {
- return baseDifference(array, slice(arguments, 1));
+ function findLastKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwnRight, true);
}
/**
- * Creates an array that is the symmetric difference of the provided arrays.
- * See http://en.wikipedia.org/wiki/Symmetric_difference.
+ * Iterates over own and inherited enumerable properties of an object invoking
+ * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, key, object). Iterator functions may exit
+ * iteration early by explicitly returning `false`.
*
* @static
* @memberOf _
- * @category Arrays
- * @param {...Array} [array] The arrays to inspect.
- * @returns {Array} Returns an array of values.
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
* @example
*
- * _.xor([1, 2, 3], [5, 2, 1, 4]);
- * // => [3, 5, 4]
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
*
- * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
- * // => [1, 4, 5]
+ * Foo.prototype.c = 3;
+ *
+ * _.forIn(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed)
*/
- function xor() {
- var index = -1,
- length = arguments.length;
-
- while (++index < length) {
- var array = arguments[index];
- if (isArray(array) || isArguments(array)) {
- var result = result
- ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
- : array;
- }
+ function forIn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
}
- return result || [];
+ return baseFor(object, iteratee, keysIn);
}
/**
- * Creates an array of grouped elements, the first of which contains the first
- * elements of the given arrays, the second of which contains the second
- * elements of the given arrays, and so on.
+ * This method is like `_.forIn` except that it iterates over properties of
+ * `object` in the opposite order.
*
* @static
* @memberOf _
- * @alias unzip
- * @category Arrays
- * @param {...Array} [array] Arrays to process.
- * @returns {Array} Returns a new array of grouped elements.
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
* @example
*
- * _.zip(['fred', 'barney'], [30, 40], [true, false]);
- * // => [['fred', 30, true], ['barney', 40, false]]
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forInRight(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c'
*/
- function zip() {
- var array = arguments.length > 1 ? arguments : arguments[0],
- index = -1,
- length = array ? max(pluck(array, 'length')) : 0,
- result = Array(length < 0 ? 0 : length);
-
- while (++index < length) {
- result[index] = pluck(array, index);
- }
- return result;
+ function forInRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keysIn);
}
/**
- * Creates an object composed from arrays of `keys` and `values`. Provide
- * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
- * or two arrays, one of `keys` and one of corresponding `values`.
+ * Iterates over own enumerable properties of an object invoking `iteratee`
+ * for each property. The `iteratee` is bound to `thisArg` and invoked with
+ * three arguments; (value, key, object). Iterator functions may exit iteration
+ * early by explicitly returning `false`.
*
* @static
* @memberOf _
- * @alias object
- * @category Arrays
- * @param {Array} keys The array of keys.
- * @param {Array} [values=[]] The array of values.
- * @returns {Object} Returns an object composed of the given keys and
- * corresponding values.
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
* @example
*
- * _.zipObject(['fred', 'barney'], [30, 40]);
- * // => { 'fred': 30, 'barney': 40 }
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs '0', '1', and 'length' (iteration order is not guaranteed)
*/
- function zipObject(keys, values) {
- var index = -1,
- length = keys ? keys.length : 0,
- result = {};
-
- if (!values && length && !isArray(keys[0])) {
- values = [];
- }
- while (++index < length) {
- var key = keys[index];
- if (values) {
- result[key] = values[index];
- } else if (key) {
- result[key[0]] = key[1];
- }
+ function forOwn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
}
- return result;
+ return baseForOwn(object, iteratee);
}
- /*--------------------------------------------------------------------------*/
-
/**
- * Creates a function that executes `func`, with the `this` binding and
- * arguments of the created function, only after being called `n` times.
+ * This method is like `_.forOwn` except that it iterates over properties of
+ * `object` in the opposite order.
*
* @static
* @memberOf _
- * @category Functions
- * @param {number} n The number of times the function must be called before
- * `func` is executed.
- * @param {Function} func The function to restrict.
- * @returns {Function} Returns the new restricted function.
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
* @example
*
- * var saves = ['profile', 'settings'];
- *
- * var done = _.after(saves.length, function() {
- * console.log('Done saving!');
- * });
- *
- * _.forEach(saves, function(type) {
- * asyncSave({ 'type': type, 'complete': done });
+ * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
* });
- * // => logs 'Done saving!', after all saves have completed
+ * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
*/
- function after(n, func) {
- if (!isFunction(func)) {
- throw new TypeError;
- }
- return function() {
- if (--n < 1) {
- return func.apply(this, arguments);
- }
- };
+ function forOwnRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keys);
}
/**
- * Creates a function that, when called, invokes `func` with the `this`
- * binding of `thisArg` and prepends any additional `bind` arguments to those
- * provided to the bound function.
+ * Creates an array of function property names from all enumerable properties,
+ * own and inherited, of `object`.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to bind.
- * @param {*} [thisArg] The `this` binding of `func`.
- * @param {...*} [arg] Arguments to be partially applied.
- * @returns {Function} Returns the new bound function.
+ * @alias methods
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of property names.
* @example
*
- * var func = function(greeting) {
- * return greeting + ' ' + this.name;
- * };
+ * _.functions(_);
+ * // => ['all', 'any', 'bind', ...]
+ */
+ function functions(object) {
+ return baseFunctions(object, keysIn(object));
+ }
+
+ /**
+ * Checks if `key` exists as a direct property of `object` instead of an
+ * inherited property.
*
- * func = _.bind(func, { 'name': 'fred' }, 'hi');
- * func();
- * // => 'hi fred'
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @param {string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` is a direct property, else `false`.
+ * @example
+ *
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+ * // => true
*/
- function bind(func, thisArg) {
- return arguments.length > 2
- ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
- : createWrapper(func, 1, null, null, thisArg);
+ function has(object, key) {
+ return object ? hasOwnProperty.call(object, key) : false;
}
/**
- * Binds methods of an object to the object itself, overwriting the existing
- * method. Method names may be specified as individual arguments or as arrays
- * of method names. If no method names are provided all the function properties
- * of `object` will be bound.
+ * Creates an object composed of the inverted keys and values of `object`.
+ * If `object` contains duplicate values, subsequent values overwrite property
+ * assignments of previous values unless `multiValue` is `true`.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Object} object The object to bind and assign the bound methods to.
- * @param {...string} [methodName] The object method names to
- * bind, specified as individual method names or arrays of method names.
- * @returns {Object} Returns `object`.
+ * @category Object
+ * @param {Object} object The object to invert.
+ * @param {boolean} [multiValue] Allow multiple values per key.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new inverted object.
* @example
*
- * var view = {
- * 'label': 'docs',
- * 'onClick': function() { console.log('clicked ' + this.label); }
- * };
+ * _.invert({ 'first': 'fred', 'second': 'barney' });
+ * // => { 'fred': 'first', 'barney': 'second' }
*
- * _.bindAll(view);
- * jQuery('#docs').on('click', view.onClick);
- * // => logs 'clicked docs', when the button is clicked
+ * // without `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' });
+ * // => { 'fred': 'third', 'barney': 'second' }
+ *
+ * // with `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }, true);
+ * // => { 'fred': ['first', 'third'], 'barney': ['second'] }
*/
- function bindAll(object) {
- var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
- index = -1,
- length = funcs.length;
+ function invert(object, multiValue, guard) {
+ if (guard && isIterateeCall(object, multiValue, guard)) {
+ multiValue = null;
+ }
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = {};
while (++index < length) {
- var key = funcs[index];
- object[key] = createWrapper(object[key], 1, null, null, object);
+ var key = props[index],
+ value = object[key];
+
+ if (multiValue) {
+ if (hasOwnProperty.call(result, value)) {
+ result[value].push(key);
+ } else {
+ result[value] = [key];
+ }
+ }
+ else {
+ result[value] = key;
+ }
}
- return object;
+ return result;
}
/**
- * Creates a function that, when called, invokes the method at `object[key]`
- * and prepends any additional `bindKey` arguments to those provided to the bound
- * function. This method differs from `_.bind` by allowing bound functions to
- * reference methods that will be redefined or don't yet exist.
- * See http://michaux.ca/articles/lazy-function-definition-pattern.
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
+ * for more details.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Object} object The object the method belongs to.
- * @param {string} key The key of the method.
- * @param {...*} [arg] Arguments to be partially applied.
- * @returns {Function} Returns the new bound function.
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
* @example
*
- * var object = {
- * 'name': 'fred',
- * 'greet': function(greeting) {
- * return greeting + ' ' + this.name;
- * }
- * };
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
*
- * var func = _.bindKey(object, 'greet', 'hi');
- * func();
- * // => 'hi fred'
+ * Foo.prototype.c = 3;
*
- * object.greet = function(greeting) {
- * return greeting + 'ya ' + this.name + '!';
- * };
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
*
- * func();
- * // => 'hiya fred!'
+ * _.keys('hi');
+ * // => ['0', '1']
*/
- function bindKey(object, key) {
- return arguments.length > 2
- ? createWrapper(key, 19, slice(arguments, 2), null, object)
- : createWrapper(key, 3, null, null, object);
- }
+ var keys = !nativeKeys ? shimKeys : function(object) {
+ if (object) {
+ var Ctor = object.constructor,
+ length = object.length;
+ }
+ if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
+ (typeof object != 'function' && (length && isLength(length)))) {
+ return shimKeys(object);
+ }
+ return isObject(object) ? nativeKeys(object) : [];
+ };
/**
- * Creates a function that is the composition of the provided functions,
- * where each function consumes the return value of the function that follows.
- * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
- * Each function is executed with the `this` binding of the composed function.
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
*
* @static
* @memberOf _
- * @category Functions
- * @param {...Function} [func] Functions to compose.
- * @returns {Function} Returns the new composed function.
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
* @example
*
- * var realNameMap = {
- * 'pebbles': 'penelope'
- * };
- *
- * var format = function(name) {
- * name = realNameMap[name.toLowerCase()] || name;
- * return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
- * };
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
*
- * var greet = function(formatted) {
- * return 'Hiya ' + formatted + '!';
- * };
+ * Foo.prototype.c = 3;
*
- * var welcome = _.compose(greet, format);
- * welcome('pebbles');
- * // => 'Hiya Penelope!'
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
*/
- function compose() {
- var funcs = arguments,
- length = funcs.length;
-
- while (length--) {
- if (!isFunction(funcs[length])) {
- throw new TypeError;
- }
+ function keysIn(object) {
+ if (object == null) {
+ return [];
}
- return function() {
- var args = arguments,
- length = funcs.length;
+ if (!isObject(object)) {
+ object = Object(object);
+ }
+ var length = object.length;
+ length = (length && isLength(length) &&
+ (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0;
- while (length--) {
- args = [funcs[length].apply(this, args)];
+ var Ctor = object.constructor,
+ index = -1,
+ isProto = typeof Ctor == 'function' && Ctor.prototype == object,
+ result = Array(length),
+ skipIndexes = length > 0;
+
+ while (++index < length) {
+ result[index] = (index + '');
+ }
+ for (var key in object) {
+ if (!(skipIndexes && isIndex(key, length)) &&
+ !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
}
- return args[0];
- };
+ }
+ return result;
}
/**
- * Creates a function which accepts one or more arguments of `func` that when
- * invoked either executes `func` returning its result, if all `func` arguments
- * have been provided, or returns a function that accepts one or more of the
- * remaining `func` arguments, and so on. The arity of `func` can be specified
- * if `func.length` is not sufficient.
+ * Creates an object with the same keys as `object` and values generated by
+ * running each own enumerable property of `object` through `iteratee`. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * If a property name is provided for `iteratee` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `iteratee` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to curry.
- * @param {number} [arity=func.length] The arity of `func`.
- * @returns {Function} Returns the new curried function.
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the new mapped object.
* @example
*
- * var curried = _.curry(function(a, b, c) {
- * console.log(a + b + c);
- * });
- *
- * curried(1)(2)(3);
- * // => 6
+ * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(n) { return n * 3; });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
*
- * curried(1, 2)(3);
- * // => 6
+ * var users = {
+ * 'fred': { 'user': 'fred', 'age': 40 },
+ * 'pebbles': { 'user': 'pebbles', 'age': 1 }
+ * };
*
- * curried(1, 2, 3);
- * // => 6
+ * // using the "_.property" callback shorthand
+ * _.mapValues(users, 'age');
+ * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
*/
- function curry(func, arity) {
- arity = typeof arity == 'number' ? arity : (+arity || func.length);
- return createWrapper(func, 4, null, null, null, arity);
+ function mapValues(object, iteratee, thisArg) {
+ var result = {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ baseForOwn(object, function(value, key, object) {
+ result[key] = iteratee(value, key, object);
+ });
+ return result;
}
/**
- * Creates a function that will delay the execution of `func` until after
- * `wait` milliseconds have elapsed since the last time it was invoked.
- * Provide an options object to indicate that `func` should be invoked on
- * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
- * to the debounced function will return the result of the last `func` call.
- *
- * Note: If `leading` and `trailing` options are `true` `func` will be called
- * on the trailing edge of the timeout only if the the debounced function is
- * invoked more than once during the `wait` timeout.
+ * Recursively merges own enumerable properties of the source object(s), that
+ * don't resolve to `undefined` into the destination object. Subsequent sources
+ * overwrite property assignments of previous sources. If `customizer` is
+ * provided it is invoked to produce the merged values of the destination and
+ * source properties. If `customizer` returns `undefined` merging is handled
+ * by the method instead. The `customizer` is bound to `thisArg` and invoked
+ * with five arguments; (objectValue, sourceValue, key, object, source).
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to debounce.
- * @param {number} wait The number of milliseconds to delay.
- * @param {Object} [options] The options object.
- * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
- * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
- * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
- * @returns {Function} Returns the new debounced function.
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
* @example
*
- * // avoid costly calculations while the window size is in flux
- * var lazyLayout = _.debounce(calculateLayout, 150);
- * jQuery(window).on('resize', lazyLayout);
+ * var users = {
+ * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
+ * };
*
- * // execute `sendMail` when the click event is fired, debouncing subsequent calls
- * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
- * 'leading': true,
- * 'trailing': false
- * });
+ * var ages = {
+ * 'data': [{ 'age': 36 }, { 'age': 40 }]
+ * };
*
- * // ensure `batchLog` is executed once after 1 second of debounced calls
- * var source = new EventSource('/stream');
- * source.addEventListener('message', _.debounce(batchLog, 250, {
- * 'maxWait': 1000
- * }, false);
+ * _.merge(users, ages);
+ * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
+ *
+ * // using a customizer callback
+ * var object = {
+ * 'fruits': ['apple'],
+ * 'vegetables': ['beet']
+ * };
+ *
+ * var other = {
+ * 'fruits': ['banana'],
+ * 'vegetables': ['carrot']
+ * };
+ *
+ * _.merge(object, other, function(a, b) {
+ * return _.isArray(a) ? a.concat(b) : undefined;
+ * });
+ * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
*/
- function debounce(func, wait, options) {
- var args,
- maxTimeoutId,
- result,
- stamp,
- thisArg,
- timeoutId,
- trailingCall,
- lastCalled = 0,
- maxWait = false,
- trailing = true;
-
- if (!isFunction(func)) {
- throw new TypeError;
- }
- wait = nativeMax(0, wait) || 0;
- if (options === true) {
- var leading = true;
- trailing = false;
- } else if (isObject(options)) {
- leading = options.leading;
- maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
- trailing = 'trailing' in options ? options.trailing : trailing;
- }
- var delayed = function() {
- var remaining = wait - (now() - stamp);
- if (remaining <= 0) {
- if (maxTimeoutId) {
- clearTimeout(maxTimeoutId);
- }
- var isCalled = trailingCall;
- maxTimeoutId = timeoutId = trailingCall = undefined;
- if (isCalled) {
- lastCalled = now();
- result = func.apply(thisArg, args);
- if (!timeoutId && !maxTimeoutId) {
- args = thisArg = null;
- }
- }
- } else {
- timeoutId = setTimeout(delayed, remaining);
- }
- };
-
- var maxDelayed = function() {
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
- maxTimeoutId = timeoutId = trailingCall = undefined;
- if (trailing || (maxWait !== wait)) {
- lastCalled = now();
- result = func.apply(thisArg, args);
- if (!timeoutId && !maxTimeoutId) {
- args = thisArg = null;
- }
- }
- };
-
- return function() {
- args = arguments;
- stamp = now();
- thisArg = this;
- trailingCall = trailing && (timeoutId || !leading);
-
- if (maxWait === false) {
- var leadingCall = leading && !timeoutId;
- } else {
- if (!maxTimeoutId && !leading) {
- lastCalled = stamp;
- }
- var remaining = maxWait - (stamp - lastCalled),
- isCalled = remaining <= 0;
+ var merge = createAssigner(baseMerge);
- if (isCalled) {
- if (maxTimeoutId) {
- maxTimeoutId = clearTimeout(maxTimeoutId);
- }
- lastCalled = stamp;
- result = func.apply(thisArg, args);
- }
- else if (!maxTimeoutId) {
- maxTimeoutId = setTimeout(maxDelayed, remaining);
- }
- }
- if (isCalled && timeoutId) {
- timeoutId = clearTimeout(timeoutId);
- }
- else if (!timeoutId && wait !== maxWait) {
- timeoutId = setTimeout(delayed, wait);
- }
- if (leadingCall) {
- isCalled = true;
- result = func.apply(thisArg, args);
- }
- if (isCalled && !timeoutId && !maxTimeoutId) {
- args = thisArg = null;
- }
- return result;
- };
+ /**
+ * The opposite of `_.pick`; this method creates an object composed of the
+ * own and inherited enumerable properties of `object` that are not omitted.
+ * Property names may be specified as individual arguments or as arrays of
+ * property names. If `predicate` is provided it is invoked for each property
+ * of `object` omitting the properties `predicate` returns truthy for. The
+ * predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to omit, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.omit(object, 'age');
+ * // => { 'user': 'fred' }
+ *
+ * _.omit(object, _.isNumber);
+ * // => { 'user': 'fred' }
+ */
+ function omit(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ if (typeof predicate != 'function') {
+ var props = arrayMap(baseFlatten(arguments, false, false, 1), String);
+ return pickByArray(object, baseDifference(keysIn(object), props));
+ }
+ predicate = bindCallback(predicate, thisArg, 3);
+ return pickByCallback(object, function(value, key, object) {
+ return !predicate(value, key, object);
+ });
}
/**
- * Defers executing the `func` function until the current call stack has cleared.
- * Additional arguments will be provided to `func` when it is invoked.
+ * Creates a two dimensional array of the key-value pairs for `object`,
+ * e.g. `[[key1, value1], [key2, value2]]`.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to defer.
- * @param {...*} [arg] Arguments to invoke the function with.
- * @returns {number} Returns the timer id.
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of key-value pairs.
* @example
*
- * _.defer(function(text) { console.log(text); }, 'deferred');
- * // logs 'deferred' after one or more milliseconds
+ * _.pairs({ 'barney': 36, 'fred': 40 });
+ * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
*/
- function defer(func) {
- if (!isFunction(func)) {
- throw new TypeError;
+ function pairs(object) {
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var key = props[index];
+ result[index] = [key, object[key]];
}
- var args = slice(arguments, 1);
- return setTimeout(function() { func.apply(undefined, args); }, 1);
+ return result;
}
/**
- * Executes the `func` function after `wait` milliseconds. Additional arguments
- * will be provided to `func` when it is invoked.
+ * Creates an object composed of the picked `object` properties. Property
+ * names may be specified as individual arguments or as arrays of property
+ * names. If `predicate` is provided it is invoked for each property of `object`
+ * picking the properties `predicate` returns truthy for. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, key, object).
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to delay.
- * @param {number} wait The number of milliseconds to delay execution.
- * @param {...*} [arg] Arguments to invoke the function with.
- * @returns {number} Returns the timer id.
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to pick, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
* @example
*
- * _.delay(function(text) { console.log(text); }, 1000, 'later');
- * // => logs 'later' after one second
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.pick(object, 'user');
+ * // => { 'user': 'fred' }
+ *
+ * _.pick(object, _.isString);
+ * // => { 'user': 'fred' }
*/
- function delay(func, wait) {
- if (!isFunction(func)) {
- throw new TypeError;
+ function pick(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
}
- var args = slice(arguments, 2);
- return setTimeout(function() { func.apply(undefined, args); }, wait);
+ return typeof predicate == 'function'
+ ? pickByCallback(object, bindCallback(predicate, thisArg, 3))
+ : pickByArray(object, baseFlatten(arguments, false, false, 1));
}
/**
- * Creates a function that memoizes the result of `func`. If `resolver` is
- * provided it will be used to determine the cache key for storing the result
- * based on the arguments provided to the memoized function. By default, the
- * first argument provided to the memoized function is used as the cache key.
- * The `func` is executed with the `this` binding of the memoized function.
- * The result cache is exposed as the `cache` property on the memoized function.
+ * Resolves the value of property `key` on `object`. If the value of `key` is
+ * a function it is invoked with the `this` binding of `object` and its result
+ * is returned, else the property value is returned. If the property value is
+ * `undefined` the `defaultValue` is used in its place.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to have its output memoized.
- * @param {Function} [resolver] A function used to resolve the cache key.
- * @returns {Function} Returns the new memoizing function.
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the property to resolve.
+ * @param {*} [defaultValue] The value returned if the property value
+ * resolves to `undefined`.
+ * @returns {*} Returns the resolved value.
* @example
*
- * var fibonacci = _.memoize(function(n) {
- * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
- * });
+ * var object = { 'user': 'fred', 'age': _.constant(40) };
*
- * fibonacci(9)
- * // => 34
+ * _.result(object, 'user');
+ * // => 'fred'
*
- * var data = {
- * 'fred': { 'name': 'fred', 'age': 40 },
- * 'pebbles': { 'name': 'pebbles', 'age': 1 }
- * };
+ * _.result(object, 'age');
+ * // => 40
*
- * // modifying the result cache
- * var get = _.memoize(function(name) { return data[name]; }, _.identity);
- * get('pebbles');
- * // => { 'name': 'pebbles', 'age': 1 }
+ * _.result(object, 'status', 'busy');
+ * // => 'busy'
*
- * get.cache.pebbles.name = 'penelope';
- * get('pebbles');
- * // => { 'name': 'penelope', 'age': 1 }
+ * _.result(object, 'status', _.constant('busy'));
+ * // => 'busy'
*/
- function memoize(func, resolver) {
- if (!isFunction(func)) {
- throw new TypeError;
- }
- var memoized = function() {
- var cache = memoized.cache,
- key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
-
- return hasOwnProperty.call(cache, key)
- ? cache[key]
- : (cache[key] = func.apply(this, arguments));
+ function result(object, key, defaultValue) {
+ var value = object == null ? undefined : object[key];
+ if (typeof value == 'undefined') {
+ value = defaultValue;
}
- memoized.cache = {};
- return memoized;
+ return isFunction(value) ? value.call(object) : value;
}
/**
- * Creates a function that is restricted to execute `func` once. Repeat calls to
- * the function will return the value of the first call. The `func` is executed
- * with the `this` binding of the created function.
+ * An alternative to `_.reduce`; this method transforms `object` to a new
+ * `accumulator` object which is the result of running each of its own enumerable
+ * properties through `iteratee`, with each invocation potentially mutating
+ * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked
+ * with four arguments; (accumulator, value, key, object). Iterator functions
+ * may exit iteration early by explicitly returning `false`.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to restrict.
- * @returns {Function} Returns the new restricted function.
+ * @category Object
+ * @param {Array|Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The custom accumulator value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
* @example
*
- * var initialize = _.once(createApplication);
- * initialize();
- * initialize();
- * // `initialize` executes `createApplication` once
+ * var squares = _.transform([1, 2, 3, 4, 5, 6], function(result, n) {
+ * n *= n;
+ * if (n % 2) {
+ * return result.push(n) < 3;
+ * }
+ * });
+ * // => [1, 9, 25]
+ *
+ * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
*/
- function once(func) {
- var ran,
- result;
+ function transform(object, iteratee, accumulator, thisArg) {
+ var isArr = isArray(object) || isTypedArray(object);
+ iteratee = getCallback(iteratee, thisArg, 4);
- if (!isFunction(func)) {
- throw new TypeError;
- }
- return function() {
- if (ran) {
- return result;
+ if (accumulator == null) {
+ if (isArr || isObject(object)) {
+ var Ctor = object.constructor;
+ if (isArr) {
+ accumulator = isArray(object) ? new Ctor : [];
+ } else {
+ accumulator = baseCreate(typeof Ctor == 'function' && Ctor.prototype);
+ }
+ } else {
+ accumulator = {};
}
- ran = true;
- result = func.apply(this, arguments);
-
- // clear the `func` variable so the function may be garbage collected
- func = null;
- return result;
- };
+ }
+ (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) {
+ return iteratee(accumulator, value, index, object);
+ });
+ return accumulator;
}
/**
- * Creates a function that, when called, invokes `func` with any additional
- * `partial` arguments prepended to those provided to the new function. This
- * method is similar to `_.bind` except it does **not** alter the `this` binding.
+ * Creates an array of the own enumerable property values of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to partially apply arguments to.
- * @param {...*} [arg] Arguments to be partially applied.
- * @returns {Function} Returns the new partially applied function.
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
* @example
*
- * var greet = function(greeting, name) { return greeting + ' ' + name; };
- * var hi = _.partial(greet, 'hi');
- * hi('fred');
- * // => 'hi fred'
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.values(new Foo);
+ * // => [1, 2] (iteration order is not guaranteed)
+ *
+ * _.values('hi');
+ * // => ['h', 'i']
*/
- function partial(func) {
- return createWrapper(func, 16, slice(arguments, 1));
+ function values(object) {
+ return baseValues(object, keys(object));
}
/**
- * This method is like `_.partial` except that `partial` arguments are
- * appended to those provided to the new function.
+ * Creates an array of the own and inherited enumerable property values
+ * of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to partially apply arguments to.
- * @param {...*} [arg] Arguments to be partially applied.
- * @returns {Function} Returns the new partially applied function.
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
* @example
*
- * var defaultsDeep = _.partialRight(_.merge, _.defaults);
- *
- * var options = {
- * 'variable': 'data',
- * 'imports': { 'jq': $ }
- * };
- *
- * defaultsDeep(options, _.templateSettings);
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
*
- * options.variable
- * // => 'data'
+ * Foo.prototype.c = 3;
*
- * options.imports
- * // => { '_': _, 'jq': $ }
+ * _.valuesIn(new Foo);
+ * // => [1, 2, 3] (iteration order is not guaranteed)
*/
- function partialRight(func) {
- return createWrapper(func, 32, null, slice(arguments, 1));
+ function valuesIn(object) {
+ return baseValues(object, keysIn(object));
}
+ /*------------------------------------------------------------------------*/
+
/**
- * Creates a function that, when executed, will only call the `func` function
- * at most once per every `wait` milliseconds. Provide an options object to
- * indicate that `func` should be invoked on the leading and/or trailing edge
- * of the `wait` timeout. Subsequent calls to the throttled function will
- * return the result of the last `func` call.
- *
- * Note: If `leading` and `trailing` options are `true` `func` will be called
- * on the trailing edge of the timeout only if the the throttled function is
- * invoked more than once during the `wait` timeout.
+ * Produces a random number between `min` and `max` (inclusive). If only one
+ * argument is provided a number between `0` and the given number is returned.
+ * If `floating` is `true`, or either `min` or `max` are floats, a floating-point
+ * number is returned instead of an integer.
*
* @static
* @memberOf _
- * @category Functions
- * @param {Function} func The function to throttle.
- * @param {number} wait The number of milliseconds to throttle executions to.
- * @param {Object} [options] The options object.
- * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
- * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
- * @returns {Function} Returns the new throttled function.
+ * @category Number
+ * @param {number} [min=0] The minimum possible value.
+ * @param {number} [max=1] The maximum possible value.
+ * @param {boolean} [floating] Specify returning a floating-point number.
+ * @returns {number} Returns the random number.
* @example
*
- * // avoid excessively updating the position while scrolling
- * var throttled = _.throttle(updatePosition, 100);
- * jQuery(window).on('scroll', throttled);
+ * _.random(0, 5);
+ * // => an integer between 0 and 5
*
- * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
- * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
- * 'trailing': false
- * }));
+ * _.random(5);
+ * // => also an integer between 0 and 5
+ *
+ * _.random(5, true);
+ * // => a floating-point number between 0 and 5
+ *
+ * _.random(1.2, 5.2);
+ * // => a floating-point number between 1.2 and 5.2
*/
- function throttle(func, wait, options) {
- var leading = true,
- trailing = true;
+ function random(min, max, floating) {
+ if (floating && isIterateeCall(min, max, floating)) {
+ max = floating = null;
+ }
+ var noMin = min == null,
+ noMax = max == null;
- if (!isFunction(func)) {
- throw new TypeError;
+ if (floating == null) {
+ if (noMax && typeof min == 'boolean') {
+ floating = min;
+ min = 1;
+ }
+ else if (typeof max == 'boolean') {
+ floating = max;
+ noMax = true;
+ }
}
- if (options === false) {
- leading = false;
- } else if (isObject(options)) {
- leading = 'leading' in options ? options.leading : leading;
- trailing = 'trailing' in options ? options.trailing : trailing;
+ if (noMin && noMax) {
+ max = 1;
+ noMax = false;
}
- debounceOptions.leading = leading;
- debounceOptions.maxWait = wait;
- debounceOptions.trailing = trailing;
-
- return debounce(func, wait, debounceOptions);
+ min = +min || 0;
+ if (noMax) {
+ max = min;
+ min = 0;
+ } else {
+ max = +max || 0;
+ }
+ if (floating || min % 1 || max % 1) {
+ var rand = nativeRandom();
+ return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max);
+ }
+ return baseRandom(min, max);
}
+ /*------------------------------------------------------------------------*/
+
/**
- * Creates a function that provides `value` to the wrapper function as its
- * first argument. Additional arguments provided to the function are appended
- * to those provided to the wrapper function. The wrapper is executed with
- * the `this` binding of the created function.
+ * Converts `string` to camel case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/CamelCase) for more details.
*
* @static
* @memberOf _
- * @category Functions
- * @param {*} value The value to wrap.
- * @param {Function} wrapper The wrapper function.
- * @returns {Function} Returns the new function.
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the camel cased string.
* @example
*
- * var p = _.wrap(_.escape, function(func, text) {
- * return '<p>' + func(text) + '</p>';
- * });
+ * _.camelCase('Foo Bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('--foo-bar');
+ * // => 'fooBar'
*
- * p('Fred, Wilma, & Pebbles');
- * // => '<p>Fred, Wilma, & Pebbles</p>'
+ * _.camelCase('__foo_bar__');
+ * // => 'fooBar'
*/
- function wrap(value, wrapper) {
- return createWrapper(wrapper, 16, [value]);
- }
+ var camelCase = createCompounder(function(result, word, index) {
+ word = word.toLowerCase();
+ return index ? (result + word.charAt(0).toUpperCase() + word.slice(1)) : word;
+ });
- /*--------------------------------------------------------------------------*/
+ /**
+ * Capitalizes the first character of `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to capitalize.
+ * @returns {string} Returns the capitalized string.
+ * @example
+ *
+ * _.capitalize('fred');
+ * // => 'Fred'
+ */
+ function capitalize(string) {
+ string = baseToString(string);
+ return string && (string.charAt(0).toUpperCase() + string.slice(1));
+ }
/**
- * Creates a function that returns `value`.
+ * Deburrs `string` by converting latin-1 supplementary letters to basic latin letters.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+ * for more details.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {*} value The value to return from the new function.
- * @returns {Function} Returns the new function.
+ * @category String
+ * @param {string} [string=''] The string to deburr.
+ * @returns {string} Returns the deburred string.
* @example
*
- * var object = { 'name': 'fred' };
- * var getter = _.constant(object);
- * getter() === object;
- * // => true
+ * _.deburr('déjà vu');
+ * // => 'deja vu'
*/
- function constant(value) {
- return function() {
- return value;
- };
+ function deburr(string) {
+ string = baseToString(string);
+ return string && string.replace(reLatin1, deburrLetter);
}
/**
- * Produces a callback bound to an optional `thisArg`. If `func` is a property
- * name the created callback will return the property value for a given element.
- * If `func` is an object the created callback will return `true` for elements
- * that contain the equivalent object properties, otherwise it will return `false`.
+ * Checks if `string` ends with the given target string.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {*} [func=identity] The value to convert to a callback.
- * @param {*} [thisArg] The `this` binding of the created callback.
- * @param {number} [argCount] The number of arguments the callback accepts.
- * @returns {Function} Returns a callback function.
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=string.length] The position to search from.
+ * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`.
* @example
*
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
+ * _.endsWith('abc', 'c');
+ * // => true
*
- * // wrap to create custom callback shorthands
- * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
- * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
- * return !match ? func(callback, thisArg) : function(object) {
- * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
- * };
- * });
+ * _.endsWith('abc', 'b');
+ * // => false
*
- * _.filter(characters, 'age__gt38');
- * // => [{ 'name': 'fred', 'age': 40 }]
+ * _.endsWith('abc', 'b', 2);
+ * // => true
*/
- function createCallback(func, thisArg, argCount) {
- var type = typeof func;
- if (func == null || type == 'function') {
- return baseCreateCallback(func, thisArg, argCount);
- }
- // handle "_.pluck" style callback shorthands
- if (type != 'object') {
- return property(func);
- }
- var props = keys(func),
- key = props[0],
- a = func[key];
-
- // handle "_.where" style callback shorthands
- if (props.length == 1 && a === a && !isObject(a)) {
- // fast path the common case of providing an object with a single
- // property containing a primitive value
- return function(object) {
- var b = object[key];
- return a === b && (a !== 0 || (1 / a == 1 / b));
- };
- }
- return function(object) {
- var length = props.length,
- result = false;
+ function endsWith(string, target, position) {
+ string = baseToString(string);
+ target = (target + '');
- while (length--) {
- if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
- break;
- }
- }
- return result;
- };
+ var length = string.length;
+ position = (typeof position == 'undefined' ? length : nativeMin(position < 0 ? 0 : (+position || 0), length)) - target.length;
+ return position >= 0 && string.indexOf(target, position) == position;
}
/**
- * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
- * corresponding HTML entities.
+ * Converts the characters "&", "<", ">", '"', "'", and '`', in `string` to
+ * their corresponding HTML entities.
+ *
+ * **Note:** No other characters are escaped. To escape additional characters
+ * use a third-party library like [_he_](http://mths.be/he).
+ *
+ * Though the ">" character is escaped for symmetry, characters like
+ * ">" and "/" don't require escaping in HTML and have no special meaning
+ * unless they're part of a tag or unquoted attribute value.
+ * See [Mathias Bynens's article](http://mathiasbynens.be/notes/ambiguous-ampersands)
+ * (under "semi-related fun fact") for more details.
+ *
+ * Backticks are escaped because in Internet Explorer < 9, they can break out
+ * of attribute values or HTML comments. See [#102](http://html5sec.org/#102),
+ * [#108](http://html5sec.org/#108), and [#133](http://html5sec.org/#133) of
+ * the [HTML5 Security Cheatsheet](http://html5sec.org/) for more details.
+ *
+ * When working with HTML you should always quote attribute values to reduce
+ * XSS vectors. See [Ryan Grove's article](http://wonko.com/post/html-escaping)
+ * for more details.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {string} string The string to escape.
+ * @category String
+ * @param {string} [string=''] The string to escape.
* @returns {string} Returns the escaped string.
* @example
*
- * _.escape('Fred, Wilma, & Pebbles');
- * // => 'Fred, Wilma, & Pebbles'
+ * _.escape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
*/
function escape(string) {
- return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
+ // Reset `lastIndex` because in IE < 9 `String#replace` does not.
+ string = baseToString(string);
+ return (string && reHasUnescapedHtml.test(string))
+ ? string.replace(reUnescapedHtml, escapeHtmlChar)
+ : string;
}
/**
- * This method returns the first argument provided to it.
+ * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*",
+ * "+", "(", ")", "[", "]", "{" and "}" in `string`.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {*} value Any value.
- * @returns {*} Returns `value`.
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
* @example
*
- * var object = { 'name': 'fred' };
- * _.identity(object) === object;
- * // => true
+ * _.escapeRegExp('[lodash](https://lodash.com/)');
+ * // => '\[lodash\]\(https://lodash\.com/\)'
*/
- function identity(value) {
- return value;
+ function escapeRegExp(string) {
+ string = baseToString(string);
+ return (string && reHasRegExpChars.test(string))
+ ? string.replace(reRegExpChars, '\\$&')
+ : string;
}
/**
- * Adds function properties of a source object to the destination object.
- * If `object` is a function methods will be added to its prototype as well.
+ * Converts `string` to kebab case (a.k.a. spinal case).
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Letter_case#Computers) for
+ * more details.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {Function|Object} [object=lodash] object The destination object.
- * @param {Object} source The object of functions to add.
- * @param {Object} [options] The options object.
- * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the kebab cased string.
* @example
*
- * function capitalize(string) {
- * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
- * }
- *
- * _.mixin({ 'capitalize': capitalize });
- * _.capitalize('fred');
- * // => 'Fred'
+ * _.kebabCase('Foo Bar');
+ * // => 'foo-bar'
*
- * _('fred').capitalize().value();
- * // => 'Fred'
+ * _.kebabCase('fooBar');
+ * // => 'foo-bar'
*
- * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
- * _('fred').capitalize();
- * // => 'Fred'
+ * _.kebabCase('__foo_bar__');
+ * // => 'foo-bar'
*/
- function mixin(object, source, options) {
- var chain = true,
- methodNames = source && functions(source);
-
- if (!source || (!options && !methodNames.length)) {
- if (options == null) {
- options = source;
- }
- ctor = lodashWrapper;
- source = object;
- object = lodash;
- methodNames = functions(source);
- }
- if (options === false) {
- chain = false;
- } else if (isObject(options) && 'chain' in options) {
- chain = options.chain;
- }
- var ctor = object,
- isFunc = isFunction(ctor);
-
- forEach(methodNames, function(methodName) {
- var func = object[methodName] = source[methodName];
- if (isFunc) {
- ctor.prototype[methodName] = function() {
- var chainAll = this.__chain__,
- value = this.__wrapped__,
- args = [value];
-
- push.apply(args, arguments);
- var result = func.apply(object, args);
- if (chain || chainAll) {
- if (value === result && isObject(result)) {
- return this;
- }
- result = new ctor(result);
- result.__chain__ = chainAll;
- }
- return result;
- };
- }
- });
- }
+ var kebabCase = createCompounder(function(result, word, index) {
+ return result + (index ? '-' : '') + word.toLowerCase();
+ });
/**
- * Reverts the '_' variable to its previous value and returns a reference to
- * the `lodash` function.
+ * Pads `string` on the left and right sides if it is shorter then the given
+ * padding length. The `chars` string may be truncated if the number of padding
+ * characters can't be evenly divided by the padding length.
*
* @static
* @memberOf _
- * @category Utilities
- * @returns {Function} Returns the `lodash` function.
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
* @example
*
- * var lodash = _.noConflict();
- */
- function noConflict() {
- context._ = oldDash;
- return this;
+ * _.pad('abc', 8);
+ * // => ' abc '
+ *
+ * _.pad('abc', 8, '_-');
+ * // => '_-abc_-_'
+ *
+ * _.pad('abc', 3);
+ * // => 'abc'
+ */
+ function pad(string, length, chars) {
+ string = baseToString(string);
+ length = +length;
+
+ var strLength = string.length;
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return string;
+ }
+ var mid = (length - strLength) / 2,
+ leftLength = floor(mid),
+ rightLength = ceil(mid);
+
+ chars = createPad('', rightLength, chars);
+ return chars.slice(0, leftLength) + string + chars;
}
/**
- * A no-operation function.
+ * Pads `string` on the left side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
*
* @static
* @memberOf _
- * @category Utilities
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
* @example
*
- * var object = { 'name': 'fred' };
- * _.noop(object) === undefined;
- * // => true
+ * _.padLeft('abc', 6);
+ * // => ' abc'
+ *
+ * _.padLeft('abc', 6, '_-');
+ * // => '_-_abc'
+ *
+ * _.padLeft('abc', 3);
+ * // => 'abc'
*/
- function noop() {
- // no operation performed
+ function padLeft(string, length, chars) {
+ string = baseToString(string);
+ return string && (createPad(string, length, chars) + string);
}
/**
- * Gets the number of milliseconds that have elapsed since the Unix epoch
- * (1 January 1970 00:00:00 UTC).
+ * Pads `string` on the right side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
*
* @static
* @memberOf _
- * @category Utilities
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
* @example
*
- * var stamp = _.now();
- * _.defer(function() { console.log(_.now() - stamp); });
- * // => logs the number of milliseconds it took for the deferred function to be called
+ * _.padRight('abc', 6);
+ * // => 'abc '
+ *
+ * _.padRight('abc', 6, '_-');
+ * // => 'abc_-_'
+ *
+ * _.padRight('abc', 3);
+ * // => 'abc'
*/
- var now = isNative(now = Date.now) && now || function() {
- return new Date().getTime();
- };
+ function padRight(string, length, chars) {
+ string = baseToString(string);
+ return string && (string + createPad(string, length, chars));
+ }
/**
- * Converts the given value into an integer of the specified radix.
- * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
- * `value` is a hexadecimal, in which case a `radix` of `16` is used.
+ * Converts `string` to an integer of the specified radix. If `radix` is
+ * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal,
+ * in which case a `radix` of `16` is used.
*
- * Note: This method avoids differences in native ES3 and ES5 `parseInt`
- * implementations. See http://es5.github.io/#E.
+ * **Note:** This method aligns with the ES5 implementation of `parseInt`.
+ * See the [ES5 spec](http://es5.github.io/#E) for more details.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {string} value The value to parse.
- * @param {number} [radix] The radix used to interpret the value to parse.
- * @returns {number} Returns the new integer value.
+ * @category String
+ * @param {string} string The string to convert.
+ * @param {number} [radix] The radix to interpret `value` by.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {number} Returns the converted integer.
* @example
*
* _.parseInt('08');
* // => 8
- */
- var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
- // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
- return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
- };
+ *
+ * _.map(['6', '08', '10'], _.parseInt);
+ * // => [6, 8, 10]
+ */
+ function parseInt(string, radix, guard) {
+ if (guard && isIterateeCall(string, radix, guard)) {
+ radix = 0;
+ }
+ return nativeParseInt(string, radix);
+ }
+ // Fallback for environments with pre-ES5 implementations.
+ if (nativeParseInt(whitespace + '08') != 8) {
+ parseInt = function(string, radix, guard) {
+ // Firefox < 21 and Opera < 15 follow ES3 for `parseInt` and
+ // Chrome fails to trim leading <BOM> whitespace characters.
+ // See https://code.google.com/p/v8/issues/detail?id=3109.
+ if (guard ? isIterateeCall(string, radix, guard) : radix == null) {
+ radix = 0;
+ } else if (radix) {
+ radix = +radix;
+ }
+ string = trim(string);
+ return nativeParseInt(string, radix || (reHexPrefix.test(string) ? 16 : 10));
+ };
+ }
/**
- * Creates a "_.pluck" style function, which returns the `key` value of a
- * given object.
+ * Repeats the given string `n` times.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {string} key The name of the property to retrieve.
- * @returns {Function} Returns the new function.
+ * @category String
+ * @param {string} [string=''] The string to repeat.
+ * @param {number} [n=0] The number of times to repeat the string.
+ * @returns {string} Returns the repeated string.
* @example
*
- * var characters = [
- * { 'name': 'fred', 'age': 40 },
- * { 'name': 'barney', 'age': 36 }
- * ];
- *
- * var getName = _.property('name');
+ * _.repeat('*', 3);
+ * // => '***'
*
- * _.map(characters, getName);
- * // => ['barney', 'fred']
+ * _.repeat('abc', 2);
+ * // => 'abcabc'
*
- * _.sortBy(characters, getName);
- * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }]
+ * _.repeat('abc', 0);
+ * // => ''
*/
- function property(key) {
- return function(object) {
- return object[key];
- };
+ function repeat(string, n) {
+ var result = '';
+ string = baseToString(string);
+ n = +n;
+ if (n < 1 || !string || !nativeIsFinite(n)) {
+ return result;
+ }
+ // Leverage the exponentiation by squaring algorithm for a faster repeat.
+ // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring.
+ do {
+ if (n % 2) {
+ result += string;
+ }
+ n = floor(n / 2);
+ string += string;
+ } while (n);
+
+ return result;
}
/**
- * Produces a random number between `min` and `max` (inclusive). If only one
- * argument is provided a number between `0` and the given number will be
- * returned. If `floating` is truey or either `min` or `max` are floats a
- * floating-point number will be returned instead of an integer.
+ * Converts `string` to snake case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Snake_case) for more details.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {number} [min=0] The minimum possible value.
- * @param {number} [max=1] The maximum possible value.
- * @param {boolean} [floating=false] Specify returning a floating-point number.
- * @returns {number} Returns a random number.
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the snake cased string.
* @example
*
- * _.random(0, 5);
- * // => an integer between 0 and 5
- *
- * _.random(5);
- * // => also an integer between 0 and 5
+ * _.snakeCase('Foo Bar');
+ * // => 'foo_bar'
*
- * _.random(5, true);
- * // => a floating-point number between 0 and 5
+ * _.snakeCase('--foo-bar');
+ * // => 'foo_bar'
*
- * _.random(1.2, 5.2);
- * // => a floating-point number between 1.2 and 5.2
+ * _.snakeCase('fooBar');
+ * // => 'foo_bar'
*/
- function random(min, max, floating) {
- var noMin = min == null,
- noMax = max == null;
-
- if (floating == null) {
- if (typeof min == 'boolean' && noMax) {
- floating = min;
- min = 1;
- }
- else if (!noMax && typeof max == 'boolean') {
- floating = max;
- noMax = true;
- }
- }
- if (noMin && noMax) {
- max = 1;
- }
- min = +min || 0;
- if (noMax) {
- max = min;
- min = 0;
- } else {
- max = +max || 0;
- }
- if (floating || min % 1 || max % 1) {
- var rand = nativeRandom();
- return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
- }
- return baseRandom(min, max);
- }
+ var snakeCase = createCompounder(function(result, word, index) {
+ return result + (index ? '_' : '') + word.toLowerCase();
+ });
/**
- * Resolves the value of property `key` on `object`. If `key` is a function
- * it will be invoked with the `this` binding of `object` and its result returned,
- * else the property value is returned. If `object` is falsey then `undefined`
- * is returned.
+ * Checks if `string` starts with the given target string.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {Object} object The object to inspect.
- * @param {string} key The name of the property to resolve.
- * @returns {*} Returns the resolved value.
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=0] The position to search from.
+ * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`.
* @example
*
- * var object = {
- * 'cheese': 'crumpets',
- * 'stuff': function() {
- * return 'nonsense';
- * }
- * };
+ * _.startsWith('abc', 'a');
+ * // => true
*
- * _.result(object, 'cheese');
- * // => 'crumpets'
+ * _.startsWith('abc', 'b');
+ * // => false
*
- * _.result(object, 'stuff');
- * // => 'nonsense'
+ * _.startsWith('abc', 'b', 1);
+ * // => true
*/
- function result(object, key) {
- if (object) {
- var value = object[key];
- return isFunction(value) ? object[key]() : value;
- }
+ function startsWith(string, target, position) {
+ string = baseToString(string);
+ position = position == null ? 0 : nativeMin(position < 0 ? 0 : (+position || 0), string.length);
+ return string.lastIndexOf(target, position) == position;
}
/**
- * A micro-templating method that handles arbitrary delimiters, preserves
- * whitespace, and correctly escapes quotes within interpolated code.
+ * Creates a compiled template function that can interpolate data properties
+ * in "interpolate" delimiters, HTML-escape interpolated data properties in
+ * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+ * properties may be accessed as free variables in the template. If a setting
+ * object is provided it takes precedence over `_.templateSettings` values.
*
- * Note: In the development build, `_.template` utilizes sourceURLs for easier
- * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
+ * **Note:** In the development build `_.template` utilizes sourceURLs for easier debugging.
+ * See the [HTML5 Rocks article on sourcemaps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+ * for more details.
*
- * For more information on precompiling templates see:
- * http://lodash.com/custom-builds
+ * For more information on precompiling templates see
+ * [Lo-Dash's custom builds documentation](https://lodash.com/custom-builds).
*
- * For more information on Chrome extension sandboxes see:
- * http://developer.chrome.com/stable/extensions/sandboxingEval.html
+ * For more information on Chrome extension sandboxes see
+ * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
*
* @static
* @memberOf _
- * @category Utilities
- * @param {string} text The template text.
- * @param {Object} data The data object used to populate the text.
+ * @category String
+ * @param {string} [string=''] The template string.
* @param {Object} [options] The options object.
- * @param {RegExp} [options.escape] The "escape" delimiter.
+ * @param {RegExp} [options.escape] The HTML "escape" delimiter.
* @param {RegExp} [options.evaluate] The "evaluate" delimiter.
- * @param {Object} [options.imports] An object to import into the template as local variables.
+ * @param {Object} [options.imports] An object to import into the template as free variables.
* @param {RegExp} [options.interpolate] The "interpolate" delimiter.
- * @param {string} [sourceURL] The sourceURL of the template's compiled source.
- * @param {string} [variable] The data object variable name.
- * @returns {Function|string} Returns a compiled function when no `data` object
- * is given, else it returns the interpolated text.
+ * @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
+ * @param {string} [options.variable] The data object variable name.
+ * @param- {Object} [otherOptions] Enables the legacy `options` param signature.
+ * @returns {Function} Returns the compiled template function.
* @example
*
* // using the "interpolate" delimiter to create a compiled template
- * var compiled = _.template('hello <%= name %>');
- * compiled({ 'name': 'fred' });
- * // => 'hello fred'
+ * var compiled = _.template('hello <%= user %>!');
+ * compiled({ 'user': 'fred' });
+ * // => 'hello fred!'
*
- * // using the "escape" delimiter to escape HTML in data property values
- * _.template('<b><%- value %></b>', { 'value': '<script>' });
+ * // using the HTML "escape" delimiter to escape data property values
+ * var compiled = _.template('<b><%- value %></b>');
+ * compiled({ 'value': '<script>' });
* // => '<b><script></b>'
*
- * // using the "evaluate" delimiter to generate HTML
- * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
- * _.template(list, { 'people': ['fred', 'barney'] });
+ * // using the "evaluate" delimiter to execute JavaScript and generate HTML
+ * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
+ * compiled({ 'users': ['fred', 'barney'] });
* // => '<li>fred</li><li>barney</li>'
*
- * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
- * _.template('hello ${ name }', { 'name': 'pebbles' });
- * // => 'hello pebbles'
- *
* // using the internal `print` function in "evaluate" delimiters
- * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
+ * var compiled = _.template('<% print("hello " + user); %>!');
+ * compiled({ 'user': 'barney' });
* // => 'hello barney!'
*
- * // using a custom template delimiters
- * _.templateSettings = {
- * 'interpolate': /{{([\s\S]+?)}}/g
- * };
- *
- * _.template('hello {{ name }}!', { 'name': 'mustache' });
+ * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
+ * var compiled = _.template('hello ${ user }!');
+ * compiled({ 'user': 'pebbles' });
+ * // => 'hello pebbles!'
+ *
+ * // using custom template delimiters
+ * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+ * var compiled = _.template('hello {{ user }}!');
+ * compiled({ 'user': 'mustache' });
* // => 'hello mustache!'
*
- * // using the `imports` option to import jQuery
- * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
- * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
+ * // using backslashes to treat delimiters as plain text
+ * var compiled = _.template('<%= "\\<%- value %\\>" %>');
+ * compiled({ 'value': 'ignored' });
+ * // => '<%- value %>'
+ *
+ * // using the `imports` option to import `jQuery` as `jq`
+ * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
+ * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
+ * compiled({ 'users': ['fred', 'barney'] });
* // => '<li>fred</li><li>barney</li>'
*
* // using the `sourceURL` option to specify a custom sourceURL for the template
- * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
+ * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
* compiled(data);
* // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
*
* // using the `variable` option to ensure a with-statement isn't used in the compiled template
- * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
+ * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
* compiled.source;
* // => function(data) {
- * var __t, __p = '', __e = _.escape;
- * __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
+ * var __t, __p = '';
+ * __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
* return __p;
* }
*
@@ -6584,27 +9542,28 @@
* };\
* ');
*/
- function template(text, data, options) {
- // based on John Resig's `tmpl` implementation
- // http://ejohn.org/blog/javascript-micro-templating/
- // and Laura Doktorova's doT.js
- // https://github.com/olado/doT
+ function template(string, options, otherOptions) {
+ // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/)
+ // and Laura Doktorova's doT.js (https://github.com/olado/doT).
var settings = lodash.templateSettings;
- text = String(text || '');
- // avoid missing dependencies when `iteratorTemplate` is not defined
- options = iteratorTemplate ? defaults({}, options, settings) : settings;
+ if (otherOptions && isIterateeCall(string, options, otherOptions)) {
+ options = otherOptions = null;
+ }
+ string = baseToString(string);
+ options = baseAssign(baseAssign({}, otherOptions || options), settings, assignOwnDefaults);
- var imports = iteratorTemplate && defaults({}, options.imports, settings.imports),
- importsKeys = iteratorTemplate ? keys(imports) : ['_'],
- importsValues = iteratorTemplate ? values(imports) : [lodash];
+ var imports = baseAssign(baseAssign({}, options.imports), settings.imports, assignOwnDefaults),
+ importsKeys = keys(imports),
+ importsValues = baseValues(imports, importsKeys);
- var isEvaluating,
+ var isEscaping,
+ isEvaluating,
index = 0,
interpolate = options.interpolate || reNoMatch,
source = "__p += '";
- // compile the regexp to match each delimiter
+ // Compile the regexp to match each delimiter.
var reDelimiters = RegExp(
(options.escape || reNoMatch).source + '|' +
interpolate.source + '|' +
@@ -6612,14 +9571,23 @@
(options.evaluate || reNoMatch).source + '|$'
, 'g');
- text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
+ // Use a sourceURL for easier debugging.
+ // See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl.
+ var sourceURL = '//# sourceURL=' +
+ ('sourceURL' in options
+ ? options.sourceURL
+ : ('lodash.templateSources[' + (++templateCounter) + ']')
+ ) + '\n';
+
+ string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
interpolateValue || (interpolateValue = esTemplateValue);
- // escape characters that cannot be included in string literals
- source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
+ // Escape characters that can't be included in string literals.
+ source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
- // replace delimiters with snippets
+ // Replace delimiters with snippets.
if (escapeValue) {
+ isEscaping = true;
source += "' +\n__e(" + escapeValue + ") +\n'";
}
if (evaluateValue) {
@@ -6631,31 +9599,35 @@
}
index = offset + match.length;
- // the JS engine embedded in Adobe products requires returning the `match`
- // string in order to produce the correct `offset` value
+ // The JS engine embedded in Adobe products requires returning the `match`
+ // string in order to produce the correct `offset` value.
return match;
});
source += "';\n";
- // if `variable` is not specified, wrap a with-statement around the generated
- // code to add the data object to the top of the scope chain
- var variable = options.variable,
- hasVariable = variable;
-
- if (!hasVariable) {
- variable = 'obj';
- source = 'with (' + variable + ') {\n' + source + '\n}\n';
+ // If `variable` is not specified wrap a with-statement around the generated
+ // code to add the data object to the top of the scope chain.
+ var variable = options.variable;
+ if (!variable) {
+ source = 'with (obj) {\n' + source + '\n}\n';
}
- // cleanup code by stripping empty strings
+ // Cleanup code by stripping empty strings.
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
.replace(reEmptyStringMiddle, '$1')
.replace(reEmptyStringTrailing, '$1;');
- // frame code as the function body
- source = 'function(' + variable + ') {\n' +
- (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
- "var __t, __p = '', __e = _.escape" +
+ // Frame code as the function body.
+ source = 'function(' + (variable || 'obj') + ') {\n' +
+ (variable
+ ? ''
+ : 'obj || (obj = {});\n'
+ ) +
+ "var __t, __p = ''" +
+ (isEscaping
+ ? ', __e = _.escape'
+ : ''
+ ) +
(isEvaluating
? ', __j = Array.prototype.join;\n' +
"function print() { __p += __j.call(arguments, '') }\n"
@@ -6664,245 +9636,730 @@
source +
'return __p\n}';
- // Use a sourceURL for easier debugging.
- // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
- var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
+ var result = attempt(function() {
+ return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues);
+ });
+
+ // Provide the compiled function's source by its `toString` method or
+ // the `source` property as a convenience for inlining compiled templates.
+ result.source = source;
+ if (isError(result)) {
+ throw result;
+ }
+ return result;
+ }
+
+ /**
+ * Removes leading and trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trim(' abc ');
+ * // => 'abc'
+ *
+ * _.trim('-_-abc-_-', '_-');
+ * // => 'abc'
+ *
+ * _.map([' foo ', ' bar '], _.trim);
+ * // => ['foo', 'bar]
+ */
+ function trim(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string), trimmedRightIndex(string) + 1);
+ }
+ chars = baseToString(chars);
+ return string.slice(charsLeftIndex(string, chars), charsRightIndex(string, chars) + 1);
+ }
+
+ /**
+ * Removes leading whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimLeft(' abc ');
+ * // => 'abc '
+ *
+ * _.trimLeft('-_-abc-_-', '_-');
+ * // => 'abc-_-'
+ */
+ function trimLeft(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string))
+ }
+ return string.slice(charsLeftIndex(string, baseToString(chars)));
+ }
+
+ /**
+ * Removes trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimRight(' abc ');
+ * // => ' abc'
+ *
+ * _.trimRight('-_-abc-_-', '_-');
+ * // => '-_-abc'
+ */
+ function trimRight(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(0, trimmedRightIndex(string) + 1)
+ }
+ return string.slice(0, charsRightIndex(string, baseToString(chars)) + 1);
+ }
+
+ /**
+ * Truncates `string` if it is longer than the given maximum string length.
+ * The last characters of the truncated string are replaced with the omission
+ * string which defaults to "...".
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to truncate.
+ * @param {Object|number} [options] The options object or maximum string length.
+ * @param {number} [options.length=30] The maximum string length.
+ * @param {string} [options.omission='...'] The string to indicate text is omitted.
+ * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the truncated string.
+ * @example
+ *
+ * _.trunc('hi-diddly-ho there, neighborino');
+ * // => 'hi-diddly-ho there, neighbo...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', 24);
+ * // => 'hi-diddly-ho there, n...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': ' ' });
+ * // => 'hi-diddly-ho there,...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': /,? +/ });
+ * //=> 'hi-diddly-ho there...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'omission': ' [...]' });
+ * // => 'hi-diddly-ho there, neig [...]'
+ */
+ function trunc(string, options, guard) {
+ if (guard && isIterateeCall(string, options, guard)) {
+ options = null;
+ }
+ var length = DEFAULT_TRUNC_LENGTH,
+ omission = DEFAULT_TRUNC_OMISSION;
+
+ if (options != null) {
+ if (isObject(options)) {
+ var separator = 'separator' in options ? options.separator : separator;
+ length = 'length' in options ? +options.length || 0 : length;
+ omission = 'omission' in options ? baseToString(options.omission) : omission;
+ } else {
+ length = +options || 0;
+ }
+ }
+ string = baseToString(string);
+ if (length >= string.length) {
+ return string;
+ }
+ var end = length - omission.length;
+ if (end < 1) {
+ return omission;
+ }
+ var result = string.slice(0, end);
+ if (separator == null) {
+ return result + omission;
+ }
+ if (isRegExp(separator)) {
+ if (string.slice(end).search(separator)) {
+ var match,
+ newEnd,
+ substring = string.slice(0, end);
+
+ if (!separator.global) {
+ separator = RegExp(separator.source, (reFlags.exec(separator) || '') + 'g');
+ }
+ separator.lastIndex = 0;
+ while ((match = separator.exec(substring))) {
+ newEnd = match.index;
+ }
+ result = result.slice(0, newEnd == null ? end : newEnd);
+ }
+ } else if (string.indexOf(separator, end) != end) {
+ var index = result.lastIndexOf(separator);
+ if (index > -1) {
+ result = result.slice(0, index);
+ }
+ }
+ return result + omission;
+ }
+
+ /**
+ * The inverse of `_.escape`; this method converts the HTML entities
+ * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to their
+ * corresponding characters.
+ *
+ * **Note:** No other HTML entities are unescaped. To unescape additional HTML
+ * entities use a third-party library like [_he_](http://mths.be/he).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to unescape.
+ * @returns {string} Returns the unescaped string.
+ * @example
+ *
+ * _.unescape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function unescape(string) {
+ string = baseToString(string);
+ return (string && reHasEscapedHtml.test(string))
+ ? string.replace(reEscapedHtml, unescapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Splits `string` into an array of its words.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to inspect.
+ * @param {RegExp|string} [pattern] The pattern to match words.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the words of `string`.
+ * @example
+ *
+ * _.words('fred, barney, & pebbles');
+ * // => ['fred', 'barney', 'pebbles']
+ *
+ * _.words('fred, barney, & pebbles', /[^, ]+/g);
+ * // => ['fred', 'barney', '&', 'pebbles']
+ */
+ function words(string, pattern, guard) {
+ if (guard && isIterateeCall(string, pattern, guard)) {
+ pattern = null;
+ }
+ string = baseToString(string);
+ return string.match(pattern || reWords) || [];
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Attempts to invoke `func`, returning either the result or the caught
+ * error object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} func The function to attempt.
+ * @returns {*} Returns the `func` result or error object.
+ * @example
+ *
+ * // avoid throwing errors for invalid selectors
+ * var elements = _.attempt(function() {
+ * return document.querySelectorAll(selector);
+ * });
+ *
+ * if (_.isError(elements)) {
+ * elements = [];
+ * }
+ */
+ function attempt(func) {
+ try {
+ return func();
+ } catch(e) {
+ return isError(e) ? e : Error(e);
+ }
+ }
+
+ /**
+ * Creates a function bound to an optional `thisArg`. If `func` is a property
+ * name the created callback returns the property value for a given element.
+ * If `func` is an object the created callback returns `true` for elements
+ * that contain the equivalent object properties, otherwise it returns `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias iteratee
+ * @category Utility
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the callback.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // wrap to create custom callback shorthands
+ * _.callback = _.wrap(_.callback, function(callback, func, thisArg) {
+ * var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
+ * if (!match) {
+ * return callback(func, thisArg);
+ * }
+ * return function(object) {
+ * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
+ * };
+ * });
+ *
+ * _.filter(users, 'age__gt36');
+ * // => [{ 'user': 'fred', 'age': 40 }]
+ */
+ function callback(func, thisArg, guard) {
+ if (guard && isIterateeCall(func, thisArg, guard)) {
+ thisArg = null;
+ }
+ return baseCallback(func, thisArg);
+ }
+
+ /**
+ * Creates a function that returns `value`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value The value to return from the new function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var getter = _.constant(object);
+ * getter() === object;
+ * // => true
+ */
+ function constant(value) {
+ return function() {
+ return value;
+ };
+ }
+
+ /**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.identity(object) === object;
+ * // => true
+ */
+ function identity(value) {
+ return value;
+ }
- try {
- var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
- } catch(e) {
- e.source = source;
- throw e;
- }
- if (data) {
- return result(data);
- }
- // provide the compiled function's source by its `toString` method, in
- // supported environments, or the `source` property as a convenience for
- // inlining compiled templates during the build process
- result.source = source;
- return result;
+ /**
+ * Creates a function which performs a deep comparison between a given object
+ * and `source`, returning `true` if the given object has equivalent property
+ * values, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 36 }
+ * ];
+ *
+ * var matchesAge = _.matches({ 'age': 36 });
+ *
+ * _.filter(users, matchesAge);
+ * // => [{ 'user': 'barney', 'age': 36 }]
+ *
+ * _.find(users, matchesAge);
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function matches(source) {
+ return baseMatches(source, true);
}
/**
- * Executes the callback `n` times, returning an array of the results
- * of each callback execution. The callback is bound to `thisArg` and invoked
- * with one argument; (index).
+ * Adds all own enumerable function properties of a source object to the
+ * destination object. If `object` is a function then methods are added to
+ * its prototype as well.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {number} n The number of times to execute the callback.
- * @param {Function} callback The function called per iteration.
- * @param {*} [thisArg] The `this` binding of `callback`.
- * @returns {Array} Returns an array of the results of each `callback` execution.
+ * @category Utility
+ * @param {Function|Object} [object=this] object The destination object.
+ * @param {Object} source The object of functions to add.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.chain=true] Specify whether the functions added
+ * are chainable.
+ * @returns {Function|Object} Returns `object`.
* @example
*
- * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
- * // => [3, 6, 4]
+ * function vowels(string) {
+ * return _.filter(string, function(v) {
+ * return /[aeiou]/i.test(v);
+ * });
+ * }
*
- * _.times(3, function(n) { mage.castSpell(n); });
- * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
+ * _.mixin({ 'vowels': vowels });
+ * _.vowels('fred');
+ * // => ['e']
*
- * _.times(3, function(n) { this.cast(n); }, mage);
- * // => also calls `mage.castSpell(n)` three times
+ * _('fred').vowels().value();
+ * // => ['e']
+ *
+ * _.mixin({ 'vowels': vowels }, { 'chain': false });
+ * _('fred').vowels();
+ * // => ['e']
*/
- function times(n, callback, thisArg) {
- n = (n = +n) > -1 ? n : 0;
- var index = -1,
- result = Array(n);
+ function mixin(object, source, options) {
+ if (options == null) {
+ var isObj = isObject(source),
+ props = isObj && keys(source),
+ methodNames = props && props.length && baseFunctions(source, props);
- callback = baseCreateCallback(callback, thisArg, 1);
- while (++index < n) {
- result[index] = callback(index);
+ if (!(methodNames ? methodNames.length : isObj)) {
+ methodNames = false;
+ options = source;
+ source = object;
+ object = this;
+ }
}
- return result;
+ if (!methodNames) {
+ methodNames = baseFunctions(source, keys(source));
+ }
+ var chain = true,
+ index = -1,
+ isFunc = isFunction(object),
+ length = methodNames.length;
+
+ if (options === false) {
+ chain = false;
+ } else if (isObject(options) && 'chain' in options) {
+ chain = options.chain;
+ }
+ while (++index < length) {
+ var methodName = methodNames[index],
+ func = source[methodName];
+
+ object[methodName] = func;
+ if (isFunc) {
+ object.prototype[methodName] = (function(func) {
+ return function() {
+ var chainAll = this.__chain__;
+ if (chain || chainAll) {
+ var result = object(this.__wrapped__);
+ (result.__actions__ = arrayCopy(this.__actions__)).push({ 'func': func, 'args': arguments, 'thisArg': object });
+ result.__chain__ = chainAll;
+ return result;
+ }
+ var args = [this.value()];
+ push.apply(args, arguments);
+ return func.apply(object, args);
+ };
+ }(func));
+ }
+ }
+ return object;
}
/**
- * The inverse of `_.escape` this method converts the HTML entities
- * `&`, `<`, `>`, `"`, and `'` in `string` to their
- * corresponding characters.
+ * Reverts the `_` variable to its previous value and returns a reference to
+ * the `lodash` function.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {string} string The string to unescape.
- * @returns {string} Returns the unescaped string.
+ * @category Utility
+ * @returns {Function} Returns the `lodash` function.
* @example
*
- * _.unescape('Fred, Barney & Pebbles');
- * // => 'Fred, Barney & Pebbles'
+ * var lodash = _.noConflict();
*/
- function unescape(string) {
- return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
+ function noConflict() {
+ context._ = oldDash;
+ return this;
}
/**
- * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
+ * A no-operation function.
*
* @static
* @memberOf _
- * @category Utilities
- * @param {string} [prefix] The value to prefix the ID with.
- * @returns {string} Returns the unique ID.
+ * @category Utility
* @example
*
- * _.uniqueId('contact_');
- * // => 'contact_104'
- *
- * _.uniqueId();
- * // => '105'
+ * var object = { 'user': 'fred' };
+ * _.noop(object) === undefined;
+ * // => true
*/
- function uniqueId(prefix) {
- var id = ++idCounter;
- return String(prefix == null ? '' : prefix) + id;
+ function noop() {
+ // No operation performed.
}
- /*--------------------------------------------------------------------------*/
-
/**
- * Creates a `lodash` object that wraps the given value with explicit
- * method chaining enabled.
+ * Creates a function which returns the property value of `key` on a given object.
*
* @static
* @memberOf _
- * @category Chaining
- * @param {*} value The value to wrap.
- * @returns {Object} Returns the wrapper object.
+ * @category Utility
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
* @example
*
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 },
- * { 'name': 'pebbles', 'age': 1 }
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'barney' }
* ];
*
- * var youngest = _.chain(characters)
- * .sortBy('age')
- * .map(function(chr) { return chr.name + ' is ' + chr.age; })
- * .first()
- * .value();
- * // => 'pebbles is 1'
+ * var getName = _.property('user');
+ *
+ * _.map(users, getName);
+ * // => ['fred', barney']
+ *
+ * _.pluck(_.sortBy(users, getName), 'user');
+ * // => ['barney', 'fred']
*/
- function chain(value) {
- value = new lodashWrapper(value);
- value.__chain__ = true;
- return value;
+ function property(key) {
+ return baseProperty(key + '');
}
/**
- * Invokes `interceptor` with the `value` as the first argument and then
- * returns `value`. The purpose of this method is to "tap into" a method
- * chain in order to perform operations on intermediate results within
- * the chain.
+ * The inverse of `_.property`; this method creates a function which returns
+ * the property value of a given key on `object`.
*
* @static
* @memberOf _
- * @category Chaining
- * @param {*} value The value to provide to `interceptor`.
- * @param {Function} interceptor The function to invoke.
- * @returns {*} Returns `value`.
+ * @category Utility
+ * @param {Object} object The object to inspect.
+ * @returns {Function} Returns the new function.
* @example
*
- * _([1, 2, 3, 4])
- * .tap(function(array) { array.pop(); })
- * .reverse()
- * .value();
- * // => [3, 2, 1]
+ * var object = { 'user': 'fred', 'age': 40, 'active': true };
+ * _.map(['active', 'user'], _.propertyOf(object));
+ * // => [true, 'fred']
+ *
+ * var object = { 'a': 3, 'b': 1, 'c': 2 };
+ * _.sortBy(['a', 'b', 'c'], _.propertyOf(object));
+ * // => ['b', 'c', 'a']
*/
- function tap(value, interceptor) {
- interceptor(value);
- return value;
+ function propertyOf(object) {
+ return function(key) {
+ return object == null ? undefined : object[key];
+ };
}
/**
- * Enables explicit method chaining on the wrapper object.
+ * Creates an array of numbers (positive and/or negative) progressing from
+ * `start` up to, but not including, `end`. If `start` is less than `end` a
+ * zero-length range is created unless a negative `step` is specified.
*
- * @name chain
+ * @static
* @memberOf _
- * @category Chaining
- * @returns {*} Returns the wrapper object.
+ * @category Utility
+ * @param {number} [start=0] The start of the range.
+ * @param {number} end The end of the range.
+ * @param {number} [step=1] The value to increment or decrement by.
+ * @returns {Array} Returns the new array of numbers.
* @example
*
- * var characters = [
- * { 'name': 'barney', 'age': 36 },
- * { 'name': 'fred', 'age': 40 }
- * ];
+ * _.range(4);
+ * // => [0, 1, 2, 3]
*
- * // without explicit chaining
- * _(characters).first();
- * // => { 'name': 'barney', 'age': 36 }
+ * _.range(1, 5);
+ * // => [1, 2, 3, 4]
*
- * // with explicit chaining
- * _(characters).chain()
- * .first()
- * .pick('age')
- * .value();
- * // => { 'age': 36 }
+ * _.range(0, 20, 5);
+ * // => [0, 5, 10, 15]
+ *
+ * _.range(0, -4, -1);
+ * // => [0, -1, -2, -3]
+ *
+ * _.range(1, 4, 0);
+ * // => [1, 1, 1]
+ *
+ * _.range(0);
+ * // => []
*/
- function wrapperChain() {
- this.__chain__ = true;
- return this;
+ function range(start, end, step) {
+ if (step && isIterateeCall(start, end, step)) {
+ end = step = null;
+ }
+ start = +start || 0;
+ step = step == null ? 1 : (+step || 0);
+
+ if (end == null) {
+ end = start;
+ start = 0;
+ } else {
+ end = +end || 0;
+ }
+ // Use `Array(length)` so engines like Chakra and V8 avoid slower modes.
+ // See http://youtu.be/XAqIpGU8ZZk#t=17m25s.
+ var index = -1,
+ length = nativeMax(ceil((end - start) / (step || 1)), 0),
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = start;
+ start += step;
+ }
+ return result;
}
/**
- * Produces the `toString` result of the wrapped value.
+ * Invokes the iteratee function `n` times, returning an array of the results
+ * of each invocation. The `iteratee` is bound to `thisArg` and invoked with
+ * one argument; (index).
*
- * @name toString
+ * @static
* @memberOf _
- * @category Chaining
- * @returns {string} Returns the string result.
+ * @category Utility
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the array of results.
* @example
*
- * _([1, 2, 3]).toString();
- * // => '1,2,3'
+ * var diceRolls = _.times(3, _.partial(_.random, 1, 6, false));
+ * // => [3, 6, 4]
+ *
+ * _.times(3, function(n) { mage.castSpell(n); });
+ * // => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2` respectively
+ *
+ * _.times(3, function(n) { this.cast(n); }, mage);
+ * // => also invokes `mage.castSpell(n)` three times
*/
- function wrapperToString() {
- return String(this.__wrapped__);
+ function times(n, iteratee, thisArg) {
+ n = +n;
+
+ // Exit early to avoid a JSC JIT bug in Safari 8
+ // where `Array(0)` is treated as `Array(1)`.
+ if (n < 1 || !nativeIsFinite(n)) {
+ return [];
+ }
+ var index = -1,
+ result = Array(nativeMin(n, MAX_ARRAY_LENGTH));
+
+ iteratee = bindCallback(iteratee, thisArg, 1);
+ while (++index < n) {
+ if (index < MAX_ARRAY_LENGTH) {
+ result[index] = iteratee(index);
+ } else {
+ iteratee(index);
+ }
+ }
+ return result;
}
/**
- * Extracts the wrapped value.
+ * Generates a unique ID. If `prefix` is provided the ID is appended to it.
*
- * @name valueOf
+ * @static
* @memberOf _
- * @alias value
- * @category Chaining
- * @returns {*} Returns the wrapped value.
+ * @category Utility
+ * @param {string} [prefix] The value to prefix the ID with.
+ * @returns {string} Returns the unique ID.
* @example
*
- * _([1, 2, 3]).valueOf();
- * // => [1, 2, 3]
+ * _.uniqueId('contact_');
+ * // => 'contact_104'
+ *
+ * _.uniqueId();
+ * // => '105'
*/
- function wrapperValueOf() {
- return this.__wrapped__;
+ function uniqueId(prefix) {
+ var id = ++idCounter;
+ return baseToString(prefix) + id;
}
- /*--------------------------------------------------------------------------*/
+ /*------------------------------------------------------------------------*/
- // add functions that return wrapped values when chaining
+ // Ensure `new LodashWrapper` is an instance of `lodash`.
+ LodashWrapper.prototype = lodash.prototype;
+
+ // Add functions to the `Map` cache.
+ MapCache.prototype['delete'] = mapDelete;
+ MapCache.prototype.get = mapGet;
+ MapCache.prototype.has = mapHas;
+ MapCache.prototype.set = mapSet;
+
+ // Add functions to the `Set` cache.
+ SetCache.prototype.push = cachePush;
+
+ // Assign cache to `_.memoize`.
+ memoize.Cache = MapCache;
+
+ // Add functions that return wrapped values when chaining.
lodash.after = after;
+ lodash.ary = ary;
lodash.assign = assign;
lodash.at = at;
+ lodash.before = before;
lodash.bind = bind;
lodash.bindAll = bindAll;
lodash.bindKey = bindKey;
+ lodash.callback = callback;
lodash.chain = chain;
+ lodash.chunk = chunk;
lodash.compact = compact;
- lodash.compose = compose;
lodash.constant = constant;
lodash.countBy = countBy;
lodash.create = create;
- lodash.createCallback = createCallback;
lodash.curry = curry;
+ lodash.curryRight = curryRight;
lodash.debounce = debounce;
lodash.defaults = defaults;
lodash.defer = defer;
lodash.delay = delay;
lodash.difference = difference;
+ lodash.drop = drop;
+ lodash.dropRight = dropRight;
+ lodash.dropRightWhile = dropRightWhile;
+ lodash.dropWhile = dropWhile;
lodash.filter = filter;
lodash.flatten = flatten;
+ lodash.flattenDeep = flattenDeep;
+ lodash.flow = flow;
+ lodash.flowRight = flowRight;
lodash.forEach = forEach;
lodash.forEachRight = forEachRight;
lodash.forIn = forIn;
@@ -6917,35 +10374,51 @@
lodash.invert = invert;
lodash.invoke = invoke;
lodash.keys = keys;
+ lodash.keysIn = keysIn;
lodash.map = map;
lodash.mapValues = mapValues;
- lodash.max = max;
+ lodash.matches = matches;
lodash.memoize = memoize;
lodash.merge = merge;
- lodash.min = min;
+ lodash.mixin = mixin;
+ lodash.negate = negate;
lodash.omit = omit;
lodash.once = once;
lodash.pairs = pairs;
lodash.partial = partial;
lodash.partialRight = partialRight;
+ lodash.partition = partition;
lodash.pick = pick;
lodash.pluck = pluck;
lodash.property = property;
+ lodash.propertyOf = propertyOf;
lodash.pull = pull;
+ lodash.pullAt = pullAt;
lodash.range = range;
+ lodash.rearg = rearg;
lodash.reject = reject;
lodash.remove = remove;
lodash.rest = rest;
lodash.shuffle = shuffle;
+ lodash.slice = slice;
lodash.sortBy = sortBy;
+ lodash.sortByAll = sortByAll;
+ lodash.take = take;
+ lodash.takeRight = takeRight;
+ lodash.takeRightWhile = takeRightWhile;
+ lodash.takeWhile = takeWhile;
lodash.tap = tap;
lodash.throttle = throttle;
+ lodash.thru = thru;
lodash.times = times;
lodash.toArray = toArray;
+ lodash.toPlainObject = toPlainObject;
lodash.transform = transform;
lodash.union = union;
lodash.uniq = uniq;
+ lodash.unzip = unzip;
lodash.values = values;
+ lodash.valuesIn = valuesIn;
lodash.where = where;
lodash.without = without;
lodash.wrap = wrap;
@@ -6953,29 +10426,35 @@
lodash.zip = zip;
lodash.zipObject = zipObject;
- // add aliases
+ // Add aliases.
+ lodash.backflow = flowRight;
lodash.collect = map;
- lodash.drop = rest;
+ lodash.compose = flowRight;
lodash.each = forEach;
lodash.eachRight = forEachRight;
lodash.extend = assign;
+ lodash.iteratee = callback;
lodash.methods = functions;
lodash.object = zipObject;
lodash.select = filter;
lodash.tail = rest;
lodash.unique = uniq;
- lodash.unzip = zip;
- // add functions to `lodash.prototype`
- mixin(lodash);
+ // Add functions to `lodash.prototype`.
+ mixin(lodash, lodash);
- /*--------------------------------------------------------------------------*/
+ /*------------------------------------------------------------------------*/
- // add functions that return unwrapped values when chaining
+ // Add functions that return unwrapped values when chaining.
+ lodash.attempt = attempt;
+ lodash.camelCase = camelCase;
+ lodash.capitalize = capitalize;
lodash.clone = clone;
lodash.cloneDeep = cloneDeep;
- lodash.contains = contains;
+ lodash.deburr = deburr;
+ lodash.endsWith = endsWith;
lodash.escape = escape;
+ lodash.escapeRegExp = escapeRegExp;
lodash.every = every;
lodash.find = find;
lodash.findIndex = findIndex;
@@ -6983,8 +10462,11 @@
lodash.findLast = findLast;
lodash.findLastIndex = findLastIndex;
lodash.findLastKey = findLastKey;
+ lodash.findWhere = findWhere;
+ lodash.first = first;
lodash.has = has;
lodash.identity = identity;
+ lodash.includes = includes;
lodash.indexOf = indexOf;
lodash.isArguments = isArguments;
lodash.isArray = isArray;
@@ -6993,80 +10475,89 @@
lodash.isElement = isElement;
lodash.isEmpty = isEmpty;
lodash.isEqual = isEqual;
+ lodash.isError = isError;
lodash.isFinite = isFinite;
lodash.isFunction = isFunction;
+ lodash.isMatch = isMatch;
lodash.isNaN = isNaN;
+ lodash.isNative = isNative;
lodash.isNull = isNull;
lodash.isNumber = isNumber;
lodash.isObject = isObject;
lodash.isPlainObject = isPlainObject;
lodash.isRegExp = isRegExp;
lodash.isString = isString;
+ lodash.isTypedArray = isTypedArray;
lodash.isUndefined = isUndefined;
+ lodash.kebabCase = kebabCase;
+ lodash.last = last;
lodash.lastIndexOf = lastIndexOf;
- lodash.mixin = mixin;
+ lodash.max = max;
+ lodash.min = min;
lodash.noConflict = noConflict;
lodash.noop = noop;
lodash.now = now;
+ lodash.pad = pad;
+ lodash.padLeft = padLeft;
+ lodash.padRight = padRight;
lodash.parseInt = parseInt;
lodash.random = random;
lodash.reduce = reduce;
lodash.reduceRight = reduceRight;
+ lodash.repeat = repeat;
lodash.result = result;
lodash.runInContext = runInContext;
lodash.size = size;
+ lodash.snakeCase = snakeCase;
lodash.some = some;
lodash.sortedIndex = sortedIndex;
+ lodash.sortedLastIndex = sortedLastIndex;
+ lodash.startsWith = startsWith;
lodash.template = template;
+ lodash.trim = trim;
+ lodash.trimLeft = trimLeft;
+ lodash.trimRight = trimRight;
+ lodash.trunc = trunc;
lodash.unescape = unescape;
lodash.uniqueId = uniqueId;
+ lodash.words = words;
- // add aliases
+ // Add aliases.
lodash.all = every;
lodash.any = some;
+ lodash.contains = includes;
lodash.detect = find;
- lodash.findWhere = find;
lodash.foldl = reduce;
lodash.foldr = reduceRight;
- lodash.include = contains;
+ lodash.head = first;
+ lodash.include = includes;
lodash.inject = reduce;
- mixin(function() {
- var source = {}
- forOwn(lodash, function(func, methodName) {
+ mixin(lodash, (function() {
+ var source = {};
+ baseForOwn(lodash, function(func, methodName) {
if (!lodash.prototype[methodName]) {
source[methodName] = func;
}
});
return source;
- }(), false);
+ }()), false);
- /*--------------------------------------------------------------------------*/
+ /*------------------------------------------------------------------------*/
- // add functions capable of returning wrapped and unwrapped values when chaining
- lodash.first = first;
- lodash.last = last;
+ // Add functions capable of returning wrapped and unwrapped values when chaining.
lodash.sample = sample;
- // add aliases
- lodash.take = first;
- lodash.head = first;
-
- forOwn(lodash, function(func, methodName) {
- var callbackable = methodName !== 'sample';
- if (!lodash.prototype[methodName]) {
- lodash.prototype[methodName]= function(n, guard) {
- var chainAll = this.__chain__,
- result = func(this.__wrapped__, n, guard);
-
- return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
- ? result
- : new lodashWrapper(result, chainAll);
- };
+ lodash.prototype.sample = function(n) {
+ if (!this.__chain__ && n == null) {
+ return sample(this.value());
}
- });
+ return this.thru(function(value) {
+ return sample(value, n);
+ });
+ };
- /*--------------------------------------------------------------------------*/
+ /*------------------------------------------------------------------------*/
/**
* The semantic version number.
@@ -7075,105 +10566,219 @@
* @memberOf _
* @type string
*/
- lodash.VERSION = '2.4.1';
+ lodash.VERSION = VERSION;
- // add "Chaining" functions to the wrapper
- lodash.prototype.chain = wrapperChain;
- lodash.prototype.toString = wrapperToString;
- lodash.prototype.value = wrapperValueOf;
- lodash.prototype.valueOf = wrapperValueOf;
+ // Assign default placeholders.
+ arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
+ lodash[methodName].placeholder = lodash;
+ });
- // add `Array` functions that return unwrapped values
- baseEach(['join', 'pop', 'shift'], function(methodName) {
- var func = arrayRef[methodName];
- lodash.prototype[methodName] = function() {
- var chainAll = this.__chain__,
- result = func.apply(this.__wrapped__, arguments);
+ // Add `LazyWrapper` methods that accept an `iteratee` value.
+ arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
+ var isFilter = index == LAZY_FILTER_FLAG;
- return chainAll
- ? new lodashWrapper(result, chainAll)
- : result;
+ LazyWrapper.prototype[methodName] = function(iteratee, thisArg) {
+ var result = this.clone(),
+ filtered = result.filtered,
+ iteratees = result.iteratees || (result.iteratees = []);
+
+ result.filtered = filtered || isFilter || (index == LAZY_WHILE_FLAG && result.dir < 0);
+ iteratees.push({ 'iteratee': getCallback(iteratee, thisArg, 3), 'type': index });
+ return result;
};
});
- // add `Array` functions that return the existing wrapped value
- baseEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
- var func = arrayRef[methodName];
- lodash.prototype[methodName] = function() {
- func.apply(this.__wrapped__, arguments);
- return this;
+ // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
+ arrayEach(['drop', 'take'], function(methodName, index) {
+ var countName = methodName + 'Count',
+ whileName = methodName + 'While';
+
+ LazyWrapper.prototype[methodName] = function(n) {
+ n = n == null ? 1 : nativeMax(+n || 0, 0);
+
+ var result = this.clone();
+ if (result.filtered) {
+ var value = result[countName];
+ result[countName] = index ? nativeMin(value, n) : (value + n);
+ } else {
+ var views = result.views || (result.views = []);
+ views.push({ 'size': n, 'type': methodName + (result.dir < 0 ? 'Right' : '') });
+ }
+ return result;
+ };
+
+ LazyWrapper.prototype[methodName + 'Right'] = function(n) {
+ return this.reverse()[methodName](n).reverse();
+ };
+
+ LazyWrapper.prototype[methodName + 'RightWhile'] = function(predicate, thisArg) {
+ return this.reverse()[whileName](predicate, thisArg).reverse();
};
});
- // add `Array` functions that return new wrapped values
- baseEach(['concat', 'slice', 'splice'], function(methodName) {
- var func = arrayRef[methodName];
- lodash.prototype[methodName] = function() {
- return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
+ // Add `LazyWrapper` methods for `_.first` and `_.last`.
+ arrayEach(['first', 'last'], function(methodName, index) {
+ var takeName = 'take' + (index ? 'Right': '');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[takeName](1).value()[0];
};
});
- // avoid array-like object bugs with `Array#shift` and `Array#splice`
- // in IE < 9, Firefox < 10, Narwhal, and RingoJS
- if (!support.spliceObjects) {
- baseEach(['pop', 'shift', 'splice'], function(methodName) {
- var func = arrayRef[methodName],
- isSplice = methodName == 'splice';
+ // Add `LazyWrapper` methods for `_.initial` and `_.rest`.
+ arrayEach(['initial', 'rest'], function(methodName, index) {
+ var dropName = 'drop' + (index ? '' : 'Right');
- lodash.prototype[methodName] = function() {
- var chainAll = this.__chain__,
- value = this.__wrapped__,
- result = func.apply(value, arguments);
+ LazyWrapper.prototype[methodName] = function() {
+ return this[dropName](1);
+ };
+ });
- if (value.length === 0) {
- delete value[0];
- }
- return (chainAll || isSplice)
- ? new lodashWrapper(result, chainAll)
- : result;
- };
+ // Add `LazyWrapper` methods for `_.pluck` and `_.where`.
+ arrayEach(['pluck', 'where'], function(methodName, index) {
+ var operationName = index ? 'filter' : 'map',
+ createCallback = index ? matches : property;
+
+ LazyWrapper.prototype[methodName] = function(value) {
+ return this[operationName](createCallback(value));
+ };
+ });
+
+ LazyWrapper.prototype.dropWhile = function(iteratee, thisArg) {
+ var done,
+ lastIndex,
+ isRight = this.dir < 0;
+
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ done = done && (isRight ? index < lastIndex : index > lastIndex);
+ lastIndex = index;
+ return done || (done = !iteratee(value, index, array));
});
- }
+ };
+
+ LazyWrapper.prototype.reject = function(iteratee, thisArg) {
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ return !iteratee(value, index, array);
+ });
+ };
+
+ LazyWrapper.prototype.slice = function(start, end) {
+ start = start == null ? 0 : (+start || 0);
+ var result = start < 0 ? this.takeRight(-start) : this.drop(start);
+
+ if (typeof end != 'undefined') {
+ end = (+end || 0);
+ result = end < 0 ? result.dropRight(-end) : result.take(end - start);
+ }
+ return result;
+ };
+
+ // Add `LazyWrapper` methods to `lodash.prototype`.
+ baseForOwn(LazyWrapper.prototype, function(func, methodName) {
+ var retUnwrapped = /^(?:first|last)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var value = this.__wrapped__,
+ args = arguments,
+ chainAll = this.__chain__,
+ isHybrid = !!this.__actions__.length,
+ isLazy = value instanceof LazyWrapper,
+ onlyLazy = isLazy && !isHybrid;
+
+ if (retUnwrapped && !chainAll) {
+ return onlyLazy
+ ? func.call(value)
+ : lodash[methodName](this.value());
+ }
+ var interceptor = function(value) {
+ var otherArgs = [value];
+ push.apply(otherArgs, args);
+ return lodash[methodName].apply(lodash, otherArgs);
+ };
+ if (isLazy || isArray(value)) {
+ var wrapper = onlyLazy ? value : new LazyWrapper(this),
+ result = func.apply(wrapper, args);
+
+ if (!retUnwrapped && (isHybrid || result.actions)) {
+ var actions = result.actions || (result.actions = []);
+ actions.push({ 'func': thru, 'args': [interceptor], 'thisArg': lodash });
+ }
+ return new LodashWrapper(result, chainAll);
+ }
+ return this.thru(interceptor);
+ };
+ });
+
+ // Add `Array.prototype` functions to `lodash.prototype`.
+ arrayEach(['concat', 'join', 'pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
+ var func = arrayProto[methodName],
+ chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
+ retUnwrapped = /^(?:join|pop|shift)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var args = arguments;
+ if (retUnwrapped && !this.__chain__) {
+ return func.apply(this.value(), args);
+ }
+ return this[chainName](function(value) {
+ return func.apply(value, args);
+ });
+ };
+ });
+
+ // Add functions to the lazy wrapper.
+ LazyWrapper.prototype.clone = lazyClone;
+ LazyWrapper.prototype.reverse = lazyReverse;
+ LazyWrapper.prototype.value = lazyValue;
+
+ // Add chaining functions to the lodash wrapper.
+ lodash.prototype.chain = wrapperChain;
+ lodash.prototype.reverse = wrapperReverse;
+ lodash.prototype.toString = wrapperToString;
+ lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
- // add pseudo private property to be used and removed during the build process
- lodash._baseEach = baseEach;
- lodash._iteratorTemplate = iteratorTemplate;
- lodash._shimKeys = shimKeys;
+ // Add function aliases to the lodash wrapper.
+ lodash.prototype.collect = lodash.prototype.map;
+ lodash.prototype.head = lodash.prototype.first;
+ lodash.prototype.select = lodash.prototype.filter;
+ lodash.prototype.tail = lodash.prototype.rest;
return lodash;
}
/*--------------------------------------------------------------------------*/
- // expose Lo-Dash
+ // Export Lo-Dash.
var _ = runInContext();
- // some AMD build optimizers like r.js check for condition patterns like the following:
+ // Some AMD build optimizers like r.js check for condition patterns like the following:
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
- // Expose Lo-Dash to the global object even when an AMD loader is present in
- // case Lo-Dash is loaded with a RequireJS shim config.
- // See http://requirejs.org/docs/api.html#config-shim
+ // Expose Lo-Dash to the global object when an AMD loader is present to avoid
+ // errors in cases where Lo-Dash is loaded by a script tag and not intended
+ // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch.
root._ = _;
- // define as an anonymous module so, through path mapping, it can be
- // referenced as the "underscore" module
+ // Define as an anonymous module so, through path mapping, it can be
+ // referenced as the "underscore" module.
define(function() {
return _;
});
}
- // check for `exports` after `define` in case a build optimizer adds an `exports` object
+ // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
else if (freeExports && freeModule) {
- // in Node.js or RingoJS
+ // Export for Node.js or RingoJS.
if (moduleExports) {
(freeModule.exports = _)._ = _;
}
- // in Narwhal or Rhino -require
+ // Export for Narwhal or Rhino -require.
else {
freeExports._ = _;
}
}
else {
- // in a browser or Rhino
+ // Export for a browser or Rhino.
root._ = _;
}
}.call(this));
diff --git a/lodash.src.js b/lodash.src.js
new file mode 100644
index 0000000..fb97e96
--- /dev/null
+++ b/lodash.src.js
@@ -0,0 +1,11020 @@
+/**
+ * @license
+ * Lo-Dash 3.0.0 <https://lodash.com/>
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+;(function() {
+
+ /** Used as a safe reference for `undefined` in pre ES5 environments. */
+ var undefined;
+
+ /** Used as the semantic version number. */
+ var VERSION = '3.0.0';
+
+ /** Used to compose bitmasks for wrapper metadata. */
+ var BIND_FLAG = 1,
+ BIND_KEY_FLAG = 2,
+ CURRY_BOUND_FLAG = 4,
+ CURRY_FLAG = 8,
+ CURRY_RIGHT_FLAG = 16,
+ PARTIAL_FLAG = 32,
+ PARTIAL_RIGHT_FLAG = 64,
+ REARG_FLAG = 128,
+ ARY_FLAG = 256;
+
+ /** Used as default options for `_.trunc`. */
+ var DEFAULT_TRUNC_LENGTH = 30,
+ DEFAULT_TRUNC_OMISSION = '...';
+
+ /** Used to detect when a function becomes hot. */
+ var HOT_COUNT = 150,
+ HOT_SPAN = 16;
+
+ /** Used to indicate the type of lazy iteratees. */
+ var LAZY_FILTER_FLAG = 0,
+ LAZY_MAP_FLAG = 1,
+ LAZY_WHILE_FLAG = 2;
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used as the internal argument placeholder. */
+ var PLACEHOLDER = '__lodash_placeholder__';
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /** Used to match empty string literals in compiled template source. */
+ var reEmptyStringLeading = /\b__p \+= '';/g,
+ reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+ /** Used to match HTML entities and HTML characters. */
+ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g,
+ reUnescapedHtml = /[&<>"'`]/g,
+ reHasEscapedHtml = RegExp(reEscapedHtml.source),
+ reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
+
+ /** Used to match template delimiters. */
+ var reEscape = /<%-([\s\S]+?)%>/g,
+ reEvaluate = /<%([\s\S]+?)%>/g,
+ reInterpolate = /<%=([\s\S]+?)%>/g;
+
+ /**
+ * Used to match ES6 template delimiters.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literal-lexical-components)
+ * for more details.
+ */
+ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
+
+ /** Used to detect named functions. */
+ var reFuncName = /^\s*function[ \n\r\t]+\w/;
+
+ /** Used to detect hexadecimal string values. */
+ var reHexPrefix = /^0[xX]/;
+
+ /** Used to detect host constructors (Safari > 5). */
+ var reHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to match latin-1 supplementary letters (excluding mathematical operators). */
+ var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g;
+
+ /** Used to ensure capturing order of template delimiters. */
+ var reNoMatch = /($^)/;
+
+ /**
+ * Used to match `RegExp` special characters.
+ * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
+ * for more details.
+ */
+ var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
+ reHasRegExpChars = RegExp(reRegExpChars.source);
+
+ /** Used to detect functions containing a `this` reference. */
+ var reThis = /\bthis\b/;
+
+ /** Used to match unescaped characters in compiled string literals. */
+ var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
+
+ /** Used to match words to create compound words. */
+ var reWords = (function() {
+ var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]',
+ lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+';
+
+ return RegExp(upper + '{2,}(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g');
+ }());
+
+ /** Used to detect and test for whitespace. */
+ var whitespace = (
+ // Basic whitespace characters.
+ ' \t\x0b\f\xa0\ufeff' +
+
+ // Line terminators.
+ '\n\r\u2028\u2029' +
+
+ // Unicode category "Zs" space separators.
+ '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
+ );
+
+ /** Used to assign default `context` object properties. */
+ var contextProps = [
+ 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array',
+ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number',
+ 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document',
+ 'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array',
+ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
+ 'window', 'WinRTError'
+ ];
+
+ /** Used to fix the JScript `[[DontEnum]]` bug. */
+ var shadowProps = [
+ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
+ 'toLocaleString', 'toString', 'valueOf'
+ ];
+
+ /** Used to make template sourceURLs easier to identify. */
+ var templateCounter = -1;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dateTag] = typedArrayTags[errorTag] =
+ typedArrayTags[funcTag] = typedArrayTags[mapTag] =
+ typedArrayTags[numberTag] = typedArrayTags[objectTag] =
+ typedArrayTags[regexpTag] = typedArrayTags[setTag] =
+ typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag] = cloneableTags[arrayTag] =
+ cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
+ cloneableTags[dateTag] = cloneableTags[float32Tag] =
+ cloneableTags[float64Tag] = cloneableTags[int8Tag] =
+ cloneableTags[int16Tag] = cloneableTags[int32Tag] =
+ cloneableTags[numberTag] = cloneableTags[objectTag] =
+ cloneableTags[regexpTag] = cloneableTags[stringTag] =
+ cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+ cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+ cloneableTags[errorTag] = cloneableTags[funcTag] =
+ cloneableTags[mapTag] = cloneableTags[setTag] =
+ cloneableTags[weakMapTag] = false;
+
+ /** Used as an internal `_.debounce` options object by `_.throttle`. */
+ var debounceOptions = {
+ 'leading': false,
+ 'maxWait': 0,
+ 'trailing': false
+ };
+
+ /** Used to map latin-1 supplementary letters to basic latin letters. */
+ var deburredLetters = {
+ '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+ '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+ '\xc7': 'C', '\xe7': 'c',
+ '\xd0': 'D', '\xf0': 'd',
+ '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+ '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+ '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+ '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
+ '\xd1': 'N', '\xf1': 'n',
+ '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+ '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+ '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+ '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
+ '\xc6': 'Ae', '\xe6': 'ae',
+ '\xde': 'Th', '\xfe': 'th',
+ '\xdf': 'ss'
+ };
+
+ /** Used to map characters to HTML entities. */
+ var htmlEscapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
+ };
+
+ /** Used to map HTML entities to characters. */
+ var htmlUnescapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ ''': "'",
+ '`': '`'
+ };
+
+ /** Used to determine if values are of the language type `Object`. */
+ var objectTypes = {
+ 'function': true,
+ 'object': true
+ };
+
+ /** Used to escape characters for inclusion in compiled string literals. */
+ var stringEscapes = {
+ '\\': '\\',
+ "'": "'",
+ '\n': 'n',
+ '\r': 'r',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ /**
+ * Used as a reference to the global object.
+ *
+ * The `this` value is used if it is the global object to avoid Greasemonkey's
+ * restricted `window` object, otherwise the `window` object is used.
+ */
+ var root = (objectTypes[typeof window] && window !== (this && this.window)) ? window : this;
+
+ /** Detect free variable `exports`. */
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
+
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */
+ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
+ root = freeGlobal;
+ }
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * The base implementation of `compareAscending` which compares values and
+ * sorts them in ascending order without guaranteeing a stable sort.
+ *
+ * @private
+ * @param {*} value The value to compare to `other`.
+ * @param {*} other The value to compare to `value`.
+ * @returns {number} Returns the sort order indicator for `value`.
+ */
+ function baseCompareAscending(value, other) {
+ if (value !== other) {
+ var valIsReflexive = value === value,
+ othIsReflexive = other === other;
+
+ if (value > other || !valIsReflexive || (typeof value == 'undefined' && othIsReflexive)) {
+ return 1;
+ }
+ if (value < other || !othIsReflexive || (typeof other == 'undefined' && valIsReflexive)) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * The base implementation of `_.indexOf` without support for binary searches.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseIndexOf(array, value, fromIndex) {
+ if (value !== value) {
+ return indexOfNaN(array, fromIndex);
+ }
+ var index = (fromIndex || 0) - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.sortBy` and `_.sortByAll` which uses `comparer`
+ * to define the sort order of `array` and replaces criteria objects with their
+ * corresponding values.
+ *
+ * @private
+ * @param {Array} array The array to sort.
+ * @param {Function} comparer The function to define sort order.
+ * @returns {Array} Returns `array`.
+ */
+ function baseSortBy(array, comparer) {
+ var length = array.length;
+
+ array.sort(comparer);
+ while (length--) {
+ array[length] = array[length].value;
+ }
+ return array;
+ }
+
+ /**
+ * Converts `value` to a string if it is not one. An empty string is returned
+ * for `null` or `undefined` values.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ if (typeof value == 'string') {
+ return value;
+ }
+ return value == null ? '' : (value + '');
+ }
+
+ /**
+ * Used by `_.max` and `_.min` as the default callback for string values.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the code unit of the first character of the string.
+ */
+ function charAtCallback(string) {
+ return string.charCodeAt(0);
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the first character not found in `chars`.
+ */
+ function charsLeftIndex(string, chars) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last character
+ * of `string` that is not found in `chars`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @param {string} chars The characters to find.
+ * @returns {number} Returns the index of the last character not found in `chars`.
+ */
+ function charsRightIndex(string, chars) {
+ var index = string.length;
+
+ while (index-- && chars.indexOf(string.charAt(index)) > -1) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.sortBy` to compare transformed elements of a collection and stable
+ * sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareAscending(object, other) {
+ return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index);
+ }
+
+ /**
+ * Used by `_.sortByAll` to compare multiple properties of each element
+ * in a collection and stable sort them in ascending order.
+ *
+ * @private
+ * @param {Object} object The object to compare to `other`.
+ * @param {Object} other The object to compare to `object`.
+ * @returns {number} Returns the sort order indicator for `object`.
+ */
+ function compareMultipleAscending(object, other) {
+ var index = -1,
+ objCriteria = object.criteria,
+ othCriteria = other.criteria,
+ length = objCriteria.length;
+
+ while (++index < length) {
+ var result = baseCompareAscending(objCriteria[index], othCriteria[index]);
+ if (result) {
+ return result;
+ }
+ }
+ // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+ // that causes it, under certain circumstances, to provide the same value
+ // for `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247.
+ //
+ // This also ensures a stable sort in V8 and other engines.
+ // See https://code.google.com/p/v8/issues/detail?id=90.
+ return object.index - other.index;
+ }
+
+ /**
+ * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
+ *
+ * @private
+ * @param {string} letter The matched letter to deburr.
+ * @returns {string} Returns the deburred letter.
+ */
+ function deburrLetter(letter) {
+ return deburredLetters[letter];
+ }
+
+ /**
+ * Used by `_.escape` to convert characters to HTML entities.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeHtmlChar(chr) {
+ return htmlEscapes[chr];
+ }
+
+ /**
+ * Used by `_.template` to escape characters for inclusion in compiled
+ * string literals.
+ *
+ * @private
+ * @param {string} chr The matched character to escape.
+ * @returns {string} Returns the escaped character.
+ */
+ function escapeStringChar(chr) {
+ return '\\' + stringEscapes[chr];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `NaN` is found in `array`.
+ * If `fromRight` is provided elements of `array` are iterated from right to left.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {number} [fromIndex] The index to search from.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched `NaN`, else `-1`.
+ */
+ function indexOfNaN(array, fromIndex, fromRight) {
+ var length = array.length,
+ index = fromRight ? (fromIndex || length) : ((fromIndex || 0) - 1);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ var other = array[index];
+ if (other !== other) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if `value` is a host object in IE < 9.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
+ */
+ var isHostObject = (function() {
+ try {
+ baseToString({ 'toString': 0 });
+ } catch(e) {
+ return function() { return false; };
+ }
+ return function(value) {
+ // IE < 9 presents many host objects as `Object` objects that can coerce
+ // to strings despite having improperly defined `toString` methods.
+ return typeof value.toString != 'function' && typeof (value + '') == 'string';
+ };
+ }());
+
+ /**
+ * Checks if `value` is object-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ */
+ function isObjectLike(value) {
+ return (value && typeof value == 'object') || false;
+ }
+
+ /**
+ * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a
+ * character code is whitespace.
+ *
+ * @private
+ * @param {number} charCode The character code to inspect.
+ * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`.
+ */
+ function isSpace(charCode) {
+ return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 ||
+ (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279)));
+ }
+
+ /**
+ * Replaces all `placeholder` elements in `array` with an internal placeholder
+ * and returns an array of their indexes.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {*} placeholder The placeholder to replace.
+ * @returns {Array} Returns the new array of placeholder indexes.
+ */
+ function replaceHolders(array, placeholder) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ if (array[index] === placeholder) {
+ array[index] = PLACEHOLDER;
+ result[++resIndex] = index;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * An implementation of `_.uniq` optimized for sorted arrays without support
+ * for callback shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function sortedUniq(array, iteratee) {
+ var seen,
+ index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (!index || seen !== computed) {
+ seen = computed;
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the first non-whitespace character.
+ */
+ function trimmedLeftIndex(string) {
+ var index = -1,
+ length = string.length;
+
+ while (++index < length && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace
+ * character of `string`.
+ *
+ * @private
+ * @param {string} string The string to inspect.
+ * @returns {number} Returns the index of the last non-whitespace character.
+ */
+ function trimmedRightIndex(string) {
+ var index = string.length;
+
+ while (index-- && isSpace(string.charCodeAt(index))) {}
+ return index;
+ }
+
+ /**
+ * Used by `_.unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} chr The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ function unescapeHtmlChar(chr) {
+ return htmlUnescapes[chr];
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Create a new pristine `lodash` function using the given `context` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} [context=root] The context object.
+ * @returns {Function} Returns a new `lodash` function.
+ * @example
+ *
+ * _.mixin({ 'add': function(a, b) { return a + b; } });
+ *
+ * var lodash = _.runInContext();
+ * lodash.mixin({ 'sub': function(a, b) { return a - b; } });
+ *
+ * _.isFunction(_.add);
+ * // => true
+ * _.isFunction(_.sub);
+ * // => false
+ *
+ * lodash.isFunction(lodash.add);
+ * // => false
+ * lodash.isFunction(lodash.sub);
+ * // => true
+ *
+ * // using `context` to mock `Date#getTime` use in `_.now`
+ * var mock = _.runInContext({
+ * 'Date': function() {
+ * return { 'getTime': getTimeMock };
+ * }
+ * });
+ *
+ * // or creating a suped-up `defer` in Node.js
+ * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+ */
+ function runInContext(context) {
+ // Avoid issues with some ES3 environments that attempt to use values, named
+ // after built-in constructors like `Object`, for the creation of literals.
+ // ES5 clears this up by stating that literals must use built-in constructors.
+ // See http://es5.github.io/#x11.1.5.
+ context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
+
+ /** Native constructor references. */
+ var Array = context.Array,
+ Date = context.Date,
+ Error = context.Error,
+ Function = context.Function,
+ Math = context.Math,
+ Number = context.Number,
+ Object = context.Object,
+ RegExp = context.RegExp,
+ String = context.String,
+ TypeError = context.TypeError;
+
+ /** Used for native method references. */
+ var arrayProto = Array.prototype,
+ errorProto = Error.prototype,
+ objectProto = Object.prototype,
+ stringProto = String.prototype;
+
+ /** Used to detect DOM support. */
+ var document = (document = context.window) && document.document;
+
+ /** Used to resolve the decompiled source of functions. */
+ var fnToString = Function.prototype.toString;
+
+ /** Used to the length of n-tuples for `_.unzip`. */
+ var getLength = baseProperty('length');
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to generate unique IDs. */
+ var idCounter = 0;
+
+ /**
+ * Used to resolve the `toStringTag` of values.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
+ * for more details.
+ */
+ var objToString = objectProto.toString;
+
+ /** Used to restore the original `_` reference in `_.noConflict`. */
+ var oldDash = context._;
+
+ /** Used to detect if a method is native. */
+ var reNative = RegExp('^' +
+ escapeRegExp(objToString)
+ .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Native method references. */
+ var ArrayBuffer = isNative(ArrayBuffer = context.ArrayBuffer) && ArrayBuffer,
+ bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice,
+ ceil = Math.ceil,
+ clearTimeout = context.clearTimeout,
+ floor = Math.floor,
+ getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
+ push = arrayProto.push,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ Set = isNative(Set = context.Set) && Set,
+ setTimeout = context.setTimeout,
+ splice = arrayProto.splice,
+ Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array,
+ unshift = arrayProto.unshift,
+ WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap;
+
+ /** Used to clone array buffers. */
+ var Float64Array = (function() {
+ // Safari 5 errors when using an array buffer to initialize a typed array
+ // where the array buffer's `byteLength` is not a multiple of the typed
+ // array's `BYTES_PER_ELEMENT`.
+ try {
+ var func = isNative(func = context.Float64Array) && func,
+ result = new func(new ArrayBuffer(10), 0, 1) && func;
+ } catch(e) {}
+ return result;
+ }());
+
+ /* Native method references for those with the same name as other `lodash` methods. */
+ var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
+ nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
+ nativeIsFinite = context.isFinite,
+ nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
+ nativeMax = Math.max,
+ nativeMin = Math.min,
+ nativeNow = isNative(nativeNow = Date.now) && nativeNow,
+ nativeNumIsFinite = isNative(nativeNumIsFinite = Number.isFinite) && nativeNumIsFinite,
+ nativeParseInt = context.parseInt,
+ nativeRandom = Math.random;
+
+ /** Used as references for `-Infinity` and `Infinity`. */
+ var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY,
+ POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
+
+ /** Used as references for the maximum length and index of an array. */
+ var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1,
+ MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+ HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+ /** Used as the size, in bytes, of each `Float64Array` element. */
+ var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;
+
+ /**
+ * Used as the maximum length of an array-like value.
+ * See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
+ * for more details.
+ */
+ var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
+
+ /** Used to store function metadata. */
+ var metaMap = WeakMap && new WeakMap;
+
+ /** Used to lookup a type array constructors by `toStringTag`. */
+ var ctorByTag = {};
+ ctorByTag[float32Tag] = context.Float32Array;
+ ctorByTag[float64Tag] = context.Float64Array;
+ ctorByTag[int8Tag] = context.Int8Array;
+ ctorByTag[int16Tag] = context.Int16Array;
+ ctorByTag[int32Tag] = context.Int32Array;
+ ctorByTag[uint8Tag] = context.Uint8Array;
+ ctorByTag[uint8ClampedTag] = context.Uint8ClampedArray;
+ ctorByTag[uint16Tag] = context.Uint16Array;
+ ctorByTag[uint32Tag] = context.Uint32Array;
+
+ /** Used to avoid iterating over non-enumerable properties in IE < 9. */
+ var nonEnumProps = {};
+ nonEnumProps[arrayTag] = nonEnumProps[dateTag] = nonEnumProps[numberTag] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
+ nonEnumProps[boolTag] = nonEnumProps[stringTag] = { 'constructor': true, 'toString': true, 'valueOf': true };
+ nonEnumProps[errorTag] = nonEnumProps[funcTag] = nonEnumProps[regexpTag] = { 'constructor': true, 'toString': true };
+ nonEnumProps[objectTag] = { 'constructor': true };
+
+ arrayEach(shadowProps, function(key) {
+ for (var tag in nonEnumProps) {
+ if (hasOwnProperty.call(nonEnumProps, tag)) {
+ var props = nonEnumProps[tag];
+ props[key] = hasOwnProperty.call(props, key);
+ }
+ }
+ });
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object which wraps `value` to enable intuitive chaining.
+ * Methods that operate on and return arrays, collections, and functions can
+ * be chained together. Methods that return a boolean or single value will
+ * automatically end the chain returning the unwrapped value. Explicit chaining
+ * may be enabled using `_.chain`. The execution of chained methods is lazy,
+ * that is, execution is deferred until `_#value` is implicitly or explicitly
+ * called.
+ *
+ * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
+ * fusion is an optimization that merges iteratees to avoid creating intermediate
+ * arrays and reduce the number of iteratee executions.
+ *
+ * Chaining is supported in custom builds as long as the `_#value` method is
+ * directly or indirectly included in the build.
+ *
+ * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
+ * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
+ * and `unshift`
+ *
+ * The wrapper functions that support shortcut fusion are:
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `first`,
+ * `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, `slice`,
+ * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `where`
+ *
+ * The chainable wrapper functions are:
+ * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
+ * `callback`, `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`,
+ * `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
+ * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`,
+ * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`,
+ * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`,
+ * `initial`, `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`,
+ * `mapValues`, `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`,
+ * `omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`,
+ * `pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`,
+ * `rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
+ * `sortBy`, `sortByAll`, `splice`, `take`, `takeRight`, `takeRightWhile`,
+ * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
+ * `transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`,
+ * `where`, `without`, `wrap`, `xor`, `zip`, and `zipObject`
+ *
+ * The wrapper functions that are **not** chainable by default are:
+ * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
+ * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`,
+ * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`,
+ * `identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`,
+ * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`,
+ * `isFunction`, `isMatch` , `isNative`, `isNaN`, `isNull`, `isNumber`,
+ * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`,
+ * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`,
+ * `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`,
+ * `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`,
+ * `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`,
+ * `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
+ * `unescape`, `uniqueId`, `value`, and `words`
+ *
+ * The wrapper function `sample` will return a wrapped value when `n` is provided,
+ * otherwise an unwrapped value is returned.
+ *
+ * @name _
+ * @constructor
+ * @category Chain
+ * @param {*} value The value to wrap in a `lodash` instance.
+ * @returns {Object} Returns a `lodash` instance.
+ * @example
+ *
+ * var wrapped = _([1, 2, 3]);
+ *
+ * // returns an unwrapped value
+ * wrapped.reduce(function(sum, n) { return sum + n; });
+ * // => 6
+ *
+ * // returns a wrapped value
+ * var squares = wrapped.map(function(n) { return n * n; });
+ *
+ * _.isArray(squares);
+ * // => false
+ *
+ * _.isArray(squares.value());
+ * // => true
+ */
+ function lodash(value) {
+ if (isObjectLike(value) && !isArray(value)) {
+ if (value instanceof LodashWrapper) {
+ return value;
+ }
+ if (hasOwnProperty.call(value, '__wrapped__')) {
+ return new LodashWrapper(value.__wrapped__, value.__chain__, arrayCopy(value.__actions__));
+ }
+ }
+ return new LodashWrapper(value);
+ }
+
+ /**
+ * The base constructor for creating `lodash` wrapper objects.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
+ * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
+ */
+ function LodashWrapper(value, chainAll, actions) {
+ this.__actions__ = actions || [];
+ this.__chain__ = !!chainAll;
+ this.__wrapped__ = value;
+ }
+
+ /**
+ * An object environment feature flags.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ var support = lodash.support = {};
+
+ (function(x) {
+ var Ctor = function() { this.x = 1; },
+ object = { '0': 1, 'length': 1 },
+ props = [];
+
+ Ctor.prototype = { 'valueOf': 1, 'y': 1 };
+ for (var key in new Ctor) { props.push(key); }
+
+ /**
+ * Detect if the `toStringTag` of `arguments` objects is resolvable
+ * (all but Firefox < 4, IE < 9).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.argsTag = objToString.call(arguments) == argsTag;
+
+ /**
+ * Detect if `name` or `message` properties of `Error.prototype` are
+ * enumerable by default (IE < 9, Safari < 5.1).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') ||
+ propertyIsEnumerable.call(errorProto, 'name');
+
+ /**
+ * Detect if `prototype` properties are enumerable by default.
+ *
+ * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
+ * (if the prototype or a property on the prototype has been set)
+ * incorrectly set the `[[Enumerable]]` value of a function's `prototype`
+ * property to `true`.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.enumPrototypes = propertyIsEnumerable.call(Ctor, 'prototype');
+
+ /**
+ * Detect if functions can be decompiled by `Function#toString`
+ * (all but Firefox OS certified apps, older Opera mobile browsers, and
+ * the PlayStation 3; forced `false` for Windows 8 apps).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
+
+ /**
+ * Detect if `Function#name` is supported (all but IE).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.funcNames = typeof Function.name == 'string';
+
+ /**
+ * Detect if the `toStringTag` of DOM nodes is resolvable (all but IE < 9).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.nodeTag = objToString.call(document) != objectTag;
+
+ /**
+ * Detect if string indexes are non-enumerable
+ * (IE < 9, RingoJS, Rhino, Narwhal).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.nonEnumStrings = !propertyIsEnumerable.call('x', 0);
+
+ /**
+ * Detect if properties shadowing those on `Object.prototype` are
+ * non-enumerable.
+ *
+ * In IE < 9 an object's own properties, shadowing non-enumerable ones,
+ * are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.nonEnumShadows = !/valueOf/.test(props);
+
+ /**
+ * Detect if own properties are iterated after inherited properties (IE < 9).
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.ownLast = props[0] != 'x';
+
+ /**
+ * Detect if `Array#shift` and `Array#splice` augment array-like objects
+ * correctly.
+ *
+ * Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array `shift()`
+ * and `splice()` functions that fail to remove the last element, `value[0]`,
+ * of array-like objects even though the `length` property is set to `0`.
+ * The `shift()` method is buggy in compatibility modes of IE 8, while `splice()`
+ * is buggy regardless of mode in IE < 9.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.spliceObjects = (splice.call(object, 0, 1), !object[0]);
+
+ /**
+ * Detect lack of support for accessing string characters by index.
+ *
+ * IE < 8 can't access characters by index. IE 8 can only access characters
+ * by index on string literals, not string objects.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx';
+
+ /**
+ * Detect if the DOM is supported.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ try {
+ support.dom = document.createDocumentFragment().nodeType === 11;
+ } catch(e) {
+ support.dom = false;
+ }
+
+ /**
+ * Detect if `arguments` object indexes are non-enumerable.
+ *
+ * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object
+ * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat
+ * `arguments` object indexes as non-enumerable and fail `hasOwnProperty`
+ * checks for indexes that exceed their function's formal parameters with
+ * associated values of `0`.
+ *
+ * @memberOf _.support
+ * @type boolean
+ */
+ try {
+ support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1);
+ } catch(e) {
+ support.nonEnumArgs = true;
+ }
+ }(0, 0));
+
+ /**
+ * By default, the template delimiters used by Lo-Dash are like those in
+ * embedded Ruby (ERB). Change the following template settings to use
+ * alternative delimiters.
+ *
+ * @static
+ * @memberOf _
+ * @type Object
+ */
+ lodash.templateSettings = {
+
+ /**
+ * Used to detect `data` property values to be HTML-escaped.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'escape': reEscape,
+
+ /**
+ * Used to detect code to be evaluated.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'evaluate': reEvaluate,
+
+ /**
+ * Used to detect `data` property values to inject.
+ *
+ * @memberOf _.templateSettings
+ * @type RegExp
+ */
+ 'interpolate': reInterpolate,
+
+ /**
+ * Used to reference the data object in the template text.
+ *
+ * @memberOf _.templateSettings
+ * @type string
+ */
+ 'variable': '',
+
+ /**
+ * Used to import variables into the compiled template.
+ *
+ * @memberOf _.templateSettings
+ * @type Object
+ */
+ 'imports': {
+
+ /**
+ * A reference to the `lodash` function.
+ *
+ * @memberOf _.templateSettings.imports
+ * @type Function
+ */
+ '_': lodash
+ }
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+ *
+ * @private
+ * @param {*} value The value to wrap.
+ */
+ function LazyWrapper(value) {
+ this.actions = null;
+ this.dir = 1;
+ this.dropCount = 0;
+ this.filtered = false;
+ this.iteratees = null;
+ this.takeCount = POSITIVE_INFINITY;
+ this.views = null;
+ this.wrapped = value;
+ }
+
+ /**
+ * Creates a clone of the lazy wrapper object.
+ *
+ * @private
+ * @name clone
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the cloned `LazyWrapper` object.
+ */
+ function lazyClone() {
+ var actions = this.actions,
+ iteratees = this.iteratees,
+ views = this.views,
+ result = new LazyWrapper(this.wrapped);
+
+ result.actions = actions ? arrayCopy(actions) : null;
+ result.dir = this.dir;
+ result.dropCount = this.dropCount;
+ result.filtered = this.filtered;
+ result.iteratees = iteratees ? arrayCopy(iteratees) : null;
+ result.takeCount = this.takeCount;
+ result.views = views ? arrayCopy(views) : null;
+ return result;
+ }
+
+ /**
+ * Reverses the direction of lazy iteration.
+ *
+ * @private
+ * @name reverse
+ * @memberOf LazyWrapper
+ * @returns {Object} Returns the new reversed `LazyWrapper` object.
+ */
+ function lazyReverse() {
+ var filtered = this.filtered,
+ result = filtered ? new LazyWrapper(this) : this.clone();
+
+ result.dir = this.dir * -1;
+ result.filtered = filtered;
+ return result;
+ }
+
+ /**
+ * Extracts the unwrapped value from its lazy wrapper.
+ *
+ * @private
+ * @name value
+ * @memberOf LazyWrapper
+ * @returns {*} Returns the unwrapped value.
+ */
+ function lazyValue() {
+ var array = this.wrapped.value();
+ if (!isArray(array)) {
+ return baseWrapperValue(array, this.actions);
+ }
+ var dir = this.dir,
+ isRight = dir < 0,
+ length = array.length,
+ view = getView(0, length, this.views),
+ start = view.start,
+ end = view.end,
+ dropCount = this.dropCount,
+ takeCount = nativeMin(end - start, this.takeCount - dropCount),
+ index = isRight ? end : start - 1,
+ iteratees = this.iteratees,
+ iterLength = iteratees ? iteratees.length : 0,
+ resIndex = 0,
+ result = [];
+
+ outer:
+ while (length-- && resIndex < takeCount) {
+ index += dir;
+
+ var iterIndex = -1,
+ value = array[index];
+
+ while (++iterIndex < iterLength) {
+ var data = iteratees[iterIndex],
+ iteratee = data.iteratee,
+ computed = iteratee(value, index, array),
+ type = data.type;
+
+ if (type == LAZY_MAP_FLAG) {
+ value = computed;
+ } else if (!computed) {
+ if (type == LAZY_FILTER_FLAG) {
+ continue outer;
+ } else {
+ break outer;
+ }
+ }
+ }
+ if (dropCount) {
+ dropCount--;
+ } else {
+ result[resIndex++] = value;
+ }
+ }
+ return isRight ? result.reverse() : result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a cache object to store key/value pairs.
+ *
+ * @private
+ * @static
+ * @name Cache
+ * @memberOf _.memoize
+ */
+ function MapCache() {
+ this.__data__ = {};
+ }
+
+ /**
+ * Removes `key` and its value from the cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`.
+ */
+ function mapDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the cached value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the cached value.
+ */
+ function mapGet(key) {
+ return key == '__proto__' ? undefined : this.__data__[key];
+ }
+
+ /**
+ * Checks if a cached value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapHas(key) {
+ return key != '__proto__' && hasOwnProperty.call(this.__data__, key);
+ }
+
+ /**
+ * Adds `value` to `key` of the cache.
+ *
+ * @private
+ * @name set
+ * @memberOf _.memoize.Cache
+ * @param {string} key The key of the value to cache.
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache object.
+ */
+ function mapSet(key, value) {
+ if (key != '__proto__') {
+ this.__data__[key] = value;
+ }
+ return this;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ *
+ * Creates a cache object to store unique values.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var length = values ? values.length : 0;
+
+ this.data = { 'hash': nativeCreate(null), 'set': new Set };
+ while (length--) {
+ this.push(values[length]);
+ }
+ }
+
+ /**
+ * Checks if `value` is in `cache` mimicking the return signature of
+ * `_.indexOf` by returning `0` if the value is found, else `-1`.
+ *
+ * @private
+ * @param {Object} cache The cache to search.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `0` if `value` is found, else `-1`.
+ */
+ function cacheIndexOf(cache, value) {
+ var data = cache.data,
+ result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
+
+ return result ? 0 : -1;
+ }
+
+ /**
+ * Adds `value` to the cache.
+ *
+ * @private
+ * @name push
+ * @memberOf SetCache
+ * @param {*} value The value to cache.
+ */
+ function cachePush(value) {
+ var data = this.data;
+ if (typeof value == 'string' || isObject(value)) {
+ data.set.add(value);
+ } else {
+ data.hash[value] = true;
+ }
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayCopy(source, array) {
+ var index = -1,
+ length = source.length;
+
+ array || (array = Array(length));
+ while (++index < length) {
+ array[index] = source[index];
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEach` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.forEachRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEachRight(array, iteratee) {
+ var length = array.length;
+
+ while (length--) {
+ if (iteratee(array[length], length, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.every` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ */
+ function arrayEvery(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (!predicate(array[index], index, array)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A specialized version of `_.filter` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function arrayFilter(array, predicate) {
+ var index = -1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.map` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function arrayMap(array, iteratee) {
+ var index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = iteratee(array[index], index, array);
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.max` for arrays without support for iteratees.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the maximum value.
+ */
+ function arrayMax(array) {
+ var index = -1,
+ length = array.length,
+ result = NEGATIVE_INFINITY;
+
+ while (++index < length) {
+ var value = array[index];
+ if (value > result) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.min` for arrays without support for iteratees.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @returns {*} Returns the minimum value.
+ */
+ function arrayMin(array) {
+ var index = -1,
+ length = array.length,
+ result = POSITIVE_INFINITY;
+
+ while (++index < length) {
+ var value = array[index];
+ if (value < result) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.reduce` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the first element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduce(array, iteratee, accumulator, initFromArray) {
+ var index = -1,
+ length = array.length;
+
+ if (initFromArray && length) {
+ accumulator = array[++index];
+ }
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.reduceRight` for arrays without support for
+ * callback shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initFromArray] Specify using the last element of `array`
+ * as the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduceRight(array, iteratee, accumulator, initFromArray) {
+ var length = array.length;
+ if (initFromArray && length) {
+ accumulator = array[--length];
+ }
+ while (length--) {
+ accumulator = iteratee(accumulator, array[length], length, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * A specialized version of `_.some` for arrays without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Used by `_.defaults` to customize its `_.assign` use.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignDefaults(objectValue, sourceValue) {
+ return typeof objectValue == 'undefined' ? sourceValue : objectValue;
+ }
+
+ /**
+ * Used by `_.template` to customize its `_.assign` use.
+ *
+ * **Note:** This method is like `assignDefaults` except that it ignores
+ * inherited property values when checking if a property is `undefined`.
+ *
+ * @private
+ * @param {*} objectValue The destination object property value.
+ * @param {*} sourceValue The source object property value.
+ * @param {string} key The key associated with the object and source values.
+ * @param {Object} object The destination object.
+ * @returns {*} Returns the value to assign to the destination object.
+ */
+ function assignOwnDefaults(objectValue, sourceValue, key, object) {
+ return (typeof objectValue == 'undefined' || !hasOwnProperty.call(object, key))
+ ? sourceValue
+ : objectValue;
+ }
+
+ /**
+ * The base implementation of `_.assign` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseAssign(object, source, customizer) {
+ var props = keys(source);
+ if (!customizer) {
+ return baseCopy(source, object, props);
+ }
+ var index = -1,
+ length = props.length
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key],
+ result = customizer(value, source[key], key, object, source);
+
+ if ((result === result ? result !== value : value === value) ||
+ (typeof value == 'undefined' && !(key in object))) {
+ object[key] = result;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.at` without support for strings and individual
+ * key arguments.
+ *
+ * @private
+ * @param {Array|Object} collection The collection to iterate over.
+ * @param {number[]|string[]} [props] The property names or indexes of elements to pick.
+ * @returns {Array} Returns the new array of picked elements.
+ */
+ function baseAt(collection, props) {
+ var index = -1,
+ length = collection.length,
+ isArr = isLength(length),
+ propsLength = props.length,
+ result = Array(propsLength);
+
+ while(++index < propsLength) {
+ var key = props[index];
+ if (isArr) {
+ key = parseFloat(key);
+ result[index] = isIndex(key, length) ? collection[key] : undefined;
+ } else {
+ result[index] = collection[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copies the properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Array} props The property names to copy.
+ * @returns {Object} Returns `object`.
+ */
+ function baseCopy(source, object, props) {
+ if (!props) {
+ props = object;
+ object = {};
+ }
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ object[key] = source[key];
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.bindAll` without support for individual
+ * method name arguments.
+ *
+ * @private
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {string[]} methodNames The object method names to bind.
+ * @returns {Object} Returns `object`.
+ */
+ function baseBindAll(object, methodNames) {
+ var index = -1,
+ length = methodNames.length;
+
+ while (++index < length) {
+ var key = methodNames[index];
+ object[key] = createWrapper(object[key], BIND_FLAG, object);
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.callback` which supports specifying the
+ * number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function baseCallback(func, thisArg, argCount) {
+ var type = typeof func;
+ if (type == 'function') {
+ return (typeof thisArg != 'undefined' && isBindable(func))
+ ? bindCallback(func, thisArg, argCount)
+ : func;
+ }
+ if (func == null) {
+ return identity;
+ }
+ // Handle "_.property" and "_.matches" style callback shorthands.
+ return type == 'object'
+ ? baseMatches(func, !argCount)
+ : baseProperty(argCount ? baseToString(func) : func);
+ }
+
+ /**
+ * The base implementation of `_.clone` without support for argument juggling
+ * and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The object `value` belongs to.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates clones with source counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
+ var result;
+ if (customizer) {
+ result = object ? customizer(value, key, object) : customizer(value);
+ }
+ if (typeof result != 'undefined') {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return arrayCopy(value, result);
+ }
+ } else {
+ var tag = objToString.call(value),
+ isFunc = tag == funcTag;
+
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ if (isHostObject(value)) {
+ return object ? value : {};
+ }
+ result = initCloneObject(isFunc ? {} : value);
+ if (!isDeep) {
+ return baseCopy(value, result, keys(value));
+ }
+ } else {
+ return cloneableTags[tag]
+ ? initCloneByTag(value, tag, isDeep)
+ : (object ? value : {});
+ }
+ }
+ // Check for circular references and return corresponding clone.
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == value) {
+ return stackB[length];
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate it with its clone.
+ stackA.push(value);
+ stackB.push(result);
+
+ // Recursively populate clone (susceptible to call stack limits).
+ (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
+ result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+ var baseCreate = (function() {
+ function Object() {}
+ return function(prototype) {
+ if (isObject(prototype)) {
+ Object.prototype = prototype;
+ var result = new Object;
+ Object.prototype = null;
+ }
+ return result || context.Object();
+ };
+ }());
+
+ /**
+ * The base implementation of `_.delay` and `_.defer` which accepts an index
+ * of where to slice the arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {Object} args The `arguments` object to slice and provide to `func`.
+ * @returns {number} Returns the timer id.
+ */
+ function baseDelay(func, wait, args, fromIndex) {
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return setTimeout(function() { func.apply(undefined, baseSlice(args, fromIndex)); }, wait);
+ }
+
+ /**
+ * The base implementation of `_.difference` which accepts a single array
+ * of values to exclude.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Array} values The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ */
+ function baseDifference(array, values) {
+ var length = array ? array.length : 0,
+ result = [];
+
+ if (!length) {
+ return result;
+ }
+ var index = -1,
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf,
+ cache = isCommon && values.length >= 200 && createCache(values),
+ valuesLength = values.length;
+
+ if (cache) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ values = cache;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index];
+
+ if (isCommon && value === value) {
+ var valuesIndex = valuesLength;
+ while (valuesIndex--) {
+ if (values[valuesIndex] === value) {
+ continue outer;
+ }
+ }
+ result.push(value);
+ }
+ else if (indexOf(values, value) < 0) {
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.forEach` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEach(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwn(collection, iteratee);
+ }
+ var index = -1,
+ iterable = toObject(collection);
+
+ while (++index < length) {
+ if (iteratee(iterable[index], index, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.forEachRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array|Object|string} Returns `collection`.
+ */
+ function baseEachRight(collection, iteratee) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ return baseForOwnRight(collection, iteratee);
+ }
+ var iterable = toObject(collection);
+ while (length--) {
+ if (iteratee(iterable[length], length, iterable) === false) {
+ break;
+ }
+ }
+ return collection;
+ }
+
+ /**
+ * The base implementation of `_.every` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`
+ */
+ function baseEvery(collection, predicate) {
+ var result = true;
+ baseEach(collection, function(value, index, collection) {
+ result = !!predicate(value, index, collection);
+ return result;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.filter` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function baseFilter(collection, predicate) {
+ var result = [];
+ baseEach(collection, function(value, index, collection) {
+ if (predicate(value, index, collection)) {
+ result.push(value);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
+ * without support for callback shorthands and `this` binding, which iterates
+ * over `collection` using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @param {boolean} [retKey] Specify returning the key of the found element
+ * instead of the element itself.
+ * @returns {*} Returns the found element or its key, else `undefined`.
+ */
+ function baseFind(collection, predicate, eachFunc, retKey) {
+ var result;
+ eachFunc(collection, function(value, key, collection) {
+ if (predicate(value, key, collection)) {
+ result = retKey ? key : value;
+ return false;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.flatten` with added support for restricting
+ * flattening and specifying the start index.
+ *
+ * @private
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param {boolean} [isStrict] Restrict flattening to arrays and `arguments` objects.
+ * @param {number} [fromIndex=0] The index to start from.
+ * @returns {Array} Returns the new flattened array.
+ */
+ function baseFlatten(array, isDeep, isStrict, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+
+ if (isObjectLike(value) && isLength(value.length) && (isArray(value) || isArguments(value))) {
+ if (isDeep) {
+ // Recursively flatten arrays (susceptible to call stack limits).
+ value = baseFlatten(value, isDeep, isStrict);
+ }
+ var valIndex = -1,
+ valLength = value.length;
+
+ result.length += valLength;
+ while (++valIndex < valLength) {
+ result[++resIndex] = value[valIndex];
+ }
+ } else if (!isStrict) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `baseForIn` and `baseForOwn` which iterates
+ * over `object` properties returned by `keysFunc` invoking `iteratee` for
+ * each property. Iterator functions may exit iteration early by explicitly
+ * returning `false`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ function baseFor(object, iteratee, keysFunc) {
+ var index = -1,
+ iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * This function is like `baseFor` except that it iterates over properties
+ * in the opposite order.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForRight(object, iteratee, keysFunc) {
+ var iterable = toObject(object),
+ props = keysFunc(object),
+ length = props.length;
+
+ while (length--) {
+ var key = props[length];
+ if (iteratee(iterable[key], key, iterable) === false) {
+ break;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * The base implementation of `_.forIn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForIn(object, iteratee) {
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * The base implementation of `_.forOwn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwn(object, iteratee) {
+ return baseFor(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.forOwnRight` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+ function baseForOwnRight(object, iteratee) {
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * The base implementation of `_.functions` which creates an array of
+ * `object` function property names filtered from those provided.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Array} props The property names to filter.
+ * @returns {Array} Returns the new array of filtered property names.
+ */
+ function baseFunctions(object, props) {
+ var index = -1,
+ length = props.length,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var key = props[index];
+ if (isFunction(object[key])) {
+ result[++resIndex] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.invoke` which requires additional arguments
+ * to be provided as an array of arguments rather than individually.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {Array} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseInvoke(collection, methodName, args) {
+ var index = -1,
+ isFunc = typeof methodName == 'function',
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value) {
+ var func = isFunc ? methodName : (value != null && value[methodName]);
+ result[++index] = func ? func.apply(value, args) : undefined;
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isEqual` without support for `this` binding
+ * `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, customizer, isWhere, stackA, stackB) {
+ // Exit early for identical values.
+ if (value === other) {
+ // Treat `+0` vs. `-0` as not equal.
+ return value !== 0 || (1 / value == 1 / other);
+ }
+ var valType = typeof value,
+ othType = typeof other;
+
+ // Exit early for unlike primitive values.
+ if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') ||
+ value == null || other == null) {
+ // Return `false` unless both values are `NaN`.
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, baseIsEqual, customizer, isWhere, stackA, stackB);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA=[]] Tracks traversed `value` objects.
+ * @param {Array} [stackB=[]] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = arrayTag,
+ othTag = arrayTag;
+
+ if (!objIsArr) {
+ objTag = objToString.call(object);
+ if (objTag == argsTag) {
+ objTag = objectTag;
+ } else if (objTag != objectTag) {
+ objIsArr = isTypedArray(object);
+ }
+ }
+ if (!othIsArr) {
+ othTag = objToString.call(other);
+ if (othTag == argsTag) {
+ othTag = objectTag;
+ } else if (othTag != objectTag) {
+ othIsArr = isTypedArray(other);
+ }
+ }
+ var objIsObj = objTag == objectTag && !isHostObject(object),
+ othIsObj = othTag == objectTag && !isHostObject(other),
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && !(objIsArr || objIsObj)) {
+ return equalByTag(object, other, objTag);
+ }
+ var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (valWrapped || othWrapped) {
+ return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isWhere, stackA, stackB);
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ // Assume cyclic structures are equal.
+ // The algorithm for detecting cyclic structures is adapted from ES 5.1
+ // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3).
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+
+ var length = stackA.length;
+ while (length--) {
+ if (stackA[length] == object) {
+ return stackB[length] == other;
+ }
+ }
+ // Add `object` and `other` to the stack of traversed objects.
+ stackA.push(object);
+ stackB.push(other);
+
+ var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isWhere, stackA, stackB);
+
+ stackA.pop();
+ stackB.pop();
+
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.isMatch` without support for callback
+ * shorthands or `this` binding.
+ *
+ * @private
+ * @param {Object} source The object to inspect.
+ * @param {Array} props The source property names to match.
+ * @param {Array} values The source values to match.
+ * @param {Array} strictCompareFlags Strict comparison flags for source values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ */
+ function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
+ var length = props.length;
+ if (object == null) {
+ return !length;
+ }
+ var index = -1,
+ noCustomizer = !customizer;
+
+ while (++index < length) {
+ if ((noCustomizer && strictCompareFlags[index])
+ ? values[index] !== object[props[index]]
+ : !hasOwnProperty.call(object, props[index])
+ ) {
+ return false;
+ }
+ }
+ index = -1;
+ while (++index < length) {
+ var key = props[index];
+ if (noCustomizer && strictCompareFlags[index]) {
+ var result = hasOwnProperty.call(object, key);
+ } else {
+ var objValue = object[key],
+ srcValue = values[index];
+
+ result = customizer ? customizer(objValue, srcValue, key) : undefined;
+ if (typeof result == 'undefined') {
+ result = baseIsEqual(srcValue, objValue, customizer, true);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.map` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the new mapped array.
+ */
+ function baseMap(collection, iteratee) {
+ var result = [];
+ baseEach(collection, function(value, key, collection) {
+ result.push(iteratee(value, key, collection));
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.matches` which supports specifying whether
+ * `source` should be cloned.
+ *
+ * @private
+ * @param {Object} source The object of property values to match.
+ * @param {boolean} [isCloned] Specify cloning the source object.
+ * @returns {Function} Returns the new function.
+ */
+ function baseMatches(source, isCloned) {
+ var props = keys(source),
+ length = props.length;
+
+ if (length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return function(object) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ };
+ }
+ }
+ if (isCloned) {
+ source = baseClone(source, true);
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = source[props[length]];
+ values[length] = value;
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return function(object) {
+ return baseIsMatch(object, props, values, strictCompareFlags);
+ };
+ }
+
+ /**
+ * The base implementation of `_.merge` without support for argument juggling,
+ * multiple sources, and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {Object} Returns the destination object.
+ */
+ function baseMerge(object, source, customizer, stackA, stackB) {
+ var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
+
+ (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
+ if (isObjectLike(srcValue)) {
+ stackA || (stackA = []);
+ stackB || (stackB = []);
+ return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ }
+ if ((isSrcArr || typeof result != 'undefined') &&
+ (isCommon || (result === result ? result !== value : value === value))) {
+ object[key] = result;
+ }
+ });
+ return object;
+ }
+
+ /**
+ * A specialized version of `baseMerge` for arrays and objects which performs
+ * deep merges and tracks traversed objects enabling objects with circular
+ * references to be merged.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {string} key The key of the value to merge.
+ * @param {Function} mergeFunc The function to merge values.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates values with source counterparts.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
+ var length = stackA.length,
+ srcValue = source[key];
+
+ while (length--) {
+ if (stackA[length] == srcValue) {
+ object[key] = stackB[length];
+ return;
+ }
+ }
+ var value = object[key],
+ result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
+ isCommon = typeof result == 'undefined';
+
+ if (isCommon) {
+ result = srcValue;
+ if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) {
+ result = isArray(value)
+ ? value
+ : (value ? arrayCopy(value) : []);
+ }
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+ result = isArguments(value)
+ ? toPlainObject(value)
+ : (isPlainObject(value) ? value : {});
+ }
+ }
+ // Add the source value to the stack of traversed objects and associate
+ // it with its merged value.
+ stackA.push(srcValue);
+ stackB.push(result);
+
+ if (isCommon) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
+ } else if (result === result ? result !== value : value === value) {
+ object[key] = result;
+ }
+ }
+
+ /**
+ * The base implementation of `_.property` which does not coerce `key` to a string.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * The base implementation of `_.pullAt` without support for individual
+ * index arguments.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {number[]} indexes The indexes of elements to remove.
+ * @returns {Array} Returns the new array of removed elements.
+ */
+ function basePullAt(array, indexes) {
+ var length = indexes.length,
+ result = baseAt(array, indexes);
+
+ indexes.sort(baseCompareAscending);
+ while (length--) {
+ var index = parseFloat(indexes[length]);
+ if (index != previous && isIndex(index)) {
+ var previous = index;
+ splice.call(array, index, 1);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.random` without support for argument juggling
+ * and returning floating-point numbers.
+ *
+ * @private
+ * @param {number} min The minimum possible value.
+ * @param {number} max The maximum possible value.
+ * @returns {number} Returns the random number.
+ */
+ function baseRandom(min, max) {
+ return min + floor(nativeRandom() * (max - min + 1));
+ }
+
+ /**
+ * The base implementation of `_.reduce` and `_.reduceRight` without support
+ * for callback shorthands or `this` binding, which iterates over `collection`
+ * using the provided `eachFunc`.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} accumulator The initial value.
+ * @param {boolean} initFromCollection Specify using the first or last element
+ * of `collection` as the initial value.
+ * @param {Function} eachFunc The function to iterate over `collection`.
+ * @returns {*} Returns the accumulated value.
+ */
+ function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
+ eachFunc(collection, function(value, index, collection) {
+ accumulator = initFromCollection
+ ? (initFromCollection = false, value)
+ : iteratee(accumulator, value, index, collection)
+ });
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `setData` without support for hot loop detection.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var baseSetData = !metaMap ? identity : function(func, data) {
+ metaMap.set(func, data);
+ return func;
+ };
+
+ /**
+ * The base implementation of `_.slice` without an iteratee call guard.
+ *
+ * @private
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function baseSlice(array, start, end) {
+ var index = -1,
+ length = array.length;
+
+ start = start == null ? 0 : (+start || 0);
+ if (start < 0) {
+ start = -start > length ? 0 : (length + start);
+ }
+ end = (typeof end == 'undefined' || end > length) ? length : (+end || 0);
+ if (end < 0) {
+ end += length;
+ }
+ length = start > end ? 0 : (end - start);
+
+ var result = Array(length);
+ while (++index < length) {
+ result[index] = array[index + start];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.some` without support for callback shorthands
+ * or `this` binding.
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function baseSome(collection, predicate) {
+ var result;
+
+ baseEach(collection, function(value, index, collection) {
+ result = predicate(value, index, collection);
+ return !result;
+ });
+ return !!result;
+ }
+
+ /**
+ * The base implementation of `_.uniq` without support for callback shorthands
+ * and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The function invoked per iteration.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ */
+ function baseUniq(array, iteratee) {
+ var index = -1,
+ indexOf = getIndexOf(),
+ length = array.length,
+ isCommon = indexOf == baseIndexOf,
+ isLarge = isCommon && length >= 200,
+ seen = isLarge && createCache(),
+ result = [];
+
+ if (seen) {
+ indexOf = cacheIndexOf;
+ isCommon = false;
+ } else {
+ isLarge = false;
+ seen = iteratee ? [] : result;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value, index, array) : value;
+
+ if (isCommon && value === value) {
+ var seenIndex = seen.length;
+ while (seenIndex--) {
+ if (seen[seenIndex] === computed) {
+ continue outer;
+ }
+ }
+ if (iteratee) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ else if (indexOf(seen, computed) < 0) {
+ if (iteratee || isLarge) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.values` and `_.valuesIn` which creates an
+ * array of `object` property values corresponding to the property names
+ * returned by `keysFunc`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array} props The property names to get values for.
+ * @returns {Object} Returns the array of property values.
+ */
+ function baseValues(object, props) {
+ var index = -1,
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = object[props[index]];
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `wrapperValue` which returns the result of
+ * performing a sequence of actions on the unwrapped `value`, where each
+ * successive action is supplied the return value of the previous.
+ *
+ * @private
+ * @param {*} value The unwrapped value.
+ * @param {Array} actions Actions to peform to resolve the unwrapped value.
+ * @returns {*} Returns the resolved unwrapped value.
+ */
+ function baseWrapperValue(value, actions) {
+ var result = value;
+ if (result instanceof LazyWrapper) {
+ result = result.value();
+ }
+ var index = -1,
+ length = actions.length;
+
+ while (++index < length) {
+ var args = [result],
+ action = actions[index];
+
+ push.apply(args, action.args);
+ result = action.func.apply(action.thisArg, args);
+ }
+ return result;
+ }
+
+ /**
+ * Performs a binary search of `array` to determine the index at which `value`
+ * should be inserted into `array` in order to maintain its sort order.
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndex(array, value, retHighest) {
+ var low = 0,
+ high = array ? array.length : low;
+
+ if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+ while (low < high) {
+ var mid = (low + high) >>> 1,
+ computed = array[mid];
+
+ if (retHighest ? (computed <= value) : (computed < value)) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return high;
+ }
+ return binaryIndexBy(array, value, identity, retHighest);
+ }
+
+ /**
+ * This function is like `binaryIndex` except that it invokes `iteratee` for
+ * `value` and each element of `array` to compute their sort ranking. The
+ * iteratee is invoked with one argument; (value).
+ *
+ * @private
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [retHighest] Specify returning the highest, instead
+ * of the lowest, index at which a value should be inserted into `array`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ */
+ function binaryIndexBy(array, value, iteratee, retHighest) {
+ value = iteratee(value);
+
+ var low = 0,
+ high = array ? array.length : 0,
+ valIsNaN = value !== value,
+ valIsUndef = typeof value == 'undefined';
+
+ while (low < high) {
+ var mid = floor((low + high) / 2),
+ computed = iteratee(array[mid]),
+ isReflexive = computed === computed;
+
+ if (valIsNaN) {
+ var setLow = isReflexive || retHighest;
+ } else if (valIsUndef) {
+ setLow = isReflexive && (retHighest || typeof computed != 'undefined');
+ } else {
+ setLow = retHighest ? (computed <= value) : (computed < value);
+ }
+ if (setLow) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return nativeMin(high, MAX_ARRAY_INDEX);
+ }
+
+ /**
+ * A specialized version of `baseCallback` which only supports `this` binding
+ * and specifying the number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+ function bindCallback(func, thisArg, argCount) {
+ if (typeof func != 'function') {
+ return identity;
+ }
+ if (typeof thisArg == 'undefined') {
+ return func;
+ }
+ switch (argCount) {
+ case 1: return function(value) {
+ return func.call(thisArg, value);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ case 5: return function(value, other, key, object, source) {
+ return func.call(thisArg, value, other, key, object, source);
+ };
+ }
+ return function() {
+ return func.apply(thisArg, arguments);
+ };
+ }
+
+ /**
+ * Creates a clone of the given array buffer.
+ *
+ * @private
+ * @param {ArrayBuffer} buffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+ function bufferClone(buffer) {
+ return bufferSlice.call(buffer, 0);
+ }
+ if (!bufferSlice) {
+ // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`.
+ bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) {
+ var byteLength = buffer.byteLength,
+ floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
+ offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
+ result = new ArrayBuffer(byteLength);
+
+ if (floatLength) {
+ var view = new Float64Array(result, 0, floatLength);
+ view.set(new Float64Array(buffer, 0, floatLength));
+ }
+ if (byteLength != offset) {
+ view = new Uint8Array(result, offset);
+ view.set(new Uint8Array(buffer, offset));
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates an array that is the composition of partially applied arguments,
+ * placeholders, and provided arguments into a single array of arguments.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to prepend to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgs(args, partials, holders) {
+ var holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ leftIndex = -1,
+ leftLength = partials.length,
+ result = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ result[leftIndex] = partials[leftIndex];
+ }
+ while (++argsIndex < holdersLength) {
+ result[holders[argsIndex]] = args[argsIndex];
+ }
+ while (argsLength--) {
+ result[leftIndex++] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * This function is like `composeArgs` except that the arguments composition
+ * is tailored for `_.partialRight`.
+ *
+ * @private
+ * @param {Array|Object} args The provided arguments.
+ * @param {Array} partials The arguments to append to those provided.
+ * @param {Array} holders The `partials` placeholder indexes.
+ * @returns {Array} Returns the new array of composed arguments.
+ */
+ function composeArgsRight(args, partials, holders) {
+ var holdersIndex = -1,
+ holdersLength = holders.length,
+ argsIndex = -1,
+ argsLength = nativeMax(args.length - holdersLength, 0),
+ rightIndex = -1,
+ rightLength = partials.length,
+ result = Array(argsLength + rightLength);
+
+ while (++argsIndex < argsLength) {
+ result[argsIndex] = args[argsIndex];
+ }
+ var pad = argsIndex;
+ while (++rightIndex < rightLength) {
+ result[pad + rightIndex] = partials[rightIndex];
+ }
+ while (++holdersIndex < holdersLength) {
+ result[pad + holders[holdersIndex]] = args[argsIndex++];
+ }
+ return result;
+ }
+
+ /**
+ * Creates a function that aggregates a collection, creating an accumulator
+ * object composed from the results of running each element in the collection
+ * through an iteratee. The `setter` sets the keys and values of the accumulator
+ * object. If `initializer` is provided initializes the accumulator object.
+ *
+ * @private
+ * @param {Function} setter The function to set keys and values of the accumulator object.
+ * @param {Function} [initializer] The function to initialize the accumulator object.
+ * @returns {Function} Returns the new aggregator function.
+ */
+ function createAggregator(setter, initializer) {
+ return function(collection, iteratee, thisArg) {
+ var result = initializer ? initializer() : {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ setter(result, value, iteratee(value, index, collection), collection);
+ }
+ } else {
+ baseEach(collection, function(value, key, collection) {
+ setter(result, value, iteratee(value, key, collection), collection);
+ });
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that assigns properties of source object(s) to a given
+ * destination object.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return function() {
+ var length = arguments.length,
+ object = arguments[0];
+
+ if (length < 2 || object == null) {
+ return object;
+ }
+ if (length > 3 && isIterateeCall(arguments[1], arguments[2], arguments[3])) {
+ length = 2;
+ }
+ // Juggle arguments.
+ if (length > 3 && typeof arguments[length - 2] == 'function') {
+ var customizer = bindCallback(arguments[--length - 1], arguments[length--], 5);
+ } else if (length > 2 && typeof arguments[length - 1] == 'function') {
+ customizer = arguments[--length];
+ }
+ var index = 0;
+ while (++index < length) {
+ var source = arguments[index];
+ if (source) {
+ assigner(object, source, customizer);
+ }
+ }
+ return object;
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the `this`
+ * binding of `thisArg`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createBindWrapper(func, thisArg) {
+ var Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ return (this instanceof wrapper ? Ctor : func).apply(thisArg, arguments);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a `Set` cache object to optimize linear searches of large arrays.
+ *
+ * @private
+ * @param {Array} [values] The values to cache.
+ * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
+ */
+ var createCache = !(nativeCreate && Set) ? constant(null) : function(values) {
+ return new SetCache(values);
+ };
+
+ /**
+ * Creates a function that produces compound words out of the words in a
+ * given string.
+ *
+ * @private
+ * @param {Function} callback The function to combine each word.
+ * @returns {Function} Returns the new compounder function.
+ */
+ function createCompounder(callback) {
+ return function(string) {
+ var index = -1,
+ array = words(deburr(string)),
+ length = array.length,
+ result = '';
+
+ while (++index < length) {
+ result = callback(result, array[index], index);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that produces an instance of `Ctor` regardless of
+ * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+ *
+ * @private
+ * @param {Function} Ctor The constructor to wrap.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createCtorWrapper(Ctor) {
+ return function() {
+ var thisBinding = baseCreate(Ctor.prototype),
+ result = Ctor.apply(thisBinding, arguments);
+
+ // Mimic the constructor's `return` behavior.
+ // See http://es5.github.io/#x13.2.2.
+ return isObject(result) ? result : thisBinding;
+ };
+ }
+
+ /**
+ * Creates a function that gets the extremum value of a collection.
+ *
+ * @private
+ * @param {Function} arrayFunc The function to get the extremum value from an array.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the maximum,
+ * extremum value.
+ * @returns {Function} Returns the new extremum function.
+ */
+ function createExtremum(arrayFunc, isMin) {
+ return function(collection, iteratee, thisArg) {
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ var func = getCallback(),
+ noIteratee = iteratee == null;
+
+ if (!(func === baseCallback && noIteratee)) {
+ noIteratee = false;
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ if (noIteratee) {
+ var isArr = isArray(collection);
+ if (!isArr && isString(collection)) {
+ iteratee = charAtCallback;
+ } else {
+ return arrayFunc(isArr ? collection : toIterable(collection));
+ }
+ }
+ return extremumBy(collection, iteratee, isMin);
+ };
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with optional `this`
+ * binding of, partial application, and currying.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to prepend to those provided to the new function.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
+ * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
+ var isAry = bitmask & ARY_FLAG,
+ isBind = bitmask & BIND_FLAG,
+ isBindKey = bitmask & BIND_KEY_FLAG,
+ isCurry = bitmask & CURRY_FLAG,
+ isCurryBound = bitmask & CURRY_BOUND_FLAG,
+ isCurryRight = bitmask & CURRY_RIGHT_FLAG;
+
+ var Ctor = !isBindKey && createCtorWrapper(func),
+ key = func;
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it to other functions.
+ var length = arguments.length,
+ index = length,
+ args = Array(length);
+
+ while (index--) {
+ args[index] = arguments[index];
+ }
+ if (partials) {
+ args = composeArgs(args, partials, holders);
+ }
+ if (partialsRight) {
+ args = composeArgsRight(args, partialsRight, holdersRight);
+ }
+ if (isCurry || isCurryRight) {
+ var placeholder = wrapper.placeholder,
+ argsHolders = replaceHolders(args, placeholder);
+
+ length -= argsHolders.length;
+ if (length < arity) {
+ var newArgPos = argPos ? arrayCopy(argPos) : null,
+ newArity = nativeMax(arity - length, 0),
+ newsHolders = isCurry ? argsHolders : null,
+ newHoldersRight = isCurry ? null : argsHolders,
+ newPartials = isCurry ? args : null,
+ newPartialsRight = isCurry ? null : args;
+
+ bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
+ bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
+
+ if (!isCurryBound) {
+ bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
+ }
+ var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity);
+ result.placeholder = placeholder;
+ return result;
+ }
+ }
+ var thisBinding = isBind ? thisArg : this;
+ if (isBindKey) {
+ func = thisBinding[key];
+ }
+ if (argPos) {
+ args = reorder(args, argPos);
+ }
+ if (isAry && ary < args.length) {
+ args.length = ary;
+ }
+ return (this instanceof wrapper ? (Ctor || createCtorWrapper(func)) : func).apply(thisBinding, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates the pad required for `string` based on the given padding length.
+ * The `chars` string may be truncated if the number of padding characters
+ * exceeds the padding length.
+ *
+ * @private
+ * @param {string} string The string to create padding for.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the pad for `string`.
+ */
+ function createPad(string, length, chars) {
+ var strLength = string.length;
+ length = +length;
+
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return '';
+ }
+ var padLength = length - strLength;
+ chars = chars == null ? ' ' : baseToString(chars);
+ return repeat(chars, ceil(padLength / chars.length)).slice(0, padLength);
+ }
+
+ /**
+ * Creates a function that wraps `func` and invokes it with the optional `this`
+ * binding of `thisArg` and the `partials` prepended to those provided to
+ * the wrapper.
+ *
+ * @private
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} partials The arguments to prepend to those provided to the new function.
+ * @returns {Function} Returns the new bound function.
+ */
+ function createPartialWrapper(func, bitmask, thisArg, partials) {
+ var isBind = bitmask & BIND_FLAG,
+ Ctor = createCtorWrapper(func);
+
+ function wrapper() {
+ // Avoid `arguments` object use disqualifying optimizations by
+ // converting it to an array before providing it `func`.
+ var argsIndex = -1,
+ argsLength = arguments.length,
+ leftIndex = -1,
+ leftLength = partials.length,
+ args = Array(argsLength + leftLength);
+
+ while (++leftIndex < leftLength) {
+ args[leftIndex] = partials[leftIndex];
+ }
+ while (argsLength--) {
+ args[leftIndex++] = arguments[++argsIndex];
+ }
+ return (this instanceof wrapper ? Ctor : func).apply(isBind ? thisArg : this, args);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Creates a function that either curries or invokes `func` with optional
+ * `this` binding and partially applied arguments.
+ *
+ * @private
+ * @param {Function|string} func The function or method name to reference.
+ * @param {number} bitmask The bitmask of flags.
+ * The bitmask may be composed of the following flags:
+ * 1 - `_.bind`
+ * 2 - `_.bindKey`
+ * 4 - `_.curry` or `_.curryRight` of a bound function
+ * 8 - `_.curry`
+ * 16 - `_.curryRight`
+ * 32 - `_.partial`
+ * 64 - `_.partialRight`
+ * 128 - `_.rearg`
+ * 256 - `_.ary`
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param {Array} [partials] The arguments to be partially applied.
+ * @param {Array} [holders] The `partials` placeholder indexes.
+ * @param {Array} [argPos] The argument positions of the new function.
+ * @param {number} [ary] The arity cap of `func`.
+ * @param {number} [arity] The arity of `func`.
+ * @returns {Function} Returns the new wrapped function.
+ */
+ function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
+ var isBindKey = bitmask & BIND_KEY_FLAG;
+ if (!isBindKey && !isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var length = partials ? partials.length : 0;
+ if (!length) {
+ bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
+ partials = holders = null;
+ }
+ length -= (holders ? holders.length : 0);
+ if (bitmask & PARTIAL_RIGHT_FLAG) {
+ var partialsRight = partials,
+ holdersRight = holders;
+
+ partials = holders = null;
+ }
+ var data = !isBindKey && getData(func),
+ newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
+
+ if (data && data !== true) {
+ mergeData(newData, data);
+ bitmask = newData[1];
+ arity = newData[9];
+ }
+ newData[9] = arity == null
+ ? (isBindKey ? 0 : func.length)
+ : (nativeMax(arity - length, 0) || 0);
+
+ if (bitmask == BIND_FLAG) {
+ var result = createBindWrapper(newData[0], newData[2]);
+ } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
+ result = createPartialWrapper.apply(null, newData);
+ } else {
+ result = createHybridWrapper.apply(null, newData);
+ }
+ var setter = data ? baseSetData : setData;
+ return setter(result, newData);
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing arrays.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var index = -1,
+ arrLength = array.length,
+ othLength = other.length,
+ result = true;
+
+ if (arrLength != othLength && !(isWhere && othLength > arrLength)) {
+ return false;
+ }
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (result && ++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, arrValue, index)
+ : customizer(arrValue, othValue, index);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (isWhere) {
+ var othIndex = othLength;
+ while (othIndex--) {
+ othValue = other[othIndex];
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ if (result) {
+ break;
+ }
+ }
+ } else {
+ result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ }
+ return !!result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} value The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag) {
+ switch (tag) {
+ case boolTag:
+ case dateTag:
+ // Coerce dates and booleans to numbers, dates to milliseconds and booleans
+ // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
+ return +object == +other;
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case numberTag:
+ // Treat `NaN` vs. `NaN` as equal.
+ return (object != +object)
+ ? other != +other
+ // But, treat `-0` vs. `+0` as not equal.
+ : (object == 0 ? ((1 / object) == (1 / other)) : object == +other);
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings (http://es5.github.io/#x15.10.6.4) and
+ // treat strings primitives and string objects as equal.
+ return object == baseToString(other);
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isWhere] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, equalFunc, customizer, isWhere, stackA, stackB) {
+ var objProps = keys(object),
+ objLength = objProps.length,
+ othProps = keys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isWhere) {
+ return false;
+ }
+ var hasCtor,
+ index = -1;
+
+ while (++index < objLength) {
+ var key = objProps[index],
+ result = hasOwnProperty.call(other, key);
+
+ if (result) {
+ var objValue = object[key],
+ othValue = other[key];
+
+ result = undefined;
+ if (customizer) {
+ result = isWhere
+ ? customizer(othValue, objValue, key)
+ : customizer(objValue, othValue, key);
+ }
+ if (typeof result == 'undefined') {
+ // Recursively compare objects (susceptible to call stack limits).
+ result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isWhere, stackA, stackB);
+ }
+ }
+ if (!result) {
+ return false;
+ }
+ hasCtor || (hasCtor = key == 'constructor');
+ }
+ if (!hasCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Gets the extremum value of `collection` invoking `iteratee` for each value
+ * in `collection` to generate the criterion by which the value is ranked.
+ * The `iteratee` is invoked with three arguments; (value, index, collection).
+ *
+ * @private
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {boolean} [isMin] Specify returning the minimum, instead of the
+ * maximum, extremum value.
+ * @returns {*} Returns the extremum value.
+ */
+ function extremumBy(collection, iteratee, isMin) {
+ var exValue = isMin ? POSITIVE_INFINITY : NEGATIVE_INFINITY,
+ computed = exValue,
+ result = computed;
+
+ baseEach(collection, function(value, index, collection) {
+ var current = iteratee(value, index, collection);
+ if ((isMin ? current < computed : current > computed) || (current === exValue && current === result)) {
+ computed = current;
+ result = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Gets the appropriate "callback" function. If the `_.callback` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseCallback` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function} Returns the chosen function or its result.
+ */
+ function getCallback(func, thisArg, argCount) {
+ var result = lodash.callback || callback;
+ result = result === callback ? baseCallback : result;
+ return argCount ? result(func, thisArg, argCount) : result;
+ }
+
+ /**
+ * Gets metadata for `func`.
+ *
+ * @private
+ * @param {Function} func The function to query.
+ * @returns {*} Returns the metadata for `func`.
+ */
+ var getData = !metaMap ? noop : function(func) {
+ return metaMap.get(func);
+ };
+
+ /**
+ * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+ * customized this function returns the custom method, otherwise it returns
+ * the `baseIndexOf` function. If arguments are provided the chosen function
+ * is invoked with them and its result is returned.
+ *
+ * @private
+ * @returns {Function|number} Returns the chosen function or its result.
+ */
+ function getIndexOf(collection, target, fromIndex) {
+ var result = lodash.indexOf || indexOf;
+ result = result === indexOf ? baseIndexOf : result;
+ return collection ? result(collection, target, fromIndex) : result;
+ }
+
+ /**
+ * Gets the view, applying any `transforms` to the `start` and `end` positions.
+ *
+ * @private
+ * @param {number} start The start of the view.
+ * @param {number} end The end of the view.
+ * @param {Array} [transforms] The transformations to apply to the view.
+ * @returns {Object} Returns an object containing the `start` and `end`
+ * positions of the view.
+ */
+ function getView(start, end, transforms) {
+ var index = -1,
+ length = transforms ? transforms.length : 0;
+
+ while (++index < length) {
+ var data = transforms[index],
+ size = data.size;
+
+ switch (data.type) {
+ case 'drop': start += size; break;
+ case 'dropRight': end -= size; break;
+ case 'take': end = nativeMin(end, start + size); break;
+ case 'takeRight': start = nativeMax(start, end - size); break;
+ }
+ }
+ return { 'start': start, 'end': end };
+ }
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = new array.constructor(length);
+
+ // Add array properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ /**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneObject(object) {
+ var Ctor = object.constructor;
+ if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
+ Ctor = Object;
+ }
+ return new Ctor;
+ }
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return bufferClone(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ // Safari 5 mobile incorrectly has `Object` as the constructor of typed arrays.
+ if (Ctor instanceof Ctor) {
+ Ctor = ctorByTag[tag];
+ }
+ var buffer = object.buffer;
+ return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ var result = new Ctor(object.source, reFlags.exec(object));
+ result.lastIndex = object.lastIndex;
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `func` is eligible for `this` binding.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is eligible, else `false`.
+ */
+ function isBindable(func) {
+ var support = lodash.support,
+ result = !(support.funcNames ? func.name : support.funcDecomp);
+
+ if (!result) {
+ var source = fnToString.call(func);
+ if (!support.funcNames) {
+ result = !reFuncName.test(source);
+ }
+ if (!result) {
+ // Check if `func` references the `this` keyword and store the result.
+ result = reThis.test(source) || isNative(func);
+ baseSetData(func, result);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ value = +value;
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return value > -1 && value % 1 == 0 && value < length;
+ }
+
+ /**
+ * Checks if the provided arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number') {
+ var length = object.length,
+ prereq = isLength(length) && isIndex(index, length);
+ } else {
+ prereq = type == 'string' && index in value;
+ }
+ return prereq && object[index] === value;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+ function isLength(value) {
+ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` if suitable for strict
+ * equality comparisons, else `false`.
+ */
+ function isStrictComparable(value) {
+ return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value));
+ }
+
+ /**
+ * Merges the function metadata of `source` into `data`.
+ *
+ * Merging metadata reduces the number of wrappers required to invoke a function.
+ * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+ * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
+ * augment function arguments, making the order in which they are executed important,
+ * preventing the merging of metadata. However, we make an exception for a safe
+ * common case where curried functions have `_.ary` and or `_.rearg` applied.
+ *
+ * @private
+ * @param {Array} data The destination metadata.
+ * @param {Array} source The source metadata.
+ * @returns {Array} Returns `data`.
+ */
+ function mergeData(data, source) {
+ var bitmask = data[1],
+ srcBitmask = source[1],
+ newBitmask = bitmask | srcBitmask;
+
+ var arityFlags = ARY_FLAG | REARG_FLAG,
+ bindFlags = BIND_FLAG | BIND_KEY_FLAG,
+ comboFlags = arityFlags | bindFlags | CURRY_BOUND_FLAG | CURRY_RIGHT_FLAG;
+
+ var isAry = bitmask & ARY_FLAG && !(srcBitmask & ARY_FLAG),
+ isRearg = bitmask & REARG_FLAG && !(srcBitmask & REARG_FLAG),
+ argPos = (isRearg ? data : source)[7],
+ ary = (isAry ? data : source)[8];
+
+ var isCommon = !(bitmask >= REARG_FLAG && srcBitmask > bindFlags) &&
+ !(bitmask > bindFlags && srcBitmask >= REARG_FLAG);
+
+ var isCombo = (newBitmask >= arityFlags && newBitmask <= comboFlags) &&
+ (bitmask < REARG_FLAG || ((isRearg || isAry) && argPos.length <= ary));
+
+ // Exit early if metadata can't be merged.
+ if (!(isCommon || isCombo)) {
+ return data;
+ }
+ // Use source `thisArg` if available.
+ if (srcBitmask & BIND_FLAG) {
+ data[2] = source[2];
+ // Set when currying a bound function.
+ newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
+ }
+ // Compose partial arguments.
+ var value = source[3];
+ if (value) {
+ var partials = data[3];
+ data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
+ data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
+ }
+ // Compose partial right arguments.
+ value = source[5];
+ if (value) {
+ partials = data[5];
+ data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
+ data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
+ }
+ // Use source `argPos` if available.
+ value = source[7];
+ if (value) {
+ data[7] = arrayCopy(value);
+ }
+ // Use source `ary` if it's smaller.
+ if (srcBitmask & ARY_FLAG) {
+ data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
+ }
+ // Use source `arity` if one is not provided.
+ if (data[9] == null) {
+ data[9] = source[9];
+ }
+ // Use source `func` and merge bitmasks.
+ data[0] = source[0];
+ data[1] = newBitmask;
+
+ return data;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties specified
+ * by the `props` array.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {string[]} props The property names to pick.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByArray(object, props) {
+ object = toObject(object);
+
+ var index = -1,
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index];
+ if (key in object) {
+ result[key] = object[key];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `_.pick` that picks `object` properties `predicate`
+ * returns truthy for.
+ *
+ * @private
+ * @param {Object} object The source object.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Object} Returns the new object.
+ */
+ function pickByCallback(object, predicate) {
+ var result = {};
+ baseForIn(object, function(value, key, object) {
+ if (predicate(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Reorder `array` according to the specified indexes where the element at
+ * the first index is assigned as the first element, the element at
+ * the second index is assigned as the second element, and so on.
+ *
+ * @private
+ * @param {Array} array The array to reorder.
+ * @param {Array} indexes The arranged array indexes.
+ * @returns {Array} Returns `array`.
+ */
+ function reorder(array, indexes) {
+ var arrLength = array.length,
+ length = nativeMin(indexes.length, arrLength),
+ oldArray = arrayCopy(array);
+
+ while (length--) {
+ var index = indexes[length];
+ array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
+ }
+ return array;
+ }
+
+ /**
+ * Sets metadata for `func`.
+ *
+ * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+ * period of time, it will trip its breaker and transition to an identity function
+ * to avoid garbage collection pauses in V8. See https://code.google.com/p/v8/issues/detail?id=2070.
+ *
+ * @private
+ * @param {Function} func The function to associate metadata with.
+ * @param {*} data The metadata.
+ * @returns {Function} Returns `func`.
+ */
+ var setData = (function() {
+ var count = 0,
+ lastCalled = 0;
+
+ return function(key, value) {
+ var stamp = now(),
+ remaining = HOT_SPAN - (stamp - lastCalled);
+
+ lastCalled = stamp;
+ if (remaining > 0) {
+ if (++count >= HOT_COUNT) {
+ return key;
+ }
+ } else {
+ count = 0;
+ }
+ return baseSetData(key, value);
+ };
+ }());
+
+ /**
+ * A fallback implementation of `_.isPlainObject` which checks if `value`
+ * is an object created by the `Object` constructor or has a `[[Prototype]]`
+ * of `null`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ */
+ function shimIsPlainObject(value) {
+ var Ctor,
+ support = lodash.support;
+
+ // Exit early for non `Object` objects.
+ if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostObject(value)) ||
+ (!hasOwnProperty.call(value, 'constructor') &&
+ (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor))) ||
+ (!support.argsTag && isArguments(value))) {
+ return false;
+ }
+ // IE < 9 iterates inherited properties before own properties. If the first
+ // iterated property is an object's own property then there are no inherited
+ // enumerable properties.
+ var result;
+ if (support.ownLast) {
+ baseForIn(value, function(subValue, key, object) {
+ result = hasOwnProperty.call(object, key);
+ return false;
+ });
+ return result !== false;
+ }
+ // In most environments an object's own properties are iterated before
+ // its inherited properties. If the last iterated property is an object's
+ // own property then there are no inherited enumerable properties.
+ baseForIn(value, function(subValue, key) {
+ result = key;
+ });
+ return typeof result == 'undefined' || hasOwnProperty.call(value, result);
+ }
+
+ /**
+ * A fallback implementation of `Object.keys` which creates an array of the
+ * own enumerable property names of `object`.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ */
+ function shimKeys(object) {
+ var props = keysIn(object),
+ propsLength = props.length,
+ length = propsLength && object.length,
+ support = lodash.support;
+
+ var allowIndexes = length && isLength(length) &&
+ (isArray(object) || (support.nonEnumStrings && isString(object)) ||
+ (support.nonEnumArgs && isArguments(object)));
+
+ var index = -1,
+ result = [];
+
+ while (++index < propsLength) {
+ var key = props[index];
+ if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `value` to an array-like object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Array|Object} Returns the array-like object.
+ */
+ function toIterable(value) {
+ if (value == null) {
+ return [];
+ }
+ if (!isLength(value.length)) {
+ return values(value);
+ }
+ if (lodash.support.unindexedChars && isString(value)) {
+ return value.split('');
+ }
+ return isObject(value) ? value : Object(value);
+ }
+
+ /**
+ * Converts `value` to an object if it is not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Object} Returns the object.
+ */
+ function toObject(value) {
+ if (lodash.support.unindexedChars && isString(value)) {
+ var index = -1,
+ length = value.length,
+ result = Object(value);
+
+ while (++index < length) {
+ result[index] = value.charAt(index);
+ }
+ return result;
+ }
+ return isObject(value) ? value : Object(value);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements split into groups the length of `size`.
+ * If `collection` can't be split evenly, the final chunk will be the remaining
+ * elements.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to process.
+ * @param {numer} [size=1] The length of each chunk.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new array containing chunks.
+ * @example
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 2);
+ * // => [['a', 'b'], ['c', 'd']]
+ *
+ * _.chunk(['a', 'b', 'c', 'd'], 3);
+ * // => [['a', 'b', 'c'], ['d']]
+ */
+ function chunk(array, size, guard) {
+ if (guard ? isIterateeCall(array, size, guard) : size == null) {
+ size = 1;
+ } else {
+ size = nativeMax(+size || 1, 1);
+ }
+ var index = 0,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = Array(ceil(length / size));
+
+ while (index < length) {
+ result[++resIndex] = baseSlice(array, index, (index += size));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array with all falsey values removed. The values `false`, `null`,
+ * `0`, `""`, `undefined`, and `NaN` are falsey.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to compact.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.compact([0, 1, false, 2, '', 3]);
+ * // => [1, 2, 3]
+ */
+ function compact(array) {
+ var index = -1,
+ length = array ? array.length : 0,
+ resIndex = -1,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (value) {
+ result[++resIndex] = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all values of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {...Array} [values] The arrays of values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.difference([1, 2, 3], [5, 2, 10]);
+ * // => [1, 3]
+ */
+ function difference() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var value = arguments[index];
+ if (isArray(value) || isArguments(value)) {
+ break;
+ }
+ }
+ return baseDifference(value, baseFlatten(arguments, false, true, ++index));
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.drop([1, 2, 3]);
+ * // => [2, 3]
+ *
+ * _.drop([1, 2, 3], 2);
+ * // => [3]
+ *
+ * _.drop([1, 2, 3], 5);
+ * // => []
+ *
+ * _.drop([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function drop(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements dropped from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to drop.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRight([1, 2, 3]);
+ * // => [1, 2]
+ *
+ * _.dropRight([1, 2, 3], 2);
+ * // => [1]
+ *
+ * _.dropRight([1, 2, 3], 5);
+ * // => []
+ *
+ * _.dropRight([1, 2, 3], 0);
+ * // => [1, 2, 3]
+ */
+ function dropRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the end.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [1]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropRightWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function dropRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, 0, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` excluding elements dropped from the beginning.
+ * Elements are dropped until `predicate` returns falsey. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.dropWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.dropWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.dropWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['pebbles']
+ */
+ function dropWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, index);
+ }
+
+ /**
+ * This method is like `_.find` except that it returns the index of the first
+ * element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findIndex(users, function(chr) { return chr.age < 40; });
+ * // => 0
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findIndex(users, { 'age': 1 });
+ * // => 2
+ *
+ * // using the "_.property" callback shorthand
+ * _.findIndex(users, 'active');
+ * // => 1
+ */
+ function findIndex(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it iterates over elements
+ * of `collection` from right to left.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {number} Returns the index of the found element, else `-1`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': true },
+ * { 'user': 'fred', 'age': 40, 'active': false },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.findLastIndex(users, function(chr) { return chr.age < 40; });
+ * // => 2
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastIndex(users, { 'age': 40 });
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastIndex(users, 'active');
+ * // => 0
+ */
+ function findLastIndex(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length--) {
+ if (predicate(array[length], length, array)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Gets the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias head
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the first element of `array`.
+ * @example
+ *
+ * _.first([1, 2, 3]);
+ * // => 1
+ *
+ * _.first([]);
+ * // => undefined
+ */
+ function first(array) {
+ return array ? array[0] : undefined;
+ }
+
+ /**
+ * Flattens a nested array. If `isDeep` is `true` the array is recursively
+ * flattened, otherwise it is only flattened a single level.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to flatten.
+ * @param {boolean} [isDeep] Specify a deep flatten.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flatten([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, [[4]]];
+ *
+ * // using `isDeep`
+ * _.flatten([1, [2], [3, [[4]]]], true);
+ * // => [1, 2, 3, 4];
+ */
+ function flatten(array, isDeep, guard) {
+ var length = array ? array.length : 0;
+ if (guard && isIterateeCall(array, isDeep, guard)) {
+ isDeep = false;
+ }
+ return length ? baseFlatten(array, isDeep) : [];
+ }
+
+ /**
+ * Recursively flattens a nested array.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to recursively flatten.
+ * @returns {Array} Returns the new flattened array.
+ * @example
+ *
+ * _.flattenDeep([1, [2], [3, [[4]]]]);
+ * // => [1, 2, 3, 4];
+ */
+ function flattenDeep(array) {
+ var length = array ? array.length : 0;
+ return length ? baseFlatten(array, true) : [];
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found in `array`
+ * using `SameValueZero` for equality comparisons. If `fromIndex` is negative,
+ * it is used as the offset from the end of `array`. If `array` is sorted
+ * providing `true` for `fromIndex` performs a faster binary search.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=0] The index to search from or `true`
+ * to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 1
+ *
+ * // using `fromIndex`
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 4
+ *
+ * // performing a binary search
+ * _.indexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 2
+ */
+ function indexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else if (fromIndex) {
+ var index = binaryIndex(array, value),
+ other = array[index];
+
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ return baseIndexOf(array, value, fromIndex);
+ }
+
+ /**
+ * Gets all but the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.initial([1, 2, 3]);
+ * // => [1, 2]
+ */
+ function initial(array) {
+ return dropRight(array, 1);
+ }
+
+ /**
+ * Creates an array of unique values in all provided arrays using `SameValueZero`
+ * for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of shared values.
+ * @example
+ *
+ * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2]
+ */
+ function intersection() {
+ var args = [],
+ argsIndex = -1,
+ argsLength = arguments.length,
+ caches = [],
+ indexOf = getIndexOf(),
+ isCommon = indexOf == baseIndexOf;
+
+ while (++argsIndex < argsLength) {
+ var value = arguments[argsIndex];
+ if (isArray(value) || isArguments(value)) {
+ args.push(value);
+ caches.push(isCommon && value.length >= 120 && createCache(argsIndex && value));
+ }
+ }
+ argsLength = args.length;
+ var array = args[0],
+ index = -1,
+ length = array ? array.length : 0,
+ result = [],
+ seen = caches[0];
+
+ outer:
+ while (++index < length) {
+ value = array[index];
+ if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value)) < 0) {
+ argsIndex = argsLength;
+ while (--argsIndex) {
+ var cache = caches[argsIndex];
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
+ continue outer;
+ }
+ }
+ if (seen) {
+ seen.push(value);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the last element of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ */
+ function last(array) {
+ var length = array ? array.length : 0;
+ return length ? array[length - 1] : undefined;
+ }
+
+ /**
+ * This method is like `_.indexOf` except that it iterates over elements of
+ * `array` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @param {boolean|number} [fromIndex=array.length-1] The index to search from
+ * or `true` to perform a binary search on a sorted array.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ * @example
+ *
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+ * // => 4
+ *
+ * // using `fromIndex`
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 1
+ *
+ * // performing a binary search
+ * _.lastIndexOf([4, 4, 5, 5, 6, 6], 5, true);
+ * // => 3
+ */
+ function lastIndexOf(array, value, fromIndex) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return -1;
+ }
+ var index = length;
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1;
+ } else if (fromIndex) {
+ index = binaryIndex(array, value, true) - 1;
+ var other = array[index];
+ return (value === value ? value === other : other !== other) ? index : -1;
+ }
+ if (value !== value) {
+ return indexOfNaN(array, index, true);
+ }
+ while (index--) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Removes all provided values from `array` using `SameValueZero` for equality
+ * comparisons.
+ *
+ * **Notes:**
+ * - Unlike `_.without`, this method mutates `array`.
+ * - `SameValueZero` comparisons are like strict equality comparisons, e.g. `===`,
+ * except that `NaN` matches `NaN`. See the [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...*} [values] The values to remove.
+ * @returns {Array} Returns `array`.
+ * @example
+ *
+ * var array = [1, 2, 3, 1, 2, 3];
+ * _.pull(array, 2, 3);
+ * console.log(array);
+ * // => [1, 1]
+ */
+ function pull() {
+ var array = arguments[0];
+ if (!(array && array.length)) {
+ return array;
+ }
+ var index = 0,
+ indexOf = getIndexOf(),
+ length = arguments.length;
+
+ while (++index < length) {
+ var fromIndex = 0,
+ value = arguments[index];
+
+ while ((fromIndex = indexOf(array, value, fromIndex)) > -1) {
+ splice.call(array, fromIndex, 1);
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Removes elements from `array` corresponding to the given indexes and returns
+ * an array of the removed elements. Indexes may be specified as an array of
+ * indexes or as individual arguments.
+ *
+ * **Note:** Unlike `_.at`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {...(number|number[])} [indexes] The indexes of elements to remove,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [5, 10, 15, 20];
+ * var evens = _.pullAt(array, [1, 3]);
+ *
+ * console.log(array);
+ * // => [5, 15]
+ *
+ * console.log(evens);
+ * // => [10, 20]
+ */
+ function pullAt(array) {
+ return basePullAt(array || [], baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Removes all elements from `array` that `predicate` returns truthy for
+ * and returns an array of the removed elements. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** Unlike `_.filter`, this method mutates `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to modify.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new array of removed elements.
+ * @example
+ *
+ * var array = [1, 2, 3, 4];
+ * var evens = _.remove(array, function(n) { return n % 2 == 0; });
+ *
+ * console.log(array);
+ * // => [1, 3]
+ *
+ * console.log(evens);
+ * // => [2, 4]
+ */
+ function remove(array, predicate, thisArg) {
+ var index = -1,
+ length = array ? array.length : 0,
+ result = [];
+
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result.push(value);
+ splice.call(array, index--, 1);
+ length--;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets all but the first element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @alias tail
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.rest([1, 2, 3]);
+ * // => [2, 3]
+ */
+ function rest(array) {
+ return drop(array, 1);
+ }
+
+ /**
+ * Creates a slice of `array` from `start` up to, but not including, `end`.
+ *
+ * **Note:** This function is used instead of `Array#slice` to support node
+ * lists in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to slice.
+ * @param {number} [start=0] The start position.
+ * @param {number} [end=array.length] The end position.
+ * @returns {Array} Returns the slice of `array`.
+ */
+ function slice(array, start, end) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
+ start = 0;
+ end = length;
+ }
+ return baseSlice(array, start, end);
+ }
+
+ /**
+ * Uses a binary search to determine the lowest index at which `value` should
+ * be inserted into `array` in order to maintain its sort order. If an iteratee
+ * function is provided it is invoked for `value` and each element of `array`
+ * to compute their sort ranking. The iteratee is bound to `thisArg` and
+ * invoked with one argument; (value).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedIndex([30, 50], 40);
+ * // => 1
+ *
+ * _.sortedIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 2
+ *
+ * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } };
+ *
+ * // using an iteratee function
+ * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) {
+ * return this.data[word];
+ * }, dict);
+ * // => 1
+ *
+ * // using the "_.property" callback shorthand
+ * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
+ * // => 1
+ */
+ function sortedIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1));
+ }
+
+ /**
+ * This method is like `_.sortedIndex` except that it returns the highest
+ * index at which `value` should be inserted into `array` in order to
+ * maintain its sort order.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The sorted array to inspect.
+ * @param {*} value The value to evaluate.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {number} Returns the index at which `value` should be inserted
+ * into `array`.
+ * @example
+ *
+ * _.sortedLastIndex([4, 4, 5, 5, 6, 6], 5);
+ * // => 4
+ */
+ function sortedLastIndex(array, value, iteratee, thisArg) {
+ var func = getCallback(iteratee);
+ return (func === baseCallback && iteratee == null)
+ ? binaryIndex(array, value, true)
+ : binaryIndexBy(array, value, func(iteratee, thisArg, 1), true);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the beginning.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.take([1, 2, 3]);
+ * // => [1]
+ *
+ * _.take([1, 2, 3], 2);
+ * // => [1, 2]
+ *
+ * _.take([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.take([1, 2, 3], 0);
+ * // => []
+ */
+ function take(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ return baseSlice(array, 0, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with `n` elements taken from the end.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {number} [n=1] The number of elements to take.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRight([1, 2, 3]);
+ * // => [3]
+ *
+ * _.takeRight([1, 2, 3], 2);
+ * // => [2, 3]
+ *
+ * _.takeRight([1, 2, 3], 5);
+ * // => [1, 2, 3]
+ *
+ * _.takeRight([1, 2, 3], 0);
+ * // => []
+ */
+ function takeRight(array, n, guard) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ if (guard ? isIterateeCall(array, n, guard) : n == null) {
+ n = 1;
+ }
+ n = length - (+n || 0);
+ return baseSlice(array, n < 0 ? 0 : n);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the end. Elements are
+ * taken until `predicate` returns falsey. The predicate is bound to `thisArg`
+ * and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeRightWhile([1, 2, 3], function(n) { return n > 1; });
+ * // => [2, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': false },
+ * { 'user': 'fred', 'status': 'busy', 'active': true },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeRightWhile(users, 'active'), 'user');
+ * // => ['fred', 'pebbles']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeRightWhile(users, { 'status': 'away' }), 'user');
+ * // => ['pebbles']
+ */
+ function takeRightWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ while (length-- && predicate(array[length], length, array)) {}
+ return baseSlice(array, length + 1);
+ }
+
+ /**
+ * Creates a slice of `array` with elements taken from the beginning. Elements
+ * are taken until `predicate` returns falsey. The predicate is bound to
+ * `thisArg` and invoked with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Array
+ * @param {Array} array The array to query.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per element.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the slice of `array`.
+ * @example
+ *
+ * _.takeWhile([1, 2, 3], function(n) { return n < 3; });
+ * // => [1, 2]
+ *
+ * var users = [
+ * { 'user': 'barney', 'status': 'busy', 'active': true },
+ * { 'user': 'fred', 'status': 'busy', 'active': false },
+ * { 'user': 'pebbles', 'status': 'away', 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.takeWhile(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.takeWhile(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function takeWhile(array, predicate, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ var index = -1;
+ predicate = getCallback(predicate, thisArg, 3);
+ while (++index < length && predicate(array[index], index, array)) {}
+ return baseSlice(array, 0, index);
+ }
+
+ /**
+ * Creates an array of unique values, in order, of the provided arrays using
+ * `SameValueZero` for equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of combined values.
+ * @example
+ *
+ * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+ * // => [1, 2, 3, 5, 4]
+ */
+ function union() {
+ return baseUniq(baseFlatten(arguments, false, true));
+ }
+
+ /**
+ * Creates a duplicate-value-free version of an array using `SameValueZero`
+ * for equality comparisons. Providing `true` for `isSorted` performs a faster
+ * search algorithm for sorted arrays. If an iteratee function is provided it
+ * is invoked for each value in the array to generate the criterion by which
+ * uniqueness is computed. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, index, array).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias unique
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {boolean} [isSorted] Specify the array is sorted.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new duplicate-value-free array.
+ * @example
+ *
+ * _.uniq([1, 2, 1]);
+ * // => [1, 2]
+ *
+ * // using `isSorted`
+ * _.uniq([1, 1, 2], true);
+ * // => [1, 2]
+ *
+ * // using an iteratee function
+ * _.uniq([1, 2.5, 1.5, 2], function(n) { return this.floor(n); }, Math);
+ * // => [1, 2.5]
+ *
+ * // using the "_.property" callback shorthand
+ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniq(array, isSorted, iteratee, thisArg) {
+ var length = array ? array.length : 0;
+ if (!length) {
+ return [];
+ }
+ // Juggle arguments.
+ if (typeof isSorted != 'boolean' && isSorted != null) {
+ thisArg = iteratee;
+ iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted;
+ isSorted = false;
+ }
+ var func = getCallback();
+ if (!(func === baseCallback && iteratee == null)) {
+ iteratee = func(iteratee, thisArg, 3);
+ }
+ return (isSorted && getIndexOf() == baseIndexOf)
+ ? sortedUniq(array, iteratee)
+ : baseUniq(array, iteratee);
+ }
+
+ /**
+ * This method is like `_.zip` except that it accepts an array of grouped
+ * elements and creates an array regrouping the elements to their pre `_.zip`
+ * configuration.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array of grouped elements to process.
+ * @returns {Array} Returns the new array of regrouped elements.
+ * @example
+ *
+ * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ *
+ * _.unzip(zipped);
+ * // => [['fred', 'barney'], [30, 40], [true, false]]
+ */
+ function unzip(array) {
+ var index = -1,
+ length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = arrayMap(array, baseProperty(index));
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array excluding all provided values using `SameValueZero` for
+ * equality comparisons.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to filter.
+ * @param {...*} [values] The values to exclude.
+ * @returns {Array} Returns the new array of filtered values.
+ * @example
+ *
+ * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+ * // => [2, 3, 4]
+ */
+ function without(array) {
+ return baseDifference(array, baseSlice(arguments, 1));
+ }
+
+ /**
+ * Creates an array that is the symmetric difference of the provided arrays.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Symmetric_difference) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to inspect.
+ * @returns {Array} Returns the new array of values.
+ * @example
+ *
+ * _.xor([1, 2, 3], [5, 2, 1, 4]);
+ * // => [3, 5, 4]
+ *
+ * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+ * // => [1, 4, 5]
+ */
+ function xor() {
+ var index = -1,
+ length = arguments.length;
+
+ while (++index < length) {
+ var array = arguments[index];
+ if (isArray(array) || isArguments(array)) {
+ var result = result
+ ? baseDifference(result, array).concat(baseDifference(array, result))
+ : array;
+ }
+ }
+ return result ? baseUniq(result) : [];
+ }
+
+ /**
+ * Creates an array of grouped elements, the first of which contains the first
+ * elements of the given arrays, the second of which contains the second elements
+ * of the given arrays, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {...Array} [arrays] The arrays to process.
+ * @returns {Array} Returns the new array of grouped elements.
+ * @example
+ *
+ * _.zip(['fred', 'barney'], [30, 40], [true, false]);
+ * // => [['fred', 30, true], ['barney', 40, false]]
+ */
+ function zip() {
+ var length = arguments.length,
+ array = Array(length);
+
+ while (length--) {
+ array[length] = arguments[length];
+ }
+ return unzip(array);
+ }
+
+ /**
+ * Creates an object composed from arrays of property names and values. Provide
+ * either a single two dimensional array, e.g. `[[key1, value1], [key2, value2]]`
+ * or two arrays, one of property names and one of corresponding values.
+ *
+ * @static
+ * @memberOf _
+ * @alias object
+ * @category Array
+ * @param {Array} props The property names.
+ * @param {Array} [values=[]] The property values.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * _.zipObject(['fred', 'barney'], [30, 40]);
+ * // => { 'fred': 30, 'barney': 40 }
+ */
+ function zipObject(props, values) {
+ var index = -1,
+ length = props ? props.length : 0,
+ result = {};
+
+ if (length && !values && !isArray(props[0])) {
+ values = [];
+ }
+ while (++index < length) {
+ var key = props[index];
+ if (values) {
+ result[key] = values[index];
+ } else if (key) {
+ result[key[0]] = key[1];
+ }
+ }
+ return result;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a `lodash` object that wraps `value` with explicit method
+ * chaining enabled.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to wrap.
+ * @returns {Object} Returns the new `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'pebbles', 'age': 1 }
+ * ];
+ *
+ * var youngest = _.chain(users)
+ * .sortBy('age')
+ * .map(function(chr) { return chr.user + ' is ' + chr.age; })
+ * .first()
+ * .value();
+ * // => 'pebbles is 1'
+ */
+ function chain(value) {
+ var result = lodash(value);
+ result.__chain__ = true;
+ return result;
+ }
+
+ /**
+ * This method invokes `interceptor` and returns `value`. The interceptor is
+ * bound to `thisArg` and invoked with one argument; (value). The purpose of
+ * this method is to "tap into" a method chain in order to perform operations
+ * on intermediate results within the chain.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .tap(function(array) { array.pop(); })
+ * .reverse()
+ * .value();
+ * // => [2, 1]
+ */
+ function tap(value, interceptor, thisArg) {
+ interceptor.call(thisArg, value);
+ return value;
+ }
+
+ /**
+ * This method is like `_.tap` except that it returns the result of `interceptor`.
+ *
+ * @static
+ * @memberOf _
+ * @category Chain
+ * @param {*} value The value to provide to `interceptor`.
+ * @param {Function} interceptor The function to invoke.
+ * @param {*} [thisArg] The `this` binding of `interceptor`.
+ * @returns {*} Returns the result of `interceptor`.
+ * @example
+ *
+ * _([1, 2, 3])
+ * .last()
+ * .thru(function(value) { return [value]; })
+ * .value();
+ * // => [3]
+ */
+ function thru(value, interceptor, thisArg) {
+ return interceptor.call(thisArg, value);
+ }
+
+ /**
+ * Enables explicit method chaining on the wrapper object.
+ *
+ * @name chain
+ * @memberOf _
+ * @category Chain
+ * @returns {*} Returns the `lodash` object.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // without explicit chaining
+ * _(users).first();
+ * // => { 'user': 'barney', 'age': 36 }
+ *
+ * // with explicit chaining
+ * _(users).chain()
+ * .first()
+ * .pick('user')
+ * .value();
+ * // => { 'user': 'barney' }
+ */
+ function wrapperChain() {
+ return chain(this);
+ }
+
+ /**
+ * Reverses the wrapped array so the first element becomes the last, the
+ * second element becomes the second to last, and so on.
+ *
+ * **Note:** This method mutates the wrapped array.
+ *
+ * @name reverse
+ * @memberOf _
+ * @category Chain
+ * @returns {Object} Returns the new reversed `lodash` object.
+ * @example
+ *
+ * var array = [1, 2, 3];
+ *
+ * _(array).reverse().value()
+ * // => [3, 2, 1]
+ *
+ * console.log(array);
+ * // => [3, 2, 1]
+ */
+ function wrapperReverse() {
+ var value = this.__wrapped__;
+ if (value instanceof LazyWrapper) {
+ return new LodashWrapper(value.reverse());
+ }
+ return this.thru(function(value) {
+ return value.reverse();
+ });
+ }
+
+ /**
+ * Produces the result of coercing the unwrapped value to a string.
+ *
+ * @name toString
+ * @memberOf _
+ * @category Chain
+ * @returns {string} Returns the coerced string value.
+ * @example
+ *
+ * _([1, 2, 3]).toString();
+ * // => '1,2,3'
+ */
+ function wrapperToString() {
+ return (this.value() + '');
+ }
+
+ /**
+ * Executes the chained sequence to extract the unwrapped value.
+ *
+ * @name value
+ * @memberOf _
+ * @alias toJSON, valueOf
+ * @category Chain
+ * @returns {*} Returns the resolved unwrapped value.
+ * @example
+ *
+ * _([1, 2, 3]).value();
+ * // => [1, 2, 3]
+ */
+ function wrapperValue() {
+ return baseWrapperValue(this.__wrapped__, this.__actions__);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates an array of elements corresponding to the given keys, or indexes,
+ * of `collection`. Keys may be specified as individual arguments or as arrays
+ * of keys.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(number|number[]|string|string[])} [props] The property names
+ * or indexes of elements to pick, specified individually or in arrays.
+ * @returns {Array} Returns the new array of picked elements.
+ * @example
+ *
+ * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
+ * // => ['a', 'c', 'e']
+ *
+ * _.at(['fred', 'barney', 'pebbles'], 0, 2);
+ * // => ['fred', 'pebbles']
+ */
+ function at(collection) {
+ var length = collection ? collection.length : 0;
+ if (isLength(length)) {
+ collection = toIterable(collection);
+ }
+ return baseAt(collection, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Checks if `value` is in `collection` using `SameValueZero` for equality
+ * comparisons. If `fromIndex` is negative, it is used as the offset from
+ * the end of `collection`.
+ *
+ * **Note:** `SameValueZero` comparisons are like strict equality comparisons,
+ * e.g. `===`, except that `NaN` matches `NaN`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @alias contains, include
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {*} target The value to search for.
+ * @param {number} [fromIndex=0] The index to search from.
+ * @returns {boolean} Returns `true` if a matching element is found, else `false`.
+ * @example
+ *
+ * _.includes([1, 2, 3], 1);
+ * // => true
+ *
+ * _.includes([1, 2, 3], 1, 2);
+ * // => false
+ *
+ * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
+ * // => true
+ *
+ * _.includes('pebbles', 'eb');
+ * // => true
+ */
+ function includes(collection, target, fromIndex) {
+ var length = collection ? collection.length : 0;
+ if (!isLength(length)) {
+ collection = values(collection);
+ length = collection.length;
+ }
+ if (!length) {
+ return false;
+ }
+ if (typeof fromIndex == 'number') {
+ fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
+ } else {
+ fromIndex = 0;
+ }
+ return (typeof collection == 'string' || !isArray(collection) && isString(collection))
+ ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
+ : (getIndexOf(collection, target, fromIndex) > -1);
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the number of times the key was returned by `iteratee`.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy([4.3, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': 1, '6': 2 }
+ *
+ * _.countBy(['one', 'two', 'three'], 'length');
+ * // => { '3': 2, '5': 1 }
+ */
+ var countBy = createAggregator(function(result, value, key) {
+ hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1);
+ });
+
+ /**
+ * Checks if `predicate` returns truthy for **all** elements of `collection`.
+ * The predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias all
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if all elements pass the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.every([true, 1, null, 'yes']);
+ * // => false
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.every(users, 'age');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.every(users, { 'age': 36 });
+ * // => false
+ */
+ function every(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayEvery : baseEvery;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning an array of all elements
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias select
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var evens = _.filter([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [2, 4]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.filter(users, 'active'), 'user');
+ * // => ['fred']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.filter(users, { 'age': 36 }), 'user');
+ * // => ['barney']
+ */
+ function filter(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, predicate);
+ }
+
+ /**
+ * Iterates over elements of `collection`, returning the first element
+ * `predicate` returns truthy for. The predicate is bound to `thisArg` and
+ * invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias detect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * _.result(_.find(users, function(chr) { return chr.age < 40; }), 'user');
+ * // => 'barney'
+ *
+ * // using the "_.matches" callback shorthand
+ * _.result(_.find(users, { 'age': 1 }), 'user');
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.result(_.find(users, 'active'), 'user');
+ * // => 'fred'
+ */
+ function find(collection, predicate, thisArg) {
+ if (isArray(collection)) {
+ var index = findIndex(collection, predicate, thisArg);
+ return index > -1 ? collection[index] : undefined;
+ }
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEach);
+ }
+
+ /**
+ * This method is like `_.find` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * _.findLast([1, 2, 3, 4], function(n) { return n % 2 == 1; });
+ * // => 3
+ */
+ function findLast(collection, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(collection, predicate, baseEachRight);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning the first element that has equivalent property
+ * values.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {*} Returns the matched element, else `undefined`.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy' },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy' }
+ * ];
+ *
+ * _.result(_.findWhere(users, { 'status': 'busy' }), 'user');
+ * // => 'barney'
+ *
+ * _.result(_.findWhere(users, { 'age': 40 }), 'user');
+ * // => 'fred'
+ */
+ function findWhere(collection, source) {
+ return find(collection, matches(source));
+ }
+
+ /**
+ * Iterates over elements of `collection` invoking `iteratee` for each element.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection). Iterator functions may exit iteration early
+ * by explicitly returning `false`.
+ *
+ * **Note:** As with other "Collections" methods, objects with a `length` property
+ * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+ * may be used for object iteration.
+ *
+ * @static
+ * @memberOf _
+ * @alias each
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEach(function(n) { console.log(n); });
+ * // => logs each value from left to right and returns the array
+ *
+ * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(n, key) { console.log(n, key); });
+ * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
+ */
+ function forEach(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEach(collection, iteratee)
+ : baseEach(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * This method is like `_.forEach` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias eachRight
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array|Object|string} Returns `collection`.
+ * @example
+ *
+ * _([1, 2, 3]).forEachRight(function(n) { console.log(n); }).join(',');
+ * // => logs each value from right to left and returns the array
+ */
+ function forEachRight(collection, iteratee, thisArg) {
+ return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
+ ? arrayEachRight(collection, iteratee)
+ : baseEachRight(collection, bindCallback(iteratee, thisArg, 3));
+ }
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is an array of the elements responsible for generating the key.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return Math.floor(n); });
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * _.groupBy([4.2, 6.1, 6.4], function(n) { return this.floor(n); }, Math);
+ * // => { '4': [4.2], '6': [6.1, 6.4] }
+ *
+ * // using the "_.property" callback shorthand
+ * _.groupBy(['one', 'two', 'three'], 'length');
+ * // => { '3': ['one', 'two'], '5': ['three'] }
+ */
+ var groupBy = createAggregator(function(result, value, key) {
+ if (hasOwnProperty.call(result, key)) {
+ result[key].push(value);
+ } else {
+ result[key] = [value];
+ }
+ });
+
+ /**
+ * Creates an object composed of keys generated from the results of running
+ * each element of `collection` through `iteratee`. The corresponding value
+ * of each key is the last element responsible for generating the key. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the composed aggregate object.
+ * @example
+ *
+ * var keyData = [
+ * { 'dir': 'left', 'code': 97 },
+ * { 'dir': 'right', 'code': 100 }
+ * ];
+ *
+ * _.indexBy(keyData, 'dir');
+ * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) { return String.fromCharCode(object.code); });
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ *
+ * _.indexBy(keyData, function(object) { return this.fromCharCode(object.code); }, String);
+ * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+ */
+ var indexBy = createAggregator(function(result, value, key) {
+ result[key] = value;
+ });
+
+ /**
+ * Invokes the method named by `methodName` on each element in `collection`,
+ * returning an array of the results of each invoked method. Any additional
+ * arguments are provided to each invoked method. If `methodName` is a function
+ * it is invoked for, and `this` bound to, each element in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|string} methodName The name of the method to invoke or
+ * the function invoked per iteration.
+ * @param {...*} [args] The arguments to invoke the method with.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+ * // => [[1, 5, 7], [1, 2, 3]]
+ *
+ * _.invoke([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
+ */
+ function invoke(collection, methodName) {
+ return baseInvoke(collection, methodName, baseSlice(arguments, 2));
+ }
+
+ /**
+ * Creates an array of values by running each element in `collection` through
+ * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias collect
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new mapped array.
+ * @example
+ *
+ * _.map([1, 2, 3], function(n) { return n * 3; });
+ * // => [3, 6, 9]
+ *
+ * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(n) { return n * 3; });
+ * // => [3, 6, 9] (iteration order is not guaranteed)
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(users, 'user');
+ * // => ['barney', 'fred']
+ */
+ function map(collection, iteratee, thisArg) {
+ var func = isArray(collection) ? arrayMap : baseMap;
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return func(collection, iteratee);
+ }
+
+ /**
+ * Gets the maximum value of `collection`. If `collection` is empty or falsey
+ * `-Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the maximum value.
+ * @example
+ *
+ * _.max([4, 2, 8, 6]);
+ * // => 8
+ *
+ * _.max([]);
+ * // => -Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.max(users, function(chr) { return chr.age; });
+ * // => { 'user': 'fred', 'age': 40 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.max(users, 'age');
+ * // => { 'user': 'fred', 'age': 40 };
+ */
+ var max = createExtremum(arrayMax);
+
+ /**
+ * Gets the minimum value of `collection`. If `collection` is empty or falsey
+ * `Infinity` is returned. If an iteratee function is provided it is invoked
+ * for each value in `collection` to generate the criterion by which the value
+ * is ranked. The `iteratee` is bound to `thisArg` and invoked with three
+ * arguments; (value, index, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [iteratee] The function invoked per iteration.
+ * If a property name or object is provided it is used to create a "_.property"
+ * or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the minimum value.
+ * @example
+ *
+ * _.min([4, 2, 8, 6]);
+ * // => 2
+ *
+ * _.min([]);
+ * // => Infinity
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.min(users, function(chr) { return chr.age; });
+ * // => { 'user': 'barney', 'age': 36 };
+ *
+ * // using the "_.property" callback shorthand
+ * _.min(users, 'age');
+ * // => { 'user': 'barney', 'age': 36 };
+ */
+ var min = createExtremum(arrayMin, true);
+
+ /**
+ * Creates an array of elements split into two groups, the first of which
+ * contains elements `predicate` returns truthy for, while the second of which
+ * contains elements `predicate` returns falsey for. The predicate is bound
+ * to `thisArg` and invoked with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the array of grouped elements.
+ * @example
+ *
+ * _.partition([1, 2, 3], function(n) { return n % 2; });
+ * // => [[1, 3], [2]]
+ *
+ * _.partition([1.2, 2.3, 3.4], function(n) { return this.floor(n) % 2; }, Math);
+ * // => [[1, 3], [2]]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true },
+ * { 'user': 'pebbles', 'age': 1, 'active': false }
+ * ];
+ *
+ * // using the "_.matches" callback shorthand
+ * _.map(_.partition(users, { 'age': 1 }), function(array) { return _.pluck(array, 'user'); });
+ * // => [['pebbles'], ['barney', 'fred']]
+ *
+ * // using the "_.property" callback shorthand
+ * _.map(_.partition(users, 'active'), function(array) { return _.pluck(array, 'user'); });
+ * // => [['fred'], ['barney', 'pebbles']]
+ */
+ var partition = createAggregator(function(result, value, key) {
+ result[key ? 0 : 1].push(value);
+ }, function() { return [[], []]; });
+
+ /**
+ * Gets the value of `key` from all elements in `collection`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {string} key The key of the property to pluck.
+ * @returns {Array} Returns the property values.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * _.pluck(users, 'user');
+ * // => ['barney', 'fred']
+ *
+ * var userIndex = _.indexBy(users, 'user');
+ * _.pluck(userIndex, 'age');
+ * // => [36, 40] (iteration order is not guaranteed)
+ */
+ function pluck(collection, key) {
+ return map(collection, property(key));
+ }
+
+ /**
+ * Reduces `collection` to a value which is the accumulated result of running
+ * each element in `collection` through `iteratee`, where each successive
+ * invocation is supplied the return value of the previous. If `accumulator`
+ * is not provided the first element of `collection` is used as the initial
+ * value. The `iteratee` is bound to `thisArg`and invoked with four arguments;
+ * (accumulator, value, index|key, collection).
+ *
+ * @static
+ * @memberOf _
+ * @alias foldl, inject
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var sum = _.reduce([1, 2, 3], function(sum, n) { return sum + n; });
+ * // => 6
+ *
+ * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * return result;
+ * }, {});
+ * // => { 'a': 3, 'b': 6, 'c': 9 } (iteration order is not guaranteed)
+ */
+ function reduce(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduce : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEach);
+ }
+
+ /**
+ * This method is like `_.reduce` except that it iterates over elements of
+ * `collection` from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias foldr
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var array = [[0, 1], [2, 3], [4, 5]];
+ * _.reduceRight(array, function(flattened, other) { return flattened.concat(other); }, []);
+ * // => [4, 5, 2, 3, 0, 1]
+ */
+ function reduceRight(collection, iteratee, accumulator, thisArg) {
+ var func = isArray(collection) ? arrayReduceRight : baseReduce;
+ return func(collection, getCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEachRight);
+ }
+
+ /**
+ * The opposite of `_.filter`; this method returns the elements of `collection`
+ * that `predicate` does **not** return truthy for.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var odds = _.reject([1, 2, 3, 4], function(n) { return n % 2 == 0; });
+ * // => [1, 3]
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.reject(users, 'active'), 'user');
+ * // => ['barney']
+ *
+ * // using the "_.matches" callback shorthand
+ * _.pluck(_.reject(users, { 'age': 36 }), 'user');
+ * // => ['fred']
+ */
+ function reject(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arrayFilter : baseFilter;
+ predicate = getCallback(predicate, thisArg, 3);
+ return func(collection, function(value, index, collection) {
+ return !predicate(value, index, collection);
+ });
+ }
+
+ /**
+ * Gets a random element or `n` random elements from a collection.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to sample.
+ * @param {number} [n] The number of elements to sample.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {*} Returns the random sample(s).
+ * @example
+ *
+ * _.sample([1, 2, 3, 4]);
+ * // => 2
+ *
+ * _.sample([1, 2, 3, 4], 2);
+ * // => [3, 1]
+ */
+ function sample(collection, n, guard) {
+ if (guard ? isIterateeCall(collection, n, guard) : n == null) {
+ collection = toIterable(collection);
+ var length = collection.length;
+ return length > 0 ? collection[baseRandom(0, length - 1)] : undefined;
+ }
+ var result = shuffle(collection);
+ result.length = nativeMin(n < 0 ? 0 : (+n || 0), result.length);
+ return result;
+ }
+
+ /**
+ * Creates an array of shuffled values, using a version of the Fisher-Yates
+ * shuffle. See [Wikipedia](http://en.wikipedia.org/wiki/Fisher-Yates_shuffle)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to shuffle.
+ * @returns {Array} Returns the new shuffled array.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4]);
+ * // => [4, 1, 3, 2]
+ */
+ function shuffle(collection) {
+ collection = toIterable(collection);
+
+ var index = -1,
+ length = collection.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var rand = baseRandom(0, index);
+ if (index != rand) {
+ result[index] = result[rand];
+ }
+ result[rand] = collection[index];
+ }
+ return result;
+ }
+
+ /**
+ * Gets the size of `collection` by returning `collection.length` for
+ * array-like values or the number of own enumerable properties for objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to inspect.
+ * @returns {number} Returns the size of `collection`.
+ * @example
+ *
+ * _.size([1, 2]);
+ * // => 2
+ *
+ * _.size({ 'one': 1, 'two': 2, 'three': 3 });
+ * // => 3
+ *
+ * _.size('pebbles');
+ * // => 7
+ */
+ function size(collection) {
+ var length = collection ? collection.length : 0;
+ return isLength(length) ? length : keys(collection).length;
+ }
+
+ /**
+ * Checks if `predicate` returns truthy for **any** element of `collection`.
+ * The function returns as soon as it finds a passing value and does not iterate
+ * over the entire collection. The predicate is bound to `thisArg` and invoked
+ * with three arguments; (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias any
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ * @example
+ *
+ * _.some([null, 0, 'yes', false], Boolean);
+ * // => true
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'active': false },
+ * { 'user': 'fred', 'age': 40, 'active': true }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.some(users, 'active');
+ * // => true
+ *
+ * // using the "_.matches" callback shorthand
+ * _.some(users, { 'age': 1 });
+ * // => false
+ */
+ function some(collection, predicate, thisArg) {
+ var func = isArray(collection) ? arraySome : baseSome;
+ if (typeof predicate != 'function' || typeof thisArg != 'undefined') {
+ predicate = getCallback(predicate, thisArg, 3);
+ }
+ return func(collection, predicate);
+ }
+
+ /**
+ * Creates an array of elements, sorted in ascending order by the results of
+ * running each element in a collection through `iteratee`. This method performs
+ * a stable sort, that is, it preserves the original sort order of equal elements.
+ * The `iteratee` is bound to `thisArg` and invoked with three arguments;
+ * (value, index|key, collection).
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {Array|Function|Object|string} [iteratee=_.identity] The function
+ * invoked per iteration. If a property name or an object is provided it is
+ * used to create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * _.sortBy([1, 2, 3], function(n) { return Math.sin(n); });
+ * // => [3, 1, 2]
+ *
+ * _.sortBy([1, 2, 3], function(n) { return this.sin(n); }, Math);
+ * // => [3, 1, 2]
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'pebbles' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * // using the "_.property" callback shorthand
+ * _.pluck(_.sortBy(users, 'user'), 'user');
+ * // => ['barney', 'fred', 'pebbles']
+ */
+ function sortBy(collection, iteratee, thisArg) {
+ var index = -1,
+ length = collection ? collection.length : 0,
+ result = isLength(length) ? Array(length) : [];
+
+ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) {
+ iteratee = null;
+ }
+ iteratee = getCallback(iteratee, thisArg, 3);
+ baseEach(collection, function(value, key, collection) {
+ result[++index] = { 'criteria': iteratee(value, key, collection), 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareAscending);
+ }
+
+ /**
+ * This method is like `_.sortBy` except that it sorts by property names
+ * instead of an iteratee function.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to iterate over.
+ * @param {...(string|string[])} props The property names to sort by,
+ * specified as individual property names or arrays of property names.
+ * @returns {Array} Returns the new sorted array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 26 },
+ * { 'user': 'fred', 'age': 30 }
+ * ];
+ *
+ * _.map(_.sortByAll(users, ['user', 'age']), _.values);
+ * // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
+ */
+ function sortByAll(collection) {
+ var args = arguments;
+ if (args.length > 3 && isIterateeCall(args[1], args[2], args[3])) {
+ args = [collection, args[1]];
+ }
+ var index = -1,
+ length = collection ? collection.length : 0,
+ props = baseFlatten(args, false, false, 1),
+ result = isLength(length) ? Array(length) : [];
+
+ baseEach(collection, function(value, key, collection) {
+ var length = props.length,
+ criteria = Array(length);
+
+ while (length--) {
+ criteria[length] = value == null ? undefined : value[props[length]];
+ }
+ result[++index] = { 'criteria': criteria, 'index': index, 'value': value };
+ });
+ return baseSortBy(result, compareMultipleAscending);
+ }
+
+ /**
+ * Performs a deep comparison between each element in `collection` and the
+ * source object, returning an array of all elements that have equivalent
+ * property values.
+ *
+ * @static
+ * @memberOf _
+ * @category Collection
+ * @param {Array|Object|string} collection The collection to search.
+ * @param {Object} source The object of property values to match.
+ * @returns {Array} Returns the new filtered array.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36, 'status': 'busy', 'pets': ['hoppy'] },
+ * { 'user': 'fred', 'age': 40, 'status': 'busy', 'pets': ['baby puss', 'dino'] }
+ * ];
+ *
+ * _.pluck(_.where(users, { 'age': 36 }), 'user');
+ * // => ['barney']
+ *
+ * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user');
+ * // => ['fred']
+ *
+ * _.pluck(_.where(users, { 'status': 'busy' }), 'user');
+ * // => ['barney', 'fred']
+ */
+ function where(collection, source) {
+ return filter(collection, matches(source));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Gets the number of milliseconds that have elapsed since the Unix epoch
+ * (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @category Date
+ * @example
+ *
+ * _.defer(function(stamp) { console.log(_.now() - stamp); }, _.now());
+ * // => logs the number of milliseconds it took for the deferred function to be invoked
+ */
+ var now = nativeNow || function() {
+ return new Date().getTime();
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The opposite of `_.before`; this method creates a function that invokes
+ * `func` once it is called `n` or more times.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls before `func` is invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var saves = ['profile', 'settings'];
+ *
+ * var done = _.after(saves.length, function() {
+ * console.log('done saving!');
+ * });
+ *
+ * _.forEach(saves, function(type) {
+ * asyncSave({ 'type': type, 'complete': done });
+ * });
+ * // => logs 'done saving!' after the two async saves have completed
+ */
+ function after(n, func) {
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ n = nativeIsFinite(n = +n) ? n : 0;
+ return function() {
+ if (--n < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ }
+
+ /**
+ * Creates a function that accepts up to `n` arguments ignoring any
+ * additional arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to cap arguments for.
+ * @param {number} [n=func.length] The arity cap.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+ * // => [6, 8, 10]
+ */
+ function ary(func, n, guard) {
+ if (guard && isIterateeCall(func, n, guard)) {
+ n = null;
+ }
+ n = n == null ? func.length : (+n || 0);
+ return createWrapper(func, ARY_FLAG, null, null, null, null, n);
+ }
+
+ /**
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it is called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * jQuery('#add').on('click', _.before(5, addContactToList));
+ * // => allows adding up to 4 contacts to the list
+ */
+ function before(n, func) {
+ var result;
+ if (!isFunction(func)) {
+ if (isFunction(n)) {
+ var temp = n;
+ n = func;
+ func = temp;
+ } else {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ }
+ return function() {
+ if (--n > 0) {
+ result = func.apply(this, arguments);
+ } else {
+ func = null;
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of `thisArg`
+ * and prepends any additional `_.bind` arguments to those provided to the
+ * bound function.
+ *
+ * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** Unlike native `Function#bind` this method does not set the `length`
+ * property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var greet = function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * };
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * var bound = _.bind(greet, object, 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * // using placeholders
+ * var bound = _.bind(greet, object, _, '!');
+ * bound('hi');
+ * // => 'hi fred!'
+ */
+ function bind(func, thisArg) {
+ var bitmask = BIND_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bind.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(func, bitmask, thisArg, partials, holders);
+ }
+
+ /**
+ * Binds methods of an object to the object itself, overwriting the existing
+ * method. Method names may be specified as individual arguments or as arrays
+ * of method names. If no method names are provided all enumerable function
+ * properties, own and inherited, of `object` are bound.
+ *
+ * **Note:** This method does not set the `length` property of bound functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object to bind and assign the bound methods to.
+ * @param {...(string|string[])} [methodNames] The object method names to bind,
+ * specified as individual method names or arrays of method names.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var view = {
+ * 'label': 'docs',
+ * 'onClick': function() { console.log('clicked ' + this.label); }
+ * };
+ *
+ * _.bindAll(view);
+ * jQuery('#docs').on('click', view.onClick);
+ * // => logs 'clicked docs' when the element is clicked
+ */
+ function bindAll(object) {
+ return baseBindAll(object,
+ arguments.length > 1
+ ? baseFlatten(arguments, false, false, 1)
+ : functions(object)
+ );
+ }
+
+ /**
+ * Creates a function that invokes the method at `object[key]` and prepends
+ * any additional `_.bindKey` arguments to those provided to the bound function.
+ *
+ * This method differs from `_.bind` by allowing bound functions to reference
+ * methods that may be redefined or don't yet exist.
+ * See [Peter Michaux's article](http://michaux.ca/articles/lazy-function-definition-pattern)
+ * for more details.
+ *
+ * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Object} object The object the method belongs to.
+ * @param {string} key The key of the method.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var object = {
+ * 'user': 'fred',
+ * 'greet': function(greeting, punctuation) {
+ * return greeting + ' ' + this.user + punctuation;
+ * }
+ * };
+ *
+ * var bound = _.bindKey(object, 'greet', 'hi');
+ * bound('!');
+ * // => 'hi fred!'
+ *
+ * object.greet = function(greeting, punctuation) {
+ * return greeting + 'ya ' + this.user + punctuation;
+ * };
+ *
+ * bound('!');
+ * // => 'hiya fred!'
+ *
+ * // using placeholders
+ * var bound = _.bindKey(object, 'greet', _, '!');
+ * bound('hi');
+ * // => 'hiya fred!'
+ */
+ function bindKey(object, key) {
+ var bitmask = BIND_FLAG | BIND_KEY_FLAG;
+ if (arguments.length > 2) {
+ var partials = baseSlice(arguments, 2),
+ holders = replaceHolders(partials, bindKey.placeholder);
+
+ bitmask |= PARTIAL_FLAG;
+ }
+ return createWrapper(key, bitmask, object, partials, holders);
+ }
+
+ /**
+ * Creates a function that accepts one or more arguments of `func` that when
+ * called either invokes `func` returning its result, if all `func` arguments
+ * have been provided, or returns a function that accepts one or more of the
+ * remaining `func` arguments, and so on. The arity of `func` may be specified
+ * if `func.length` is not sufficient.
+ *
+ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+ * may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curry(abc);
+ *
+ * curried(1)(2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2)(3);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(1)(_, 3)(2);
+ * // => [1, 2, 3]
+ */
+ function curry(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curry.placeholder;
+ return result;
+ }
+
+ /**
+ * This method is like `_.curry` except that arguments are applied to `func`
+ * in the manner of `_.partialRight` instead of `_.partial`.
+ *
+ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for provided arguments.
+ *
+ * **Note:** This method does not set the `length` property of curried functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to curry.
+ * @param {number} [arity=func.length] The arity of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the new curried function.
+ * @example
+ *
+ * var abc = function(a, b, c) {
+ * return [a, b, c];
+ * };
+ *
+ * var curried = _.curryRight(abc);
+ *
+ * curried(3)(2)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(2, 3)(1);
+ * // => [1, 2, 3]
+ *
+ * curried(1, 2, 3);
+ * // => [1, 2, 3]
+ *
+ * // using placeholders
+ * curried(3)(1, _)(2);
+ * // => [1, 2, 3]
+ */
+ function curryRight(func, arity, guard) {
+ if (guard && isIterateeCall(func, arity, guard)) {
+ arity = null;
+ }
+ var result = createWrapper(func, CURRY_RIGHT_FLAG, null, null, null, null, null, arity);
+ result.placeholder = curryRight.placeholder;
+ return result;
+ }
+
+ /**
+ * Creates a function that delays invoking `func` until after `wait` milliseconds
+ * have elapsed since the last time it was invoked. The created function comes
+ * with a `cancel` method to cancel delayed invocations. Provide an options
+ * object to indicate that `func` should be invoked on the leading and/or
+ * trailing edge of the `wait` timeout. Subsequent calls to the debounced
+ * function return the result of the last `func` invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the debounced function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.debounce` and `_.throttle`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} wait The number of milliseconds to delay.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=false] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {number} [options.maxWait] The maximum time `func` is allowed to be
+ * delayed before it is invoked.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // avoid costly calculations while the window size is in flux
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+ *
+ * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
+ * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
+ *
+ * // ensure `batchLog` is invoked once after 1 second of debounced calls
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', _.debounce(batchLog, 250, {
+ * 'maxWait': 1000
+ * }));
+ *
+ * // cancel a debounced call
+ * var todoChanges = _.debounce(batchLog, 1000);
+ * Object.observe(models.todo, todoChanges);
+ *
+ * Object.observe(models, function(changes) {
+ * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
+ * todoChanges.cancel();
+ * }
+ * }, ['delete']);
+ *
+ * // ...at some point `models.todo` is changed
+ * models.todo.completed = true;
+ *
+ * // ...before 1 second has passed `models.todo` is deleted
+ * // which cancels the debounced `todoChanges` call
+ * delete models.todo;
+ */
+ function debounce(func, wait, options) {
+ var args,
+ maxTimeoutId,
+ result,
+ stamp,
+ thisArg,
+ timeoutId,
+ trailingCall,
+ lastCalled = 0,
+ maxWait = false,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = wait < 0 ? 0 : wait;
+ if (options === true) {
+ var leading = true;
+ trailing = false;
+ } else if (isObject(options)) {
+ leading = options.leading;
+ maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
+ trailing = 'trailing' in options ? options.trailing : trailing;
+ }
+
+ function cancel() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ }
+
+ function delayed() {
+ var remaining = wait - (now() - stamp);
+ if (remaining <= 0 || remaining > wait) {
+ if (maxTimeoutId) {
+ clearTimeout(maxTimeoutId);
+ }
+ var isCalled = trailingCall;
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (isCalled) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ } else {
+ timeoutId = setTimeout(delayed, remaining);
+ }
+ }
+
+ function maxDelayed() {
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+ maxTimeoutId = timeoutId = trailingCall = undefined;
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = now();
+ result = func.apply(thisArg, args);
+ if (!timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ }
+ }
+
+ function debounced() {
+ args = arguments;
+ stamp = now();
+ thisArg = this;
+ trailingCall = trailing && (timeoutId || !leading);
+
+ if (maxWait === false) {
+ var leadingCall = leading && !timeoutId;
+ } else {
+ if (!maxTimeoutId && !leading) {
+ lastCalled = stamp;
+ }
+ var remaining = maxWait - (stamp - lastCalled),
+ isCalled = remaining <= 0 || remaining > maxWait;
+
+ if (isCalled) {
+ if (maxTimeoutId) {
+ maxTimeoutId = clearTimeout(maxTimeoutId);
+ }
+ lastCalled = stamp;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (isCalled && timeoutId) {
+ timeoutId = clearTimeout(timeoutId);
+ }
+ else if (!timeoutId && wait !== maxWait) {
+ timeoutId = setTimeout(delayed, wait);
+ }
+ if (leadingCall) {
+ isCalled = true;
+ result = func.apply(thisArg, args);
+ }
+ if (isCalled && !timeoutId && !maxTimeoutId) {
+ args = thisArg = null;
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ return debounced;
+ }
+
+ /**
+ * Defers invoking the `func` until the current call stack has cleared. Any
+ * additional arguments are provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to defer.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.defer(function(text) { console.log(text); }, 'deferred');
+ * // logs 'deferred' after one or more milliseconds
+ */
+ function defer(func) {
+ return baseDelay(func, 1, arguments, 1);
+ }
+
+ /**
+ * Invokes `func` after `wait` milliseconds. Any additional arguments are
+ * provided to `func` when it is invoked.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to delay.
+ * @param {number} wait The number of milliseconds to delay invocation.
+ * @param {...*} [args] The arguments to invoke the function with.
+ * @returns {number} Returns the timer id.
+ * @example
+ *
+ * _.delay(function(text) { console.log(text); }, 1000, 'later');
+ * // => logs 'later' after one second
+ */
+ function delay(func, wait) {
+ return baseDelay(func, wait, arguments, 2);
+ }
+
+ /**
+ * Creates a function that returns the result of invoking the provided
+ * functions with the `this` binding of the created function, where each
+ * successive invocation is supplied the return value of the previous.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function add(x, y) {
+ * return x + y;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flow(add, square);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ function flow() {
+ var funcs = arguments,
+ length = funcs.length;
+
+ if (!length) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = 0,
+ result = funcs[index].apply(this, arguments);
+
+ while (++index < length) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * This method is like `_.flow` except that it creates a function that
+ * invokes the provided functions from right to left.
+ *
+ * @static
+ * @memberOf _
+ * @alias backflow, compose
+ * @category Function
+ * @param {...Function} [funcs] Functions to invoke.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function add(x, y) {
+ * return x + y;
+ * }
+ *
+ * function square(n) {
+ * return n * n;
+ * }
+ *
+ * var addSquare = _.flowRight(square, add);
+ * addSquare(1, 2);
+ * // => 9
+ */
+ function flowRight() {
+ var funcs = arguments,
+ fromIndex = funcs.length - 1;
+
+ if (fromIndex < 0) {
+ return function() {};
+ }
+ if (!arrayEvery(funcs, isFunction)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ var index = fromIndex,
+ result = funcs[index].apply(this, arguments);
+
+ while (index--) {
+ result = funcs[index].call(this, result);
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is coerced to a string and used as the
+ * cache key. The `func` is invoked with the `this` binding of the memoized
+ * function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the ES6 `Map` method interface
+ * of `get`, `has`, and `set`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoizing function.
+ * @example
+ *
+ * var upperCase = _.memoize(function(string) {
+ * return string.toUpperCase();
+ * });
+ *
+ * upperCase('fred');
+ * // => 'FRED'
+ *
+ * // modifying the result cache
+ * upperCase.cache.set('fred, 'BARNEY');
+ * upperCase('fred');
+ * // => 'BARNEY'
+ *
+ * // replacing `_.memoize.Cache`
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'barney' };
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'fred' }
+ *
+ * _.memoize.Cache = WeakMap;
+ * var identity = _.memoize(_.identity);
+ *
+ * identity(object);
+ * // => { 'user': 'fred' }
+ * identity(other);
+ * // => { 'user': 'barney' }
+ */
+ function memoize(func, resolver) {
+ if (!isFunction(func) || (resolver && !isFunction(resolver))) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var cache = memoized.cache,
+ key = resolver ? resolver.apply(this, arguments) : arguments[0];
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, arguments);
+ cache.set(key, result);
+ return result;
+ };
+ memoized.cache = new memoize.Cache;
+ return memoized;
+ }
+
+ /**
+ * Creates a function that negates the result of the predicate `func`. The
+ * `func` predicate is invoked with the `this` binding and arguments of the
+ * created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} predicate The predicate to negate.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * function isEven(n) {
+ * return n % 2 == 0;
+ * }
+ *
+ * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+ * // => [1, 3, 5]
+ */
+ function negate(predicate) {
+ if (!isFunction(predicate)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
+ }
+
+ /**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first call. The `func` is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @type Function
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // `initialize` invokes `createApplication` once
+ */
+ function once(func) {
+ return before(func, 2);
+ }
+
+ /**
+ * Creates a function that invokes `func` with `partial` arguments prepended
+ * to those provided to the new function. This method is like `_.bind` except
+ * it does **not** alter the `this` binding.
+ *
+ * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var sayHelloTo = _.partial(greet, 'hello');
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ *
+ * // using placeholders
+ * var greetFred = _.partial(greet, _, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ */
+ function partial(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partial.placeholder);
+
+ return createWrapper(func, PARTIAL_FLAG, null, partials, holders);
+ }
+
+ /**
+ * This method is like `_.partial` except that partially applied arguments
+ * are appended to those provided to the new function.
+ *
+ * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+ * builds, may be used as a placeholder for partially applied arguments.
+ *
+ * **Note:** This method does not set the `length` property of partially
+ * applied functions.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to partially apply arguments to.
+ * @param {...*} [args] The arguments to be partially applied.
+ * @returns {Function} Returns the new partially applied function.
+ * @example
+ *
+ * var greet = function(greeting, name) {
+ * return greeting + ' ' + name;
+ * };
+ *
+ * var greetFred = _.partialRight(greet, 'fred');
+ * greetFred('hi');
+ * // => 'hi fred'
+ *
+ * // using placeholders
+ * var sayHelloTo = _.partialRight(greet, 'hello', _);
+ * sayHelloTo('fred');
+ * // => 'hello fred'
+ */
+ function partialRight(func) {
+ var partials = baseSlice(arguments, 1),
+ holders = replaceHolders(partials, partialRight.placeholder);
+
+ return createWrapper(func, PARTIAL_RIGHT_FLAG, null, partials, holders);
+ }
+
+ /**
+ * Creates a function that invokes `func` with arguments arranged according
+ * to the specified indexes where the argument value at the first index is
+ * provided as the first argument, the argument value at the second index is
+ * provided as the second argument, and so on.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to rearrange arguments for.
+ * @param {...(number|number[])} indexes The arranged argument indexes,
+ * specified as individual indexes or arrays of indexes.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var rearged = _.rearg(function(a, b, c) {
+ * return [a, b, c];
+ * }, 2, 0, 1);
+ *
+ * rearged('b', 'c', 'a')
+ * // => ['a', 'b', 'c']
+ *
+ * var map = _.rearg(_.map, [1, 0]);
+ * map(function(n) { return n * 3; }, [1, 2, 3]);
+ * // => [3, 6, 9]
+ */
+ function rearg(func) {
+ var indexes = baseFlatten(arguments, false, false, 1);
+ return createWrapper(func, REARG_FLAG, null, null, null, indexes);
+ }
+
+ /**
+ * Creates a function that only invokes `func` at most once per every `wait`
+ * milliseconds. The created function comes with a `cancel` method to cancel
+ * delayed invocations. Provide an options object to indicate that `func`
+ * should be invoked on the leading and/or trailing edge of the `wait` timeout.
+ * Subsequent calls to the throttled function return the result of the last
+ * `func` call.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
+ * on the trailing edge of the timeout only if the the throttled function is
+ * invoked more than once during the `wait` timeout.
+ *
+ * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
+ * for details over the differences between `_.throttle` and `_.debounce`.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} wait The number of milliseconds to throttle invocations to.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.leading=true] Specify invoking on the leading
+ * edge of the timeout.
+ * @param {boolean} [options.trailing=true] Specify invoking on the trailing
+ * edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // avoid excessively updating the position while scrolling
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+ *
+ * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false })
+ * jQuery('.interactive').on('click', throttled);
+ *
+ * // cancel a trailing throttled call
+ * jQuery(window).on('popstate', throttled.cancel);
+ */
+ function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (!isFunction(func)) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ if (options === false) {
+ leading = false;
+ } else if (isObject(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+ debounceOptions.leading = leading;
+ debounceOptions.maxWait = +wait;
+ debounceOptions.trailing = trailing;
+ return debounce(func, wait, debounceOptions);
+ }
+
+ /**
+ * Creates a function that provides `value` to the wrapper function as its
+ * first argument. Any additional arguments provided to the function are
+ * appended to those provided to the wrapper function. The wrapper is invoked
+ * with the `this` binding of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {*} value The value to wrap.
+ * @param {Function} wrapper The wrapper function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var p = _.wrap(_.escape, function(func, text) {
+ * return '<p>' + func(text) + '</p>';
+ * });
+ *
+ * p('fred, barney, & pebbles');
+ * // => '<p>fred, barney, & pebbles</p>'
+ */
+ function wrap(value, wrapper) {
+ wrapper = wrapper == null ? identity : wrapper;
+ return createWrapper(wrapper, PARTIAL_FLAG, null, [value], []);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
+ * otherwise they are assigned by reference. If `customizer` is provided it is
+ * invoked to produce the cloned values. If `customizer` returns `undefined`
+ * cloning is handled by the method instead. The `customizer` is bound to
+ * `thisArg` and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var shallow = _.clone(users);
+ * shallow[0] === users[0];
+ * // => true
+ *
+ * var deep = _.clone(users, true);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var body = _.clone(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(false) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 0
+ */
+ function clone(value, isDeep, customizer, thisArg) {
+ // Juggle arguments.
+ if (typeof isDeep != 'boolean' && isDeep != null) {
+ thisArg = customizer;
+ customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep;
+ isDeep = false;
+ }
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, isDeep, customizer);
+ }
+
+ /**
+ * Creates a deep clone of `value`. If `customizer` is provided it is invoked
+ * to produce the cloned values. If `customizer` returns `undefined` cloning
+ * is handled by the method instead. The `customizer` is bound to `thisArg`
+ * and invoked with two argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the structured clone algorithm.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the deep cloned value.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney' },
+ * { 'user': 'fred' }
+ * ];
+ *
+ * var deep = _.cloneDeep(users);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var el = _.cloneDeep(document.body, function(value) {
+ * return _.isElement(value) ? value.cloneNode(true) : undefined;
+ * });
+ *
+ * body === document.body
+ * // => false
+ * body.nodeName
+ * // => BODY
+ * body.childNodes.length;
+ * // => 20
+ */
+ function cloneDeep(value, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
+ return baseClone(value, true, customizer);
+ }
+
+ /**
+ * Checks if `value` is classified as an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * (function() { return _.isArguments(arguments); })();
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ var length = isObjectLike(value) ? value.length : undefined;
+ return (isLength(length) && objToString.call(value) == argsTag) || false;
+ }
+ // Fallback for environments without a `toStringTag` for `arguments` objects.
+ if (!support.argsTag) {
+ isArguments = function(value) {
+ var length = isObjectLike(value) ? value.length : undefined;
+ return (isLength(length) && hasOwnProperty.call(value, 'callee') &&
+ !propertyIsEnumerable.call(value, 'callee')) || false;
+ };
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * (function() { return _.isArray(arguments); })();
+ * // => false
+ */
+ var isArray = nativeIsArray || function(value) {
+ return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false;
+ };
+
+ /**
+ * Checks if `value` is classified as a boolean primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isBoolean(false);
+ * // => true
+ *
+ * _.isBoolean(null);
+ * // => false
+ */
+ function isBoolean(value) {
+ return (value === true || value === false || isObjectLike(value) && objToString.call(value) == boolTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Date` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isDate(new Date);
+ * // => true
+ *
+ * _.isDate('Mon April 23 2012');
+ * // => false
+ */
+ function isDate(value) {
+ return (isObjectLike(value) && objToString.call(value) == dateTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a DOM element.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
+ * @example
+ *
+ * _.isElement(document.body);
+ * // => true
+ *
+ * _.isElement('<body>');
+ * // => false
+ */
+ function isElement(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) &&
+ (lodash.support.nodeTag ? objToString.call(value).indexOf('Element') > -1 : isHostObject(value))) || false;
+ }
+ // Fallback for environments without DOM support.
+ if (!support.dom) {
+ isElement = function(value) {
+ return (value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value)) || false;
+ };
+ }
+
+ /**
+ * Checks if a value is empty. A value is considered empty unless it is an
+ * `arguments` object, array, string, or jQuery-like collection with a length
+ * greater than `0` or an object with own enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Array|Object|string} value The value to inspect.
+ * @returns {boolean} Returns `true` if `value` is empty, else `false`.
+ * @example
+ *
+ * _.isEmpty(null);
+ * // => true
+ *
+ * _.isEmpty(true);
+ * // => true
+ *
+ * _.isEmpty(1);
+ * // => true
+ *
+ * _.isEmpty([1, 2, 3]);
+ * // => false
+ *
+ * _.isEmpty({ 'a': 1 });
+ * // => false
+ */
+ function isEmpty(value) {
+ if (value == null) {
+ return true;
+ }
+ var length = value.length;
+ if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) ||
+ (isObjectLike(value) && isFunction(value.splice)))) {
+ return !length;
+ }
+ return !keys(value).length;
+ }
+
+ /**
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent. If `customizer` is provided it is invoked to compare values.
+ * If `customizer` returns `undefined` comparisons are handled by the method
+ * instead. The `customizer` is bound to `thisArg` and invoked with three
+ * arguments; (value, other [, index|key]).
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Functions and DOM nodes
+ * are **not** supported. Provide a customizer function to extend support
+ * for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'fred' };
+ *
+ * object == other;
+ * // => false
+ *
+ * _.isEqual(object, other);
+ * // => true
+ *
+ * // using a customizer callback
+ * var array = ['hello', 'goodbye'];
+ * var other = ['hi', 'goodbye'];
+ *
+ * _.isEqual(array, other, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isEqual(value, other, customizer, thisArg) {
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && isStrictComparable(value) && isStrictComparable(other)) {
+ return value === other;
+ }
+ var result = customizer ? customizer(value, other) : undefined;
+ return typeof result == 'undefined' ? baseIsEqual(value, other, customizer) : !!result;
+ }
+
+ /**
+ * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+ * `SyntaxError`, `TypeError`, or `URIError` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
+ * @example
+ *
+ * _.isError(new Error);
+ * // => true
+ *
+ * _.isError(Error);
+ * // => false
+ */
+ function isError(value) {
+ return (isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a finite primitive number.
+ *
+ * **Note:** This method is based on ES6 `Number.isFinite`. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
+ * @example
+ *
+ * _.isFinite(10);
+ * // => true
+ *
+ * _.isFinite('10');
+ * // => false
+ *
+ * _.isFinite(true);
+ * // => false
+ *
+ * _.isFinite(Object(10));
+ * // => false
+ *
+ * _.isFinite(Infinity);
+ * // => false
+ */
+ var isFinite = nativeNumIsFinite || function(value) {
+ return typeof value == 'number' && nativeIsFinite(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // Avoid a Chakra JIT bug in compatibility modes of IE 11.
+ // See https://github.com/jashkenas/underscore/issues/1621.
+ return typeof value == 'function' || false;
+ }
+ // Fallback for environments that return incorrect `typeof` operator results.
+ if (isFunction(/x/) || (Uint8Array && !isFunction(Uint8Array))) {
+ isFunction = function(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in older versions of Chrome and Safari which return 'function' for regexes
+ // and Safari 8 equivalents which return 'object' for typed array constructors.
+ return objToString.call(value) == funcTag;
+ };
+ }
+
+ /**
+ * Checks if `value` is the language type of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * **Note:** See the [ES5 spec](http://es5.github.io/#x8) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+ function isObject(value) {
+ // Avoid a V8 JIT bug in Chrome 19-20.
+ // See https://code.google.com/p/v8/issues/detail?id=2291.
+ var type = typeof value;
+ return type == 'function' || (value && type == 'object') || false;
+ }
+
+ /**
+ * Performs a deep comparison between `object` and `source` to determine if
+ * `object` contains equivalent property values. If `customizer` is provided
+ * it is invoked to compare values. If `customizer` returns `undefined`
+ * comparisons are handled by the method instead. The `customizer` is bound
+ * to `thisArg` and invoked with three arguments; (value, other, index|key).
+ *
+ * **Note:** This method supports comparing properties of arrays, booleans,
+ * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions
+ * and DOM nodes are **not** supported. Provide a customizer function to extend
+ * support for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {Object} source The object to inspect.
+ * @param {Object} source The object of property values to match.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.isMatch(object, { 'age': 40 });
+ * // => true
+ *
+ * _.isMatch(object, { 'age': 36 });
+ * // => false
+ *
+ * // using a customizer callback
+ * var object = { 'greeting': 'hello' };
+ * var source = { 'greeting': 'hi' };
+ *
+ * _.isMatch(object, source, function(value, other) {
+ * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined;
+ * });
+ * // => true
+ */
+ function isMatch(object, source, customizer, thisArg) {
+ var props = keys(source),
+ length = props.length;
+
+ customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
+ if (!customizer && length == 1) {
+ var key = props[0],
+ value = source[key];
+
+ if (isStrictComparable(value)) {
+ return object != null && value === object[key] && hasOwnProperty.call(object, key);
+ }
+ }
+ var values = Array(length),
+ strictCompareFlags = Array(length);
+
+ while (length--) {
+ value = values[length] = source[props[length]];
+ strictCompareFlags[length] = isStrictComparable(value);
+ }
+ return baseIsMatch(object, props, values, strictCompareFlags, customizer);
+ }
+
+ /**
+ * Checks if `value` is `NaN`.
+ *
+ * **Note:** This method is not the same as native `isNaN` which returns `true`
+ * for `undefined` and other non-numeric values. See the [ES5 spec](http://es5.github.io/#x15.1.2.4)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+ * @example
+ *
+ * _.isNaN(NaN);
+ * // => true
+ *
+ * _.isNaN(new Number(NaN));
+ * // => true
+ *
+ * isNaN(undefined);
+ * // => true
+ *
+ * _.isNaN(undefined);
+ * // => false
+ */
+ function isNaN(value) {
+ // An `NaN` primitive is the only value that is not equal to itself.
+ // Perform the `toStringTag` check first to avoid errors with some host objects in IE.
+ return isNumber(value) && value != +value;
+ }
+
+ /**
+ * Checks if `value` is a native function.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
+ * @example
+ *
+ * _.isNative(Array.prototype.push);
+ * // => true
+ *
+ * _.isNative(_);
+ * // => false
+ */
+ function isNative(value) {
+ if (value == null) {
+ return false;
+ }
+ if (objToString.call(value) == funcTag) {
+ return reNative.test(fnToString.call(value));
+ }
+ return (isObjectLike(value) &&
+ (isHostObject(value) ? reNative : reHostCtor).test(value)) || false;
+ }
+
+ /**
+ * Checks if `value` is `null`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
+ * @example
+ *
+ * _.isNull(null);
+ * // => true
+ *
+ * _.isNull(void 0);
+ * // => false
+ */
+ function isNull(value) {
+ return value === null;
+ }
+
+ /**
+ * Checks if `value` is classified as a `Number` primitive or object.
+ *
+ * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified
+ * as numbers, use the `_.isFinite` method.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isNumber(8.4);
+ * // => true
+ *
+ * _.isNumber(NaN);
+ * // => true
+ *
+ * _.isNumber('8.4');
+ * // => false
+ */
+ function isNumber(value) {
+ return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag) || false;
+ }
+
+ /**
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
+ *
+ * **Note:** This method assumes objects created by the `Object` constructor
+ * have no inherited enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * }
+ *
+ * _.isPlainObject(new Foo);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ *
+ * _.isPlainObject(Object.create(null));
+ * // => true
+ */
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
+ if (!(value && objToString.call(value) == objectTag) || (!lodash.support.argsTag && isArguments(value))) {
+ return false;
+ }
+ var valueOf = value.valueOf,
+ objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
+
+ return objProto
+ ? (value == objProto || getPrototypeOf(value) == objProto)
+ : shimIsPlainObject(value);
+ };
+
+ /**
+ * Checks if `value` is classified as a `RegExp` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isRegExp(/abc/);
+ * // => true
+ *
+ * _.isRegExp('/abc/');
+ * // => false
+ */
+ function isRegExp(value) {
+ return (isObject(value) && objToString.call(value) == regexpTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a `String` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isString('abc');
+ * // => true
+ *
+ * _.isString(1);
+ * // => false
+ */
+ function isString(value) {
+ return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag) || false;
+ }
+
+ /**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+ function isTypedArray(value) {
+ return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false;
+ }
+
+ /**
+ * Checks if `value` is `undefined`.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+ * @example
+ *
+ * _.isUndefined(void 0);
+ * // => true
+ *
+ * _.isUndefined(null);
+ * // => false
+ */
+ function isUndefined(value) {
+ return typeof value == 'undefined';
+ }
+
+ /**
+ * Converts `value` to an array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Array} Returns the converted array.
+ * @example
+ *
+ * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3);
+ * // => [2, 3]
+ */
+ function toArray(value) {
+ var length = value ? value.length : 0;
+ if (!isLength(length)) {
+ return values(value);
+ }
+ if (!length) {
+ return [];
+ }
+ return (lodash.support.unindexedChars && isString(value))
+ ? value.split('')
+ : arrayCopy(value);
+ }
+
+ /**
+ * Converts `value` to a plain object flattening inherited enumerable
+ * properties of `value` to own properties of the plain object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Object} Returns the converted plain object.
+ * @example
+ *
+ * function Foo() {
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.assign({ 'a': 1 }, new Foo);
+ * // => { 'a': 1, 'b': 2 }
+ *
+ * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+ * // => { 'a': 1, 'b': 2, 'c': 3 }
+ */
+ function toPlainObject(value) {
+ return baseCopy(value, keysIn(value));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources overwrite property assignments of previous sources.
+ * If `customizer` is provided it is invoked to produce the assigned values.
+ * The `customizer` is bound to `thisArg` and invoked with five arguments;
+ * (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @alias extend
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+ * // => { 'user': 'fred', 'age': 40 }
+ *
+ * // using a customizer callback
+ * var defaults = _.partialRight(_.assign, function(value, other) {
+ * return typeof value == 'undefined' ? other : value;
+ * });
+ *
+ * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ var assign = createAssigner(baseAssign);
+
+ /**
+ * Creates an object that inherits from the given `prototype` object. If a
+ * `properties` object is provided its own enumerable properties are assigned
+ * to the created object.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} prototype The object to inherit from.
+ * @param {Object} [properties] The properties to assign to the object.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * function Shape() {
+ * this.x = 0;
+ * this.y = 0;
+ * }
+ *
+ * function Circle() {
+ * Shape.call(this);
+ * }
+ *
+ * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
+ *
+ * var circle = new Circle;
+ * circle instanceof Circle;
+ * // => true
+ *
+ * circle instanceof Shape;
+ * // => true
+ */
+ function create(prototype, properties, guard) {
+ var result = baseCreate(prototype);
+ if (guard && isIterateeCall(prototype, properties, guard)) {
+ properties = null;
+ }
+ return properties ? baseCopy(properties, result, keys(properties)) : result;
+ }
+
+ /**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object for all destination properties that resolve to `undefined`. Once a
+ * property is set, additional defaults of the same property are ignored.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function defaults(object) {
+ if (object == null) {
+ return object;
+ }
+ var args = arrayCopy(arguments);
+ args.push(assignDefaults);
+ return assign.apply(undefined, args);
+ }
+
+ /**
+ * This method is like `_.findIndex` except that it returns the key of the
+ * first element `predicate` returns truthy for, instead of the element itself.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findKey(users, function(chr) { return chr.age < 40; });
+ * // => 'barney' (iteration order is not guaranteed)
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findKey(users, { 'age': 1 });
+ * // => 'pebbles'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findKey(users, 'active');
+ * // => 'barney'
+ */
+ function findKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwn, true);
+ }
+
+ /**
+ * This method is like `_.findKey` except that it iterates over elements of
+ * a collection in the opposite order.
+ *
+ * If a property name is provided for `predicate` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `predicate` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to search.
+ * @param {Function|Object|string} [predicate=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {string|undefined} Returns the key of the matched element, else `undefined`.
+ * @example
+ *
+ * var users = {
+ * 'barney': { 'age': 36, 'active': true },
+ * 'fred': { 'age': 40, 'active': false },
+ * 'pebbles': { 'age': 1, 'active': true }
+ * };
+ *
+ * _.findLastKey(users, function(chr) { return chr.age < 40; });
+ * // => returns `pebbles` assuming `_.findKey` returns `barney`
+ *
+ * // using the "_.matches" callback shorthand
+ * _.findLastKey(users, { 'age': 36 });
+ * // => 'barney'
+ *
+ * // using the "_.property" callback shorthand
+ * _.findLastKey(users, 'active');
+ * // => 'pebbles'
+ */
+ function findLastKey(object, predicate, thisArg) {
+ predicate = getCallback(predicate, thisArg, 3);
+ return baseFind(object, predicate, baseForOwnRight, true);
+ }
+
+ /**
+ * Iterates over own and inherited enumerable properties of an object invoking
+ * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked
+ * with three arguments; (value, key, object). Iterator functions may exit
+ * iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forIn(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed)
+ */
+ function forIn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return baseFor(object, iteratee, keysIn);
+ }
+
+ /**
+ * This method is like `_.forIn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.forInRight(new Foo, function(value, key) {
+ * console.log(key);
+ * });
+ * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c'
+ */
+ function forInRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keysIn);
+ }
+
+ /**
+ * Iterates over own enumerable properties of an object invoking `iteratee`
+ * for each property. The `iteratee` is bound to `thisArg` and invoked with
+ * three arguments; (value, key, object). Iterator functions may exit iteration
+ * early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs '0', '1', and 'length' (iteration order is not guaranteed)
+ */
+ function forOwn(object, iteratee, thisArg) {
+ if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ }
+ return baseForOwn(object, iteratee);
+ }
+
+ /**
+ * This method is like `_.forOwn` except that it iterates over properties of
+ * `object` in the opposite order.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) {
+ * console.log(key);
+ * });
+ * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
+ */
+ function forOwnRight(object, iteratee, thisArg) {
+ iteratee = bindCallback(iteratee, thisArg, 3);
+ return baseForRight(object, iteratee, keys);
+ }
+
+ /**
+ * Creates an array of function property names from all enumerable properties,
+ * own and inherited, of `object`.
+ *
+ * @static
+ * @memberOf _
+ * @alias methods
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of property names.
+ * @example
+ *
+ * _.functions(_);
+ * // => ['all', 'any', 'bind', ...]
+ */
+ function functions(object) {
+ return baseFunctions(object, keysIn(object));
+ }
+
+ /**
+ * Checks if `key` exists as a direct property of `object` instead of an
+ * inherited property.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @param {string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` is a direct property, else `false`.
+ * @example
+ *
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+ * // => true
+ */
+ function has(object, key) {
+ return object ? hasOwnProperty.call(object, key) : false;
+ }
+
+ /**
+ * Creates an object composed of the inverted keys and values of `object`.
+ * If `object` contains duplicate values, subsequent values overwrite property
+ * assignments of previous values unless `multiValue` is `true`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to invert.
+ * @param {boolean} [multiValue] Allow multiple values per key.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Object} Returns the new inverted object.
+ * @example
+ *
+ * _.invert({ 'first': 'fred', 'second': 'barney' });
+ * // => { 'fred': 'first', 'barney': 'second' }
+ *
+ * // without `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' });
+ * // => { 'fred': 'third', 'barney': 'second' }
+ *
+ * // with `multiValue`
+ * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }, true);
+ * // => { 'fred': ['first', 'third'], 'barney': ['second'] }
+ */
+ function invert(object, multiValue, guard) {
+ if (guard && isIterateeCall(object, multiValue, guard)) {
+ multiValue = null;
+ }
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = {};
+
+ while (++index < length) {
+ var key = props[index],
+ value = object[key];
+
+ if (multiValue) {
+ if (hasOwnProperty.call(result, value)) {
+ result[value].push(key);
+ } else {
+ result[value] = [key];
+ }
+ }
+ else {
+ result[value] = key;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES6 spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ var keys = !nativeKeys ? shimKeys : function(object) {
+ if (object) {
+ var Ctor = object.constructor,
+ length = object.length;
+ }
+ if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
+ (typeof object == 'function' ? lodash.support.enumPrototypes : (length && isLength(length)))) {
+ return shimKeys(object);
+ }
+ return isObject(object) ? nativeKeys(object) : [];
+ };
+
+ /**
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+ */
+ function keysIn(object) {
+ if (object == null) {
+ return [];
+ }
+ if (!isObject(object)) {
+ object = Object(object);
+ }
+ var length = object.length,
+ support = lodash.support;
+
+ length = (length && isLength(length) &&
+ (isArray(object) || (support.nonEnumStrings && isString(object)) ||
+ (support.nonEnumArgs && isArguments(object))) && length) || 0;
+
+ var Ctor = object.constructor,
+ index = -1,
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto,
+ isProto = proto === object,
+ result = Array(length),
+ skipIndexes = length > 0,
+ skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error),
+ skipProto = support.enumPrototypes && typeof object == 'function';
+
+ while (++index < length) {
+ result[index] = (index + '');
+ }
+ // Lo-Dash skips the `constructor` property when it infers it is iterating
+ // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]`
+ // attribute of an existing property and the `constructor` property of a
+ // prototype defaults to non-enumerable.
+ for (var key in object) {
+ if (!(skipProto && key == 'prototype') &&
+ !(skipErrorProps && (key == 'message' || key == 'name')) &&
+ !(skipIndexes && isIndex(key, length)) &&
+ !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
+ }
+ }
+ if (support.nonEnumShadows && object !== objectProto) {
+ var tag = object === stringProto ? stringTag : object === errorProto ? errorTag : objToString.call(object),
+ nonEnums = nonEnumProps[tag] || nonEnumProps[objectTag];
+
+ if (tag == objectTag) {
+ proto = objectProto;
+ }
+ length = shadowProps.length;
+ while (length--) {
+ key = shadowProps[length];
+ var nonEnum = nonEnums[key];
+ if (!(isProto && nonEnum) &&
+ (nonEnum ? hasOwnProperty.call(object, key) : object[key] !== proto[key])) {
+ result.push(key);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object with the same keys as `object` and values generated by
+ * running each own enumerable property of `object` through `iteratee`. The
+ * iteratee function is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * If a property name is provided for `iteratee` the created "_.property"
+ * style callback returns the property value of the given element.
+ *
+ * If an object is provided for `iteratee` the created "_.matches" style
+ * callback returns `true` for elements that have the properties of the given
+ * object, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to iterate over.
+ * @param {Function|Object|string} [iteratee=_.identity] The function invoked
+ * per iteration. If a property name or object is provided it is used to
+ * create a "_.property" or "_.matches" style callback respectively.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Object} Returns the new mapped object.
+ * @example
+ *
+ * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(n) { return n * 3; });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ *
+ * var users = {
+ * 'fred': { 'user': 'fred', 'age': 40 },
+ * 'pebbles': { 'user': 'pebbles', 'age': 1 }
+ * };
+ *
+ * // using the "_.property" callback shorthand
+ * _.mapValues(users, 'age');
+ * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+ */
+ function mapValues(object, iteratee, thisArg) {
+ var result = {};
+ iteratee = getCallback(iteratee, thisArg, 3);
+
+ baseForOwn(object, function(value, key, object) {
+ result[key] = iteratee(value, key, object);
+ });
+ return result;
+ }
+
+ /**
+ * Recursively merges own enumerable properties of the source object(s), that
+ * don't resolve to `undefined` into the destination object. Subsequent sources
+ * overwrite property assignments of previous sources. If `customizer` is
+ * provided it is invoked to produce the merged values of the destination and
+ * source properties. If `customizer` returns `undefined` merging is handled
+ * by the method instead. The `customizer` is bound to `thisArg` and invoked
+ * with five arguments; (objectValue, sourceValue, key, object, source).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize merging properties.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var users = {
+ * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
+ * };
+ *
+ * var ages = {
+ * 'data': [{ 'age': 36 }, { 'age': 40 }]
+ * };
+ *
+ * _.merge(users, ages);
+ * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
+ *
+ * // using a customizer callback
+ * var object = {
+ * 'fruits': ['apple'],
+ * 'vegetables': ['beet']
+ * };
+ *
+ * var other = {
+ * 'fruits': ['banana'],
+ * 'vegetables': ['carrot']
+ * };
+ *
+ * _.merge(object, other, function(a, b) {
+ * return _.isArray(a) ? a.concat(b) : undefined;
+ * });
+ * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
+ */
+ var merge = createAssigner(baseMerge);
+
+ /**
+ * The opposite of `_.pick`; this method creates an object composed of the
+ * own and inherited enumerable properties of `object` that are not omitted.
+ * Property names may be specified as individual arguments or as arrays of
+ * property names. If `predicate` is provided it is invoked for each property
+ * of `object` omitting the properties `predicate` returns truthy for. The
+ * predicate is bound to `thisArg` and invoked with three arguments;
+ * (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to omit, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.omit(object, 'age');
+ * // => { 'user': 'fred' }
+ *
+ * _.omit(object, _.isNumber);
+ * // => { 'user': 'fred' }
+ */
+ function omit(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ if (typeof predicate != 'function') {
+ var props = arrayMap(baseFlatten(arguments, false, false, 1), String);
+ return pickByArray(object, baseDifference(keysIn(object), props));
+ }
+ predicate = bindCallback(predicate, thisArg, 3);
+ return pickByCallback(object, function(value, key, object) {
+ return !predicate(value, key, object);
+ });
+ }
+
+ /**
+ * Creates a two dimensional array of the key-value pairs for `object`,
+ * e.g. `[[key1, value1], [key2, value2]]`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns the new array of key-value pairs.
+ * @example
+ *
+ * _.pairs({ 'barney': 36, 'fred': 40 });
+ * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
+ */
+ function pairs(object) {
+ var index = -1,
+ props = keys(object),
+ length = props.length,
+ result = Array(length);
+
+ while (++index < length) {
+ var key = props[index];
+ result[index] = [key, object[key]];
+ }
+ return result;
+ }
+
+ /**
+ * Creates an object composed of the picked `object` properties. Property
+ * names may be specified as individual arguments or as arrays of property
+ * names. If `predicate` is provided it is invoked for each property of `object`
+ * picking the properties `predicate` returns truthy for. The predicate is
+ * bound to `thisArg` and invoked with three arguments; (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The source object.
+ * @param {Function|...(string|string[])} [predicate] The function invoked per
+ * iteration or property names to pick, specified as individual property
+ * names or arrays of property names.
+ * @param {*} [thisArg] The `this` binding of `predicate`.
+ * @returns {Object} Returns the new object.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40 };
+ *
+ * _.pick(object, 'user');
+ * // => { 'user': 'fred' }
+ *
+ * _.pick(object, _.isString);
+ * // => { 'user': 'fred' }
+ */
+ function pick(object, predicate, thisArg) {
+ if (object == null) {
+ return {};
+ }
+ return typeof predicate == 'function'
+ ? pickByCallback(object, bindCallback(predicate, thisArg, 3))
+ : pickByArray(object, baseFlatten(arguments, false, false, 1));
+ }
+
+ /**
+ * Resolves the value of property `key` on `object`. If the value of `key` is
+ * a function it is invoked with the `this` binding of `object` and its result
+ * is returned, else the property value is returned. If the property value is
+ * `undefined` the `defaultValue` is used in its place.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the property to resolve.
+ * @param {*} [defaultValue] The value returned if the property value
+ * resolves to `undefined`.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': _.constant(40) };
+ *
+ * _.result(object, 'user');
+ * // => 'fred'
+ *
+ * _.result(object, 'age');
+ * // => 40
+ *
+ * _.result(object, 'status', 'busy');
+ * // => 'busy'
+ *
+ * _.result(object, 'status', _.constant('busy'));
+ * // => 'busy'
+ */
+ function result(object, key, defaultValue) {
+ var value = object == null ? undefined : object[key];
+ if (typeof value == 'undefined') {
+ value = defaultValue;
+ }
+ return isFunction(value) ? value.call(object) : value;
+ }
+
+ /**
+ * An alternative to `_.reduce`; this method transforms `object` to a new
+ * `accumulator` object which is the result of running each of its own enumerable
+ * properties through `iteratee`, with each invocation potentially mutating
+ * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked
+ * with four arguments; (accumulator, value, key, object). Iterator functions
+ * may exit iteration early by explicitly returning `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Array|Object} object The object to iterate over.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [accumulator] The custom accumulator value.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {*} Returns the accumulated value.
+ * @example
+ *
+ * var squares = _.transform([1, 2, 3, 4, 5, 6], function(result, n) {
+ * n *= n;
+ * if (n % 2) {
+ * return result.push(n) < 3;
+ * }
+ * });
+ * // => [1, 9, 25]
+ *
+ * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) {
+ * result[key] = n * 3;
+ * });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ */
+ function transform(object, iteratee, accumulator, thisArg) {
+ var isArr = isArray(object) || isTypedArray(object);
+ iteratee = getCallback(iteratee, thisArg, 4);
+
+ if (accumulator == null) {
+ if (isArr || isObject(object)) {
+ var Ctor = object.constructor;
+ if (isArr) {
+ accumulator = isArray(object) ? new Ctor : [];
+ } else {
+ accumulator = baseCreate(typeof Ctor == 'function' && Ctor.prototype);
+ }
+ } else {
+ accumulator = {};
+ }
+ }
+ (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) {
+ return iteratee(accumulator, value, index, object);
+ });
+ return accumulator;
+ }
+
+ /**
+ * Creates an array of the own enumerable property values of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.values(new Foo);
+ * // => [1, 2] (iteration order is not guaranteed)
+ *
+ * _.values('hi');
+ * // => ['h', 'i']
+ */
+ function values(object) {
+ return baseValues(object, keys(object));
+ }
+
+ /**
+ * Creates an array of the own and inherited enumerable property values
+ * of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property values.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.valuesIn(new Foo);
+ * // => [1, 2, 3] (iteration order is not guaranteed)
+ */
+ function valuesIn(object) {
+ return baseValues(object, keysIn(object));
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Produces a random number between `min` and `max` (inclusive). If only one
+ * argument is provided a number between `0` and the given number is returned.
+ * If `floating` is `true`, or either `min` or `max` are floats, a floating-point
+ * number is returned instead of an integer.
+ *
+ * @static
+ * @memberOf _
+ * @category Number
+ * @param {number} [min=0] The minimum possible value.
+ * @param {number} [max=1] The maximum possible value.
+ * @param {boolean} [floating] Specify returning a floating-point number.
+ * @returns {number} Returns the random number.
+ * @example
+ *
+ * _.random(0, 5);
+ * // => an integer between 0 and 5
+ *
+ * _.random(5);
+ * // => also an integer between 0 and 5
+ *
+ * _.random(5, true);
+ * // => a floating-point number between 0 and 5
+ *
+ * _.random(1.2, 5.2);
+ * // => a floating-point number between 1.2 and 5.2
+ */
+ function random(min, max, floating) {
+ if (floating && isIterateeCall(min, max, floating)) {
+ max = floating = null;
+ }
+ var noMin = min == null,
+ noMax = max == null;
+
+ if (floating == null) {
+ if (noMax && typeof min == 'boolean') {
+ floating = min;
+ min = 1;
+ }
+ else if (typeof max == 'boolean') {
+ floating = max;
+ noMax = true;
+ }
+ }
+ if (noMin && noMax) {
+ max = 1;
+ noMax = false;
+ }
+ min = +min || 0;
+ if (noMax) {
+ max = min;
+ min = 0;
+ } else {
+ max = +max || 0;
+ }
+ if (floating || min % 1 || max % 1) {
+ var rand = nativeRandom();
+ return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max);
+ }
+ return baseRandom(min, max);
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Converts `string` to camel case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/CamelCase) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the camel cased string.
+ * @example
+ *
+ * _.camelCase('Foo Bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('--foo-bar');
+ * // => 'fooBar'
+ *
+ * _.camelCase('__foo_bar__');
+ * // => 'fooBar'
+ */
+ var camelCase = createCompounder(function(result, word, index) {
+ word = word.toLowerCase();
+ return index ? (result + word.charAt(0).toUpperCase() + word.slice(1)) : word;
+ });
+
+ /**
+ * Capitalizes the first character of `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to capitalize.
+ * @returns {string} Returns the capitalized string.
+ * @example
+ *
+ * _.capitalize('fred');
+ * // => 'Fred'
+ */
+ function capitalize(string) {
+ string = baseToString(string);
+ return string && (string.charAt(0).toUpperCase() + string.slice(1));
+ }
+
+ /**
+ * Deburrs `string` by converting latin-1 supplementary letters to basic latin letters.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to deburr.
+ * @returns {string} Returns the deburred string.
+ * @example
+ *
+ * _.deburr('déjà vu');
+ * // => 'deja vu'
+ */
+ function deburr(string) {
+ string = baseToString(string);
+ return string && string.replace(reLatin1, deburrLetter);
+ }
+
+ /**
+ * Checks if `string` ends with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=string.length] The position to search from.
+ * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`.
+ * @example
+ *
+ * _.endsWith('abc', 'c');
+ * // => true
+ *
+ * _.endsWith('abc', 'b');
+ * // => false
+ *
+ * _.endsWith('abc', 'b', 2);
+ * // => true
+ */
+ function endsWith(string, target, position) {
+ string = baseToString(string);
+ target = (target + '');
+
+ var length = string.length;
+ position = (typeof position == 'undefined' ? length : nativeMin(position < 0 ? 0 : (+position || 0), length)) - target.length;
+ return position >= 0 && string.indexOf(target, position) == position;
+ }
+
+ /**
+ * Converts the characters "&", "<", ">", '"', "'", and '`', in `string` to
+ * their corresponding HTML entities.
+ *
+ * **Note:** No other characters are escaped. To escape additional characters
+ * use a third-party library like [_he_](http://mths.be/he).
+ *
+ * Though the ">" character is escaped for symmetry, characters like
+ * ">" and "/" don't require escaping in HTML and have no special meaning
+ * unless they're part of a tag or unquoted attribute value.
+ * See [Mathias Bynens's article](http://mathiasbynens.be/notes/ambiguous-ampersands)
+ * (under "semi-related fun fact") for more details.
+ *
+ * Backticks are escaped because in Internet Explorer < 9, they can break out
+ * of attribute values or HTML comments. See [#102](http://html5sec.org/#102),
+ * [#108](http://html5sec.org/#108), and [#133](http://html5sec.org/#133) of
+ * the [HTML5 Security Cheatsheet](http://html5sec.org/) for more details.
+ *
+ * When working with HTML you should always quote attribute values to reduce
+ * XSS vectors. See [Ryan Grove's article](http://wonko.com/post/html-escaping)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function escape(string) {
+ // Reset `lastIndex` because in IE < 9 `String#replace` does not.
+ string = baseToString(string);
+ return (string && reHasUnescapedHtml.test(string))
+ ? string.replace(reUnescapedHtml, escapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*",
+ * "+", "(", ")", "[", "]", "{" and "}" in `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to escape.
+ * @returns {string} Returns the escaped string.
+ * @example
+ *
+ * _.escapeRegExp('[lodash](https://lodash.com/)');
+ * // => '\[lodash\]\(https://lodash\.com/\)'
+ */
+ function escapeRegExp(string) {
+ string = baseToString(string);
+ return (string && reHasRegExpChars.test(string))
+ ? string.replace(reRegExpChars, '\\$&')
+ : string;
+ }
+
+ /**
+ * Converts `string` to kebab case (a.k.a. spinal case).
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Letter_case#Computers) for
+ * more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the kebab cased string.
+ * @example
+ *
+ * _.kebabCase('Foo Bar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('fooBar');
+ * // => 'foo-bar'
+ *
+ * _.kebabCase('__foo_bar__');
+ * // => 'foo-bar'
+ */
+ var kebabCase = createCompounder(function(result, word, index) {
+ return result + (index ? '-' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Pads `string` on the left and right sides if it is shorter then the given
+ * padding length. The `chars` string may be truncated if the number of padding
+ * characters can't be evenly divided by the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.pad('abc', 8);
+ * // => ' abc '
+ *
+ * _.pad('abc', 8, '_-');
+ * // => '_-abc_-_'
+ *
+ * _.pad('abc', 3);
+ * // => 'abc'
+ */
+ function pad(string, length, chars) {
+ string = baseToString(string);
+ length = +length;
+
+ var strLength = string.length;
+ if (strLength >= length || !nativeIsFinite(length)) {
+ return string;
+ }
+ var mid = (length - strLength) / 2,
+ leftLength = floor(mid),
+ rightLength = ceil(mid);
+
+ chars = createPad('', rightLength, chars);
+ return chars.slice(0, leftLength) + string + chars;
+ }
+
+ /**
+ * Pads `string` on the left side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padLeft('abc', 6);
+ * // => ' abc'
+ *
+ * _.padLeft('abc', 6, '_-');
+ * // => '_-_abc'
+ *
+ * _.padLeft('abc', 3);
+ * // => 'abc'
+ */
+ function padLeft(string, length, chars) {
+ string = baseToString(string);
+ return string && (createPad(string, length, chars) + string);
+ }
+
+ /**
+ * Pads `string` on the right side if it is shorter then the given padding
+ * length. The `chars` string may be truncated if the number of padding
+ * characters exceeds the padding length.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to pad.
+ * @param {number} [length=0] The padding length.
+ * @param {string} [chars=' '] The string used as padding.
+ * @returns {string} Returns the padded string.
+ * @example
+ *
+ * _.padRight('abc', 6);
+ * // => 'abc '
+ *
+ * _.padRight('abc', 6, '_-');
+ * // => 'abc_-_'
+ *
+ * _.padRight('abc', 3);
+ * // => 'abc'
+ */
+ function padRight(string, length, chars) {
+ string = baseToString(string);
+ return string && (string + createPad(string, length, chars));
+ }
+
+ /**
+ * Converts `string` to an integer of the specified radix. If `radix` is
+ * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal,
+ * in which case a `radix` of `16` is used.
+ *
+ * **Note:** This method aligns with the ES5 implementation of `parseInt`.
+ * See the [ES5 spec](http://es5.github.io/#E) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} string The string to convert.
+ * @param {number} [radix] The radix to interpret `value` by.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {number} Returns the converted integer.
+ * @example
+ *
+ * _.parseInt('08');
+ * // => 8
+ *
+ * _.map(['6', '08', '10'], _.parseInt);
+ * // => [6, 8, 10]
+ */
+ function parseInt(string, radix, guard) {
+ if (guard && isIterateeCall(string, radix, guard)) {
+ radix = 0;
+ }
+ return nativeParseInt(string, radix);
+ }
+ // Fallback for environments with pre-ES5 implementations.
+ if (nativeParseInt(whitespace + '08') != 8) {
+ parseInt = function(string, radix, guard) {
+ // Firefox < 21 and Opera < 15 follow ES3 for `parseInt` and
+ // Chrome fails to trim leading <BOM> whitespace characters.
+ // See https://code.google.com/p/v8/issues/detail?id=3109.
+ if (guard ? isIterateeCall(string, radix, guard) : radix == null) {
+ radix = 0;
+ } else if (radix) {
+ radix = +radix;
+ }
+ string = trim(string);
+ return nativeParseInt(string, radix || (reHexPrefix.test(string) ? 16 : 10));
+ };
+ }
+
+ /**
+ * Repeats the given string `n` times.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to repeat.
+ * @param {number} [n=0] The number of times to repeat the string.
+ * @returns {string} Returns the repeated string.
+ * @example
+ *
+ * _.repeat('*', 3);
+ * // => '***'
+ *
+ * _.repeat('abc', 2);
+ * // => 'abcabc'
+ *
+ * _.repeat('abc', 0);
+ * // => ''
+ */
+ function repeat(string, n) {
+ var result = '';
+ string = baseToString(string);
+ n = +n;
+ if (n < 1 || !string || !nativeIsFinite(n)) {
+ return result;
+ }
+ // Leverage the exponentiation by squaring algorithm for a faster repeat.
+ // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring.
+ do {
+ if (n % 2) {
+ result += string;
+ }
+ n = floor(n / 2);
+ string += string;
+ } while (n);
+
+ return result;
+ }
+
+ /**
+ * Converts `string` to snake case.
+ * See [Wikipedia](http://en.wikipedia.org/wiki/Snake_case) for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to convert.
+ * @returns {string} Returns the snake cased string.
+ * @example
+ *
+ * _.snakeCase('Foo Bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('--foo-bar');
+ * // => 'foo_bar'
+ *
+ * _.snakeCase('fooBar');
+ * // => 'foo_bar'
+ */
+ var snakeCase = createCompounder(function(result, word, index) {
+ return result + (index ? '_' : '') + word.toLowerCase();
+ });
+
+ /**
+ * Checks if `string` starts with the given target string.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to search.
+ * @param {string} [target] The string to search for.
+ * @param {number} [position=0] The position to search from.
+ * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`.
+ * @example
+ *
+ * _.startsWith('abc', 'a');
+ * // => true
+ *
+ * _.startsWith('abc', 'b');
+ * // => false
+ *
+ * _.startsWith('abc', 'b', 1);
+ * // => true
+ */
+ function startsWith(string, target, position) {
+ string = baseToString(string);
+ position = position == null ? 0 : nativeMin(position < 0 ? 0 : (+position || 0), string.length);
+ return string.lastIndexOf(target, position) == position;
+ }
+
+ /**
+ * Creates a compiled template function that can interpolate data properties
+ * in "interpolate" delimiters, HTML-escape interpolated data properties in
+ * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+ * properties may be accessed as free variables in the template. If a setting
+ * object is provided it takes precedence over `_.templateSettings` values.
+ *
+ * **Note:** In the development build `_.template` utilizes sourceURLs for easier debugging.
+ * See the [HTML5 Rocks article on sourcemaps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+ * for more details.
+ *
+ * For more information on precompiling templates see
+ * [Lo-Dash's custom builds documentation](https://lodash.com/custom-builds).
+ *
+ * For more information on Chrome extension sandboxes see
+ * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The template string.
+ * @param {Object} [options] The options object.
+ * @param {RegExp} [options.escape] The HTML "escape" delimiter.
+ * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
+ * @param {Object} [options.imports] An object to import into the template as free variables.
+ * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
+ * @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
+ * @param {string} [options.variable] The data object variable name.
+ * @param- {Object} [otherOptions] Enables the legacy `options` param signature.
+ * @returns {Function} Returns the compiled template function.
+ * @example
+ *
+ * // using the "interpolate" delimiter to create a compiled template
+ * var compiled = _.template('hello <%= user %>!');
+ * compiled({ 'user': 'fred' });
+ * // => 'hello fred!'
+ *
+ * // using the HTML "escape" delimiter to escape data property values
+ * var compiled = _.template('<b><%- value %></b>');
+ * compiled({ 'value': '<script>' });
+ * // => '<b><script></b>'
+ *
+ * // using the "evaluate" delimiter to execute JavaScript and generate HTML
+ * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the internal `print` function in "evaluate" delimiters
+ * var compiled = _.template('<% print("hello " + user); %>!');
+ * compiled({ 'user': 'barney' });
+ * // => 'hello barney!'
+ *
+ * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
+ * var compiled = _.template('hello ${ user }!');
+ * compiled({ 'user': 'pebbles' });
+ * // => 'hello pebbles!'
+ *
+ * // using custom template delimiters
+ * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+ * var compiled = _.template('hello {{ user }}!');
+ * compiled({ 'user': 'mustache' });
+ * // => 'hello mustache!'
+ *
+ * // using backslashes to treat delimiters as plain text
+ * var compiled = _.template('<%= "\\<%- value %\\>" %>');
+ * compiled({ 'value': 'ignored' });
+ * // => '<%- value %>'
+ *
+ * // using the `imports` option to import `jQuery` as `jq`
+ * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
+ * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
+ * compiled({ 'users': ['fred', 'barney'] });
+ * // => '<li>fred</li><li>barney</li>'
+ *
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
+ * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
+ * compiled(data);
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
+ *
+ * // using the `variable` option to ensure a with-statement isn't used in the compiled template
+ * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
+ * compiled.source;
+ * // => function(data) {
+ * var __t, __p = '';
+ * __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
+ * return __p;
+ * }
+ *
+ * // using the `source` property to inline compiled templates for meaningful
+ * // line numbers in error messages and a stack trace
+ * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
+ * var JST = {\
+ * "main": ' + _.template(mainText).source + '\
+ * };\
+ * ');
+ */
+ function template(string, options, otherOptions) {
+ // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/)
+ // and Laura Doktorova's doT.js (https://github.com/olado/doT).
+ var settings = lodash.templateSettings;
+
+ if (otherOptions && isIterateeCall(string, options, otherOptions)) {
+ options = otherOptions = null;
+ }
+ string = baseToString(string);
+ options = baseAssign(baseAssign({}, otherOptions || options), settings, assignOwnDefaults);
+
+ var imports = baseAssign(baseAssign({}, options.imports), settings.imports, assignOwnDefaults),
+ importsKeys = keys(imports),
+ importsValues = baseValues(imports, importsKeys);
+
+ var isEscaping,
+ isEvaluating,
+ index = 0,
+ interpolate = options.interpolate || reNoMatch,
+ source = "__p += '";
+
+ // Compile the regexp to match each delimiter.
+ var reDelimiters = RegExp(
+ (options.escape || reNoMatch).source + '|' +
+ interpolate.source + '|' +
+ (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
+ (options.evaluate || reNoMatch).source + '|$'
+ , 'g');
+
+ // Use a sourceURL for easier debugging.
+ // See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl.
+ var sourceURL = '//# sourceURL=' +
+ ('sourceURL' in options
+ ? options.sourceURL
+ : ('lodash.templateSources[' + (++templateCounter) + ']')
+ ) + '\n';
+
+ string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
+ interpolateValue || (interpolateValue = esTemplateValue);
+
+ // Escape characters that can't be included in string literals.
+ source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
+
+ // Replace delimiters with snippets.
+ if (escapeValue) {
+ isEscaping = true;
+ source += "' +\n__e(" + escapeValue + ") +\n'";
+ }
+ if (evaluateValue) {
+ isEvaluating = true;
+ source += "';\n" + evaluateValue + ";\n__p += '";
+ }
+ if (interpolateValue) {
+ source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
+ }
+ index = offset + match.length;
+
+ // The JS engine embedded in Adobe products requires returning the `match`
+ // string in order to produce the correct `offset` value.
+ return match;
+ });
+
+ source += "';\n";
+
+ // If `variable` is not specified wrap a with-statement around the generated
+ // code to add the data object to the top of the scope chain.
+ var variable = options.variable;
+ if (!variable) {
+ source = 'with (obj) {\n' + source + '\n}\n';
+ }
+ // Cleanup code by stripping empty strings.
+ source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
+ .replace(reEmptyStringMiddle, '$1')
+ .replace(reEmptyStringTrailing, '$1;');
+
+ // Frame code as the function body.
+ source = 'function(' + (variable || 'obj') + ') {\n' +
+ (variable
+ ? ''
+ : 'obj || (obj = {});\n'
+ ) +
+ "var __t, __p = ''" +
+ (isEscaping
+ ? ', __e = _.escape'
+ : ''
+ ) +
+ (isEvaluating
+ ? ', __j = Array.prototype.join;\n' +
+ "function print() { __p += __j.call(arguments, '') }\n"
+ : ';\n'
+ ) +
+ source +
+ 'return __p\n}';
+
+ var result = attempt(function() {
+ return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues);
+ });
+
+ // Provide the compiled function's source by its `toString` method or
+ // the `source` property as a convenience for inlining compiled templates.
+ result.source = source;
+ if (isError(result)) {
+ throw result;
+ }
+ return result;
+ }
+
+ /**
+ * Removes leading and trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trim(' abc ');
+ * // => 'abc'
+ *
+ * _.trim('-_-abc-_-', '_-');
+ * // => 'abc'
+ *
+ * _.map([' foo ', ' bar '], _.trim);
+ * // => ['foo', 'bar]
+ */
+ function trim(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string), trimmedRightIndex(string) + 1);
+ }
+ chars = baseToString(chars);
+ return string.slice(charsLeftIndex(string, chars), charsRightIndex(string, chars) + 1);
+ }
+
+ /**
+ * Removes leading whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimLeft(' abc ');
+ * // => 'abc '
+ *
+ * _.trimLeft('-_-abc-_-', '_-');
+ * // => 'abc-_-'
+ */
+ function trimLeft(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(trimmedLeftIndex(string))
+ }
+ return string.slice(charsLeftIndex(string, baseToString(chars)));
+ }
+
+ /**
+ * Removes trailing whitespace or specified characters from `string`.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to trim.
+ * @param {string} [chars=whitespace] The characters to trim.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the trimmed string.
+ * @example
+ *
+ * _.trimRight(' abc ');
+ * // => ' abc'
+ *
+ * _.trimRight('-_-abc-_-', '_-');
+ * // => '-_-abc'
+ */
+ function trimRight(string, chars, guard) {
+ var value = string;
+ string = baseToString(string);
+ if (!string) {
+ return string;
+ }
+ if (guard ? isIterateeCall(value, chars, guard) : chars == null) {
+ return string.slice(0, trimmedRightIndex(string) + 1)
+ }
+ return string.slice(0, charsRightIndex(string, baseToString(chars)) + 1);
+ }
+
+ /**
+ * Truncates `string` if it is longer than the given maximum string length.
+ * The last characters of the truncated string are replaced with the omission
+ * string which defaults to "...".
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to truncate.
+ * @param {Object|number} [options] The options object or maximum string length.
+ * @param {number} [options.length=30] The maximum string length.
+ * @param {string} [options.omission='...'] The string to indicate text is omitted.
+ * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {string} Returns the truncated string.
+ * @example
+ *
+ * _.trunc('hi-diddly-ho there, neighborino');
+ * // => 'hi-diddly-ho there, neighbo...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', 24);
+ * // => 'hi-diddly-ho there, n...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': ' ' });
+ * // => 'hi-diddly-ho there,...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'length': 24, 'separator': /,? +/ });
+ * //=> 'hi-diddly-ho there...'
+ *
+ * _.trunc('hi-diddly-ho there, neighborino', { 'omission': ' [...]' });
+ * // => 'hi-diddly-ho there, neig [...]'
+ */
+ function trunc(string, options, guard) {
+ if (guard && isIterateeCall(string, options, guard)) {
+ options = null;
+ }
+ var length = DEFAULT_TRUNC_LENGTH,
+ omission = DEFAULT_TRUNC_OMISSION;
+
+ if (options != null) {
+ if (isObject(options)) {
+ var separator = 'separator' in options ? options.separator : separator;
+ length = 'length' in options ? +options.length || 0 : length;
+ omission = 'omission' in options ? baseToString(options.omission) : omission;
+ } else {
+ length = +options || 0;
+ }
+ }
+ string = baseToString(string);
+ if (length >= string.length) {
+ return string;
+ }
+ var end = length - omission.length;
+ if (end < 1) {
+ return omission;
+ }
+ var result = string.slice(0, end);
+ if (separator == null) {
+ return result + omission;
+ }
+ if (isRegExp(separator)) {
+ if (string.slice(end).search(separator)) {
+ var match,
+ newEnd,
+ substring = string.slice(0, end);
+
+ if (!separator.global) {
+ separator = RegExp(separator.source, (reFlags.exec(separator) || '') + 'g');
+ }
+ separator.lastIndex = 0;
+ while ((match = separator.exec(substring))) {
+ newEnd = match.index;
+ }
+ result = result.slice(0, newEnd == null ? end : newEnd);
+ }
+ } else if (string.indexOf(separator, end) != end) {
+ var index = result.lastIndexOf(separator);
+ if (index > -1) {
+ result = result.slice(0, index);
+ }
+ }
+ return result + omission;
+ }
+
+ /**
+ * The inverse of `_.escape`; this method converts the HTML entities
+ * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to their
+ * corresponding characters.
+ *
+ * **Note:** No other HTML entities are unescaped. To unescape additional HTML
+ * entities use a third-party library like [_he_](http://mths.be/he).
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to unescape.
+ * @returns {string} Returns the unescaped string.
+ * @example
+ *
+ * _.unescape('fred, barney, & pebbles');
+ * // => 'fred, barney, & pebbles'
+ */
+ function unescape(string) {
+ string = baseToString(string);
+ return (string && reHasEscapedHtml.test(string))
+ ? string.replace(reEscapedHtml, unescapeHtmlChar)
+ : string;
+ }
+
+ /**
+ * Splits `string` into an array of its words.
+ *
+ * @static
+ * @memberOf _
+ * @category String
+ * @param {string} [string=''] The string to inspect.
+ * @param {RegExp|string} [pattern] The pattern to match words.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Array} Returns the words of `string`.
+ * @example
+ *
+ * _.words('fred, barney, & pebbles');
+ * // => ['fred', 'barney', 'pebbles']
+ *
+ * _.words('fred, barney, & pebbles', /[^, ]+/g);
+ * // => ['fred', 'barney', '&', 'pebbles']
+ */
+ function words(string, pattern, guard) {
+ if (guard && isIterateeCall(string, pattern, guard)) {
+ pattern = null;
+ }
+ string = baseToString(string);
+ return string.match(pattern || reWords) || [];
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * Attempts to invoke `func`, returning either the result or the caught
+ * error object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} func The function to attempt.
+ * @returns {*} Returns the `func` result or error object.
+ * @example
+ *
+ * // avoid throwing errors for invalid selectors
+ * var elements = _.attempt(function() {
+ * return document.querySelectorAll(selector);
+ * });
+ *
+ * if (_.isError(elements)) {
+ * elements = [];
+ * }
+ */
+ function attempt(func) {
+ try {
+ return func();
+ } catch(e) {
+ return isError(e) ? e : Error(e);
+ }
+ }
+
+ /**
+ * Creates a function bound to an optional `thisArg`. If `func` is a property
+ * name the created callback returns the property value for a given element.
+ * If `func` is an object the created callback returns `true` for elements
+ * that contain the equivalent object properties, otherwise it returns `false`.
+ *
+ * @static
+ * @memberOf _
+ * @alias iteratee
+ * @category Utility
+ * @param {*} [func=_.identity] The value to convert to a callback.
+ * @param {*} [thisArg] The `this` binding of `func`.
+ * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
+ * @returns {Function} Returns the callback.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'barney', 'age': 36 },
+ * { 'user': 'fred', 'age': 40 }
+ * ];
+ *
+ * // wrap to create custom callback shorthands
+ * _.callback = _.wrap(_.callback, function(callback, func, thisArg) {
+ * var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
+ * if (!match) {
+ * return callback(func, thisArg);
+ * }
+ * return function(object) {
+ * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
+ * };
+ * });
+ *
+ * _.filter(users, 'age__gt36');
+ * // => [{ 'user': 'fred', 'age': 40 }]
+ */
+ function callback(func, thisArg, guard) {
+ if (guard && isIterateeCall(func, thisArg, guard)) {
+ thisArg = null;
+ }
+ return baseCallback(func, thisArg);
+ }
+
+ /**
+ * Creates a function that returns `value`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value The value to return from the new function.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var getter = _.constant(object);
+ * getter() === object;
+ * // => true
+ */
+ function constant(value) {
+ return function() {
+ return value;
+ };
+ }
+
+ /**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.identity(object) === object;
+ * // => true
+ */
+ function identity(value) {
+ return value;
+ }
+
+ /**
+ * Creates a function which performs a deep comparison between a given object
+ * and `source`, returning `true` if the given object has equivalent property
+ * values, else `false`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred', 'age': 40 },
+ * { 'user': 'barney', 'age': 36 }
+ * ];
+ *
+ * var matchesAge = _.matches({ 'age': 36 });
+ *
+ * _.filter(users, matchesAge);
+ * // => [{ 'user': 'barney', 'age': 36 }]
+ *
+ * _.find(users, matchesAge);
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+ function matches(source) {
+ return baseMatches(source, true);
+ }
+
+ /**
+ * Adds all own enumerable function properties of a source object to the
+ * destination object. If `object` is a function then methods are added to
+ * its prototype as well.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Function|Object} [object=this] object The destination object.
+ * @param {Object} source The object of functions to add.
+ * @param {Object} [options] The options object.
+ * @param {boolean} [options.chain=true] Specify whether the functions added
+ * are chainable.
+ * @returns {Function|Object} Returns `object`.
+ * @example
+ *
+ * function vowels(string) {
+ * return _.filter(string, function(v) {
+ * return /[aeiou]/i.test(v);
+ * });
+ * }
+ *
+ * _.mixin({ 'vowels': vowels });
+ * _.vowels('fred');
+ * // => ['e']
+ *
+ * _('fred').vowels().value();
+ * // => ['e']
+ *
+ * _.mixin({ 'vowels': vowels }, { 'chain': false });
+ * _('fred').vowels();
+ * // => ['e']
+ */
+ function mixin(object, source, options) {
+ if (options == null) {
+ var isObj = isObject(source),
+ props = isObj && keys(source),
+ methodNames = props && props.length && baseFunctions(source, props);
+
+ if (!(methodNames ? methodNames.length : isObj)) {
+ methodNames = false;
+ options = source;
+ source = object;
+ object = this;
+ }
+ }
+ if (!methodNames) {
+ methodNames = baseFunctions(source, keys(source));
+ }
+ var chain = true,
+ index = -1,
+ isFunc = isFunction(object),
+ length = methodNames.length;
+
+ if (options === false) {
+ chain = false;
+ } else if (isObject(options) && 'chain' in options) {
+ chain = options.chain;
+ }
+ while (++index < length) {
+ var methodName = methodNames[index],
+ func = source[methodName];
+
+ object[methodName] = func;
+ if (isFunc) {
+ object.prototype[methodName] = (function(func) {
+ return function() {
+ var chainAll = this.__chain__;
+ if (chain || chainAll) {
+ var result = object(this.__wrapped__);
+ (result.__actions__ = arrayCopy(this.__actions__)).push({ 'func': func, 'args': arguments, 'thisArg': object });
+ result.__chain__ = chainAll;
+ return result;
+ }
+ var args = [this.value()];
+ push.apply(args, arguments);
+ return func.apply(object, args);
+ };
+ }(func));
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Reverts the `_` variable to its previous value and returns a reference to
+ * the `lodash` function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @returns {Function} Returns the `lodash` function.
+ * @example
+ *
+ * var lodash = _.noConflict();
+ */
+ function noConflict() {
+ context._ = oldDash;
+ return this;
+ }
+
+ /**
+ * A no-operation function.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * _.noop(object) === undefined;
+ * // => true
+ */
+ function noop() {
+ // No operation performed.
+ }
+
+ /**
+ * Creates a function which returns the property value of `key` on a given object.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var users = [
+ * { 'user': 'fred' },
+ * { 'user': 'barney' }
+ * ];
+ *
+ * var getName = _.property('user');
+ *
+ * _.map(users, getName);
+ * // => ['fred', barney']
+ *
+ * _.pluck(_.sortBy(users, getName), 'user');
+ * // => ['barney', 'fred']
+ */
+ function property(key) {
+ return baseProperty(key + '');
+ }
+
+ /**
+ * The inverse of `_.property`; this method creates a function which returns
+ * the property value of a given key on `object`.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {Object} object The object to inspect.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var object = { 'user': 'fred', 'age': 40, 'active': true };
+ * _.map(['active', 'user'], _.propertyOf(object));
+ * // => [true, 'fred']
+ *
+ * var object = { 'a': 3, 'b': 1, 'c': 2 };
+ * _.sortBy(['a', 'b', 'c'], _.propertyOf(object));
+ * // => ['b', 'c', 'a']
+ */
+ function propertyOf(object) {
+ return function(key) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * Creates an array of numbers (positive and/or negative) progressing from
+ * `start` up to, but not including, `end`. If `start` is less than `end` a
+ * zero-length range is created unless a negative `step` is specified.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} [start=0] The start of the range.
+ * @param {number} end The end of the range.
+ * @param {number} [step=1] The value to increment or decrement by.
+ * @returns {Array} Returns the new array of numbers.
+ * @example
+ *
+ * _.range(4);
+ * // => [0, 1, 2, 3]
+ *
+ * _.range(1, 5);
+ * // => [1, 2, 3, 4]
+ *
+ * _.range(0, 20, 5);
+ * // => [0, 5, 10, 15]
+ *
+ * _.range(0, -4, -1);
+ * // => [0, -1, -2, -3]
+ *
+ * _.range(1, 4, 0);
+ * // => [1, 1, 1]
+ *
+ * _.range(0);
+ * // => []
+ */
+ function range(start, end, step) {
+ if (step && isIterateeCall(start, end, step)) {
+ end = step = null;
+ }
+ start = +start || 0;
+ step = step == null ? 1 : (+step || 0);
+
+ if (end == null) {
+ end = start;
+ start = 0;
+ } else {
+ end = +end || 0;
+ }
+ // Use `Array(length)` so engines like Chakra and V8 avoid slower modes.
+ // See http://youtu.be/XAqIpGU8ZZk#t=17m25s.
+ var index = -1,
+ length = nativeMax(ceil((end - start) / (step || 1)), 0),
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = start;
+ start += step;
+ }
+ return result;
+ }
+
+ /**
+ * Invokes the iteratee function `n` times, returning an array of the results
+ * of each invocation. The `iteratee` is bound to `thisArg` and invoked with
+ * one argument; (index).
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+ * @param {*} [thisArg] The `this` binding of `iteratee`.
+ * @returns {Array} Returns the array of results.
+ * @example
+ *
+ * var diceRolls = _.times(3, _.partial(_.random, 1, 6, false));
+ * // => [3, 6, 4]
+ *
+ * _.times(3, function(n) { mage.castSpell(n); });
+ * // => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2` respectively
+ *
+ * _.times(3, function(n) { this.cast(n); }, mage);
+ * // => also invokes `mage.castSpell(n)` three times
+ */
+ function times(n, iteratee, thisArg) {
+ n = +n;
+
+ // Exit early to avoid a JSC JIT bug in Safari 8
+ // where `Array(0)` is treated as `Array(1)`.
+ if (n < 1 || !nativeIsFinite(n)) {
+ return [];
+ }
+ var index = -1,
+ result = Array(nativeMin(n, MAX_ARRAY_LENGTH));
+
+ iteratee = bindCallback(iteratee, thisArg, 1);
+ while (++index < n) {
+ if (index < MAX_ARRAY_LENGTH) {
+ result[index] = iteratee(index);
+ } else {
+ iteratee(index);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Generates a unique ID. If `prefix` is provided the ID is appended to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {string} [prefix] The value to prefix the ID with.
+ * @returns {string} Returns the unique ID.
+ * @example
+ *
+ * _.uniqueId('contact_');
+ * // => 'contact_104'
+ *
+ * _.uniqueId();
+ * // => '105'
+ */
+ function uniqueId(prefix) {
+ var id = ++idCounter;
+ return baseToString(prefix) + id;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ // Ensure `new LodashWrapper` is an instance of `lodash`.
+ LodashWrapper.prototype = lodash.prototype;
+
+ // Add functions to the `Map` cache.
+ MapCache.prototype['delete'] = mapDelete;
+ MapCache.prototype.get = mapGet;
+ MapCache.prototype.has = mapHas;
+ MapCache.prototype.set = mapSet;
+
+ // Add functions to the `Set` cache.
+ SetCache.prototype.push = cachePush;
+
+ // Assign cache to `_.memoize`.
+ memoize.Cache = MapCache;
+
+ // Add functions that return wrapped values when chaining.
+ lodash.after = after;
+ lodash.ary = ary;
+ lodash.assign = assign;
+ lodash.at = at;
+ lodash.before = before;
+ lodash.bind = bind;
+ lodash.bindAll = bindAll;
+ lodash.bindKey = bindKey;
+ lodash.callback = callback;
+ lodash.chain = chain;
+ lodash.chunk = chunk;
+ lodash.compact = compact;
+ lodash.constant = constant;
+ lodash.countBy = countBy;
+ lodash.create = create;
+ lodash.curry = curry;
+ lodash.curryRight = curryRight;
+ lodash.debounce = debounce;
+ lodash.defaults = defaults;
+ lodash.defer = defer;
+ lodash.delay = delay;
+ lodash.difference = difference;
+ lodash.drop = drop;
+ lodash.dropRight = dropRight;
+ lodash.dropRightWhile = dropRightWhile;
+ lodash.dropWhile = dropWhile;
+ lodash.filter = filter;
+ lodash.flatten = flatten;
+ lodash.flattenDeep = flattenDeep;
+ lodash.flow = flow;
+ lodash.flowRight = flowRight;
+ lodash.forEach = forEach;
+ lodash.forEachRight = forEachRight;
+ lodash.forIn = forIn;
+ lodash.forInRight = forInRight;
+ lodash.forOwn = forOwn;
+ lodash.forOwnRight = forOwnRight;
+ lodash.functions = functions;
+ lodash.groupBy = groupBy;
+ lodash.indexBy = indexBy;
+ lodash.initial = initial;
+ lodash.intersection = intersection;
+ lodash.invert = invert;
+ lodash.invoke = invoke;
+ lodash.keys = keys;
+ lodash.keysIn = keysIn;
+ lodash.map = map;
+ lodash.mapValues = mapValues;
+ lodash.matches = matches;
+ lodash.memoize = memoize;
+ lodash.merge = merge;
+ lodash.mixin = mixin;
+ lodash.negate = negate;
+ lodash.omit = omit;
+ lodash.once = once;
+ lodash.pairs = pairs;
+ lodash.partial = partial;
+ lodash.partialRight = partialRight;
+ lodash.partition = partition;
+ lodash.pick = pick;
+ lodash.pluck = pluck;
+ lodash.property = property;
+ lodash.propertyOf = propertyOf;
+ lodash.pull = pull;
+ lodash.pullAt = pullAt;
+ lodash.range = range;
+ lodash.rearg = rearg;
+ lodash.reject = reject;
+ lodash.remove = remove;
+ lodash.rest = rest;
+ lodash.shuffle = shuffle;
+ lodash.slice = slice;
+ lodash.sortBy = sortBy;
+ lodash.sortByAll = sortByAll;
+ lodash.take = take;
+ lodash.takeRight = takeRight;
+ lodash.takeRightWhile = takeRightWhile;
+ lodash.takeWhile = takeWhile;
+ lodash.tap = tap;
+ lodash.throttle = throttle;
+ lodash.thru = thru;
+ lodash.times = times;
+ lodash.toArray = toArray;
+ lodash.toPlainObject = toPlainObject;
+ lodash.transform = transform;
+ lodash.union = union;
+ lodash.uniq = uniq;
+ lodash.unzip = unzip;
+ lodash.values = values;
+ lodash.valuesIn = valuesIn;
+ lodash.where = where;
+ lodash.without = without;
+ lodash.wrap = wrap;
+ lodash.xor = xor;
+ lodash.zip = zip;
+ lodash.zipObject = zipObject;
+
+ // Add aliases.
+ lodash.backflow = flowRight;
+ lodash.collect = map;
+ lodash.compose = flowRight;
+ lodash.each = forEach;
+ lodash.eachRight = forEachRight;
+ lodash.extend = assign;
+ lodash.iteratee = callback;
+ lodash.methods = functions;
+ lodash.object = zipObject;
+ lodash.select = filter;
+ lodash.tail = rest;
+ lodash.unique = uniq;
+
+ // Add functions to `lodash.prototype`.
+ mixin(lodash, lodash);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions that return unwrapped values when chaining.
+ lodash.attempt = attempt;
+ lodash.camelCase = camelCase;
+ lodash.capitalize = capitalize;
+ lodash.clone = clone;
+ lodash.cloneDeep = cloneDeep;
+ lodash.deburr = deburr;
+ lodash.endsWith = endsWith;
+ lodash.escape = escape;
+ lodash.escapeRegExp = escapeRegExp;
+ lodash.every = every;
+ lodash.find = find;
+ lodash.findIndex = findIndex;
+ lodash.findKey = findKey;
+ lodash.findLast = findLast;
+ lodash.findLastIndex = findLastIndex;
+ lodash.findLastKey = findLastKey;
+ lodash.findWhere = findWhere;
+ lodash.first = first;
+ lodash.has = has;
+ lodash.identity = identity;
+ lodash.includes = includes;
+ lodash.indexOf = indexOf;
+ lodash.isArguments = isArguments;
+ lodash.isArray = isArray;
+ lodash.isBoolean = isBoolean;
+ lodash.isDate = isDate;
+ lodash.isElement = isElement;
+ lodash.isEmpty = isEmpty;
+ lodash.isEqual = isEqual;
+ lodash.isError = isError;
+ lodash.isFinite = isFinite;
+ lodash.isFunction = isFunction;
+ lodash.isMatch = isMatch;
+ lodash.isNaN = isNaN;
+ lodash.isNative = isNative;
+ lodash.isNull = isNull;
+ lodash.isNumber = isNumber;
+ lodash.isObject = isObject;
+ lodash.isPlainObject = isPlainObject;
+ lodash.isRegExp = isRegExp;
+ lodash.isString = isString;
+ lodash.isTypedArray = isTypedArray;
+ lodash.isUndefined = isUndefined;
+ lodash.kebabCase = kebabCase;
+ lodash.last = last;
+ lodash.lastIndexOf = lastIndexOf;
+ lodash.max = max;
+ lodash.min = min;
+ lodash.noConflict = noConflict;
+ lodash.noop = noop;
+ lodash.now = now;
+ lodash.pad = pad;
+ lodash.padLeft = padLeft;
+ lodash.padRight = padRight;
+ lodash.parseInt = parseInt;
+ lodash.random = random;
+ lodash.reduce = reduce;
+ lodash.reduceRight = reduceRight;
+ lodash.repeat = repeat;
+ lodash.result = result;
+ lodash.runInContext = runInContext;
+ lodash.size = size;
+ lodash.snakeCase = snakeCase;
+ lodash.some = some;
+ lodash.sortedIndex = sortedIndex;
+ lodash.sortedLastIndex = sortedLastIndex;
+ lodash.startsWith = startsWith;
+ lodash.template = template;
+ lodash.trim = trim;
+ lodash.trimLeft = trimLeft;
+ lodash.trimRight = trimRight;
+ lodash.trunc = trunc;
+ lodash.unescape = unescape;
+ lodash.uniqueId = uniqueId;
+ lodash.words = words;
+
+ // Add aliases.
+ lodash.all = every;
+ lodash.any = some;
+ lodash.contains = includes;
+ lodash.detect = find;
+ lodash.foldl = reduce;
+ lodash.foldr = reduceRight;
+ lodash.head = first;
+ lodash.include = includes;
+ lodash.inject = reduce;
+
+ mixin(lodash, (function() {
+ var source = {};
+ baseForOwn(lodash, function(func, methodName) {
+ if (!lodash.prototype[methodName]) {
+ source[methodName] = func;
+ }
+ });
+ return source;
+ }()), false);
+
+ /*------------------------------------------------------------------------*/
+
+ // Add functions capable of returning wrapped and unwrapped values when chaining.
+ lodash.sample = sample;
+
+ lodash.prototype.sample = function(n) {
+ if (!this.__chain__ && n == null) {
+ return sample(this.value());
+ }
+ return this.thru(function(value) {
+ return sample(value, n);
+ });
+ };
+
+ /*------------------------------------------------------------------------*/
+
+ /**
+ * The semantic version number.
+ *
+ * @static
+ * @memberOf _
+ * @type string
+ */
+ lodash.VERSION = VERSION;
+
+ // Assign default placeholders.
+ arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
+ lodash[methodName].placeholder = lodash;
+ });
+
+ // Add `LazyWrapper` methods that accept an `iteratee` value.
+ arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
+ var isFilter = index == LAZY_FILTER_FLAG;
+
+ LazyWrapper.prototype[methodName] = function(iteratee, thisArg) {
+ var result = this.clone(),
+ filtered = result.filtered,
+ iteratees = result.iteratees || (result.iteratees = []);
+
+ result.filtered = filtered || isFilter || (index == LAZY_WHILE_FLAG && result.dir < 0);
+ iteratees.push({ 'iteratee': getCallback(iteratee, thisArg, 3), 'type': index });
+ return result;
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
+ arrayEach(['drop', 'take'], function(methodName, index) {
+ var countName = methodName + 'Count',
+ whileName = methodName + 'While';
+
+ LazyWrapper.prototype[methodName] = function(n) {
+ n = n == null ? 1 : nativeMax(+n || 0, 0);
+
+ var result = this.clone();
+ if (result.filtered) {
+ var value = result[countName];
+ result[countName] = index ? nativeMin(value, n) : (value + n);
+ } else {
+ var views = result.views || (result.views = []);
+ views.push({ 'size': n, 'type': methodName + (result.dir < 0 ? 'Right' : '') });
+ }
+ return result;
+ };
+
+ LazyWrapper.prototype[methodName + 'Right'] = function(n) {
+ return this.reverse()[methodName](n).reverse();
+ };
+
+ LazyWrapper.prototype[methodName + 'RightWhile'] = function(predicate, thisArg) {
+ return this.reverse()[whileName](predicate, thisArg).reverse();
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.first` and `_.last`.
+ arrayEach(['first', 'last'], function(methodName, index) {
+ var takeName = 'take' + (index ? 'Right': '');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[takeName](1).value()[0];
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.initial` and `_.rest`.
+ arrayEach(['initial', 'rest'], function(methodName, index) {
+ var dropName = 'drop' + (index ? '' : 'Right');
+
+ LazyWrapper.prototype[methodName] = function() {
+ return this[dropName](1);
+ };
+ });
+
+ // Add `LazyWrapper` methods for `_.pluck` and `_.where`.
+ arrayEach(['pluck', 'where'], function(methodName, index) {
+ var operationName = index ? 'filter' : 'map',
+ createCallback = index ? matches : property;
+
+ LazyWrapper.prototype[methodName] = function(value) {
+ return this[operationName](createCallback(value));
+ };
+ });
+
+ LazyWrapper.prototype.dropWhile = function(iteratee, thisArg) {
+ var done,
+ lastIndex,
+ isRight = this.dir < 0;
+
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ done = done && (isRight ? index < lastIndex : index > lastIndex);
+ lastIndex = index;
+ return done || (done = !iteratee(value, index, array));
+ });
+ };
+
+ LazyWrapper.prototype.reject = function(iteratee, thisArg) {
+ iteratee = getCallback(iteratee, thisArg, 3);
+ return this.filter(function(value, index, array) {
+ return !iteratee(value, index, array);
+ });
+ };
+
+ LazyWrapper.prototype.slice = function(start, end) {
+ start = start == null ? 0 : (+start || 0);
+ var result = start < 0 ? this.takeRight(-start) : this.drop(start);
+
+ if (typeof end != 'undefined') {
+ end = (+end || 0);
+ result = end < 0 ? result.dropRight(-end) : result.take(end - start);
+ }
+ return result;
+ };
+
+ // Add `LazyWrapper` methods to `lodash.prototype`.
+ baseForOwn(LazyWrapper.prototype, function(func, methodName) {
+ var retUnwrapped = /^(?:first|last)$/.test(methodName);
+
+ lodash.prototype[methodName] = function() {
+ var value = this.__wrapped__,
+ args = arguments,
+ chainAll = this.__chain__,
+ isHybrid = !!this.__actions__.length,
+ isLazy = value instanceof LazyWrapper,
+ onlyLazy = isLazy && !isHybrid;
+
+ if (retUnwrapped && !chainAll) {
+ return onlyLazy
+ ? func.call(value)
+ : lodash[methodName](this.value());
+ }
+ var interceptor = function(value) {
+ var otherArgs = [value];
+ push.apply(otherArgs, args);
+ return lodash[methodName].apply(lodash, otherArgs);
+ };
+ if (isLazy || isArray(value)) {
+ var wrapper = onlyLazy ? value : new LazyWrapper(this),
+ result = func.apply(wrapper, args);
+
+ if (!retUnwrapped && (isHybrid || result.actions)) {
+ var actions = result.actions || (result.actions = []);
+ actions.push({ 'func': thru, 'args': [interceptor], 'thisArg': lodash });
+ }
+ return new LodashWrapper(result, chainAll);
+ }
+ return this.thru(interceptor);
+ };
+ });
+
+ // Add `Array.prototype` functions to `lodash.prototype`.
+ arrayEach(['concat', 'join', 'pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
+ var arrayFunc = arrayProto[methodName],
+ chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
+ fixObjects = !support.spliceObjects && /^(?:pop|shift|splice)$/.test(methodName),
+ retUnwrapped = /^(?:join|pop|shift)$/.test(methodName);
+
+ // Avoid array-like object bugs with `Array#shift` and `Array#splice` in
+ // IE < 9, Firefox < 10, Narwhal, and RingoJS.
+ var func = !fixObjects ? arrayFunc : function() {
+ var result = arrayFunc.apply(this, arguments);
+ if (this.length === 0) {
+ delete this[0];
+ }
+ return result;
+ };
+
+ lodash.prototype[methodName] = function() {
+ var args = arguments;
+ if (retUnwrapped && !this.__chain__) {
+ return func.apply(this.value(), args);
+ }
+ return this[chainName](function(value) {
+ return func.apply(value, args);
+ });
+ };
+ });
+
+ // Add functions to the lazy wrapper.
+ LazyWrapper.prototype.clone = lazyClone;
+ LazyWrapper.prototype.reverse = lazyReverse;
+ LazyWrapper.prototype.value = lazyValue;
+
+ // Add chaining functions to the lodash wrapper.
+ lodash.prototype.chain = wrapperChain;
+ lodash.prototype.reverse = wrapperReverse;
+ lodash.prototype.toString = wrapperToString;
+ lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
+
+ // Add function aliases to the lodash wrapper.
+ lodash.prototype.collect = lodash.prototype.map;
+ lodash.prototype.head = lodash.prototype.first;
+ lodash.prototype.select = lodash.prototype.filter;
+ lodash.prototype.tail = lodash.prototype.rest;
+
+ return lodash;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // Export Lo-Dash.
+ var _ = runInContext();
+
+ // Some AMD build optimizers like r.js check for condition patterns like the following:
+ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ // Expose Lo-Dash to the global object when an AMD loader is present to avoid
+ // errors in cases where Lo-Dash is loaded by a script tag and not intended
+ // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch.
+ root._ = _;
+
+ // Define as an anonymous module so, through path mapping, it can be
+ // referenced as the "underscore" module.
+ define(function() {
+ return _;
+ });
+ }
+ // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
+ else if (freeExports && freeModule) {
+ // Export for Node.js or RingoJS.
+ if (moduleExports) {
+ (freeModule.exports = _)._ = _;
+ }
+ // Export for Narwhal or Rhino -require.
+ else {
+ freeExports._ = _;
+ }
+ }
+ else {
+ // Export for a browser or Rhino.
+ root._ = _;
+ }
+}.call(this));
diff --git a/package.json b/package.json
index 499f521..3db59bb 100644
--- a/package.json
+++ b/package.json
@@ -1,58 +1,29 @@
{
"name": "lodash",
- "version": "2.4.1",
- "description": "A utility library delivering consistency, customization, performance, & extras.",
- "homepage": "http://lodash.com/",
- "license": "MIT",
- "main": "dist/lodash.js",
- "keywords": ["amd", "browser", "client", "customize", "functional", "server", "util"],
- "author": "John-David Dalton <john.david.dalton at gmail.com> (http://allyoucanleet.com/)",
- "contributors": [
- "John-David Dalton <john.david.dalton at gmail.com> (http://allyoucanleet.com/)",
- "Blaine Bublitz <blaine at iceddev.com> (http://www.iceddev.com/)",
- "Kit Cambridge <github at kitcambridge.be> (http://kitcambridge.be/)",
- "Mathias Bynens <mathias at qiwi.be> (http://mathiasbynens.be/)"
- ],
- "bugs": "https://github.com/lodash/lodash/issues",
- "repository": { "type": "git", "url": "https://github.com/lodash/lodash.git" },
- "engines": ["node", "rhino"],
- "files": [
- "LICENSE.txt",
- "lodash.js",
- "dist/lodash.js",
- "dist/lodash.min.js",
- "dist/lodash.compat.js",
- "dist/lodash.compat.min.js",
- "dist/lodash.underscore.js",
- "dist/lodash.underscore.min.js"
- ],
- "jam": {
- "main": "dist/lodash.compat.js",
- "include": [
- "LICENSE.txt",
- "dist/lodash.js",
- "dist/lodash.min.js",
- "dist/lodash.compat.js",
- "dist/lodash.compat.min.js",
- "dist/lodash.underscore.js",
- "dist/lodash.underscore.min.js"
- ]
+ "version": "3.0.0",
+ "main": "lodash.src.js",
+ "private": true,
+ "devDependencies": {
+ "curl-amd": "0.8.12",
+ "dojo": "~1.10.2",
+ "jquery": "~1.11.2",
+ "platform": "~1.3.0",
+ "qunit-extras": "~1.4.0",
+ "qunitjs": "~1.16.0",
+ "requirejs": "~2.1.15"
},
"volo": {
"type": "directory",
"ignore": [
".*",
"*.custom.*",
- "*.min.*",
- "*.template.*",
+ "*.log",
"*.map",
"*.md",
- "lodash.js",
- "index.js",
+ "lodash.src.js",
"bower.json",
"component.json",
"doc",
- "modularize",
"node_modules",
"perf",
"test",
diff --git a/perf/asset/perf-ui.js b/perf/asset/perf-ui.js
index ecb5b7c..b475082 100644
--- a/perf/asset/perf-ui.js
+++ b/perf/asset/perf-ui.js
@@ -1,16 +1,16 @@
;(function(window) {
'use strict';
- /** The base path of the builds */
+ /** The base path of the Lo-Dash builds. */
var basePath = '../';
- /** The Lo-Dash build to load */
+ /** The Lo-Dash build to load. */
var build = (build = /build=([^&]+)/.exec(location.search)) && decodeURIComponent(build[1]);
- /** The other library to load */
+ /** The other library to load. */
var other = (other = /other=([^&]+)/.exec(location.search)) && decodeURIComponent(other[1]);
- /** The `ui` object */
+ /** The `ui` object. */
var ui = {};
/*--------------------------------------------------------------------------*/
@@ -34,7 +34,7 @@
/*--------------------------------------------------------------------------*/
- // initialize controls
+ // Initialize controls.
addListener(window, 'load', function() {
function eventHandler(event) {
var buildIndex = buildList.selectedIndex,
@@ -59,10 +59,7 @@
'<label for="perf-build">Build: </label>' +
'<select id="perf-build">' +
'<option value="lodash-compat">Lo-Dash (compat)</option>' +
- '<option value="lodash-legacy">Lo-Dash (legacy)</option>' +
- '<option value="lodash-mobile">Lo-Dash (mobile)</option>' +
'<option value="lodash-modern">Lo-Dash (modern)</option>' +
- '<option value="lodash-underscore">Lo-Dash (underscore)</option>' +
'<option value="lodash-custom-dev">Lo-Dash (custom development)</option>' +
'<option value="lodash-custom">Lo-Dash (custom production)</option>' +
'</select>';
@@ -75,10 +72,7 @@
'<option value="underscore-dev">Underscore (development)</option>' +
'<option value="underscore">Underscore (production)</option>' +
'<option value="lodash-compat">Lo-Dash (compat)</option>' +
- '<option value="lodash-legacy">Lo-Dash (legacy)</option>' +
- '<option value="lodash-mobile">Lo-Dash (mobile)</option>' +
'<option value="lodash-modern">Lo-Dash (modern)</option>' +
- '<option value="lodash-underscore">Lo-Dash (underscore)</option>' +
'<option value="lodash-custom-dev">Lo-Dash (custom development)</option>' +
'<option value="lodash-custom">Lo-Dash (custom production)</option>' +
'</select>';
@@ -93,13 +87,10 @@
buildList.selectedIndex = (function() {
switch (build) {
case 'lodash-compat': return 0;
- case 'lodash-legacy': return 1;
- case 'lodash-mobile': return 2;
- case 'lodash-underscore': return 4;
- case 'lodash-custom-dev': return 5;
- case 'lodash-custom': return 6;
+ case 'lodash-custom-dev': return 2;
+ case 'lodash-custom': return 3;
case 'lodash-modern':
- case null: return 3;
+ case null: return 1;
}
return -1;
}());
@@ -108,12 +99,9 @@
switch (other) {
case 'underscore-dev': return 0;
case 'lodash-compat': return 2;
- case 'lodash-legacy': return 3;
- case 'lodash-mobile': return 4;
- case 'lodash-modern': return 5;
- case 'lodash-underscore': return 6;
- case 'lodash-custom-dev': return 7;
- case 'lodash-custom': return 8;
+ case 'lodash-modern': return 3;
+ case 'lodash-custom-dev': return 4;
+ case 'lodash-custom': return 5;
case 'underscore':
case null: return 1;
}
@@ -124,49 +112,38 @@
addListener(otherList, 'change', eventHandler);
});
- // expose Lo-Dash build file path
+ // The Lo-Dash build file path.
ui.buildPath = (function() {
var result;
switch (build) {
- case 'lodash-compat': result = 'dist/lodash.compat.min.js'; break;
- case 'lodash-legacy': result = 'dist/lodash.legacy.min.js'; break;
- case 'lodash-mobile': result = 'dist/lodash.mobile.min.js'; break;
- case 'lodash-underscore': result = 'dist/lodash.underscore.min.js'; break;
+ case 'lodash-compat': result = 'lodash.compat.min.js'; break;
case 'lodash-custom-dev': result = 'lodash.custom.js'; break;
case 'lodash-custom': result = 'lodash.custom.min.js'; break;
- case null: build = 'lodash-modern';
- case 'lodash-modern': result = 'dist/lodash.min.js'; break;
+ case null: build = 'lodash-modern';
+ case 'lodash-modern': result = 'lodash.min.js'; break;
default: return build;
}
return basePath + result;
}());
- // expose other library file path
+ // The other library file path.
ui.otherPath = (function() {
var result;
switch (other) {
- case 'lodash-compat': result = 'dist/lodash.compat.min.js'; break;
- case 'lodash-legacy': result = 'dist/lodash.legacy.min.js'; break;
- case 'lodash-mobile': result = 'dist/lodash.mobile.min.js'; break;
- case 'lodash-modern': result = 'dist/lodash.min.js'; break;
- case 'lodash-underscore': result = 'dist/lodash.underscore.min.js'; break;
+ case 'lodash-compat': result = 'lodash.compat.min.js'; break;
+ case 'lodash-modern': result = 'lodash.min.js'; break;
case 'lodash-custom-dev': result = 'lodash.custom.js'; break;
case 'lodash-custom': result = 'lodash.custom.min.js'; break;
case 'underscore-dev': result = 'vendor/underscore/underscore.js'; break;
- case null: other = 'underscore';
+ case null: other = 'underscore';
case 'underscore': result = 'vendor/underscore/underscore-min.js'; break;
default: return other;
}
return basePath + result;
}());
- // expose `ui.urlParams` properties
- ui.urlParams = {
- 'build': build,
- 'other': other
- };
+ ui.urlParams = { 'build': build, 'other': other };
- // expose `ui`
window.ui = ui;
}(this));
diff --git a/perf/index.html b/perf/index.html
index 2c559a3..a5285ac 100644
--- a/perf/index.html
+++ b/perf/index.html
@@ -28,8 +28,8 @@
</head>
<body>
<div id="perf-toolbar"></div>
- <script src="../vendor/platform.js/platform.js"></script>
- <script src="../lodash.js"></script>
+ <script src="../node_modules/platform/platform.js"></script>
+ <script src="../lodash.src.js"></script>
<script src="../vendor/benchmark.js/benchmark.js"></script>
<script src="../vendor/firebug-lite/src/firebug-lite-debug.js"></script>
<script src="./asset/perf-ui.js"></script>
@@ -69,8 +69,8 @@
// is the applet permitted?
if (!/[?&]nojava=true(?:&|$)/.test(location.search)) {
// is the applet really needed?
- while (!(measured = new Date - begin)) { }
- if (measured != 1 && !((perfNow = window.performance) && typeof (perfNow.now || perfNow.webkitNow) == 'function')) {
+ while (!(measured = new Date - begin)) {}
+ if (measured > 1 && !((perfNow = window.performance) && typeof (perfNow.now || perfNow.webkitNow) == 'function')) {
// load applet
document.write('<applet code="nano" archive="../vendor/benchmark.js/nano.jar"></applet>');
}
diff --git a/perf/perf.js b/perf/perf.js
index 34d84ed..274e6dd 100644
--- a/perf/perf.js
+++ b/perf/perf.js
@@ -1,94 +1,121 @@
-;(function(root) {
+;(function() {
- /** Use a single "load" function */
- var load = typeof require == 'function' ? require : root.load;
-
- /** The file path of the Lo-Dash file to test */
- var filePath = (function() {
- var min = 0;
- var result = root.phantom
- ? phantom.args
- : (root.system
- ? (min = 1, system.args)
- : (root.process ? (min = 2, process.argv) : (root.arguments || []))
- );
+ /** Used to access the Firebug Lite panel (set by `run`). */
+ var fbPanel;
- var last = result[result.length - 1];
- result = (result.length > min && !/perf(?:\.js)?$/.test(last))
- ? last
- : '../lodash.js';
+ /** Used as a safe reference for `undefined` in pre ES5 environments. */
+ var undefined;
- try {
- result = require('fs').realpathSync(result);
- } catch(e) { }
+ /** Used as a reference to the global object. */
+ var root = typeof global == 'object' && global || this;
- return result;
- }());
+ /** Method and object shortcuts. */
+ var phantom = root.phantom,
+ amd = root.define && define.amd,
+ argv = root.process && process.argv,
+ document = !phantom && root.document,
+ noop = function() {},
+ params = root.arguments,
+ system = root.system;
- /** Load Lo-Dash */
- var lodash = root.lodash || (root.lodash = (
- lodash = load(filePath) || root._,
- lodash = lodash._ || lodash,
- lodash.noConflict()
- ));
+ /** Add `console.log()` support for Narwhal, Rhino, and RingoJS. */
+ var console = root.console || (root.console = { 'log': root.print });
- /** Load Benchmark.js */
- var Benchmark = root.Benchmark || (root.Benchmark = (
- Benchmark = load('../vendor/benchmark.js/benchmark.js') || root.Benchmark,
- Benchmark = Benchmark.Benchmark || Benchmark,
- Benchmark.runInContext(lodash.extend({}, root, { '_': lodash }))
- ));
+ /** The file path of the Lo-Dash file to test. */
+ var filePath = (function() {
+ var min = 0,
+ result = [];
+
+ if (phantom) {
+ result = params = phantom.args;
+ } else if (system) {
+ min = 1;
+ result = params = system.args;
+ } else if (argv) {
+ min = 2;
+ result = params = argv;
+ } else if (params) {
+ result = params;
+ }
+ var last = result[result.length - 1];
+ result = (result.length > min && !/perf(?:\.js)?$/.test(last)) ? last : '../lodash.src.js';
- /** Load Underscore */
- var _ = root._ || (root._ = (
- _ = load('../vendor/underscore/underscore.js') || root._,
- _._ || _
- ));
+ if (!amd) {
+ try {
+ result = require('fs').realpathSync(result);
+ } catch(e) {}
- /** Used to access the Firebug Lite panel (set by `run`) */
- var fbPanel;
+ try {
+ result = require.resolve(result);
+ } catch(e) {}
+ }
+ return result;
+ }());
- /** Used to match path separators */
+ /** Used to match path separators. */
var rePathSeparator = /[\/\\]/;
- /** Used to detect primitive types */
+ /** Used to detect primitive types. */
var rePrimitive = /^(?:boolean|number|string|undefined)$/;
- /** Used to match RegExp special characters */
+ /** Used to match RegExp special characters. */
var reSpecialChars = /[.*+?^=!:${}()|[\]\/\\]/g;
- /** Used to score performance */
- var score = { 'a': [], 'b': [] };
-
- /** Used to queue benchmark suites */
- var suites = [];
-
- /** Used to resolve a value's internal [[Class]] */
- var toString = Object.prototype.toString;
-
- /** The `ui` object */
+ /** The `ui` object. */
var ui = root.ui || (root.ui = {
'buildPath': basename(filePath, '.js'),
'otherPath': 'underscore'
});
- /** The Lo-Dash build basename */
+ /** The Lo-Dash build basename. */
var buildName = root.buildName = basename(ui.buildPath, '.js');
- /** The other library basename */
+ /** The other library basename. */
var otherName = root.otherName = (function() {
var result = basename(ui.otherPath, '.js');
return result + (result == buildName ? ' (2)' : '');
}());
- /** Detect if in a browser environment */
+ /** Used to score performance. */
+ var score = { 'a': [], 'b': [] };
+
+ /** Used to queue benchmark suites. */
+ var suites = [];
+
+ /** Used to resolve a value's internal [[Class]]. */
+ var toString = Object.prototype.toString;
+
+ /** Detect if in a browser environment. */
var isBrowser = isHostType(root, 'document') && isHostType(root, 'navigator');
- /** Detect Java environment */
+ /** Detect if in a Java environment. */
var isJava = !isBrowser && /Java/.test(toString.call(root.java));
- /** Add `console.log()` support for Narwhal, Rhino, and RingoJS */
- var console = root.console || (root.console = { 'log': root.print });
+ /** Use a single "load" function. */
+ var load = (typeof require == 'function' && !amd)
+ ? require
+ : (isJava && root.load) || noop;
+
+ /** Load Lo-Dash. */
+ var lodash = root.lodash || (root.lodash = (
+ lodash = load(filePath) || root._,
+ lodash = lodash._ || lodash,
+ (lodash.runInContext ? lodash.runInContext(root) : lodash),
+ lodash.noConflict()
+ ));
+
+ /** Load Benchmark.js. */
+ var Benchmark = root.Benchmark || (root.Benchmark = (
+ Benchmark = load('../vendor/benchmark.js/benchmark.js') || root.Benchmark,
+ Benchmark = Benchmark.Benchmark || Benchmark,
+ Benchmark.runInContext(lodash.extend({}, root, { '_': lodash }))
+ ));
+
+ /** Load Underscore. */
+ var _ = root._ || (root._ = (
+ _ = load('../vendor/underscore/underscore.js') || root._,
+ _._ || _
+ ));
/*--------------------------------------------------------------------------*/
@@ -162,7 +189,7 @@
function log(text) {
console.log(text + '');
if (fbPanel) {
- // scroll the Firebug Lite panel down
+ // Scroll the Firebug Lite panel down.
fbPanel.scrollTop = fbPanel.scrollHeight;
}
}
@@ -222,15 +249,15 @@
'% faster.'
);
}
- // add score adjusted for margin of error
+ // Add score adjusted for margin of error.
score.a.push(aHz);
score.b.push(bHz);
}
- // remove current suite from queue
+ // Remove current suite from queue.
suites.shift();
if (suites.length) {
- // run next suite
+ // Run next suite.
suites[0].run({ 'async': !isJava });
}
else {
@@ -242,7 +269,7 @@
percentFaster = formatNumber(Math.round((xFaster - 1) * 100)),
message = 'is ' + percentFaster + '% ' + (xFaster == 1 ? '' : '(' + formatNumber(xFaster.toFixed(2)) + 'x) ') + 'faster than';
- // report results
+ // Report results.
if (aMeanHz >= bMeanHz) {
log('\n' + buildName + ' ' + message + ' ' + otherName + '.');
} else {
@@ -261,9 +288,8 @@
lodash = global.lodash,\
belt = this.name == buildName ? lodash : _;\
\
- var index,\
- date = new Date,\
- limit = 20,\
+ var date = new Date,\
+ limit = 50,\
regexp = /x/,\
object = {},\
objects = Array(limit),\
@@ -273,17 +299,18 @@
nestedObjects = [{}, [{}], [{}, [[{}]]]],\
twoNumbers = [12, 23];\
\
- for (index = 0; index < limit; index++) {\
+ for (var index = 0; index < limit; index++) {\
numbers[index] = index;\
object["key" + index] = index;\
objects[index] = { "num": index };\
}\
+ var strNumbers = numbers + "";\
\
if (typeof bind != "undefined") {\
var thisArg = { "name": "fred" };\
\
var func = function(greeting, punctuation) {\
- return greeting + " " + this.name + (punctuation || ".");\
+ return (greeting || "hi") + " " + this.name + (punctuation || ".");\
};\
\
var _boundNormal = _.bind(func, thisArg),\
@@ -299,7 +326,6 @@
lodashBoundMultiple = lodash.bind(lodashBoundMultiple, { "name": "fred" + index });\
}\
}\
- \
if (typeof bindAll != "undefined") {\
var bindAllCount = -1,\
bindAllObjects = Array(this.count);\
@@ -308,7 +334,7 @@
return /^_/.test(funcName);\
});\
\
- // potentially expensive\n\
+ // Potentially expensive.\n\
for (index = 0; index < this.count; index++) {\
bindAllObjects[index] = belt.reduce(funcNames, function(object, funcName) {\
object[funcName] = belt[funcName];\
@@ -317,8 +343,12 @@
}\
}\
if (typeof chaining != "undefined") {\
- var _chaining = _.chain ? _(numbers).chain() : _(numbers),\
- lodashChaining = lodash(numbers);\
+ var even = function(v) { return v % 2 == 0; },\
+ square = function(v) { return v * v; };\
+ \
+ var largeArray = belt.range(10000),\
+ _chaining = _.chain ? _(largeArray).chain() : _(largeArray),\
+ lodashChaining = lodash(largeArray);\
}\
if (typeof compact != "undefined") {\
var uncompacted = numbers.slice();\
@@ -326,7 +356,14 @@
uncompacted[6] = null;\
uncompacted[18] = "";\
}\
- \
+ if (typeof compose != "undefined") {\
+ var compAddOne = function(n) { return n + 1; },\
+ compAddTwo = function(n) { return n + 2; },\
+ compAddThree = function(n) { return n + 3; };\
+ \
+ var _composed = _.compose(compAddThree, compAddTwo, compAddOne),\
+ lodashComposed = lodash.compose(compAddThree, compAddTwo, compAddOne);\
+ }\
if (typeof countBy != "undefined" || typeof omit != "undefined") {\
var wordToNumber = {\
"one": 1,\
@@ -373,7 +410,10 @@
\
var words = belt.keys(wordToNumber).slice(0, limit);\
}\
- \
+ if (typeof flatten != "undefined") {\
+ var _flattenDeep = _.flatten([[1]])[0] !== 1,\
+ lodashFlattenDeep = lodash.flatten([[1]]) !== 1;\
+ }\
if (typeof isEqual != "undefined") {\
var objectOfPrimitives = {\
"boolean": true,\
@@ -387,101 +427,53 @@
"string": new String("a")\
};\
\
+ var objectOfObjects2 = {\
+ "boolean": new Boolean(true),\
+ "number": new Number(1),\
+ "string": new String("A")\
+ };\
+ \
var object2 = {},\
+ object3 = {},\
objects2 = Array(limit),\
+ objects3 = Array(limit),\
numbers2 = Array(limit),\
+ numbers3 = Array(limit),\
nestedNumbers2 = [1, [2], [3, [[4]]]],\
- nestedNumbers3 = [1, [2], [5, [[6]]]],\
- simpleObject = { "a": 1 },\
- simpleObject2 = { "a": 2 },\
- simpleObjects = [simpleObject],\
- simpleObjects2 = [simpleObject2],\
- twoNumbers2 = [18, 27];\
+ nestedNumbers3 = [1, [2], [3, [[6]]]];\
\
for (index = 0; index < limit; index++) {\
object2["key" + index] = index;\
+ object3["key" + index] = index;\
objects2[index] = { "num": index };\
+ objects3[index] = { "num": index };\
numbers2[index] = index;\
+ numbers3[index] = index;\
}\
+ object3["key" + (limit - 1)] = -1;\
+ objects3[limit - 1].num = -1;\
+ numbers3[limit - 1] = -1;\
}\
- \
- if (typeof multiArrays != "undefined") {\
- var twentyValues = Array(20),\
- twentyValues2 = Array(20),\
- twentyFiveValues = Array(25),\
- twentyFiveValues2 = Array(25),\
- thirtyValues = Array(30),\
- thirtyValues2 = Array(30),\
- fortyValues = Array(40),\
- fortyValues2 = Array(40),\
- fiftyValues = Array(50),\
- fiftyValues2 = Array(50),\
- seventyFiveValues = Array(75),\
- seventyFiveValues2 = Array(75),\
- oneHundredValues = Array(100),\
- oneHundredValues2 = Array(100),\
- twoHundredValues = Array(200),\
- twoHundredValues2 = Array(200),\
- lowerChars = "abcdefghijklmnopqrstuvwxyz".split(""),\
- upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");\
+ if (typeof matches != "undefined") {\
+ var source = { "num": 9 };\
\
- for (index = 0; index < 200; index++) {\
- if (index < 15) {\
- twentyValues[index] = lowerChars[index];\
- twentyValues2[index] = upperChars[index];\
- }\
- if (index < 20) {\
- twentyValues[index] =\
- twentyValues2[index] = index;\
- \
- twentyFiveValues[index] = lowerChars[index];\
- twentyFiveValues2[index] = upperChars[index];\
- }\
- if (index < 25) {\
- twentyFiveValues[index] =\
- twentyFiveValues2[index] = index;\
- \
- thirtyValues[index] =\
- fortyValues[index] =\
- fiftyValues[index] =\
- seventyFiveValues[index] =\
- oneHundredValues[index] =\
- twoHundredValues[index] = lowerChars[index];\
- \
- thirtyValues2[index] =\
- fortyValues2[index] =\
- fiftyValues2[index] =\
- seventyFiveValues2[index] =\
- oneHundredValues2[index] =\
- twoHundredValues2[index] = upperChars[index];\
- }\
- else {\
- if (index < 30) {\
- thirtyValues[index] =\
- thirtyValues2[index] = index;\
- }\
- if (index < 40) {\
- fortyValues[index] =\
- fortyValues2[index] = index;\
- }\
- if (index < 50) {\
- fiftyValues[index] =\
- fiftyValues2[index] = index;\
- }\
- if (index < 75) {\
- seventyFiveValues[index] =\
- seventyFiveValues2[index] = index;\
- }\
- if (index < 100) {\
- oneHundredValues[index] =\
- oneHundredValues2[index] = index;\
- }\
- twoHundredValues[index] =\
- twoHundredValues2[index] = index;\
- }\
- }\
+ var _findWhere = _.findWhere || _.find,\
+ _match = (_.matches || _.createCallback || _.noop)(source);\
+ \
+ var lodashFindWhere = lodash.findWhere || lodash.find,\
+ lodashMatch = (lodash.matches || lodash.createCallback || lodash.noop)(source);\
+ }\
+ if (typeof multiArrays != "undefined") {\
+ var twentyValues = belt.shuffle(belt.range(20)),\
+ fortyValues = belt.shuffle(belt.range(40)),\
+ hundredSortedValues = belt.range(100),\
+ hundredValues = belt.shuffle(hundredSortedValues),\
+ hundredValues2 = belt.shuffle(hundredValues),\
+ hundredTwentyValues = belt.shuffle(belt.range(120)),\
+ hundredTwentyValues2 = belt.shuffle(hundredTwentyValues),\
+ twoHundredValues = belt.shuffle(belt.range(200)),\
+ twoHundredValues2 = belt.shuffle(twoHundredValues);\
}\
- \
if (typeof partial != "undefined") {\
var func = function(greeting, punctuation) {\
return greeting + " fred" + (punctuation || ".");\
@@ -490,7 +482,6 @@
var _partial = _.partial(func, "hi"),\
lodashPartial = lodash.partial(func, "hi");\
}\
- \
if (typeof template != "undefined") {\
var tplData = {\
"header1": "Header1",\
@@ -540,11 +531,6 @@
var lodashTpl = lodash.template(tpl),\
lodashTplVerbose = lodash.template(tplVerbose, null, settingsObject);\
}\
- if (typeof where != "undefined") {\
- var _findWhere = _.findWhere || _.find,\
- lodashFindWhere = lodash.findWhere || lodash.find,\
- whereObject = { "num": 9 };\
- }\
if (typeof wrap != "undefined") {\
var add = function(a, b) {\
return a + b;\
@@ -565,60 +551,27 @@
/*--------------------------------------------------------------------------*/
suites.push(
- Benchmark.Suite('`_(...)` with a number')
- .add(buildName, '\
- lodash(2)'
- )
- .add(otherName, '\
- _(2)'
- )
- );
-
- suites.push(
- Benchmark.Suite('`_(...)` with an array')
- .add(buildName, '\
- lodash(numbers)'
- )
- .add(otherName, '\
- _(numbers)'
- )
- );
-
- suites.push(
- Benchmark.Suite('`_(...)` with an object')
- .add(buildName, '\
- lodash(object)'
- )
- .add(otherName, '\
- _(object)'
- )
+ Benchmark.Suite('`_(...).map(...).filter(...).take(...).value()`')
+ .add(buildName, {
+ 'fn': 'lodashChaining.map(square).filter(even).take(100).value()',
+ 'teardown': 'function chaining(){}'
+ })
+ .add(otherName, {
+ 'fn': '_chaining.map(square).filter(even).take(100).value()',
+ 'teardown': 'function chaining(){}'
+ })
);
- // avoid Underscore induced `OutOfMemoryError` in Rhino, Narwhal, and Ringo
- if (!isJava) {
- suites.push(
- Benchmark.Suite('`_(...).tap(...)`')
- .add(buildName, {
- 'fn': 'lodashChaining.tap(lodash.identity)',
- 'teardown': 'function chaining(){}'
- })
- .add(otherName, {
- 'fn': '_chaining.tap(_.identity)',
- 'teardown': 'function chaining(){}'
- })
- );
- }
-
/*--------------------------------------------------------------------------*/
suites.push(
- Benchmark.Suite('`_.bind`')
+ Benchmark.Suite('`_.bind` (slow path)')
.add(buildName, {
- 'fn': 'lodash.bind(func, { "name": "fred" })',
+ 'fn': 'lodash.bind(function() { return this.name; }, { "name": "fred" })',
'teardown': 'function bind(){}'
})
.add(otherName, {
- 'fn': '_.bind(func, { "name": "fred" })',
+ 'fn': '_.bind(function() { return this.name; }, { "name": "fred" })',
'teardown': 'function bind(){}'
})
);
@@ -688,6 +641,16 @@
/*--------------------------------------------------------------------------*/
suites.push(
+ Benchmark.Suite('`_.clone` with an array')
+ .add(buildName, '\
+ lodash.clone(numbers)'
+ )
+ .add(otherName, '\
+ _.clone(numbers)'
+ )
+ );
+
+ suites.push(
Benchmark.Suite('`_.clone` with an object')
.add(buildName, '\
lodash.clone(object)'
@@ -714,23 +677,27 @@
/*--------------------------------------------------------------------------*/
suites.push(
- Benchmark.Suite('`_.contains` iterating an array')
- .add(buildName, '\
- lodash.contains(numbers, limit - 1)'
- )
- .add(otherName, '\
- _.contains(numbers, limit - 1)'
- )
+ Benchmark.Suite('`_.compose`')
+ .add(buildName, {
+ 'fn': 'lodash.compose(compAddThree, compAddTwo, compAddOne)',
+ 'teardown': 'function compose(){}'
+ })
+ .add(otherName, {
+ 'fn': '_.compose(compAddThree, compAddTwo, compAddOne)',
+ 'teardown': 'function compose(){}'
+ })
);
suites.push(
- Benchmark.Suite('`_.contains` iterating an object')
- .add(buildName, '\
- lodash.contains(object, limit - 1)'
- )
- .add(otherName, '\
- _.contains(object, limit - 1)'
- )
+ Benchmark.Suite('composed call')
+ .add(buildName, {
+ 'fn': 'lodashComposed(0)',
+ 'teardown': 'function compose(){}'
+ })
+ .add(otherName, {
+ 'fn': '_composed(0)',
+ 'teardown': 'function compose(){}'
+ })
);
/*--------------------------------------------------------------------------*/
@@ -794,13 +761,13 @@
);
suites.push(
- Benchmark.Suite('`_.difference` iterating 75 elements')
+ Benchmark.Suite('`_.difference` iterating 20 and 40 elements')
.add(buildName, {
- 'fn': 'lodash.difference(seventyFiveValues, seventyFiveValues2)',
+ 'fn': 'lodash.difference(twentyValues, fortyValues)',
'teardown': 'function multiArrays(){}'
})
.add(otherName, {
- 'fn': '_.difference(seventyFiveValues, seventyFiveValues2)',
+ 'fn': '_.difference(twentyValues, fortyValues)',
'teardown': 'function multiArrays(){}'
})
);
@@ -817,18 +784,6 @@
})
);
- suites.push(
- Benchmark.Suite('`_.difference` iterating 20 and 40 elements')
- .add(buildName, {
- 'fn': 'lodash.difference(twentyValues, fortyValues2)',
- 'teardown': 'function multiArrays(){}'
- })
- .add(otherName, {
- 'fn': '_.difference(twentyValues, fortyValues2)',
- 'teardown': 'function multiArrays(){}'
- })
- );
-
/*--------------------------------------------------------------------------*/
suites.push(
@@ -885,12 +840,12 @@
Benchmark.Suite('`_.every` iterating an array')
.add(buildName, '\
lodash.every(numbers, function(num) {\
- return num + "";\
+ return num < limit;\
})'
)
.add(otherName, '\
_.every(numbers, function(num) {\
- return num + "";\
+ return num < limit;\
})'
)
);
@@ -899,12 +854,12 @@
Benchmark.Suite('`_.every` iterating an object')
.add(buildName, '\
lodash.every(object, function(num) {\
- return num + "";\
+ return num < limit;\
})'
)
.add(otherName, '\
_.every(object, function(num) {\
- return num + "";\
+ return num < limit;\
})'
)
);
@@ -995,17 +950,17 @@
)
);
- // avoid Underscore induced `OutOfMemoryError` in Rhino, Narwhal, and Ringo
+ // Avoid Underscore induced `OutOfMemoryError` in Rhino, Narwhal, and Ringo.
if (!isJava) {
suites.push(
Benchmark.Suite('`_.find` with `properties`')
.add(buildName, {
- 'fn': 'lodashFindWhere(objects, whereObject)',
- 'teardown': 'function where(){}'
+ 'fn': 'lodashFindWhere(objects, source)',
+ 'teardown': 'function matches(){}'
})
.add(otherName, {
- 'fn': '_findWhere(objects, whereObject)',
- 'teardown': 'function where(){}'
+ 'fn': '_findWhere(objects, source)',
+ 'teardown': 'function matches(){}'
})
);
}
@@ -1014,32 +969,38 @@
suites.push(
Benchmark.Suite('`_.flatten`')
- .add(buildName, '\
- lodash.flatten(nestedNumbers)'
- )
- .add(otherName, '\
- _.flatten(nestedNumbers)'
- )
+ .add(buildName, {
+ 'fn': 'lodash.flatten(nestedNumbers, !lodashFlattenDeep)',
+ 'teardown': 'function flatten(){}'
+ })
+ .add(otherName, {
+ 'fn': '_.flatten(nestedNumbers, !_flattenDeep)',
+ 'teardown': 'function flatten(){}'
+ })
);
suites.push(
- Benchmark.Suite('`_.flatten` with objects')
- .add(buildName, '\
- lodash.flatten(nestedObjects)'
- )
- .add(otherName, '\
- _.flatten(nestedObjects)'
- )
+ Benchmark.Suite('`_.flatten` nested arrays of numbers with `isDeep`')
+ .add(buildName, {
+ 'fn': 'lodash.flatten(nestedNumbers, lodashFlattenDeep)',
+ 'teardown': 'function flatten(){}'
+ })
+ .add(otherName, {
+ 'fn': '_.flatten(nestedNumbers, _flattenDeep)',
+ 'teardown': 'function flatten(){}'
+ })
);
suites.push(
- Benchmark.Suite('`_.flatten` with `shallow`')
- .add(buildName, '\
- lodash.flatten(nestedNumbers, true)'
- )
- .add(otherName, '\
- _.flatten(nestedNumbers, true)'
- )
+ Benchmark.Suite('`_.flatten` nest arrays of objects with `isDeep`')
+ .add(buildName, {
+ 'fn': 'lodash.flatten(nestedObjects, lodashFlattenDeep)',
+ 'teardown': 'function flatten(){}'
+ })
+ .add(otherName, {
+ 'fn': '_.flatten(nestedObjects, _flattenDeep)',
+ 'teardown': 'function flatten(){}'
+ })
);
/*--------------------------------------------------------------------------*/
@@ -1093,6 +1054,40 @@
/*--------------------------------------------------------------------------*/
suites.push(
+ Benchmark.Suite('`_.includes` searching an array')
+ .add(buildName, '\
+ lodash.include(numbers, limit - 1)'
+ )
+ .add(otherName, '\
+ _.include(numbers, limit - 1)'
+ )
+ );
+
+ suites.push(
+ Benchmark.Suite('`_.includes` searching an object')
+ .add(buildName, '\
+ lodash.include(object, limit - 1)'
+ )
+ .add(otherName, '\
+ _.include(object, limit - 1)'
+ )
+ );
+
+ if (lodash.include('ab', 'ab') && _.include('ab', 'ab')) {
+ suites.push(
+ Benchmark.Suite('`_.includes` searching a string')
+ .add(buildName, '\
+ lodash.include(strNumbers, "," + (limit - 1))'
+ )
+ .add(otherName, '\
+ _.include(strNumbers, "," + (limit - 1))'
+ )
+ );
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ suites.push(
Benchmark.Suite('`_.indexBy` with `callback` iterating an array')
.add(buildName, '\
lodash.indexBy(numbers, function(num) { return num >> 1; })'
@@ -1131,11 +1126,23 @@
suites.push(
Benchmark.Suite('`_.indexOf`')
.add(buildName, {
- 'fn': 'lodash.indexOf(twoHundredValues, 199)',
+ 'fn': 'lodash.indexOf(hundredSortedValues, 99)',
'teardown': 'function multiArrays(){}'
})
.add(otherName, {
- 'fn': '_.indexOf(twoHundredValues, 199)',
+ 'fn': '_.indexOf(hundredSortedValues, 99)',
+ 'teardown': 'function multiArrays(){}'
+ })
+ );
+
+ suites.push(
+ Benchmark.Suite('`_.indexOf` performing a binary search')
+ .add(buildName, {
+ 'fn': 'lodash.indexOf(hundredSortedValues, 99, true)',
+ 'teardown': 'function multiArrays(){}'
+ })
+ .add(otherName, {
+ 'fn': '_.indexOf(hundredSortedValues, 99, true)',
'teardown': 'function multiArrays(){}'
})
);
@@ -1153,25 +1160,13 @@
);
suites.push(
- Benchmark.Suite('`_.intersection` iterating 75 elements')
+ Benchmark.Suite('`_.intersection` iterating 120 elements')
.add(buildName, {
- 'fn': 'lodash.intersection(seventyFiveValues, seventyFiveValues2)',
+ 'fn': 'lodash.intersection(hundredTwentyValues, hundredTwentyValues2)',
'teardown': 'function multiArrays(){}'
})
.add(otherName, {
- 'fn': '_.intersection(seventyFiveValues, seventyFiveValues2)',
- 'teardown': 'function multiArrays(){}'
- })
- );
-
- suites.push(
- Benchmark.Suite('`_.intersection` iterating 200 elements')
- .add(buildName, {
- 'fn': 'lodash.intersection(twoHundredValues, twoHundredValues2)',
- 'teardown': 'function multiArrays(){}'
- })
- .add(otherName, {
- 'fn': '_.intersection(twoHundredValues, twoHundredValues2)',
+ 'fn': '_.intersection(hundredTwentyValues, hundredTwentyValues2)',
'teardown': 'function multiArrays(){}'
})
);
@@ -1193,43 +1188,73 @@
suites.push(
Benchmark.Suite('`_.invoke` iterating an array')
.add(buildName, '\
- lodash.invoke(numbers, "toFixed", "2")'
+ lodash.invoke(numbers, "toFixed")'
+ )
+ .add(otherName, '\
+ _.invoke(numbers, "toFixed")'
+ )
+ );
+
+ suites.push(
+ Benchmark.Suite('`_.invoke` with arguments iterating an array')
+ .add(buildName, '\
+ lodash.invoke(numbers, "toFixed", 1)'
)
.add(otherName, '\
- _.invoke(numbers, "toFixed", "2")'
+ _.invoke(numbers, "toFixed", 1)'
)
);
suites.push(
Benchmark.Suite('`_.invoke` with a function for `methodName` iterating an array')
.add(buildName, '\
- lodash.invoke(numbers, String.prototype.split, "")'
+ lodash.invoke(numbers, Number.prototype.toFixed, 1)'
)
.add(otherName, '\
- _.invoke(numbers, String.prototype.split, "")'
+ _.invoke(numbers, Number.prototype.toFixed, 1)'
)
);
suites.push(
Benchmark.Suite('`_.invoke` iterating an object')
.add(buildName, '\
- lodash.invoke(object, "toFixed", "2")'
+ lodash.invoke(object, "toFixed", 1)'
)
.add(otherName, '\
- _.invoke(object, "toFixed", "2")'
+ _.invoke(object, "toFixed", 1)'
)
);
/*--------------------------------------------------------------------------*/
suites.push(
- Benchmark.Suite('`_.isEqual` comparing primitives and objects (edge case)')
+ Benchmark.Suite('`_.isEqual` comparing primitives')
.add(buildName, {
- 'fn': 'lodash.isEqual(objectOfPrimitives, objectOfObjects)',
+ 'fn': '\
+ lodash.isEqual(1, "1");\
+ lodash.isEqual(1, 1)',
'teardown': 'function isEqual(){}'
})
.add(otherName, {
- 'fn': '_.isEqual(objectOfPrimitives, objectOfObjects)',
+ 'fn': '\
+ _.isEqual(1, "1");\
+ _.isEqual(1, 1);',
+ 'teardown': 'function isEqual(){}'
+ })
+ );
+
+ suites.push(
+ Benchmark.Suite('`_.isEqual` comparing primitives and their object counterparts (edge case)')
+ .add(buildName, {
+ 'fn': '\
+ lodash.isEqual(objectOfPrimitives, objectOfObjects);\
+ lodash.isEqual(objectOfPrimitives, objectOfObjects2)',
+ 'teardown': 'function isEqual(){}'
+ })
+ .add(otherName, {
+ 'fn': '\
+ _.isEqual(objectOfPrimitives, objectOfObjects);\
+ _.isEqual(objectOfPrimitives, objectOfObjects2)',
'teardown': 'function isEqual(){}'
})
);
@@ -1239,13 +1264,13 @@
.add(buildName, {
'fn': '\
lodash.isEqual(numbers, numbers2);\
- lodash.isEqual(twoNumbers, twoNumbers2)',
+ lodash.isEqual(numbers2, numbers3)',
'teardown': 'function isEqual(){}'
})
.add(otherName, {
'fn': '\
_.isEqual(numbers, numbers2);\
- _.isEqual(twoNumbers, twoNumbers2)',
+ _.isEqual(numbers2, numbers3)',
'teardown': 'function isEqual(){}'
})
);
@@ -1271,13 +1296,13 @@
.add(buildName, {
'fn': '\
lodash.isEqual(objects, objects2);\
- lodash.isEqual(simpleObjects, simpleObjects2)',
+ lodash.isEqual(objects2, objects3)',
'teardown': 'function isEqual(){}'
})
.add(otherName, {
'fn': '\
_.isEqual(objects, objects2);\
- _.isEqual(simpleObjects, simpleObjects2)',
+ _.isEqual(objects2, objects3)',
'teardown': 'function isEqual(){}'
})
);
@@ -1287,13 +1312,13 @@
.add(buildName, {
'fn': '\
lodash.isEqual(object, object2);\
- lodash.isEqual(simpleObject, simpleObject2)',
+ lodash.isEqual(object2, object3)',
'teardown': 'function isEqual(){}'
})
.add(otherName, {
'fn': '\
_.isEqual(object, object2);\
- _.isEqual(simpleObject, simpleObject2)',
+ _.isEqual(object2, object3)',
'teardown': 'function isEqual(){}'
})
);
@@ -1348,12 +1373,26 @@
suites.push(
Benchmark.Suite('`_.lastIndexOf`')
- .add(buildName, '\
- lodash.lastIndexOf(numbers, 9)'
- )
- .add(otherName, '\
- _.lastIndexOf(numbers, 9)'
- )
+ .add(buildName, {
+ 'fn': 'lodash.lastIndexOf(hundredSortedValues, 0)',
+ 'teardown': 'function multiArrays(){}'
+ })
+ .add(otherName, {
+ 'fn': '_.lastIndexOf(hundredSortedValues, 0)',
+ 'teardown': 'function multiArrays(){}'
+ })
+ );
+
+ suites.push(
+ Benchmark.Suite('`_.lastIndexOf` performing a binary search')
+ .add(buildName, {
+ 'fn': 'lodash.lastIndexOf(hundredSortedValues, 0, true)',
+ 'teardown': 'function multiArrays(){}'
+ })
+ .add(otherName, {
+ 'fn': '_.lastIndexOf(hundredSortedValues, 0, true)',
+ 'teardown': 'function multiArrays(){}'
+ })
);
/*--------------------------------------------------------------------------*/
@@ -1403,6 +1442,20 @@
/*--------------------------------------------------------------------------*/
suites.push(
+ Benchmark.Suite('`_.matches` predicate')
+ .add(buildName, {
+ 'fn': 'lodash.filter(objects, lodashMatch)',
+ 'teardown': 'function matches(){}'
+ })
+ .add(otherName, {
+ 'fn': '_.filter(objects, _match)',
+ 'teardown': 'function matches(){}'
+ })
+ );
+
+ /*--------------------------------------------------------------------------*/
+
+ suites.push(
Benchmark.Suite('`_.max`')
.add(buildName, '\
lodash.max(numbers)'
@@ -1463,13 +1516,13 @@
/*--------------------------------------------------------------------------*/
suites.push(
- Benchmark.Suite('`_.partial`')
+ Benchmark.Suite('`_.partial` (slow path)')
.add(buildName, {
- 'fn': 'lodash.partial(func, "hi")',
+ 'fn': 'lodash.partial(function(greeting) { return greeting + " " + this.name; }, "hi")',
'teardown': 'function partial(){}'
})
.add(otherName, {
- 'fn': '_.partial(func, "hi")',
+ 'fn': '_.partial(function(greeting) { return greeting + " " + this.name; }, "hi")',
'teardown': 'function partial(){}'
})
);
@@ -1489,6 +1542,50 @@
/*--------------------------------------------------------------------------*/
suites.push(
+ Benchmark.Suite('`_.partition` iterating an array')
+ .add(buildName, '\
+ lodash.partition(numbers, function(num) {\
+ return num % 2;\
+ })'
+ )
+ .add(otherName, '\
+ _.partition(numbers, function(num) {\
+ return num % 2;\
+ })'
+ )
+ );
+
+ suites.push(
+ Benchmark.Suite('`_.partition` iterating an array with `thisArg` (slow path)')
+ .add(buildName, '\
+ lodash.partition(numbers, function(num, index) {\
+ return this["key" + index] % 2;\
+ }, object)'
+ )
+ .add(otherName, '\
+ _.partition(numbers, function(num, index) {\
+ return this["key" + index] % 2;\
+ }, object)'
+ )
+ );
+
+ suites.push(
+ Benchmark.Suite('`_.partition` iterating an object')
+ .add(buildName, '\
+ lodash.partition(object, function(num) {\
+ return num % 2;\
+ })'
+ )
+ .add(otherName, '\
+ _.partition(object, function(num) {\
+ return num % 2;\
+ })'
+ )
+ );
+
+ /*--------------------------------------------------------------------------*/
+
+ suites.push(
Benchmark.Suite('`_.pick`')
.add(buildName, '\
lodash.pick(object, "key6", "key13")'
@@ -1612,12 +1709,12 @@
Benchmark.Suite('`_.reject` iterating an object')
.add(buildName, '\
lodash.reject(object, function(num) {\
- return num % 2\
+ return num % 2;\
})'
)
.add(otherName, '\
_.reject(object, function(num) {\
- return num % 2\
+ return num % 2;\
})'
)
);
@@ -1739,6 +1836,16 @@
/*--------------------------------------------------------------------------*/
suites.push(
+ Benchmark.Suite('`_.sortedIndex`')
+ .add(buildName, '\
+ lodash.sortedIndex(numbers, limit)'
+ )
+ .add(otherName, '\
+ _.sortedIndex(numbers, limit)'
+ )
+ );
+
+ suites.push(
Benchmark.Suite('`_.sortedIndex` with `callback`')
.add(buildName, {
'fn': '\
@@ -1761,11 +1868,11 @@
suites.push(
Benchmark.Suite('`_.template` (slow path)')
.add(buildName, {
- 'fn': 'lodash.template(tpl, tplData)',
+ 'fn': 'lodash.template(tpl)(tplData)',
'teardown': 'function template(){}'
})
.add(otherName, {
- 'fn': '_.template(tpl, tplData)',
+ 'fn': '_.template(tpl)(tplData)',
'teardown': 'function template(){}'
})
);
@@ -1809,7 +1916,7 @@
);
suites.push(
- Benchmark.Suite('`_.times` with `thisArg`')
+ Benchmark.Suite('`_.times` with `thisArg` (slow path)')
.add(buildName, '\
var result = [];\
lodash.times(limit, function(n) { result.push(this.sin(n)); }, Math)'
@@ -1845,35 +1952,45 @@
/*--------------------------------------------------------------------------*/
suites.push(
- Benchmark.Suite('`_.union`')
+ Benchmark.Suite('`_.unescape` string without html entities')
.add(buildName, '\
- lodash.union(numbers, twoNumbers, fourNumbers)'
+ lodash.unescape("`&`, `<`, `>`, `\\"`, and `\'`")'
)
.add(otherName, '\
- _.union(numbers, twoNumbers, fourNumbers)'
+ _.unescape("`&`, `<`, `>`, `\\"`, and `\'`")'
)
);
suites.push(
- Benchmark.Suite('`_.union` iterating an array of 75 elements')
- .add(buildName, {
- 'fn': 'lodash.union(twentyFiveValues, fiftyValues2)',
- 'teardown': 'function multiArrays(){}'
- })
- .add(otherName, {
- 'fn': '_.union(twentyFiveValues, fiftyValues2)',
- 'teardown': 'function multiArrays(){}'
- })
+ Benchmark.Suite('`_.unescape` string with html entities')
+ .add(buildName, '\
+ lodash.unescape("`&`, `<`, `>`, `"`, and `'`")'
+ )
+ .add(otherName, '\
+ _.unescape("`&`, `<`, `>`, `"`, and `'`")'
+ )
+ );
+
+ /*--------------------------------------------------------------------------*/
+
+ suites.push(
+ Benchmark.Suite('`_.union`')
+ .add(buildName, '\
+ lodash.union(numbers, twoNumbers, fourNumbers)'
+ )
+ .add(otherName, '\
+ _.union(numbers, twoNumbers, fourNumbers)'
+ )
);
suites.push(
Benchmark.Suite('`_.union` iterating an array of 200 elements')
.add(buildName, {
- 'fn': 'lodash.union(oneHundredValues, oneHundredValues2)',
+ 'fn': 'lodash.union(hundredValues, hundredValues2)',
'teardown': 'function multiArrays(){}'
})
.add(otherName, {
- 'fn': '_.union(oneHundredValues, oneHundredValues2)',
+ 'fn': '_.union(hundredValues, hundredValues2)',
'teardown': 'function multiArrays(){}'
})
);
@@ -1905,25 +2022,13 @@
);
suites.push(
- Benchmark.Suite('`_.uniq` iterating an array of 75 elements')
- .add(buildName, {
- 'fn': 'lodash.uniq(twentyFiveValues.concat(fiftyValues2))',
- 'teardown': 'function multiArrays(){}'
- })
- .add(otherName, {
- 'fn': '_.uniq(twentyFiveValues.concat(fiftyValues2))',
- 'teardown': 'function multiArrays(){}'
- })
- );
-
- suites.push(
Benchmark.Suite('`_.uniq` iterating an array of 200 elements')
.add(buildName, {
- 'fn': 'lodash.uniq(oneHundredValues.concat(oneHundredValues2))',
+ 'fn': 'lodash.uniq(twoHundredValues)',
'teardown': 'function multiArrays(){}'
})
.add(otherName, {
- 'fn': '_.uniq(oneHundredValues.concat(oneHundredValues2))',
+ 'fn': '_.uniq(twoHundredValues)',
'teardown': 'function multiArrays(){}'
})
);
@@ -1945,12 +2050,12 @@
suites.push(
Benchmark.Suite('`_.where`')
.add(buildName, {
- 'fn': 'lodash.where(objects, whereObject)',
- 'teardown': 'function where(){}'
+ 'fn': 'lodash.where(objects, source)',
+ 'teardown': 'function matches(){}'
})
.add(otherName, {
- 'fn': '_.where(objects, whereObject)',
- 'teardown': 'function where(){}'
+ 'fn': '_.where(objects, source)',
+ 'teardown': 'function matches(){}'
})
);
@@ -1999,10 +2104,10 @@
if (Benchmark.platform + '') {
log(Benchmark.platform);
}
- // in the browser, expose `run` to be called later
- if (root.document && !root.phantom) {
+ // Expose `run` to be called later when executing in a browser.
+ if (document) {
root.run = run;
} else {
run();
}
-}(typeof global == 'object' && global || this));
+}.call(this));
diff --git a/perf/run-perf.sh b/perf/run-perf.sh
index b140631..c219fd1 100755
--- a/perf/run-perf.sh
+++ b/perf/run-perf.sh
@@ -1,12 +1,12 @@
cd "$(dirname "$0")"
echo "Running performance suite in node..."
-node perf.js ../dist/lodash.js && node perf.js ../dist/lodash.min.js
+node perf.js ../lodash.js && node perf.js ../lodash.min.js
for cmd in rhino "rhino -require" narwhal ringo phantomjs; do
echo ""
echo "Running performance suite in $cmd..."
- $cmd perf.js ../dist/lodash.compat.js && $cmd perf.js ../dist/lodash.compat.min.js
+ $cmd perf.js ../lodash.src.js
done
echo ""
diff --git a/test/asset/set.js b/test/asset/set.js
new file mode 100644
index 0000000..d32d124
--- /dev/null
+++ b/test/asset/set.js
@@ -0,0 +1,146 @@
+;(function() {
+
+ /** Used to determine if values are of the language type Object. */
+ var objectTypes = {
+ 'function': true,
+ 'object': true
+ };
+
+ /** Used as the `Set#toString` return value. */
+ var nativeString = String(Object.prototype.toString).replace(/toString/g, 'Set');
+
+ /** Used as a reference to the global object. */
+ var root = (objectTypes[typeof window] && window) || this;
+
+ /** Detect free variable `exports`. */
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */
+ var freeGlobal = objectTypes[typeof global] && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
+ root = freeGlobal;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Installs `Set` on the given `context` object.
+ *
+ * @memberOf exports
+ * @param {Object} context The context object.
+ */
+ function runInContext(context) {
+
+ /**
+ * Creates a `Set` object.
+ */
+ function Set() {
+ this.__cache__ = {};
+ }
+
+ /**
+ * Gets the index at which the first occurrence of `value` is found using
+ * strict equality for comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns the index of the matched value or `-1`.
+ */
+ function indexOf(array, value) {
+ var index = -1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if `value` is in the set.
+ *
+ * @memberOf Set
+ * @param {*} value The value to search for.
+ * @returns {boolean} Returns `true` if `value` is found, else `false`.
+ */
+ function has(value) {
+ var type = typeof value,
+ cache = this.__cache__;
+
+ if (type == 'boolean' || value == null) {
+ return cache[value] || false;
+ }
+ if (type != 'number' && type != 'string') {
+ type = 'object';
+ }
+ var key = type == 'number' ? value : '_' + value;
+ cache = (cache = cache[type]) && cache[key];
+
+ return type == 'object'
+ ? (cache && indexOf(cache, value) > -1 ? true : false)
+ : (cache || false);
+ }
+
+ /**
+ * Adds `value` to the set.
+ *
+ * @memberOf Set
+ * @param {*} value The value to add.
+ */
+ function add(value) {
+ var cache = this.__cache__,
+ type = typeof value;
+
+ if (type == 'boolean' || value == null) {
+ cache[value] = true;
+ } else {
+ if (type != 'number' && type != 'string') {
+ type = 'object';
+ }
+ var key = type == 'number' ? value : '_' + value,
+ typeCache = cache[type] || (cache[type] = {});
+
+ if (type == 'object') {
+ var array = typeCache[key];
+ if (array) {
+ array.push(value);
+ } else {
+ typeCache[key] = [value];
+ }
+ } else {
+ typeCache[key] = true;
+ }
+ }
+ }
+
+ /**
+ * Produces the `toString` result of `Set`.
+ *
+ * @static
+ * @memberOf Set
+ * @returns {string} Returns the string result.
+ */
+ function toString() {
+ return nativeString;
+ }
+
+ Set.toString = toString;
+ Set.prototype.add = add;
+ Set.prototype.has = has;
+
+ if (!root.Set) {
+ context.Set = Set;
+ }
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ if (freeExports) {
+ freeExports.runInContext = runInContext;
+ } else {
+ runInContext(root);
+ }
+}.call(this));
diff --git a/test/asset/test-ui.js b/test/asset/test-ui.js
index ab5b038..4f87736 100644
--- a/test/asset/test-ui.js
+++ b/test/asset/test-ui.js
@@ -1,16 +1,16 @@
;(function(window) {
'use strict';
- /** The base path of the builds */
+ /** The base path of the Lo-Dash builds. */
var basePath = '../';
- /** The Lo-Dash build to load */
+ /** The Lo-Dash build to load. */
var build = (build = /build=([^&]+)/.exec(location.search)) && decodeURIComponent(build[1]);
- /** The module loader to use */
+ /** The module loader to use. */
var loader = (loader = /loader=([^&]+)/.exec(location.search)) && decodeURIComponent(loader[1]);
- /** The `ui` object */
+ /** The `ui` object. */
var ui = {};
/*--------------------------------------------------------------------------*/
@@ -34,7 +34,7 @@
/*--------------------------------------------------------------------------*/
- // initialize controls
+ // Initialize controls.
addListener(window, 'load', function() {
function eventHandler(event) {
var buildIndex = buildList.selectedIndex,
@@ -55,43 +55,39 @@
function init() {
var toolbar = document.getElementById('qunit-testrunner-toolbar');
- if (toolbar) {
- toolbar.appendChild(span1);
- toolbar.appendChild(span2);
-
- buildList.selectedIndex = (function() {
- switch (build) {
- case 'lodash-compat': return 1;
- case 'lodash-modern-dev': return 2;
- case 'lodash-modern': return 3;
- case 'lodash-legacy': return 4;
- case 'lodash-mobile': return 5;
- case 'lodash-underscore': return 6;
- case 'lodash-custom-dev': return 7;
- case 'lodash-custom': return 8;
- case 'lodash-compat-dev':
- case null: return 0;
- }
- return -1;
- }());
-
- loaderList.selectedIndex = (function() {
- switch (loader) {
- case 'curl': return 1;
- case 'dojo': return 2;
- case 'requirejs': return 3;
- case 'none':
- case null: return 0;
- }
- return -1;
- }());
-
- addListener(buildList, 'change', eventHandler);
- addListener(loaderList, 'change', eventHandler);
- }
- else {
+ if (!toolbar) {
setTimeout(init, 15);
+ return;
}
+ toolbar.appendChild(span1);
+ toolbar.appendChild(span2);
+
+ buildList.selectedIndex = (function() {
+ switch (build) {
+ case 'lodash-compat': return 1;
+ case 'lodash-modern-dev': return 2;
+ case 'lodash-modern': return 3;
+ case 'lodash-custom-dev': return 4;
+ case 'lodash-custom': return 5;
+ case 'lodash-compat-dev':
+ case null: return 0;
+ }
+ return -1;
+ }());
+
+ loaderList.selectedIndex = (function() {
+ switch (loader) {
+ case 'curl': return 1;
+ case 'dojo': return 2;
+ case 'requirejs': return 3;
+ case 'none':
+ case null: return 0;
+ }
+ return -1;
+ }());
+
+ addListener(buildList, 'change', eventHandler);
+ addListener(loaderList, 'change', eventHandler);
}
var span1 = document.createElement('span');
@@ -103,9 +99,6 @@
'<option value="lodash-compat">Lo-Dash (compat production)</option>' +
'<option value="lodash-modern-dev">Lo-Dash (modern development)</option>' +
'<option value="lodash-modern">Lo-Dash (modern production)</option>' +
- '<option value="lodash-legacy">Lo-Dash (legacy)</option>' +
- '<option value="lodash-mobile">Lo-Dash (mobile)</option>' +
- '<option value="lodash-underscore">Lo-Dash (underscore)</option>' +
'<option value="lodash-custom-dev">Lo-Dash (custom development)</option>' +
'<option value="lodash-custom">Lo-Dash (custom production)</option>' +
'</select>';
@@ -124,51 +117,57 @@
var buildList = span1.lastChild,
loaderList = span2.lastChild;
+ setTimeout(function() {
+ ui.timing.loadEventEnd = +new Date;
+ }, 1);
+
init();
});
- // expose Lo-Dash build file path
+ // Used to indicate testing a foreign file.
+ ui.isForeign = RegExp('^(\\w+:)?//').test(build);
+
+ // Used to indicate testing a modularized build.
+ ui.isModularize = /\b(?:amd|commonjs|es|node|npm|(index|main)\.js)\b/.test([location.pathname, location.search]);
+
+ // Used to indicate testing in Sauce Labs' automated test cloud.
+ ui.isSauceLabs = location.port == '9001';
+
+ // Used to indicate that Lo-Dash is in strict mode.
+ ui.isStrict = /\bes\b/.test([location.pathname, location.search]);
+
+ // The Lo-Dash build file path.
ui.buildPath = (function() {
var result;
switch (build) {
- case 'lodash-compat': result = 'dist/lodash.compat.min.js'; break;
- case 'lodash-modern-dev': result = 'dist/lodash.js'; break;
- case 'lodash-modern': result = 'dist/lodash.min.js'; break;
- case 'lodash-legacy': result = 'dist/lodash.legacy.min.js'; break;
- case 'lodash-mobile': result = 'dist/lodash.mobile.min.js'; break;
- case 'lodash-underscore': result = 'dist/lodash.underscore.min.js'; break;
+ case 'lodash-compat': result = 'lodash.compat.min.js'; break;
+ case 'lodash-modern-dev': result = 'lodash.js'; break;
+ case 'lodash-modern': result = 'lodash.min.js'; break;
case 'lodash-custom-dev': result = 'lodash.custom.js'; break;
case 'lodash-custom': result = 'lodash.custom.min.js'; break;
- case null: build = 'lodash-compat-dev';
- case 'lodash-compat-dev': result = 'lodash.js'; break;
+ case null: build = 'lodash-compat-dev';
+ case 'lodash-compat-dev': result = 'lodash.src.js'; break;
default: return build;
}
return basePath + result;
}());
- // expose module loader file path
+ // The module loader file path.
ui.loaderPath = (function() {
var result;
switch (loader) {
- case 'curl': result = 'vendor/curl/dist/curl-kitchen-sink/curl.js'; break;
- case 'dojo': result = 'vendor/dojo/dojo.js'; break;
- case 'requirejs': result = 'vendor/requirejs/require.js'; break;
+ case 'curl': result = 'node_modules/curl-amd/dist/curl-kitchen-sink/curl.js'; break;
+ case 'dojo': result = 'node_modules/dojo/dojo.js'; break;
+ case 'requirejs': result = 'node_modules/requirejs/require.js'; break;
case null: loader = 'none'; return '';
default: return loader;
}
return basePath + result;
}());
- // expose `ui.urlParams` properties
- ui.urlParams = {
- 'build': build,
- 'loader': loader
- };
-
- // used to indicate testing a modularized build
- ui.isModularize = /\b(?:commonjs|(index|main)\.js|lodash-(?:amd|node)|modularize|npm)\b/.test([location.pathname, location.search, ui.buildPath]);
+ ui.urlParams = { 'build': build, 'loader': loader };
+ ui.timing = { 'loadEventEnd': 0 };
- // expose `ui`
window.ui = ui;
}(this));
diff --git a/test/asset/weakmap.js b/test/asset/weakmap.js
new file mode 100644
index 0000000..7040876
--- /dev/null
+++ b/test/asset/weakmap.js
@@ -0,0 +1,91 @@
+;(function() {
+
+ /** Used to determine if values are of the language type Object. */
+ var objectTypes = {
+ 'function': true,
+ 'object': true
+ };
+
+ /** Used as the `WeakMap#toString` return value. */
+ var nativeString = String(Object.prototype.toString).replace(/toString/g, 'WeakMap');
+
+ /** Used as a reference to the global object. */
+ var root = (objectTypes[typeof window] && window) || this;
+
+ /** Detect free variable `exports`. */
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */
+ var freeGlobal = objectTypes[typeof global] && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
+ root = freeGlobal;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Installs `WeakMap` on the given `context` object.
+ *
+ * @memberOf exports
+ * @param {Object} context The context object.
+ */
+ function runInContext(context) {
+
+ /**
+ * Creates a `WeakMap` object.
+ */
+ function WeakMap() {
+ // No operation performed.
+ }
+
+ /**
+ * Gets the value associated with the given key.
+ *
+ * @memberOf WeakMap
+ * @param {Object} key The key object.
+ * @returns {*} Returns the associated value, else `undefined`.
+ */
+ function get(key) {
+ return key.__weakmap__;
+ }
+
+ /**
+ * Sets a value for the given key.
+ *
+ * @memberOf WeakMap
+ * @param {Object} key The key object.
+ * @param {*} value The value to set.
+ */
+ function set(key, value) {
+ key.__weakmap__ = value;
+ return this;
+ }
+
+ /**
+ * Produces the `toString` result of `WeakMap`.
+ *
+ * @static
+ * @memberOf WeakMap
+ * @returns {string} Returns the string result.
+ */
+ function toString() {
+ return nativeString;
+ }
+
+ WeakMap.toString = toString;
+ WeakMap.prototype.get = get;
+ WeakMap.prototype.set = set;
+
+ if (!root.WeakMap) {
+ context.WeakMap = WeakMap;
+ }
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ if (freeExports) {
+ freeExports.runInContext = runInContext;
+ } else {
+ runInContext(root);
+ }
+}.call(this));
diff --git a/test/asset/worker.js b/test/asset/worker.js
index 75f21c9..513f33b 100644
--- a/test/asset/worker.js
+++ b/test/asset/worker.js
@@ -1,6 +1,12 @@
+self.console || (self.console = { 'log': function() {} });
+
addEventListener('message', function(e) {
if (e.data) {
- importScripts('../' + e.data);
+ try {
+ importScripts('../' + e.data);
+ } catch(e) {
+ self._ = { 'VERSION': e.message };
+ }
postMessage(_.VERSION);
}
}, false);
diff --git a/test/backbone.html b/test/backbone.html
index 4f7b03a..f27884c 100644
--- a/test/backbone.html
+++ b/test/backbone.html
@@ -3,74 +3,144 @@
<head>
<meta charset="utf-8">
<title>Backbone Test Suite</title>
- <link rel="stylesheet" href="../vendor/qunit/qunit/qunit.css">
- <style>
- body > #qunit-header {
- display: none;
- }
- </style>
+ <link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
</head>
<body>
<div id="qunit"></div>
- <h1 id="qunit-header"></h1>
<div id="qunit-fixture">
<div id='testElement'>
<h1>Test</h1>
</div>
</div>
- <script src="../vendor/qunit/qunit/qunit.js"></script>
- <script src="../vendor/qunit-extras/qunit-extras.js"></script>
+ <script>
+ // avoid reporting tests to Sauce Labs when script errors occur
+ if (location.port == '9001') {
+ window.onerror = function(message) {
+ if (window.QUnit) {
+ QUnit.config.done.length = 0;
+ }
+ global_test_results = { 'message': message };
+ };
+ }
+ </script>
+ <script src="../node_modules/qunitjs/qunit/qunit.js"></script>
+ <script src="../node_modules/qunit-extras/qunit-extras.js"></script>
<script src="../vendor/json-js/json2.js"></script>
- <script src="../vendor/jquery/jquery.js"></script>
- <script src="../vendor/platform.js/platform.js"></script>
+ <script src="../node_modules/platform/platform.js"></script>
<script src="./asset/test-ui.js"></script>
- <script src="../lodash.js"></script>
+ <script src="../lodash.src.js"></script>
<script>
- var lodash = _.noConflict();
+ var mixinPrereqs = (function() {
+ var lodash = _.noConflict();
+ return function(_) {
+ _.mixin({
+ 'debounce': _.debounce || lodash.debounce,
+ 'defer': _.defer || lodash.defer,
+ 'pluck': _.pluck || lodash.pluck
+ });
+ };
+ }());
- QUnit.config.asyncRetries = 5;
- QUnit.config.hidepassed = true;
+ QUnit.config.asyncRetries = 10;
- // excuse tests we intentionally fail or those with problems
- QUnit.config.excused = {
- 'Backbone.Collection': {
- 'set with many models does not overflow the stack': true
- },
- 'Backbone.Router': {
- '#2656 - No trailing slash on root.': true,
- '#2765 - Fragment matching sans query/hash.': true
- }
- };
-
- // only excuse `Backbone.Router` tests in IE < 8
- if (!(document.attachEvent && (document.documentMode || 0) < 8)) {
- delete QUnit.config.excused['Backbone.Router'];
- }
-
- // assign results to `global_test_results` for Sauce Labs
- var global_test_results;
- QUnit.done(function(results) {
- global_test_results = results;
+ QUnit.begin(function() {
+ QUnit.config.hidepassed = true;
+ document.getElementById('qunit-tests').className += ' hidepass';
+ document.getElementById('qunit-urlconfig-hidepassed').checked = true;
});
- // load the build of Lo-Dash
- document.write('<script src="' + ui.buildPath + '"><\/script>');
+ // load Lo-Dash
+ if (!ui.isModularize) {
+ document.write('<script src="' + ui.buildPath + '"><\/script>');
+ }
+ // load test scripts
+ document.write(ui.urlParams.loader != 'none'
+ ? '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>'
+ : ([
+ '<script src="' + ui.buildPath + '"><\/script>',
+ '<script src="../node_modules/jquery/dist/jquery.js"><\/script>',
+ '<script src="../vendor/backbone/backbone.js"><\/script>',
+ '<script src="../vendor/backbone/test/environment.js"><\/script>',
+ '<script src="../vendor/backbone/test/noconflict.js"><\/script>',
+ '<script src="../vendor/backbone/test/events.js"><\/script>',
+ '<script src="../vendor/backbone/test/model.js"><\/script>',
+ '<script src="../vendor/backbone/test/collection.js"><\/script>',
+ '<script src="../vendor/backbone/test/router.js"><\/script>',
+ '<script src="../vendor/backbone/test/view.js"><\/script>',
+ '<script src="../vendor/backbone/test/sync.js"><\/script>'
+ ].join('\n'))
+ );
</script>
<script>
- _.mixin({
- 'debounce': _.debounce || lodash.debounce,
- 'defer': _.defer || lodash.defer,
- 'pluck': _.pluck || lodash.pluck
- });
+ (function() {
+ if (window.curl) {
+ curl.config({ 'apiName': 'require' });
+ }
+ if (!window.require) {
+ mixinPrereqs(_);
+ return;
+ }
+ var reBasename = /[\w.-]+$/,
+ basePath = ('//' + location.host + location.pathname.replace(reBasename, '')).replace(/\btest\/$/, ''),
+ modulePath = ui.buildPath.replace(/\.js$/, ''),
+ locationPath = modulePath.replace(reBasename, '').replace(/^\/|\/$/g, ''),
+ moduleMain = modulePath.match(reBasename)[0],
+ uid = +new Date;
+
+ function getConfig() {
+ var result = {
+ 'baseUrl': './',
+ 'urlArgs': 't=' + uid++,
+ 'waitSeconds': 0,
+ 'paths': {
+ 'backbone': '../vendor/backbone/backbone',
+ 'jquery': '../node_modules/jquery/dist/jquery'
+ },
+ 'packages': [{
+ 'name': 'test',
+ 'location': '../vendor/backbone/test',
+ 'config': {
+ // work around no global being exported
+ 'exports': 'QUnit',
+ 'loader': 'curl/loader/legacy'
+ }
+ }]
+ };
+
+ if (ui.isModularize) {
+ result.packages.push({
+ 'name': 'underscore',
+ 'location': locationPath,
+ 'main': moduleMain
+ });
+ } else {
+ result.paths.underscore = modulePath;
+ }
+ return result;
+ }
+
+ QUnit.config.autostart = false;
+
+ require(getConfig(), ['underscore', 'backbone'], function(lodash) {
+ mixinPrereqs(lodash);
+
+ if (ui.isModularize) {
+ window._ = lodash;
+ }
+ require(getConfig(), [
+ 'test/environment',
+ 'test/noconflict',
+ 'test/events',
+ 'test/model',
+ 'test/collection',
+ 'test/router',
+ 'test/view',
+ 'test/sync'
+ ], function() {
+ QUnit.start();
+ });
+ });
+ }());
</script>
- <script src="../vendor/backbone/backbone.js"></script>
- <script src="../vendor/backbone/test/environment.js"></script>
- <script src="../vendor/backbone/test/noconflict.js"></script>
- <script src="../vendor/backbone/test/events.js"></script>
- <script src="../vendor/backbone/test/model.js"></script>
- <script src="../vendor/backbone/test/collection.js"></script>
- <script src="../vendor/backbone/test/router.js"></script>
- <script src="../vendor/backbone/test/view.js"></script>
- <script src="../vendor/backbone/test/sync.js"></script>
</body>
</html>
diff --git a/test/index.html b/test/index.html
index f005761..8d21689 100644
--- a/test/index.html
+++ b/test/index.html
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>Lo-Dash Test Suite</title>
- <link rel="stylesheet" href="../vendor/qunit/qunit/qunit.css">
+ <link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
<style>
#exports {
display: none;
@@ -11,99 +11,257 @@
</style>
</head>
<body>
- <script src="../vendor/qunit/qunit/qunit.js"></script>
- <script src="../vendor/qunit-extras/qunit-extras.js"></script>
- <script src="../vendor/platform.js/platform.js"></script>
+ <script>
+ // avoid reporting tests to Sauce Labs when script errors occur
+ if (location.port == '9001') {
+ window.onerror = function(message) {
+ if (window.QUnit) {
+ QUnit.config.done.length = 0;
+ }
+ global_test_results = { 'message': message };
+ };
+ }
+ </script>
+ <script src="../node_modules/qunitjs/qunit/qunit.js"></script>
+ <script src="../node_modules/qunit-extras/qunit-extras.js"></script>
+ <script src="../node_modules/platform/platform.js"></script>
+ <script src="./asset/set.js"></script>
+ <script src="./asset/weakmap.js"></script>
<script src="./asset/test-ui.js"></script>
<div id="qunit"></div>
<div id="exports"></div>
<script>
- // set bad shims
- Array._isArray = Array.isArray;
- Array.isArray = function() {};
+ var setProperty = (function() {
+ var _defineProperty = Object.defineProperty;
+ return function(object, key, value) {
+ try {
+ _defineProperty(object, key, {
+ 'configurable': true,
+ 'enumerable': false,
+ 'writable': true,
+ 'value': value
+ });
+ } catch(e) {
+ object[key] = value;
+ }
+ };
+ }());
- Date._now = Date.now;
- Date.now = function() {};
+ function addBizarroMethods() {
+ var funcProto = Function.prototype,
+ objectProto = Object.prototype,
+ stringProto = String.prototype;
- Function.prototype._bind = Function.prototype.bind;
- Function.prototype.bind = function() { return function() {}; };
+ var hasOwnProperty = objectProto.hasOwnProperty,
+ fnToString = funcProto.toString,
+ nativeString = fnToString.call(objectProto.toString),
+ noop = function() {},
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ reToString = /toString/g,
+ whitespace = ' \t\x0B\f\xA0\ufeff\n\r\u2028\u2029\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000';
- Object._create = Object.create;
- Object.create = function() {};
+ function constant(value) {
+ return function() {
+ return value;
+ };
+ }
+ function createToString(funcName) {
+ return constant(nativeString.replace(reToString, funcName));
+ }
+ // allow bypassing native checks
+ setProperty(funcProto, 'toString', (function() {
+ function wrapper() {
+ setProperty(funcProto, 'toString', fnToString);
+ var result = hasOwnProperty.call(this, 'toString') ? this.toString() : fnToString.call(this);
+ setProperty(funcProto, 'toString', wrapper);
+ return result;
+ }
+ return wrapper;
+ }()));
- Object._defineProperty = Object.defineProperty;
- Object.defineProperty = function() {};
+ // add extensions
+ funcProto._method = noop;
- Object._getPrototypeOf = Object.getPrototypeOf;
- Object.getPrototypeOf = function() {};
+ // set bad shims
+ setProperty(Array, '_isArray', Array.isArray);
+ setProperty(Array, 'isArray', noop);
- Object._keys = Object.keys;
- Object.keys = function() {};
+ setProperty(Date, '_now', Date.now);
+ setProperty(Date, 'now', noop);
- // load Lo-Dash and expose it to the bad shims
- document.write('<script src="' + (ui.isModularize ? '../lodash.js' : ui.buildPath) + '"><\/script>');
- </script>
- <script>
- // store Lo-Dash to test for bad shim detection
- var lodashBadShim = window._;
-
- // restore native methods
- if (Array._isArray) {
- Array.isArray = Array._isArray;
- } else {
- delete Array.isArray;
- }
- if (Date._now) {
- Date.now = Date._now;
- } else {
- delete Date.now;
- }
- if (Function.prototype._bind) {
- Function.prototype.bind = Function.prototype._bind;
- } else {
- delete Function.prototype.bind;
- }
- if (Object._create) {
- Object.create = Object._create;
- } else {
- delete Object.create;
+ setProperty(Object, '_getPrototypeOf', Object.getPrototypeOf);
+ setProperty(Object, 'getPrototypeOf', noop);
+
+ setProperty(Object, '_keys', Object.keys);
+ setProperty(Object, 'keys', noop);
+
+ setProperty(objectProto, '_propertyIsEnumerable', propertyIsEnumerable);
+ setProperty(objectProto, 'propertyIsEnumerable', function(key) {
+ if (key == '1' && this && typeof this == 'object' && this.length === 2 &&
+ hasOwnProperty.call(this, 'callee') &&
+ !propertyIsEnumerable.call(this, 'callee') &&
+ this[0] === 0 && this[1] === 0) {
+ throw new Error;
+ }
+ return propertyIsEnumerable.call(this, key);
+ });
+
+ setProperty(Number, '_isFinite', Number.isFinite);
+ setProperty(Number, 'isFinite', noop);
+
+ setProperty(window, '_ArrayBuffer', window.ArrayBuffer);
+ if (window.ArrayBuffer && window.Uint8Array) {
+ ArrayBuffer = (function(_ArrayBuffer) {
+ function ArrayBuffer(byteLength) {
+ var buffer = new _ArrayBuffer(byteLength);
+ if (!byteLength) {
+ setProperty(buffer, 'slice', buffer.slice ? null : bufferSlice);
+ }
+ return buffer;
+ }
+ function bufferSlice() {
+ var newBuffer = new _ArrayBuffer(this.byteLength),
+ view = new Uint8Array(newBuffer);
+
+ view.set(new Uint8Array(this));
+ return newBuffer;
+ }
+ setProperty(ArrayBuffer, 'toString', createToString('ArrayBuffer'));
+ setProperty(bufferSlice, 'toString', createToString('slice'));
+ return ArrayBuffer;
+ }(_ArrayBuffer));
+ }
+ if (!window.Float64Array && window.Uint8Array) {
+ Float64Array = (function() {
+ function Float64Array(buffer, byteOffset, length) {
+ return arguments.length == 1
+ ? new Uint8Array(buffer)
+ : new Uint8Array(buffer, byteOffset || 0, length || buffer.byteLength);
+ }
+ setProperty(Float64Array, 'BYTES_PER_ELEMENT', 8);
+ setProperty(Float64Array, 'toString', createToString('Float64Array'));
+ return Float64Array;
+ }());
+ }
+ setProperty(window, '_Set', window.Set);
+ setProperty(window, 'Set', noop);
+
+ setProperty(window, '_WeakMap', window.WeakMap);
+ setProperty(window, 'WeakMap', noop);
+
+ setProperty(window, '_parseInt', parseInt);
+ setProperty(window, 'parseInt', (function(_parseInt) {
+ var checkStr = whitespace + '08',
+ isFaked = _parseInt(checkStr) != 8,
+ reHexPrefix = /^0[xX]/,
+ reTrim = RegExp('^[' + whitespace + ']+|[' + whitespace + ']+$');
+
+ return function(value, radix) {
+ if (value == checkStr && !isFaked) {
+ isFaked = true;
+ return 0;
+ }
+ value = String(value == null ? '' : value).replace(reTrim, '');
+ return _parseInt(value, +radix || (reHexPrefix.test(value) ? 16 : 10));
+ };
+ }(_parseInt)));
+
+ // fake lack of DOM support
+ setProperty(document, '_createDocumentFragment', document.createDocumentFragment);
+ document.createDocumentFragment = noop;
+
+ // fake `WinRTError`
+ setProperty(window, 'WinRTError', Error);
+
+ // fake free variable `global`
+ setProperty(window, 'exports', window);
+ setProperty(window, 'global', window);
+ setProperty(window, 'module', {});
}
- if (Object._defineProperty) {
- Object.defineProperty = Object._defineProperty;
- } else {
- delete Object.defineProperty;
+
+ function removeBizarroMethods() {
+ var funcProto = Function.prototype,
+ objectProto = Object.prototype,
+ stringProto = String.prototype;
+
+ if (Array._isArray) {
+ setProperty(Array, 'isArray', Array._isArray);
+ } else {
+ delete Array.isArray;
+ }
+ if (Date._now) {
+ setProperty(Date, 'now', Date._now);
+ } else {
+ delete Date.now;
+ }
+ if (Object._getPrototypeOf) {
+ setProperty(Object, 'getPrototypeOf', Object._getPrototypeOf);
+ } else {
+ delete Object.getPrototypeOf;
+ }
+ if (Object._keys) {
+ setProperty(Object, 'keys', Object._keys);
+ } else {
+ delete Object.keys;
+ }
+ if (Number._isFinite) {
+ setProperty(Number, 'isFinite', Number._isFinite);
+ } else {
+ delete Number.isFinite;
+ }
+ if (window._ArrayBuffer) {
+ ArrayBuffer = _ArrayBuffer;
+ }
+ setProperty(window, '_ArrayBuffer', undefined);
+
+ if (window._Set) {
+ Set = _Set;
+ }
+ setProperty(window, '_Set', undefined);
+
+ if (window._WeakMap) {
+ WeakMap = _WeakMap;
+ }
+ setProperty(window, '_WeakMap', undefined);
+
+ setProperty(window, 'parseInt', window._parseInt);
+ setProperty(window, '_parseInt', undefined);
+
+ document.createDocumentFragment = document._createDocumentFragment;
+ setProperty(document, '_createDocumentFragment', undefined);
+
+ setProperty(window, 'WinRTError', undefined);
+
+ setProperty(window, 'exports', undefined);
+ setProperty(window, 'global', undefined);
+ setProperty(window, 'module', undefined);
+
+ setProperty(objectProto, 'propertyIsEnumerable', objectProto._propertyIsEnumerable);
+
+ delete Array._isArray;
+ delete Date._now;
+ delete funcProto._method;
+ delete Object._create;
+ delete Object._getPrototypeOf;
+ delete Object._keys;
+ delete objectProto._propertyIsEnumerable;
}
- if (Object._getPrototypeOf) {
- Object.getPrototypeOf = Object._getPrototypeOf;
- } else {
- delete Object.getPrototypeOf;
+
+ // load Lo-Dash and expose it to the bad extensions/shims
+ if (!ui.isModularize) {
+ addBizarroMethods();
+ document.write('<script src="' + ui.buildPath + '"><\/script>');
}
- if (Object._keys) {
- Object.keys = Object._keys;
- } else {
- delete Object.keys;
+ </script>
+ <script>
+ // store Lo-Dash to test for bad extensions/shims
+ if (!ui.isModularize) {
+ var lodashBizarro = window._;
+ window._ = undefined;
+ removeBizarroMethods();
}
- delete Array._isArray;
- delete Date._now;
- delete Function.prototype._bind;
- delete Object._create;
- delete Object._defineProperty;
- delete Object._getPrototypeOf;
- delete Object._keys;
-
- QUnit.config.hidepassed = true;
-
- // assign results to `global_test_results` for Sauce Labs
- var global_test_results;
- QUnit.done(function(results) {
- global_test_results = results;
- });
-
- // clear existing `_` value
- window._ = undefined;
-
- // load Lo-Dash and test scripts
- document.write(ui.urlParams.loader == 'none'
+ // load test scripts
+ document.write((ui.isForeign || ui.urlParams.loader == 'none')
? '<script src="' + ui.buildPath + '"><\/script><script src="test.js"><\/script>'
: '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>'
);
@@ -117,74 +275,118 @@
if (window.curl) {
curl.config({ 'apiName': 'require' });
}
- if (!window.require) {
+ if (ui.isForeign || !window.require) {
return;
}
var reBasename = /[\w.-]+$/,
basePath = ('//' + location.host + location.pathname.replace(reBasename, '')).replace(/\btest\/$/, ''),
modulePath = ui.buildPath.replace(/\.js$/, ''),
- locationPath = modulePath.replace(reBasename, ''),
- moduleMain = modulePath.match(reBasename)[0];
-
- QUnit.config.autostart = false;
+ moduleMain = modulePath.match(reBasename)[0],
+ locationPath = modulePath.replace(reBasename, '').replace(/^\/|\/$/g, ''),
+ shimmedLocationPath = './abc/../' + locationPath,
+ underscoreLocationPath = './xyz/../' + locationPath,
+ uid = +new Date;
- // load Lo-Dash as a module
- require({
- 'baseUrl': './',
- 'urlArgs': 't=' + (+new Date),
- 'packages': [
- {
- 'name': 'lodash',
- 'location': locationPath,
- 'main': moduleMain
- },
- {
- 'name': 'shimmed',
- 'location': './abc/../' + locationPath,
- 'main': moduleMain
- },
- {
- 'name': 'underscore',
- 'location': './xyz/../' + locationPath,
- 'main': moduleMain
- },
- {
+ function getConfig() {
+ var result = {
+ 'baseUrl': './',
+ 'urlArgs': 't=' + uid++,
+ 'waitSeconds': 0,
+ 'paths': {},
+ 'packages': [{
'name': 'test',
- 'location': basePath + '/test',
+ 'location': basePath + 'test',
'main': 'test',
'config': {
// work around no global being exported
'exports': 'QUnit',
'loader': 'curl/loader/legacy'
}
+ }],
+ 'shim': {
+ 'shimmed': {
+ 'exports': '_'
+ }
}
- ],
- 'shim': {
- 'shimmed': {
- 'exports': '_'
- }
- }
- },
- ['lodash', 'shimmed', 'underscore'], function(lodash, shimmed, underscore) {
- if (shimmed && shimmed.noConflict) {
- shimmedModule = shimmed.noConflict();
- shimmedModule.moduleName = 'shimmed';
- }
- if (underscore && underscore.noConflict) {
- underscoreModule = underscore.noConflict();
- underscoreModule.moduleName = 'underscore';
- }
- if (lodash) {
- lodashModule = lodash;
- lodashModule.moduleName = 'lodash';
- }
+ };
+
if (ui.isModularize) {
- window._ = lodash;
+ result.packages.push({
+ 'name': 'lodash',
+ 'location': locationPath,
+ 'main': moduleMain
+ }, {
+ 'name': 'shimmed',
+ 'location': shimmedLocationPath,
+ 'main': moduleMain
+ }, {
+ 'name': 'underscore',
+ 'location': underscoreLocationPath,
+ 'main': moduleMain
+ });
+ } else {
+ result.paths.lodash = modulePath;
+ result.paths.shimmed = shimmedLocationPath + '/' + moduleMain;
+ result.paths.underscore = underscoreLocationPath + '/' + moduleMain;
}
- require(['test'], function() {
+ return result;
+ }
+
+ function loadTests() {
+ require(getConfig(), ['test'], function() {
QUnit.start();
});
- });
+ }
+
+ function loadModulesAndTests() {
+ require(getConfig(), ['lodash', 'shimmed', 'underscore'], function(lodash, shimmed, underscore) {
+ lodashModule = lodash;
+ lodashModule.moduleName = 'lodash';
+
+ if (shimmed) {
+ shimmedModule = shimmed.result(shimmed, 'noConflict') || shimmed;
+ shimmedModule.moduleName = 'shimmed';
+ }
+ if (underscore) {
+ underscoreModule = underscore.result(underscore, 'noConflict') || underscore;
+ underscoreModule.moduleName = 'underscore';
+ }
+ if (ui.isModularize) {
+ window._ = lodash;
+ }
+ if (ui.isModularize) {
+ require(getConfig(), [
+ 'lodash/internal/baseEach',
+ 'lodash/internal/isIndex',
+ 'lodash/internal/isIterateeCall',
+ 'lodash/internal/isLength'
+ ], function(baseEach, isIndex, isIterateeCall, isLength) {
+ lodash._baseEach = baseEach;
+ lodash._isIndex = isIndex;
+ lodash._isIterateeCall = isIterateeCall;
+ lodash._isLength = isLength;
+ loadTests();
+ });
+ } else {
+ loadTests();
+ }
+ });
+ }
+
+ QUnit.config.autostart = false;
+
+ if (window.requirejs) {
+ addBizarroMethods();
+ require(getConfig(), ['lodash'], function(lodash) {
+ lodashBizarro = lodash.result(lodash, 'noConflict') || lodash;
+ delete requirejs.s.contexts._;
+
+ removeBizarroMethods();
+ loadModulesAndTests();
+ });
+ } else {
+ loadModulesAndTests();
+ }
}());
// set a more readable browser name
diff --git a/test/run-test.sh b/test/run-test.sh
index 70a41bc..44346ea 100644
--- a/test/run-test.sh
+++ b/test/run-test.sh
@@ -1,14 +1,14 @@
cd "$(dirname "$0")"
-for cmd in rhino "rhino -require" narwhal ringo phantomjs; do
- echo "Testing in $cmd..."
- $cmd test.js ../dist/lodash.compat.js && $cmd test.js ../dist/lodash.compat.min.js
+echo "Testing in node..."
+node test.js ../lodash.src.js
+
+for cmd in rhino "rhino -require" ringo phantomjs; do
echo ""
+ echo "Testing in $cmd..."
+ $cmd test.js ../lodash.src.js
done
-echo "Testing in node..."
-node test.js ../dist/lodash.js && node test.js ../dist/lodash.min.js
-
echo ""
echo "Testing in a browser..."
open index.html
diff --git a/test/saucelabs.js b/test/saucelabs.js
index ea80422..ad6eb83 100644
--- a/test/saucelabs.js
+++ b/test/saucelabs.js
@@ -1,353 +1,933 @@
-;(function() {
- 'use strict';
-
- /** Environment shortcut */
- var env = process.env;
-
- if (isFinite(env.TRAVIS_PULL_REQUEST)) {
- console.error('Testing skipped for pull requests');
- process.exit(0);
- }
-
- /** Load Node.js modules */
- var http = require('http'),
- path = require('path'),
- url = require('url');
-
- /** Load other modules */
- var _ = require('../lodash.js'),
- ecstatic = require('ecstatic'),
- request = require('request'),
- SauceTunnel = require('sauce-tunnel');
-
- /** Used by `logInline` to clear previously logged messages */
- var prevLine = '';
-
- /** Used to display the wait throbber */
- var throbberId,
- throbberDelay = 500,
- waitCount = -1;
-
- /** Used as request `auth` and `options` values */
- var accessKey = env.SAUCE_ACCESS_KEY,
- build = env.TRAVIS_COMMIT.slice(0, 10),
- port = 9001,
- tunnelId = 'lodash_' + env.TRAVIS_JOB_NUMBER,
- username = env.SAUCE_USERNAME;
-
- var compatMode = process.argv.reduce(function(result, value) {
- return optionToValue('compatMode', value) || result;
- }, null);
-
- var runner = process.argv.reduce(function(result, value) {
- value = optionToValue('runner', value);
- return value == null
- ? result
- : '/' + value.replace(/^\W+/, '');
- }, '/test/index.html');
-
- var sessionName = process.argv.reduce(function(result, value) {
- return optionToValue('name', value) || result;
- }, 'lodash tests');
-
- var tags = process.argv.reduce(function(result, value) {
- value = optionToArray('tags', value);
- return value.length
- ? _.union(result, value)
- : result;
- }, []);
-
- /** List of platforms to load the runner on */
- var platforms = [
- ['Windows 8.1', 'chrome', '31'],
- ['Windows 8.1', 'chrome', '28'],
- ['Windows 8.1', 'chrome', '26'],
- ['OS X 10.6', 'firefox', '25'],
- ['OS X 10.6', 'firefox', '20'],
- ['OS X 10.6', 'firefox', '10'],
- ['OS X 10.6', 'firefox', '6'],
- ['OS X 10.6', 'firefox', '4'],
- ['Windows 7', 'firefox', '3.6'],
+#!/usr/bin/env node
+'use strict';
+
+/** Environment shortcut. */
+var env = process.env;
+
+if (env.TRAVIS_SECURE_ENV_VARS == 'false') {
+ console.log('Skipping Sauce Labs jobs; secure environment variables are unavailable');
+ process.exit(0);
+}
+
+/** Load Node.js modules. */
+var EventEmitter = require('events').EventEmitter,
+ http = require('http'),
+ path = require('path'),
+ url = require('url'),
+ util = require('util');
+
+/** Load other modules. */
+var _ = require('../lodash.src.js'),
+ chalk = require('chalk'),
+ ecstatic = require('ecstatic'),
+ request = require('request'),
+ SauceTunnel = require('sauce-tunnel');
+
+/** Used for Sauce Labs credentials. */
+var accessKey = env.SAUCE_ACCESS_KEY,
+ username = env.SAUCE_USERNAME;
+
+/** Used as the default maximum number of times to retry a job and tunnel. */
+var maxJobRetries = 3,
+ maxTunnelRetries = 3;
+
+/** Used as the static file server middleware. */
+var mount = ecstatic({
+ 'cache': 'no-cache',
+ 'root': process.cwd()
+});
+
+/** Used as the list of ports supported by Sauce Connect. */
+var ports = [
+ 80, 443, 888, 2000, 2001, 2020, 2109, 2222, 2310, 3000, 3001, 3030, 3210,
+ 3333, 4000, 4001, 4040, 4321, 4502, 4503, 4567, 5000, 5001, 5050, 5555, 5432,
+ 6000, 6001, 6060, 6666, 6543, 7000, 7070, 7774, 7777, 8000, 8001, 8003, 8031,
+ 8080, 8081, 8765, 8777, 8888, 9000, 9001, 9080, 9090, 9876, 9877, 9999, 49221,
+ 55001
+];
+
+/** Used by `logInline` to clear previously logged messages. */
+var prevLine = '';
+
+/** Method shortcut. */
+var push = Array.prototype.push;
+
+/** Used to detect error messages. */
+var reError = /(?:\be|E)rror\b/;
+
+/** Used to detect valid job ids. */
+var reJobId = /^[a-z0-9]{32}$/;
+
+/** Used to display the wait throbber. */
+var throbberDelay = 500,
+ waitCount = -1;
+
+/**
+ * Used as Sauce Labs config values.
+ * See the [Sauce Labs documentation](https://docs.saucelabs.com/reference/test-configuration/)
+ * for more details.
+ */
+var advisor = getOption('advisor', false),
+ build = getOption('build', (env.TRAVIS_COMMIT || '').slice(0, 10)),
+ commandTimeout = getOption('commandTimeout', 90),
+ compatMode = getOption('compatMode', null),
+ customData = Function('return {' + getOption('customData', '').replace(/^\{|}$/g, '') + '}')(),
+ deviceOrientation = getOption('deviceOrientation', 'portrait'),
+ framework = getOption('framework', 'qunit'),
+ idleTimeout = getOption('idleTimeout', 60),
+ jobName = getOption('name', 'unit tests'),
+ maxDuration = getOption('maxDuration', 120),
+ port = ports[Math.min(_.sortedIndex(ports, getOption('port', 9001)), ports.length - 1)],
+ publicAccess = getOption('public', true),
+ queueTimeout = getOption('queueTimeout', 240),
+ recordVideo = getOption('recordVideo', true),
+ recordScreenshots = getOption('recordScreenshots', false),
+ runner = getOption('runner', 'test/index.html').replace(/^\W+/, ''),
+ runnerUrl = getOption('runnerUrl', 'http://localhost:' + port + '/' + runner),
+ statusInterval = getOption('statusInterval', 5),
+ tags = getOption('tags', []),
+ throttled = getOption('throttled', 10),
+ tunneled = getOption('tunneled', true),
+ tunnelId = getOption('tunnelId', 'tunnel_' + (env.TRAVIS_JOB_ID || 0)),
+ tunnelTimeout = getOption('tunnelTimeout', 120),
+ videoUploadOnPass = getOption('videoUploadOnPass', false);
+
+/** Used to convert Sauce Labs browser identifiers to their formal names. */
+var browserNameMap = {
+ 'googlechrome': 'Chrome',
+ 'iehta': 'Internet Explorer',
+ 'ipad': 'iPad',
+ 'iphone': 'iPhone'
+};
+
+/** List of platforms to load the runner on. */
+var platforms = [
+ ['Linux', 'android', '4.3'],
+ ['Linux', 'android', '4.0'],
+ ['Windows 8.1', 'firefox', '35'],
+ ['Windows 8.1', 'firefox', '34'],
+ ['Windows 8.1', 'firefox', '20'],
+ ['Windows 8.1', 'chrome', '39'],
+ ['Windows 8.1', 'chrome', '38'],
+ ['Windows 8.1', 'internet explorer', '11'],
+ ['Windows 8', 'internet explorer', '10'],
+ ['Windows 7', 'internet explorer', '9'],
+ ['Windows 7', 'internet explorer', '8'],
+ ['Windows XP', 'internet explorer', '7'],
+ ['Windows XP', 'internet explorer', '6'],
+ ['Windows 7', 'opera', '12'],
+ ['Windows 7', 'opera', '11'],
+ ['OS X 10.9', 'ipad', '8.1'],
+ ['OS X 10.6', 'ipad', '4'],
+ ['OS X 10.10', 'safari', '8'],
+ ['OS X 10.9', 'safari', '7'],
+ ['OS X 10.8', 'safari', '6'],
+ ['OS X 10.6', 'safari', '5']
+];
+
+/** Used to tailor the `platforms` array. */
+var isAMD = _.includes(tags, 'amd'),
+ isBackbone = _.includes(tags, 'backbone'),
+ isModern = _.includes(tags, 'modern');
+
+// The platforms to test IE compatibility modes.
+if (compatMode) {
+ platforms = [
['Windows 8.1', 'internet explorer', '11'],
['Windows 8', 'internet explorer', '10'],
['Windows 7', 'internet explorer', '9'],
- ['Windows 7', 'internet explorer', '8'],
- ['Windows XP', 'internet explorer', '7'],
- ['Windows XP', 'internet explorer', '6'],
- //['Windows 7', 'opera', '12'],
- //['Windows 7', 'opera', '11'],
- ['OS X 10.8', 'safari', '6'],
- ['Windows 7', 'safari', '5'],
- ['Windows XP', 'safari', '4']
+ ['Windows 7', 'internet explorer', '8']
];
-
- /** Used to tailor the `platforms` array */
- var runnerQuery = url.parse(runner, true).query,
- isBackbone = /\bbackbone\b/i.test(runner),
- isMobile = /\bmobile\b/i.test(runnerQuery.build),
- isModern = /\bmodern\b/i.test(runnerQuery.build);
-
- // platforms to test IE compat mode
- if (compatMode) {
- platforms = [
- ['Windows 8.1', 'internet explorer', '11'],
- ['Windows 8', 'internet explorer', '10'],
- ['Windows 7', 'internet explorer', '9'],
- ['Windows 7', 'internet explorer', '8']
- ];
+}
+// The platforms for AMD tests.
+if (isAMD) {
+ platforms = _.filter(platforms, function(platform) {
+ var browser = browserName(platform[1]),
+ version = +platform[2];
+
+ switch (browser) {
+ case 'Android': return version >= 4.4;
+ case 'Opera': return version >= 10;
+ }
+ return true;
+ });
+}
+// The platforms for Backbone tests.
+if (isBackbone) {
+ platforms = _.filter(platforms, function(platform) {
+ var browser = browserName(platform[1]),
+ version = +platform[2];
+
+ switch (browser) {
+ case 'Firefox': return version >= 4;
+ case 'iPad': return version >= 5;
+ case 'Opera': return version >= 12;
+ }
+ return true;
+ });
+}
+// The platforms for modern builds.
+if (isModern) {
+ platforms = _.filter(platforms, function(platform) {
+ var browser = browserName(platform[1]),
+ version = +platform[2];
+
+ switch (browser) {
+ case 'Android': return version >= 4.1;
+ case 'Firefox': return version >= 10;
+ case 'Internet Explorer': return version >= 9;
+ case 'iPad': return version >= 6;
+ case 'Opera': return version >= 12;
+ case 'Safari': return version >= 6;
+ }
+ return true;
+ });
+}
+
+/** Used as the default `Job` options object. */
+var jobOptions = {
+ 'build': build,
+ 'command-timeout': commandTimeout,
+ 'custom-data': customData,
+ 'device-orientation': deviceOrientation,
+ 'framework': framework,
+ 'idle-timeout': idleTimeout,
+ 'max-duration': maxDuration,
+ 'name': jobName,
+ 'public': publicAccess,
+ 'platforms': platforms,
+ 'record-screenshots': recordScreenshots,
+ 'record-video': recordVideo,
+ 'sauce-advisor': advisor,
+ 'tags': tags,
+ 'url': runnerUrl,
+ 'video-upload-on-pass': videoUploadOnPass
+};
+
+if (publicAccess === true) {
+ jobOptions['public'] = 'public';
+}
+if (tunneled) {
+ jobOptions['tunnel-identifier'] = tunnelId;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Resolves the formal browser name for a given Sauce Labs browser identifier.
+ *
+ * @private
+ * @param {string} identifier The browser identifier.
+ * @returns {string} Returns the formal browser name.
+ */
+function browserName(identifier) {
+ return browserNameMap[identifier] || capitalizeWords(identifier);
+}
+
+/**
+ * Capitalizes the first character of each word in `string`.
+ *
+ * @private
+ * @param {string} string The string to augment.
+ * @returns {string} Returns the augmented string.
+ */
+function capitalizeWords(string) {
+ return _.map(string.split(' '), _.capitalize).join(' ');
+}
+
+/**
+ * Gets the value for the given option name. If no value is available the
+ * `defaultValue` is returned.
+ *
+ * @private
+ * @param {string} name The name of the option.
+ * @param {*} defaultValue The default option value.
+ * @returns {*} Returns the option value.
+ */
+function getOption(name, defaultValue) {
+ var isArr = _.isArray(defaultValue);
+ return _.reduce(process.argv, function(result, value) {
+ if (isArr) {
+ value = optionToArray(name, value);
+ return _.isEmpty(value) ? result : value;
+ }
+ value = optionToValue(name, value);
+
+ return value == null ? result : value;
+ }, defaultValue);
+}
+
+/**
+ * Checks if `value` is a job ID.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a job ID, else `false`.
+ */
+function isJobId(value) {
+ return reJobId.test(value);
+}
+
+/**
+ * Writes an inline message to standard output.
+ *
+ * @private
+ * @param {string} [text=''] The text to log.
+ */
+function logInline(text) {
+ var blankLine = _.repeat(' ', _.size(prevLine));
+ prevLine = text = _.trunc(text, 40);
+ process.stdout.write(text + blankLine.slice(text.length) + '\r');
+}
+
+/**
+ * Writes the wait throbber to standard output.
+ *
+ * @private
+ */
+function logThrobber() {
+ logInline('Please wait' + _.repeat('.', (++waitCount % 3) + 1));
+}
+
+/**
+ * Converts a comma separated option value into an array.
+ *
+ * @private
+ * @param {string} name The name of the option to inspect.
+ * @param {string} string The options string.
+ * @returns {Array} Returns the new converted array.
+ */
+function optionToArray(name, string) {
+ return _.compact(_.invoke((optionToValue(name, string) || '').split(/, */), 'trim'));
+}
+
+/**
+ * Extracts the option value from an option string.
+ *
+ * @private
+ * @param {string} name The name of the option to inspect.
+ * @param {string} string The options string.
+ * @returns {string|undefined} Returns the option value, else `undefined`.
+ */
+function optionToValue(name, string) {
+ var result = string.match(RegExp('^' + name + '(?:=([\\s\\S]+))?$'));
+ if (result) {
+ result = _.result(result, 1);
+ result = result ? _.trim(result) : true;
}
- // platforms for Backbone tests
- if (isBackbone) {
- platforms = platforms.filter(function(platform) {
- var browser = platform[1],
- version = +platform[2];
-
- switch (browser) {
- case 'firefox': return version >= 4;
- case 'opera': return version >= 12;
- }
- return true;
- });
+ if (result === 'false') {
+ return false;
}
- // platforms for mobile and modern builds
- if (isMobile || isModern) {
- platforms = platforms.filter(function(platform) {
- var browser = platform[1],
- version = +platform[2];
-
- switch (browser) {
- case 'firefox': return version >= 10;
- case 'internet explorer': return version >= 9;
- case 'opera': return version >= 12;
- case 'safari': return version >= (isMobile ? 3 : 6);
- }
- return true;
- });
+ return result || undefined;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * The `Job#remove` and `Tunnel#stop` callback used by `Jobs#restart`
+ * and `Tunnel#restart` respectively.
+ *
+ * @private
+ */
+function onGenericRestart() {
+ this.restarting = false;
+ this.emit('restart');
+ this.start();
+}
+
+/**
+ * The `request.put` and `SauceTunnel#stop` callback used by `Jobs#stop`
+ * and `Tunnel#stop` respectively.
+ *
+ * @private
+ * @param {Object} [error] The error object.
+ */
+function onGenericStop(error) {
+ this.running = this.stopping = false;
+ this.emit('stop', error);
+}
+
+/**
+ * The `request.del` callback used by `Jobs#remove`.
+ *
+ * @private
+ */
+function onJobRemove(error, res, body) {
+ this.id = this.taskId = this.url = null;
+ this.removing = false;
+ this.emit('remove');
+}
+
+/**
+ * The `Job#remove` callback used by `Jobs#reset`.
+ *
+ * @private
+ */
+function onJobReset() {
+ this.attempts = 0;
+ this.failed = this.resetting = false;
+ this._pollerId = this.id = this.result = this.taskId = this.url = null;
+ this.emit('reset');
+}
+
+/**
+ * The `request.post` callback used by `Jobs#start`.
+ *
+ * @private
+ * @param {Object} [error] The error object.
+ * @param {Object} res The response data object.
+ * @param {Object} body The response body JSON object.
+ */
+function onJobStart(error, res, body) {
+ this.starting = false;
+
+ if (this.stopping) {
+ return;
}
+ var statusCode = _.result(res, 'statusCode'),
+ taskId = _.first(_.result(body, 'js tests'));
- /*--------------------------------------------------------------------------*/
-
- /**
- * Writes an inline message to standard output.
- *
- * @private
- * @param {string} text The text to log.
- */
- function logInline(text) {
- var blankLine = repeat(' ', prevLine.length);
- if (text.length > 40) {
- text = text.slice(0, 37) + '...';
+ if (error || !taskId || statusCode != 200) {
+ if (this.attempts < this.retries) {
+ this.restart();
+ return;
+ }
+ var na = 'unavailable',
+ bodyStr = _.isObject(body) ? '\n' + JSON.stringify(body) : na,
+ statusStr = _.isFinite(statusCode) ? statusCode : na;
+
+ logInline();
+ console.error('Failed to start job; status: %s, body: %s', statusStr, bodyStr);
+ if (error) {
+ console.error(error);
}
- prevLine = text;
- process.stdout.write(text + blankLine.slice(text.length) + '\r');
+ this.failed = true;
+ this.emit('complete');
+ return;
}
-
- /**
- * Writes the wait throbber to standard output.
- *
- * @private
- */
- function logThrobber() {
- logInline('Please wait' + repeat('.', (++waitCount % 3) + 1));
+ this.running = true;
+ this.taskId = taskId;
+ this.timestamp = _.now();
+ this.emit('start');
+ this.status();
+}
+
+/**
+ * The `request.post` callback used by `Job#status`.
+ *
+ * @private
+ * @param {Object} [error] The error object.
+ * @param {Object} res The response data object.
+ * @param {Object} body The response body JSON object.
+ */
+function onJobStatus(error, res, body) {
+ this.checking = false;
+
+ if (!this.running || this.stopping) {
+ return;
}
-
- /**
- * Converts a comma separated option value into an array.
- *
- * @private
- * @param {string} name The name of the option to inspect.
- * @param {string} string The options string.
- * @returns {Array} Returns the new converted array.
- */
- function optionToArray(name, string) {
- return _.compact(_.isArray(string)
- ? string
- : _.invoke((optionToValue(name, string) || '').split(/, */), 'trim')
- );
+ var completed = _.result(body, 'completed', false),
+ data = _.first(_.result(body, 'js tests')),
+ elapsed = (_.now() - this.timestamp) / 1000,
+ jobId = _.result(data, 'job_id', null),
+ jobResult = _.result(data, 'result', null),
+ jobStatus = _.result(data, 'status', ''),
+ jobUrl = _.result(data, 'url', null),
+ expired = (elapsed >= queueTimeout && !_.includes(jobStatus, 'in progress')),
+ options = this.options,
+ platform = options.platforms[0];
+
+ if (_.isObject(jobResult)) {
+ var message = _.result(jobResult, 'message');
+ } else {
+ if (typeof jobResult == 'string') {
+ message = jobResult;
+ }
+ jobResult = null;
}
-
- /**
- * Extracts the option value from an option string.
- *
- * @private
- * @param {string} name The name of the option to inspect.
- * @param {string} string The options string.
- * @returns {string|undefined} Returns the option value, else `undefined`.
- */
- function optionToValue(name, string) {
- var result = (result = string.match(RegExp('^' + name + '=([\\s\\S]+)$'))) && result[1].trim();
- return result || undefined;
+ if (isJobId(jobId)) {
+ this.id = jobId;
+ this.result = jobResult;
+ this.url = jobUrl;
+ } else {
+ completed = false;
}
+ this.emit('status', jobStatus);
- /**
- * Creates a string with `text` repeated `n` number of times.
- *
- * @private
- * @param {string} text The text to repeat.
- * @param {number} n The number of times to repeat `text`.
- * @returns {string} The created string.
- */
- function repeat(text, n) {
- return Array(n + 1).join(text);
+ if (!completed && !expired) {
+ this._pollerId = _.delay(_.bind(this.status, this), this.statusInterval * 1000);
+ return;
}
+ var description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + capitalizeWords(platform[0]),
+ errored = !jobResult || !jobResult.passed || reError.test(message) || reError.test(jobStatus),
+ failures = _.result(jobResult, 'failed'),
+ label = options.name + ':',
+ tunnel = this.tunnel;
+
+ if (errored || failures) {
+ if (errored && this.attempts < this.retries) {
+ this.restart();
+ return;
+ }
+ var details = 'See ' + jobUrl + ' for details.';
+ this.failed = true;
- /*--------------------------------------------------------------------------*/
-
- /**
- * Processes the result object of the test session.
- *
- * @private
- * @param {Object} results The result object to process.
- */
- function handleTestResults(results) {
- var failingTests = results.filter(function(test) {
- var result = test.result;
- return !result || result.failed || /\berror\b/i.test(result.message);
- });
-
- var failingPlatforms = failingTests.map(function(test) {
- return test.platform;
- });
-
- if (!failingTests.length) {
- console.log('Tests passed');
+ logInline();
+ if (failures) {
+ console.error(label + ' %s ' + chalk.red('failed') + ' %d test' + (failures > 1 ? 's' : '') + '. %s', description, failures, details);
+ }
+ else if (tunnel.attempts < tunnel.retries) {
+ tunnel.restart();
+ return;
}
else {
- console.error('Tests failed on platforms: ' + JSON.stringify(failingPlatforms));
-
- failingTests.forEach(function(test) {
- var result = test.result || {},
- details = 'See ' + test.url + ' for details.',
- failed = result.failed,
- platform = JSON.stringify(test.platform);
-
- if (failed) {
- console.error(failed + ' failures on ' + platform + '. ' + details);
- } else {
- var message = result.message || 'no results available. ' + details;
- console.error('Testing on ' + platform + ' failed; ' + message);
- }
- });
+ if (typeof message == 'undefined') {
+ message = 'Results are unavailable. ' + details;
+ }
+ console.error(label, description, chalk.red('failed') + ';', message);
+ }
+ }
+ else {
+ logInline();
+ console.log(label, description, chalk.green('passed'));
+ }
+ this.running = false;
+ this.emit('complete');
+}
+
+/**
+ * The `SauceTunnel#start` callback used by `Tunnel#start`.
+ *
+ * @private
+ * @param {boolean} success The connection success indicator.
+ */
+function onTunnelStart(success) {
+ this.starting = false;
+
+ if (this._timeoutId) {
+ clearTimeout(this._timeoutId);
+ this._timeoutId = null;
+ }
+ if (!success) {
+ if (this.attempts < this.retries) {
+ this.restart();
+ return;
}
+ logInline();
+ console.error('Failed to open Sauce Connect tunnel');
+ process.exit(2);
+ }
+ logInline();
+ console.log('Sauce Connect tunnel opened');
+
+ var jobs = this.jobs;
+ push.apply(jobs.queue, jobs.all);
+
+ this.running = true;
+ this.emit('start');
+
+ console.log('Starting jobs...');
+ this.dequeue();
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * The Job constructor.
+ *
+ * @private
+ * @param {Object} [properties] The properties to initialize a job with.
+ */
+function Job(properties) {
+ EventEmitter.call(this);
+
+ this.options = {};
+ this.retries = maxJobRetries;
+ this.statusInterval = statusInterval;
+
+ _.merge(this, properties);
+ _.defaults(this.options, _.cloneDeep(jobOptions));
+
+ this.attempts = 0;
+ this.checking = this.failed = this.removing = this.resetting = this.restarting = this.running = this.starting = this.stopping = false;
+ this._pollerId = this.id = this.result = this.taskId = this.url = null;
+}
+
+util.inherits(Job, EventEmitter);
+
+/**
+ * Removes the job.
+ *
+ * @memberOf Job
+ * @param {Function} callback The function called once the job is removed.
+ * @param {Object} Returns the job instance.
+ */
+Job.prototype.remove = function(callback) {
+ this.once('remove', _.callback(callback));
+ if (this.removing) {
+ return this;
+ }
+ this.removing = true;
+ return this.stop(function() {
+ var onRemove = _.bind(onJobRemove, this);
+ if (!this.id) {
+ _.defer(onRemove);
+ return;
+ }
+ request.del(_.template('https://saucelabs.com/rest/v1/${user}/jobs/${id}')(this), {
+ 'auth': { 'user': this.user, 'pass': this.pass }
+ }, onRemove);
+ });
+};
+
+/**
+ * Resets the job.
+ *
+ * @memberOf Job
+ * @param {Function} callback The function called once the job is reset.
+ * @param {Object} Returns the job instance.
+ */
+Job.prototype.reset = function(callback) {
+ this.once('reset', _.callback(callback));
+ if (this.resetting) {
+ return this;
+ }
+ this.resetting = true;
+ return this.remove(onJobReset);
+};
+
+/**
+ * Restarts the job.
+ *
+ * @memberOf Job
+ * @param {Function} callback The function called once the job is restarted.
+ * @param {Object} Returns the job instance.
+ */
+Job.prototype.restart = function(callback) {
+ this.once('restart', _.callback(callback));
+ if (this.restarting) {
+ return this;
+ }
+ this.restarting = true;
+
+ var options = this.options,
+ platform = options.platforms[0],
+ description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + capitalizeWords(platform[0]),
+ label = options.name + ':';
+
+ logInline();
+ console.log('%s %s restart %d of %d', label, description, ++this.attempts, this.retries);
+
+ return this.remove(onGenericRestart);
+};
+
+/**
+ * Starts the job.
+ *
+ * @memberOf Job
+ * @param {Function} callback The function called once the job is started.
+ * @param {Object} Returns the job instance.
+ */
+Job.prototype.start = function(callback) {
+ this.once('start', _.callback(callback));
+ if (this.starting || this.running) {
+ return this;
+ }
+ this.starting = true;
+ request.post(_.template('https://saucelabs.com/rest/v1/${user}/js-tests')(this), {
+ 'auth': { 'user': this.user, 'pass': this.pass },
+ 'json': this.options
+ }, _.bind(onJobStart, this));
+
+ return this;
+};
+
+/**
+ * Checks the status of a job.
+ *
+ * @memberOf Job
+ * @param {Function} callback The function called once the status is resolved.
+ * @param {Object} Returns the job instance.
+ */
+Job.prototype.status = function(callback) {
+ this.once('status', _.callback(callback));
+ if (this.checking || this.removing || this.resetting || this.restarting || this.starting || this.stopping) {
+ return this;
+ }
+ this._pollerId = null;
+ this.checking = true;
+ request.post(_.template('https://saucelabs.com/rest/v1/${user}/js-tests/status')(this), {
+ 'auth': { 'user': this.user, 'pass': this.pass },
+ 'json': { 'js tests': [this.taskId] }
+ }, _.bind(onJobStatus, this));
+
+ return this;
+};
+
+/**
+ * Stops the job.
+ *
+ * @memberOf Job
+ * @param {Function} callback The function called once the job is stopped.
+ * @param {Object} Returns the job instance.
+ */
+Job.prototype.stop = function(callback) {
+ this.once('stop', _.callback(callback));
+ if (this.stopping) {
+ return this;
+ }
+ this.stopping = true;
+ if (this._pollerId) {
+ clearTimeout(this._pollerId);
+ this._pollerId = null;
+ this.checking = false;
+ }
+ var onStop = _.bind(onGenericStop, this);
+ if (!this.running || !this.id) {
+ _.defer(onStop);
+ return this;
+ }
+ request.put(_.template('https://saucelabs.com/rest/v1/${user}/jobs/${id}/stop')(this), {
+ 'auth': { 'user': this.user, 'pass': this.pass }
+ }, onStop);
+
+ return this;
+};
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * The Tunnel constructor.
+ *
+ * @private
+ * @param {Object} [properties] The properties to initialize the tunnel with.
+ */
+function Tunnel(properties) {
+ EventEmitter.call(this);
+
+ this.retries = maxTunnelRetries;
+ _.merge(this, properties);
+
+ var active = [],
+ queue = [];
+
+ var all = _.map(this.platforms, function(platform) {
+ return new Job(_.merge({
+ 'user': this.user,
+ 'pass': this.pass,
+ 'tunnel': this,
+ 'options': { 'platforms': [platform] }
+ }, this.job));
+ }, this);
+
+ var completed = 0,
+ restarted = [],
+ success = true,
+ total = all.length,
+ tunnel = this;
+
+ _.invoke(all, 'on', 'complete', function() {
+ _.pull(active, this);
+ if (success) {
+ success = !this.failed;
+ }
+ if (++completed == total) {
+ tunnel.stop(_.partial(tunnel.emit, 'complete', success));
+ return;
+ }
+ tunnel.dequeue();
+ });
- clearInterval(throbberId);
- console.log('Shutting down Sauce Connect tunnel...');
+ _.invoke(all, 'on', 'restart', function() {
+ if (!_.includes(restarted, this)) {
+ restarted.push(this);
+ }
+ // Restart tunnel if all active jobs have restarted.
+ var threshold = Math.min(all.length, _.isFinite(throttled) ? throttled : 3);
+ if (tunnel.attempts < tunnel.retries &&
+ active.length >= threshold && _.isEmpty(_.difference(active, restarted))) {
+ tunnel.restart();
+ }
+ });
+
+ this.on('restart', function() {
+ completed = 0;
+ success = true;
+ restarted.length = 0;
+ });
- tunnel.stop(function() {
- process.exit(failingTests.length ? 1 : 0);
- });
+ this._timeoutId = null;
+ this.attempts = 0;
+ this.restarting = this.running = this.starting = this.stopping = false;
+ this.jobs = { 'active': active, 'all': all, 'queue': queue };
+ this.connection = new SauceTunnel(this.user, this.pass, this.id, this.tunneled, ['-P', '0']);
+}
+
+util.inherits(Tunnel, EventEmitter);
+
+/**
+ * Restarts the tunnel.
+ *
+ * @memberOf Tunnel
+ * @param {Function} callback The function called once the tunnel is restarted.
+ */
+Tunnel.prototype.restart = function(callback) {
+ this.once('restart', _.callback(callback));
+ if (this.restarting) {
+ return this;
}
+ this.restarting = true;
- /**
- * Makes a request for Sauce Labs to start the test session.
- *
- * @private
- */
- function runTests() {
- var options = {
- 'build': build,
- 'framework': 'qunit',
- 'idle-timeout': 300,
- 'max-duration': 600,
- 'name': sessionName,
- 'public': 'public',
- 'platforms': platforms,
- 'record-screenshots': false,
- 'tags': tags,
- 'tunnel': 'tunnel-identifier:' + tunnelId,
- 'url': 'http://localhost:' + port + runner,
- 'video-upload-on-pass': false
- };
-
- console.log('Starting saucelabs tests: ' + JSON.stringify(options));
-
- request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests', {
- 'auth': { 'user': username, 'pass': accessKey },
- 'json': options
- }, function(error, response, body) {
- var statusCode = response && response.statusCode;
- if (statusCode == 200) {
- waitForTestCompletion(body);
- } else {
- console.error('Failed to submit test to Sauce Labs; status: ' + statusCode + ', body:\n' + JSON.stringify(body));
- if (error) {
- console.error(error);
- }
- process.exit(3);
- }
- });
+ logInline();
+ console.log('Tunnel %s: restart %d of %d', this.id, ++this.attempts, this.retries);
- // initialize the wait throbber
- if (!throbberId) {
- throbberId = setInterval(logThrobber, throbberDelay);
- logThrobber();
- }
- }
+ var jobs = this.jobs,
+ active = jobs.active,
+ all = jobs.all;
- /**
- * Checks the status of the test session. If the session has completed it
- * passes the result object to `handleTestResults`, else it checks the status
- * again in five seconds.
- *
- * @private
- * @param {Object} testIdentifier The object used to identify the session.
- */
- function waitForTestCompletion(testIdentifier) {
- request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests/status', {
- 'auth': { 'user': username, 'pass': accessKey },
- 'json': testIdentifier
- }, function(error, response, body) {
- var statusCode = response && response.statusCode;
- if (statusCode == 200) {
- if (body.completed) {
- logInline('');
- handleTestResults(body['js tests']);
- }
- else {
- setTimeout(function() {
- waitForTestCompletion(testIdentifier);
- }, 5000);
- }
- } else {
- logInline('');
- console.error('Failed to check test status on Sauce Labs; status: ' + statusCode + ', body:\n' + JSON.stringify(body));
- if (error) {
- console.error(error);
- }
- process.exit(4);
- }
- });
+ var reset = _.after(all.length, _.bind(this.stop, this, onGenericRestart)),
+ stop = _.after(active.length, _.partial(_.invoke, all, 'reset', reset));
+
+ if (_.isEmpty(active)) {
+ _.defer(stop);
+ }
+ if (_.isEmpty(all)) {
+ _.defer(reset);
}
+ _.invoke(active, 'stop', function() {
+ _.pull(active, this);
+ stop();
+ });
- /*--------------------------------------------------------------------------*/
+ if (this._timeoutId) {
+ clearTimeout(this._timeoutId);
+ this._timeoutId = null;
+ }
+ return this;
+};
+
+/**
+ * Starts the tunnel.
+ *
+ * @memberOf Tunnel
+ * @param {Function} callback The function called once the tunnel is started.
+ * @param {Object} Returns the tunnel instance.
+ */
+Tunnel.prototype.start = function(callback) {
+ this.once('start', _.callback(callback));
+ if (this.starting || this.running) {
+ return this;
+ }
+ this.starting = true;
- // create a web server for the local dir
- var mount = ecstatic({
- 'cache': false,
- 'root': process.cwd()
- });
+ logInline();
+ console.log('Opening Sauce Connect tunnel...');
- http.createServer(function(req, res) {
- // see http://msdn.microsoft.com/en-us/library/ff955275(v=vs.85).aspx
- if (compatMode && path.extname(url.parse(req.url).pathname) == '.html') {
- res.setHeader('X-UA-Compatible', 'IE=' + compatMode);
- }
- mount(req, res);
- }).listen(port);
+ var onStart = _.bind(onTunnelStart, this);
+ if (this.timeout) {
+ this._timeoutId = _.delay(onStart, this.timeout * 1000, false);
+ }
+ this.connection.start(onStart);
+ return this;
+};
+
+/**
+ * Removes jobs from the queue and starts them.
+ *
+ * @memberOf Tunnel
+ * @param {Object} Returns the tunnel instance.
+ */
+Tunnel.prototype.dequeue = function() {
+ var jobs = this.jobs,
+ active = jobs.active,
+ queue = jobs.queue,
+ throttled = this.throttled;
+
+ while (queue.length && (active.length < throttled)) {
+ active.push(queue.shift().start());
+ }
+ return this;
+};
+
+/**
+ * Stops the tunnel.
+ *
+ * @memberOf Tunnel
+ * @param {Function} callback The function called once the tunnel is stopped.
+ * @param {Object} Returns the tunnel instance.
+ */
+Tunnel.prototype.stop = function(callback) {
+ this.once('stop', _.callback(callback));
+ if (this.stopping) {
+ return this;
+ }
+ this.stopping = true;
- // set up Sauce Connect so we can use this server from Sauce Labs
- var tunnelTimeout = 10000,
- tunnel = new SauceTunnel(username, accessKey, tunnelId, true, tunnelTimeout);
+ logInline();
+ console.log('Shutting down Sauce Connect tunnel...');
- console.log('Opening Sauce Connect tunnel...');
+ var jobs = this.jobs,
+ active = jobs.active;
- tunnel.start(function(success) {
- if (success) {
- console.log('Sauce Connect tunnel opened');
- runTests();
+ var stop = _.after(active.length, _.bind(function() {
+ var onStop = _.bind(onGenericStop, this);
+ if (this.running) {
+ this.connection.stop(onStop);
} else {
- console.error('Failed to open Sauce Connect tunnel');
- process.exit(2);
+ onStop();
}
+ }, this));
+
+ jobs.queue.length = 0;
+ if (_.isEmpty(active)) {
+ _.defer(stop);
+ }
+ _.invoke(active, 'stop', function() {
+ _.pull(active, this);
+ stop();
});
-}());
+
+ if (this._timeoutId) {
+ clearTimeout(this._timeoutId);
+ this._timeoutId = null;
+ }
+ return this;
+};
+
+/*----------------------------------------------------------------------------*/
+
+// Cleanup any inline logs when exited via `ctrl+c`.
+process.on('SIGINT', function() {
+ logInline();
+ process.exit();
+});
+
+// Create a web server for the current working directory.
+http.createServer(function(req, res) {
+ // See http://msdn.microsoft.com/en-us/library/ff955275(v=vs.85).aspx.
+ if (compatMode && path.extname(url.parse(req.url).pathname) == '.html') {
+ res.setHeader('X-UA-Compatible', 'IE=' + compatMode);
+ }
+ mount(req, res);
+}).listen(port);
+
+// Setup Sauce Connect so we can use this server from Sauce Labs.
+var tunnel = new Tunnel({
+ 'user': username,
+ 'pass': accessKey,
+ 'id': tunnelId,
+ 'job': { 'retries': maxJobRetries, 'statusInterval': statusInterval },
+ 'platforms': platforms,
+ 'retries': maxTunnelRetries,
+ 'throttled': throttled,
+ 'tunneled': tunneled,
+ 'timeout': tunnelTimeout
+});
+
+tunnel.on('complete', function(success) {
+ process.exit(success ? 0 : 1);
+});
+
+tunnel.start();
+
+setInterval(logThrobber, throbberDelay);
diff --git a/test/test.js b/test/test.js
index f7d7226..6ef56b0 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1,26 +1,70 @@
-;(function(root, undefined) {
- 'use strict';
+;(function() {
- /** Used to store Lo-Dash to test for bad shim detection */
- var lodashBadShim = root.lodashBadShim;
+ /** Used as a safe reference for `undefined` in pre ES5 environments. */
+ var undefined;
- /** Method and object shortcuts */
+ /** Used to detect when a function becomes hot. */
+ var HOT_COUNT = 150;
+
+ /** Used as the size to cover large array optimizations. */
+ var LARGE_ARRAY_SIZE = 200;
+
+ /** Used as references for the max length and index of an array. */
+ var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1,
+ MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1;
+
+ /** Used as the maximum length an array-like object. */
+ var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
+
+ /** `Object#toString` result references. */
+ var funcTag = '[object Function]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]';
+
+ /** Used as a reference to the global object. */
+ var root = (typeof global == 'object' && global) || this;
+
+ /** Used to store Lo-Dash to test for bad extensions/shims. */
+ var lodashBizarro = root.lodashBizarro;
+
+ /** Used for native method references. */
+ var arrayProto = Array.prototype,
+ errorProto = Error.prototype,
+ funcProto = Function.prototype,
+ objectProto = Object.prototype,
+ stringProto = String.prototype;
+
+ /** Method and object shortcuts. */
var phantom = root.phantom,
amd = root.define && define.amd,
argv = root.process && process.argv,
+ ArrayBuffer = root.ArrayBuffer,
document = !phantom && root.document,
- body = document && document.body,
+ body = root.document && root.document.body,
create = Object.create,
+ fnToString = funcProto.toString,
freeze = Object.freeze,
+ hasOwnProperty = objectProto.hasOwnProperty,
+ JSON = root.JSON,
noop = function() {},
+ objToString = objectProto.toString,
params = root.arguments,
- push = Array.prototype.push,
- slice = Array.prototype.slice,
+ push = arrayProto.push,
+ slice = arrayProto.slice,
system = root.system,
- toString = Object.prototype.toString,
- Worker = document && root.Worker;
+ Uint8Array = root.Uint8Array;
+
+ /** Used to set property descriptors. */
+ var defineProperty = (function() {
+ try {
+ var o = {},
+ func = Object.defineProperty,
+ result = func(o, o, o) && func;
+ } catch(e) {}
+ return result;
+ }());
- /** The file path of the Lo-Dash file to test */
+ /** The file path of the Lo-Dash file to test. */
var filePath = (function() {
var min = 0,
result = [];
@@ -37,65 +81,95 @@
result = params;
}
var last = result[result.length - 1];
- result = (result.length > min && !/test(?:\.js)?$/.test(last)) ? last : '../lodash.js';
+ result = (result.length > min && !/test(?:\.js)?$/.test(last)) ? last : '../lodash.src.js';
if (!amd) {
try {
- return require('fs').realpathSync(result);
- } catch(e) { }
+ result = require('fs').realpathSync(result);
+ } catch(e) {}
+
+ try {
+ result = require.resolve(result);
+ } catch(e) {}
}
return result;
}());
- /** The `ui` object */
+ /** The `ui` object. */
var ui = root.ui || (root.ui = {
'buildPath': filePath,
'loaderPath': '',
+ 'isModularize': /\b(?:amd|commonjs|es|node|npm|(index|main)\.js)\b/.test(filePath),
+ 'isStrict': /\bes\b/.test(filePath),
'urlParams': {}
});
- /** The basename of the Lo-Dash file to test */
+ /** The basename of the Lo-Dash file to test. */
var basename = /[\w.-]+$/.exec(filePath)[0];
- /** Used to indicate testing a modularized build */
- var isModularize = ui.isModularize || /\b(?:commonjs|(index|main)\.js|lodash-(?:amd|node)|modularize|npm)\b/.test([ui.buildPath, ui.urlParams.build, basename]);
+ /** Detect if in a Java environment. */
+ var isJava = !document && !!root.java;
- /** Detect if testing `npm` modules */
- var isNpm = isModularize && /\bnpm\b/.test([ui.buildPath, ui.urlParams.build]);
+ /** Used to indicate testing a modularized build. */
+ var isModularize = ui.isModularize;
- /** Detect if running in Java */
- var isJava = !document && !!root.java;
+ /** Detect if testing `npm` modules. */
+ var isNpm = isModularize && /\bnpm\b/.test([ui.buildPath, ui.urlParams.build]);
- /** Detects if running in a PhantomJS web page */
- var isPhantomPage = typeof callPhantom == 'function';
+ /** Detect if running in PhantomJS. */
+ var isPhantom = phantom || typeof callPhantom == 'function';
- /** Detect if running in Rhino */
+ /** Detect if running in Rhino. */
var isRhino = isJava && typeof global == 'function' && global().Array === root.Array;
- /** Use a single "load" function */
+ /** Detect if Lo-Dash is in strict mode. */
+ var isStrict = ui.isStrict;
+
+ /** Used to test Web Workers. */
+ var Worker = !(ui.isForeign || ui.isSauceLabs || isModularize) && document && root.Worker;
+
+ /** Used to test host objects in IE. */
+ try {
+ var xml = new ActiveXObject('Microsoft.XMLDOM');
+ } catch(e) {}
+
+ /** Use a single "load" function. */
var load = (typeof require == 'function' && !amd)
? require
- : (isJava && root.load);
+ : (isJava ? root.load : noop);
+
+ /** The unit testing framework. */
+ var QUnit = root.QUnit || (root.QUnit = (
+ QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit,
+ QUnit = QUnit.QUnit || QUnit
+ ));
+
+ /** Load and install QUnit Extras and ES6 Set/WeakMap shims. */
+ (function() {
+ var paths = [
+ './asset/set.js',
+ './asset/weakmap.js',
+ '../node_modules/qunit-extras/qunit-extras.js'
+ ];
- /** The unit testing framework */
- var QUnit = (function() {
- return root.QUnit || (
- root.addEventListener || (root.addEventListener = noop),
- root.setTimeout || (root.setTimeout = noop),
- root.QUnit = load('../vendor/qunit/qunit/qunit.js') || root.QUnit,
- (load('../vendor/qunit-extras/qunit-extras.js') || { 'runInContext': noop }).runInContext(root),
- addEventListener === noop && delete root.addEventListener,
- root.QUnit
- );
+ var index = -1,
+ length = paths.length;
+
+ while (++index < length) {
+ var object = load(paths[index]);
+ if (object) {
+ object.runInContext(root);
+ }
+ }
}());
/*--------------------------------------------------------------------------*/
- // log params passed to `test.js`
+ // Log params provided to `test.js`.
if (params) {
console.log('test.js invoked with arguments: ' + JSON.stringify(slice.call(params)));
}
- // exit early if going to run tests in a PhantomJS web page
+ // Exit early if going to run tests in a PhantomJS web page.
if (phantom && isModularize) {
var page = require('webpage').create();
page.open(filePath, function(status) {
@@ -106,6 +180,14 @@
});
page.onCallback = function(details) {
+ var coverage = details.coverage;
+ if (coverage) {
+ var fs = require('fs'),
+ cwd = fs.workingDirectory,
+ sep = fs.separator;
+
+ fs.write([cwd, 'coverage', 'coverage.json'].join(sep), JSON.stringify(coverage));
+ }
phantom.exit(details.failed ? 1 : 0);
};
@@ -116,7 +198,10 @@
page.onInitialized = function() {
page.evaluate(function() {
document.addEventListener('DOMContentLoaded', function() {
- QUnit.done(callPhantom);
+ QUnit.done(function(details) {
+ details.coverage = window.__coverage__;
+ callPhantom(details);
+ });
});
});
};
@@ -126,34 +211,48 @@
/*--------------------------------------------------------------------------*/
- /** The `lodash` function to test */
+ /** The `lodash` function to test. */
var _ = root._ || (root._ = (
_ = load(filePath) || root._,
- _ = _._ || _,
+ _ = _._ || (isStrict = ui.isStrict = isStrict || 'default' in _, _['default']) || _,
(_.runInContext ? _.runInContext(root) : _)
));
- /** Used to pass falsey values to methods */
+ /** List of latin-1 supplementary letters to basic latin letters. */
+ var burredLetters = [
+ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce',
+ '\xcf', '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde',
+ '\xdf', '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee',
+ '\xef', '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff'
+ ];
+
+ /** List of `burredLetters` translated to basic latin letters. */
+ var deburredLetters = [
+ 'A', 'A', 'A', 'A', 'A', 'A', 'Ae', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I',
+ 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 'Th',
+ 'ss', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i',
+ 'i', 'd', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'th', 'y'
+ ];
+
+ /** Used to provide falsey values to methods. */
var falsey = [, '', 0, false, NaN, null, undefined];
- /** Used to pass empty values to methods */
+ /** Used to provide empty values to methods. */
var empties = [[], {}].concat(falsey.slice(1));
- /** Used as the size when optimizations are enabled for large arrays */
- var largeArraySize = 75;
-
- /** Used to set property descriptors */
- var defineProperty = (function() {
- try {
- var o = {},
- func = Object.defineProperty,
- result = func(o, o, o) && func;
- } catch(e) { }
- return result;
- }());
+ /** Used to test error objects. */
+ var errors = [
+ new Error,
+ new EvalError,
+ new RangeError,
+ new ReferenceError,
+ new SyntaxError,
+ new TypeError,
+ new URIError
+ ];
- /** Used to check problem JScript properties (a.k.a. the [[DontEnum]] bug) */
- var shadowedProps = [
+ /** Used to check problem JScript properties (a.k.a. the `[[DontEnum]]` bug). */
+ var shadowProps = [
'constructor',
'hasOwnProperty',
'isPrototypeOf',
@@ -163,8 +262,50 @@
'valueOf'
];
- /** Used to check problem JScript properties too */
- var shadowedObject = _.invert(shadowedProps);
+ /** Used to check problem JScript properties too. */
+ var shadowObject = _.invert(shadowProps);
+
+ /** Used to check whether methods support typed arrays. */
+ var typedArrays = [
+ 'Float32Array',
+ 'Float64Array',
+ 'Int8Array',
+ 'Int16Array',
+ 'Int32Array',
+ 'Uint8Array',
+ 'Uint8ClampedArray',
+ 'Uint16Array',
+ 'Uint32Array'
+ ];
+
+ /**
+ * Used to check for problems removing whitespace. For a whitespace reference
+ * see V8's unit test https://code.google.com/p/v8/source/browse/branches/bleeding_edge/test/mjsunit/whitespaces.js.
+ */
+ var whitespace = ' \t\x0b\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000';
+
+ /**
+ * Extracts the unwrapped value from its wrapper.
+ *
+ * @private
+ * @param {Object} wrapper The wrapper to unwrap.
+ * @returns {*} Returns the unwrapped value.
+ */
+ function getUnwrappedValue(wrapper) {
+ var index = -1,
+ actions = wrapper.__actions__,
+ length = actions.length,
+ result = wrapper.__wrapped__;
+
+ while (++index < length) {
+ var args = [result],
+ action = actions[index];
+
+ push.apply(args, action.args);
+ result = action.func.apply(action.thisArg, args);
+ }
+ return result;
+ }
/**
* Removes all own enumerable properties from a given object.
@@ -179,6 +320,31 @@
}
/**
+ * Sets a non-enumerable property value on `object`.
+ *
+ * Note: This function is used to avoid a bug in older versions of V8 where
+ * overwriting non-enumerable built-ins makes them enumerable.
+ * See https://code.google.com/p/v8/issues/detail?id=1623
+ *
+ * @private
+ * @param {Object} object The object augment.
+ * @param {string} key The name of the property to set.
+ * @param {*} value The property value.
+ */
+ function setProperty(object, key, value) {
+ try {
+ defineProperty(object, key, {
+ 'configurable': true,
+ 'enumerable': false,
+ 'writable': true,
+ 'value': value
+ });
+ } catch(e) {
+ object[key] = value;
+ }
+ }
+
+ /**
* Skips a given number of tests with a passing result.
*
* @private
@@ -193,102 +359,246 @@
/*--------------------------------------------------------------------------*/
- // add values from other realms
+ // Setup values for Node.js.
(function() {
- if (!amd) {
- try {
- emptyObject(require.cache);
-
- _.extend(_, require('vm').runInNewContext([
- '({',
- "'_arguments': (function() { return arguments; }(1, 2, 3)),",
- "'_array': [1, 2, 3],",
- "'_boolean': new Boolean(false),",
- "'_date': new Date,",
- "'_function': function() {},",
- "'_nan': NaN,",
- "'_null': null,",
- "'_number': new Number(0),",
- "'_object': { 'a': 1, 'b': 2, 'c': 3 },",
- "'_regexp': /x/,",
- "'_string': new String('a'),",
- "'_undefined': undefined,",
- '})'
- ].join('\n')));
-
- // set bad shims
- Array._isArray = Array.isArray;
- Array.isArray = function() {};
-
- Date._now = Date.now;
- Date.now = function() {};
-
- Function.prototype._bind = Function.prototype.bind;
- Function.prototype.bind = function() { return function() {}; };
-
- Object._create = Object.create;
- Object.create = function() {};
-
- Object._defineProperty = Object.defineProperty;
- Object.defineProperty = function() {};
-
- Object._getPrototypeOf = Object.getPrototypeOf;
- Object.getPrototypeOf = function() {};
-
- Object._keys = Object.keys;
- Object.keys = function() {};
-
- // load Lo-Dash and expose it to the bad shims
- lodashBadShim = (lodashBadShim = require(filePath))._ || lodashBadShim;
-
- // restore native methods
- Array.isArray = Array._isArray;
- Date.now = Date._now;
- Function.prototype.bind = Function.prototype._bind;
- Object.create = Object._create;
- Object.defineProperty = Object._defineProperty;
- Object.getPrototypeOf = Object._getPrototypeOf;
- Object.keys = Object._keys;
-
- delete Array._isArray;
- delete Date._now;
- delete Function.prototype._bind;
- delete Object._create;
- delete Object._defineProperty;
- delete Object._getPrototypeOf;
- delete Object._keys;
- } catch(e) { }
+ if (amd) {
+ return;
+ }
+ try {
+ // Add values from a different realm.
+ _.extend(_, require('vm').runInNewContext([
+ '(function() {',
+ ' var object = {',
+ " '_arguments': (function() { return arguments; }(1, 2, 3)),",
+ " '_array': [1, 2, 3],",
+ " '_boolean': Object(false),",
+ " '_date': new Date,",
+ " '_errors': [new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError],",
+ " '_function': function() {},",
+ " '_nan': NaN,",
+ " '_null': null,",
+ " '_number': Object(0),",
+ " '_object': { 'a': 1, 'b': 2, 'c': 3 },",
+ " '_regexp': /x/,",
+ " '_string': Object('a'),",
+ " '_undefined': undefined",
+ ' };',
+ '',
+ " ['" + typedArrays.join("', '") + "'].forEach(function(type) {",
+ " var Ctor = Function('return typeof ' + type + \" != 'undefined' && \" + type)()",
+ ' if (Ctor) {',
+ " object['_' + type.toLowerCase()] = new Ctor(new ArrayBuffer(24));",
+ ' }',
+ " });",
+ '',
+ ' return object;',
+ '}())'
+ ].join('\n')));
+ }
+ catch(e) {
+ if (!phantom) {
+ return;
+ }
+ }
+ var nativeString = fnToString.call(toString),
+ reToString = /toString/g;
+
+ function createToString(funcName) {
+ return _.constant(nativeString.replace(reToString, funcName));
+ }
+
+ // Expose `baseEach` for better code coverage.
+ if (isModularize && !isNpm) {
+ _.each(['baseEach', 'isIndex', 'isIterateeCall', 'isLength'], function(funcName) {
+ var path = require('path'),
+ func = require(path.join(path.dirname(filePath), 'internal', 'baseEach.js'));
+
+ _['_' + funcName] = func[funcName] || func['default'] || func;
+ });
+ }
+ // Allow bypassing native checks.
+ setProperty(funcProto, 'toString', function wrapper() {
+ setProperty(funcProto, 'toString', fnToString);
+ var result = _.has(this, 'toString') ? this.toString() : fnToString.call(this);
+ setProperty(funcProto, 'toString', wrapper);
+ return result;
+ });
+
+ // Add extensions.
+ funcProto._method = _.noop;
+
+ // Set bad shims.
+ var _isArray = Array.isArray;
+ setProperty(Array, 'isArray', _.noop);
+
+ var _now = Date.now;
+ setProperty(Date, 'now', _.noop);
+
+ var _getPrototypeOf = Object.getPrototypeOf;
+ setProperty(Object, 'getPrototypeOf', _.noop);
+
+ var _keys = Object.keys;
+ setProperty(Object, 'keys', _.noop);
+
+ var _propertyIsEnumerable = objectProto.propertyIsEnumerable;
+ setProperty(objectProto, 'propertyIsEnumerable', function(key) {
+ if (key == '1' && _.isArguments(this) && _.isEqual(_.values(this), [0, 0])) {
+ throw new Error;
+ }
+ return _.has(this, key);
+ });
+
+ var _isFinite = Number.isFinite;
+ setProperty(Number, 'isFinite', _.noop);
+
+ var _ArrayBuffer = ArrayBuffer;
+ setProperty(root, 'ArrayBuffer', (function() {
+ function ArrayBuffer(byteLength) {
+ var buffer = new _ArrayBuffer(byteLength);
+ if (!byteLength) {
+ setProperty(buffer, 'slice', buffer.slice ? null : bufferSlice);
+ }
+ return buffer;
+ }
+ function bufferSlice() {
+ var newBuffer = new _ArrayBuffer(this.byteLength),
+ view = new Uint8Array(newBuffer);
+
+ view.set(new Uint8Array(this));
+ return newBuffer;
+ }
+ setProperty(ArrayBuffer, 'toString', createToString('ArrayBuffer'));
+ setProperty(bufferSlice, 'toString', createToString('slice'));
+ return ArrayBuffer;
+ }()));
+
+ if (!root.Float64Array) {
+ setProperty(root, 'Float64Array', (function() {
+ function Float64Array(buffer, byteOffset, length) {
+ return arguments.length == 1
+ ? new Uint8Array(buffer)
+ : new Uint8Array(buffer, byteOffset || 0, length || buffer.byteLength);
+ }
+ setProperty(Float64Array, 'BYTES_PER_ELEMENT', 8);
+ setProperty(Float64Array, 'toString', createToString('Float64Array'));
+ return Float64Array;
+ }()));
+ }
+ var _parseInt = parseInt;
+ setProperty(root, 'parseInt', (function() {
+ var checkStr = whitespace + '08',
+ isFaked = _parseInt(checkStr) != 8,
+ reHexPrefix = /^0[xX]/,
+ reTrim = RegExp('^[' + whitespace + ']+|[' + whitespace + ']+$');
+
+ return function(value, radix) {
+ if (value == checkStr && !isFaked) {
+ isFaked = true;
+ return 0;
+ }
+ value = String(value == null ? '' : value).replace(reTrim, '');
+ return _parseInt(value, +radix || (reHexPrefix.test(value) ? 16 : 10));
+ };
+ }()));
+
+ var _Set = root.Set;
+ setProperty(root, 'Set', _.noop);
+
+ var _WeakMap = root.WeakMap;
+ setProperty(root, 'WeakMap', _.noop);
+
+ // Fake the DOM
+ setProperty(root, 'window', {});
+ setProperty(root.window, 'document', {});
+ setProperty(root.window.document, 'createDocumentFragment', function() {
+ return { 'nodeType': 11 };
+ });
+
+ // Fake `WinRTError`.
+ setProperty(root, 'WinRTError', Error);
+
+ // Clear cache so Lo-Dash can be reloaded.
+ emptyObject(require.cache);
+
+ // Load Lo-Dash and expose it to the bad extensions/shims.
+ lodashBizarro = (lodashBizarro = require(filePath))._ || lodashBizarro['default'] || lodashBizarro;
+
+ // Restore native methods.
+ setProperty(Array, 'isArray', _isArray);
+ setProperty(Date, 'now', _now);
+ setProperty(Object, 'getPrototypeOf', _getPrototypeOf);
+ setProperty(Object, 'keys', _keys);
+
+ setProperty(objectProto, 'propertyIsEnumerable', _propertyIsEnumerable);
+ setProperty(root, 'parseInt', _parseInt);
+
+ if (_isFinite) {
+ setProperty(Number, 'isFinite', _isFinite);
+ } else {
+ delete Number.isFinite;
+ }
+ if (_ArrayBuffer) {
+ setProperty(root, 'ArrayBuffer', _ArrayBuffer);
+ } else {
+ delete root.ArrayBuffer;
}
- if (!_._object && document) {
- var iframe = document.createElement('iframe');
- iframe.frameBorder = iframe.height = iframe.width = 0;
- body.appendChild(iframe);
-
- var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc;
- idoc.write([
- '<script>',
- 'parent._._arguments = (function() { return arguments; }(1, 2, 3));',
- 'parent._._array = [1, 2, 3];',
- 'parent._._boolean = new Boolean(false);',
- 'parent._._date = new Date;',
- "parent._._element = document.createElement('div');",
- 'parent._._function = function() {};',
- 'parent._._nan = NaN;',
- 'parent._._null = null;',
- 'parent._._number = new Number(0);',
- "parent._._object = { 'a': 1, 'b': 2, 'c': 3 };",
- 'parent._._regexp = /x/;',
- "parent._._string = new String('a');",
- 'parent._._undefined = undefined;',
- '<\/script>'
- ].join('\n'));
- idoc.close();
+ if (_Set) {
+ setProperty(root, 'Set', Set);
+ } else {
+ delete root.Set;
}
+ if (_WeakMap) {
+ setProperty(root, 'WeakMap', WeakMap);
+ } else {
+ delete root.WeakMap;
+ }
+ delete root.WinRTError;
+ delete root.window;
+ delete funcProto._method;
+ }());
+
+ // Add values from an iframe.
+ (function() {
+ if (_._object || !document) {
+ return;
+ }
+ var iframe = document.createElement('iframe');
+ iframe.frameBorder = iframe.height = iframe.width = 0;
+ body.appendChild(iframe);
+
+ var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc;
+ idoc.write([
+ '<script>',
+ 'parent._._arguments = (function() { return arguments; }(1, 2, 3));',
+ 'parent._._array = [1, 2, 3];',
+ 'parent._._boolean = Object(false);',
+ 'parent._._date = new Date;',
+ "parent._._element = document.createElement('div');",
+ 'parent._._errors = [new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError];',
+ 'parent._._function = function() {};',
+ 'parent._._nan = NaN;',
+ 'parent._._null = null;',
+ 'parent._._number = Object(0);',
+ "parent._._object = { 'a': 1, 'b': 2, 'c': 3 };",
+ 'parent._._regexp = /x/;',
+ "parent._._string = Object('a');",
+ 'parent._._undefined = undefined;',
+ '',
+ 'var root = this;',
+ "parent._.each(['" + typedArrays.join("', '") + "'], function(type) {",
+ ' var Ctor = root[type];',
+ ' if (Ctor) {',
+ " parent._['_' + type.toLowerCase()] = new Ctor(new ArrayBuffer(24));",
+ ' }',
+ '});',
+ '<\/script>'
+ ].join('\n'));
+ idoc.close();
}());
- // add web worker
+ // Add a web worker.
(function() {
- if (!Worker || isModularize) {
+ if (!Worker) {
return;
}
var worker = new Worker('./asset/worker.js?t=' + (+new Date));
@@ -301,38 +611,40 @@
/*--------------------------------------------------------------------------*/
- // explicitly call `QUnit.module()` instead of `module()`
- // in case we are in a CLI environment
+ // Explicitly call `QUnit.module()` instead of `module()` in case we are
+ // in a CLI environment.
QUnit.module(basename);
(function() {
test('supports loading ' + basename + ' as the "lodash" module', 1, function() {
if (amd) {
- equal((lodashModule || {}).moduleName, 'lodash');
- } else {
+ strictEqual((lodashModule || {}).moduleName, 'lodash');
+ }
+ else {
skipTest();
}
});
test('supports loading ' + basename + ' with the Require.js "shim" configuration option', 1, function() {
- if (amd && /requirejs/.test(ui.loaderPath)) {
- equal((shimmedModule || {}).moduleName, 'shimmed');
+ if (amd && _.includes(ui.loaderPath, 'requirejs')) {
+ strictEqual((shimmedModule || {}).moduleName, 'shimmed');
} else {
skipTest();
}
});
test('supports loading ' + basename + ' as the "underscore" module', 1, function() {
- if (amd && !/dojo/.test(ui.loaderPath)) {
- equal((underscoreModule || {}).moduleName, 'underscore');
- } else {
+ if (amd) {
+ strictEqual((underscoreModule || {}).moduleName, 'underscore');
+ }
+ else {
skipTest();
}
});
asyncTest('supports loading ' + basename + ' in a web worker', 1, function() {
- if (Worker && !isModularize) {
- var limit = 15000,
+ if (Worker) {
+ var limit = 30000 / QUnit.config.asyncRetries,
start = +new Date;
var attempt = function() {
@@ -341,7 +653,7 @@
setTimeout(attempt, 16);
return;
}
- equal(actual, _.VERSION);
+ strictEqual(actual, _.VERSION);
QUnit.start();
};
@@ -353,60 +665,110 @@
}
});
- test('avoids overwritten native methods', 7, function() {
+ test('should not add `Function.prototype` extensions to lodash', 1, function() {
+ if (lodashBizarro) {
+ ok(!('_method' in lodashBizarro));
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ test('should avoid overwritten native methods', 12, function() {
function Foo() {}
- function message(methodName) {
- return '`_.' + methodName + '` should avoid overwritten native methods';
+ function message(lodashMethod, nativeMethod) {
+ return '`' + lodashMethod + '` should avoid overwritten native `' + nativeMethod + '`';
}
- var object = { 'a': true };
- if (lodashBadShim) {
+ var object = { 'a': 1 },
+ otherObject = { 'b': 2 },
+ largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(object));
+
+ if (lodashBizarro) {
+ try {
+ var actual = [lodashBizarro.isArray([]), lodashBizarro.isArray({ 'length': 0 })];
+ } catch(e) {
+ actual = null;
+ }
+ deepEqual(actual, [true, false], message('_.isArray', 'Array.isArray'));
+
try {
- actual = [lodashBadShim.isArray([]), lodashBadShim.isArray({ 'length': 0 })];
+ actual = lodashBizarro.now();
} catch(e) {
actual = null;
}
- deepEqual(actual, [true, false], message('Array.isArray'));
+ ok(typeof actual == 'number', message('_.now', 'Date.now'));
try {
- actual = lodashBadShim.now();
+ actual = [lodashBizarro.isPlainObject({}), lodashBizarro.isPlainObject([])];
} catch(e) {
actual = null;
}
- ok(typeof actual == 'number', message('Date.now'));
+ deepEqual(actual, [true, false], message('_.isPlainObject', 'Object.getPrototypeOf'));
try {
- actual = [lodashBadShim.create(Foo.prototype, object), lodashBadShim.create()];
+ actual = [lodashBizarro.keys(object), lodashBizarro.keys()];
} catch(e) {
actual = null;
}
- ok(actual[0] instanceof Foo, message('Object.create'));
- deepEqual(actual[1], {}, message('Object.create'));
+ deepEqual(actual, [['a'], []], message('_.keys', 'Object.keys'));
try {
- var actual = lodashBadShim.bind(function() { return this.a; }, object)();
+ actual = [lodashBizarro.isFinite(1), lodashBizarro.isFinite(NaN)];
} catch(e) {
actual = null;
}
- ok(actual, message('Object.defineProperty'));
+ deepEqual(actual, [true, false], message('_.isFinite', 'Number.isFinite'));
try {
- actual = [lodashBadShim.isPlainObject({}), lodashBadShim.isPlainObject([])];
+ actual = [
+ lodashBizarro.difference([object, otherObject], largeArray),
+ lodashBizarro.intersection(largeArray, [object]),
+ lodashBizarro.uniq(largeArray)
+ ];
} catch(e) {
actual = null;
}
- deepEqual(actual, [true, false], message('Object.getPrototypeOf'));
+ deepEqual(actual, [[otherObject], [object], [object]], message('_.difference`, `_.intersection`, and `_.uniq', 'Set'));
try {
- actual = [lodashBadShim.keys(object), lodashBadShim.keys()];
+ actual = _.map(['6', '08', '10'], lodashBizarro.parseInt);
} catch(e) {
actual = null;
}
- deepEqual(actual, [['a'], []], message('Object.keys'));
+ deepEqual(actual, [6, 8, 10], '`_.parseInt` should work in its bizarro form');
+
+ if (ArrayBuffer) {
+ try {
+ var buffer = new ArrayBuffer(10);
+ actual = lodashBizarro.clone(buffer);
+ } catch(e) {
+ actual = null;
+ }
+ deepEqual(actual, buffer, message('_.clone', 'ArrayBuffer#slice'));
+ notStrictEqual(actual, buffer, message('_.clone', 'ArrayBuffer#slice'));
+ }
+ else {
+ skipTest(2);
+ }
+ if (ArrayBuffer && Uint8Array) {
+ try {
+ var array = new Uint8Array(new ArrayBuffer(10));
+ actual = lodashBizarro.cloneDeep(array);
+ } catch(e) {
+ actual = null;
+ }
+ deepEqual(actual, array, message('_.cloneDeep', 'Float64Array'));
+ notStrictEqual(actual && actual.buffer, array.buffer, message('_.cloneDeep', 'Float64Array'));
+ notStrictEqual(actual, array, message('_.cloneDeep', 'Float64Array'));
+ }
+ else {
+ skipTest(3);
+ }
}
else {
- skipTest(7);
+ skipTest(12);
}
});
}());
@@ -416,13 +778,51 @@
QUnit.module('lodash constructor');
(function() {
+ var values = empties.concat(true, 1, 'a'),
+ expected = _.map(values, _.constant(true));
+
test('creates a new instance when called without the `new` operator', 1, function() {
- ok(_() instanceof _);
+ if (!isNpm) {
+ var actual = _.map(values, function(value) {
+ return _(value) instanceof _;
+ });
+
+ deepEqual(actual, expected);
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ test('should return provided `lodash` instances', 1, function() {
+ if (!isNpm) {
+ var actual = _.map(values, function(value) {
+ var wrapped = _(value);
+ return _(wrapped) === wrapped;
+ });
+
+ deepEqual(actual, expected);
+ }
+ else {
+ skipTest();
+ }
});
- test('should return provided `lodash` instances', 1,function() {
- var wrapped = _(false);
- equal(_(wrapped), wrapped);
+ test('should convert foreign wrapped values to `lodash` instances', 1, function() {
+ if (!isNpm && lodashBizarro) {
+ var actual = _.map(values, function(value) {
+ var wrapped = _(lodashBizarro(value)),
+ unwrapped = wrapped.value();
+
+ return wrapped instanceof _ &&
+ (unwrapped === value || (_.isNaN(unwrapped) && _.isNaN(value)));
+ });
+
+ deepEqual(actual, expected);
+ }
+ else {
+ skipTest();
+ }
});
}());
@@ -431,37 +831,108 @@
QUnit.module('lodash.after');
(function() {
- test('should create a function that executes `func` after `n` calls', 4, function() {
- function after(n, times) {
- var count = 0;
- _.times(times, _.after(n, function() { count++; }));
- return count;
- }
+ function after(n, times) {
+ var count = 0;
+ _.times(times, _.after(n, function() { count++; }));
+ return count;
+ }
+ test('should create a function that invokes `func` after `n` calls', 4, function() {
+ strictEqual(after(5, 5), 1, 'after(n) should invoke `func` after being called `n` times');
+ strictEqual(after(5, 4), 0, 'after(n) should not invoke `func` before being called `n` times');
+ strictEqual(after(0, 0), 0, 'after(0) should not invoke `func` immediately');
+ strictEqual(after(0, 1), 1, 'after(0) should invoke `func` when called once');
+ });
+
+ test('should coerce non-finite `n` values to `0`', 1, function() {
+ var values = [-Infinity, NaN, Infinity],
+ expected = _.map(values, _.constant(1));
+
+ var actual = _.map(values, function(n) {
+ return after(n, 1);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should allow `func` as the first argument', 1, function() {
+ var count = 0;
+
+ try {
+ var after = _.after(function() { count++; }, 1);
+ after();
+ after();
+ } catch(e) {}
+
+ strictEqual(count, 2);
+ });
+
+ test('should not set a `this` binding', 2, function() {
+ var after = _.after(1, function() { return ++this.count; }),
+ object = { 'count': 0, 'after': after };
- strictEqual(after(5, 5), 1, 'after(n) should execute `func` after being called `n` times');
- strictEqual(after(5, 4), 0, 'after(n) should not execute `func` unless called `n` times');
- strictEqual(after(0, 0), 0, 'after(0) should not execute `func` immediately');
- strictEqual(after(0, 1), 1, 'after(0) should execute `func` when called once');
+ object.after();
+ strictEqual(object.after(), 2);
+ strictEqual(object.count, 2);
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.assign');
+ QUnit.module('lodash.ary');
(function() {
- test('should assign properties of a source object to the destination object', 1, function() {
- deepEqual(_.assign({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 });
+ function fn(a, b, c) {
+ return slice.call(arguments);
+ }
+
+ test('should cap the numer of params provided to `func`', 2, function() {
+ var actual = _.map(['6', '8', '10'], _.ary(parseInt, 1));
+ deepEqual(actual, [6, 8, 10]);
+
+ var capped = _.ary(fn, 2);
+ deepEqual(capped('a', 'b', 'c', 'd'), ['a', 'b']);
});
- test('should assign own source properties', 1, function() {
- function Foo() {
- this.a = 1;
- this.c = 3;
+ test('should use `func.length` if `n` is not provided', 1, function() {
+ var capped = _.ary(fn);
+ deepEqual(capped('a', 'b', 'c', 'd'), ['a', 'b', 'c']);
+ });
+
+ test('should work when provided less than the capped numer of arguments', 1, function() {
+ var capped = _.ary(fn, 3);
+ deepEqual(capped('a'), ['a']);
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var funcs = _.map([fn], _.ary),
+ actual = funcs[0]('a', 'b', 'c');
+
+ deepEqual(actual, ['a', 'b', 'c']);
+ });
+
+ test('should work when combined with other methods that use metadata', 2, function() {
+ var array = ['a', 'b', 'c'],
+ includes = _.curry(_.rearg(_.ary(_.includes, 2), 1, 0), 2);
+
+ strictEqual(includes('b')(array, 2), true);
+
+ if (!isNpm) {
+ includes = _(_.includes).ary(2).rearg(1, 0).curry(2).value();
+ strictEqual(includes('b')(array, 2), true);
+ }
+ else {
+ skipTest();
}
+ });
+ }());
- Foo.prototype.b = 2;
- deepEqual(_.assign({}, new Foo), { 'a': 1, 'c': 3 });
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.assign');
+
+ (function() {
+ test('should assign properties of a source object to the destination object', 1, function() {
+ deepEqual(_.assign({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 });
});
test('should accept multiple source objects', 2, function() {
@@ -470,7 +941,7 @@
deepEqual(_.assign({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected);
});
- test('should overwrite source properties', 1, function() {
+ test('should overwrite destination properties', 1, function() {
var expected = { 'a': 3, 'b': 2, 'c': 1 };
deepEqual(_.assign({ 'a': 1, 'b': 2 }, expected), expected);
});
@@ -480,15 +951,7 @@
deepEqual(_.assign({ 'a': 1, 'b': 2 }, expected), expected);
});
- test('should not error on `null` or `undefined` sources (test in IE < 9)', 1, function() {
- try {
- deepEqual(_.assign({}, null, undefined, { 'a': 1 }), { 'a': 1 });
- } catch(e) {
- ok(false);
- }
- });
-
- test('should work with a `callback`', 1, function() {
+ test('should work with a `customizer` callback', 1, function() {
var actual = _.assign({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) {
return typeof a == 'undefined' ? b : a;
});
@@ -496,22 +959,9 @@
deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
});
- test('should pass the correct `callback` arguments', 1, function() {
- var args;
-
- _.assign({ 'a': 1 }, { 'b': 2 }, function() {
- args || (args = slice.call(arguments));
- });
-
- deepEqual(args, [undefined, 2]);
- });
-
- test('should support the `thisArg` argument', 1, function() {
- var actual = _.assign({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) {
- return typeof this[a] == 'undefined' ? this[b] : this[a];
- }, { '1': 1, '2': 2, '3': 3 });
-
- deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
+ test('should work with a `customizer` that returns `undefined`', 1, function() {
+ var expected = { 'a': undefined };
+ deepEqual(_.assign({}, expected, _.identity), expected);
});
test('should be aliased', 1, function() {
@@ -524,64 +974,201 @@
QUnit.module('lodash.at');
(function() {
- var args = arguments;
+ var args = arguments,
+ array = ['a', 'b', 'c'];
- test('should return `undefined` for nonexistent keys', 1, function() {
- var actual = _.at(['a', 'b', 'c'], [0, 2, 4]);
- deepEqual(actual, ['a', 'c', undefined]);
- });
+ array['1.1'] = array['-1'] = 1;
- test('should return an empty array when no keys are provided', 1, function() {
- deepEqual(_.at(['a', 'b', 'c']), []);
+ test('should return the elements corresponding to the specified keys', 1, function() {
+ var actual = _.at(array, [0, 2]);
+ deepEqual(actual, ['a', 'c']);
});
- test('should accept multiple key arguments', 1, function() {
- var actual = _.at(['a', 'b', 'c', 'd'], 0, 2, 3);
- deepEqual(actual, ['a', 'c', 'd']);
+ test('should return `undefined` for nonexistent keys', 1, function() {
+ var actual = _.at(array, [2, 4, 0]);
+ deepEqual(actual, ['c', undefined, 'a']);
});
- test('should work with an `arguments` object for `collection`', 1, function() {
- var actual = _.at(args, [0, 2]);
- deepEqual(actual, ['a', 'c']);
+ test('should use `undefined` for non-index keys on array-like values', 1, function() {
+ var values = _.reject(empties, function(value) {
+ return value === 0 || _.isArray(value);
+ }).concat(-1, 1.1);
+
+ var expected = _.map(values, _.constant(undefined)),
+ actual = _.at(array, values);
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return an empty array when no keys are provided', 2, function() {
+ deepEqual(_.at(array), []);
+ deepEqual(_.at(array, [], []), []);
+ });
+
+ test('should accept multiple key arguments', 1, function() {
+ var actual = _.at(['a', 'b', 'c', 'd'], 3, 0, 2);
+ deepEqual(actual, ['d', 'a', 'c']);
+ });
+
+ test('should work with a falsey `collection` argument when keys are provided', 1, function() {
+ var expected = _.map(falsey, _.constant([undefined, undefined]));
+
+ var actual = _.map(falsey, function(value) {
+ try {
+ return _.at(value, 0, 1);
+ } catch(e) {}
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should work with an `arguments` object for `collection`', 1, function() {
+ var actual = _.at(args, [2, 0]);
+ deepEqual(actual, [3, 1]);
+ });
+
+ test('should work with `arguments` object as secondary arguments', 1, function() {
+ var actual = _.at([1, 2, 3, 4, 5], args);
+ deepEqual(actual, [2, 3, 4]);
});
test('should work with an object for `collection`', 1, function() {
- var actual = _.at({ 'a': 1, 'b': 2, 'c': 3 }, ['a', 'c']);
- deepEqual(actual, [1, 3]);
+ var actual = _.at({ 'a': 1, 'b': 2, 'c': 3 }, ['c', 'a']);
+ deepEqual(actual, [3, 1]);
});
- test('should work when used as `callback` for `_.map`', 1, function() {
- var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
- actual = _.map(array, _.at);
+ test('should pluck inherited property values', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
- deepEqual(actual, [[1], [5], [9]]);
+ var actual = _.at(new Foo, 'b');
+ deepEqual(actual, [2]);
});
- _.forEach({
+ _.each({
'literal': 'abc',
'object': Object('abc')
},
function(collection, key) {
test('should work with a string ' + key + ' for `collection`', 1, function() {
- deepEqual(_.at(collection, [0, 2]), ['a', 'c']);
+ deepEqual(_.at(collection, [2, 0]), ['c', 'a']);
+ });
+ });
+ }(1, 2, 3));
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.attempt');
+
+ (function() {
+ test('should return the result of `func`', 1, function() {
+ strictEqual(_.attempt(_.constant('x')), 'x');
+ });
+
+ test('should return the caught error', 1, function() {
+ var expected = _.map(errors, _.constant(true));
+
+ var actual = _.map(errors, function(error) {
+ return _.attempt(function() { throw error; }) === error;
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should coerce errors to error objects', 1, function() {
+ var actual = _.attempt(function() { throw 'x'; });
+ ok(_.isEqual(actual, Error('x')));
+ });
+
+ test('should work with an error object from another realm', 1, function() {
+ if (_._object) {
+ var expected = _.map(_._errors, _.constant(true));
+
+ var actual = _.map(_._errors, function(error) {
+ return _.attempt(function() { throw error; }) === error;
+ });
+
+ deepEqual(actual, expected);
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ test('should return an unwrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ strictEqual(_(_.constant('x')).attempt(), 'x');
+ }
+ else {
+ skipTest();
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.before');
+
+ (function() {
+ function before(n, times) {
+ var count = 0;
+ _.times(times, _.before(n, function() { count++; }));
+ return count;
+ }
+ test('should create a function that invokes `func` after `n` calls', 4, function() {
+ strictEqual(before(5, 4), 4, 'before(n) should invoke `func` before being called `n` times');
+ strictEqual(before(5, 6), 4, 'before(n) should not invoke `func` after being called `n - 1` times');
+ strictEqual(before(0, 0), 0, 'before(0) should not invoke `func` immediately');
+ strictEqual(before(0, 1), 0, 'before(0) should not invoke `func` when called');
+ });
+
+ test('should coerce non-finite `n` values to `0`', 1, function() {
+ var values = [-Infinity, NaN, Infinity],
+ expected = _.map(values, _.constant(0));
+
+ var actual = _.map(values, function(n) {
+ return before(n);
});
+
+ deepEqual(actual, expected);
+ });
+
+ test('should allow `func` as the first argument', 1, function() {
+ var count = 0;
+
+ try {
+ var before = _.before(function() { count++; }, 2);
+ before();
+ before();
+ } catch(e) {}
+
+ strictEqual(count, 1);
+ });
+
+ test('should not set a `this` binding', 2, function() {
+ var before = _.before(2, function() { return ++this.count; }),
+ object = { 'count': 0, 'before': before };
+
+ object.before();
+ strictEqual(object.before(), 1);
+ strictEqual(object.count, 1);
});
- }('a', 'b', 'c'));
+ }());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.bind');
(function() {
- function func() {
- var args = [this];
- push.apply(args, arguments);
- return args;
+ function fn() {
+ var result = [this];
+ push.apply(result, arguments);
+ return result;
}
test('should bind a function to an object', 1, function() {
var object = {},
- bound = _.bind(func, object);
+ bound = _.bind(fn, object);
deepEqual(bound('a'), [object, 'a']);
});
@@ -590,11 +1177,11 @@
var values = _.reject(falsey.slice(1), function(value) { return value == null; }),
expected = _.map(values, function(value) { return [value]; });
- var actual = _.map(values, function(value, index) {
+ var actual = _.map(values, function(value) {
try {
- var bound = _.bind(func, value);
+ var bound = _.bind(fn, value);
return bound();
- } catch(e) { }
+ } catch(e) {}
});
ok(_.every(actual, function(value, index) {
@@ -602,38 +1189,54 @@
}));
});
- test('should bind a function to `null` or `undefined`', 4, function() {
- var bound = _.bind(func, null),
+ test('should bind a function to `null` or `undefined`', 6, function() {
+ var bound = _.bind(fn, null),
actual = bound('a');
ok(actual[0] === null || actual[0] && actual[0].Array);
- equal(actual[1], 'a');
+ strictEqual(actual[1], 'a');
- bound = _.bind(func, undefined);
- actual = bound('b');
+ _.times(2, function(index) {
+ bound = index ? _.bind(fn, undefined) : _.bind(fn);
+ actual = bound('b');
- ok(actual[0] === undefined || actual[0] && actual[0].Array);
- equal(actual[1], 'b');
+ ok(actual[0] === undefined || actual[0] && actual[0].Array);
+ strictEqual(actual[1], 'b');
+ });
});
test('should partially apply arguments ', 4, function() {
var object = {},
- bound = _.bind(func, object, 'a');
+ bound = _.bind(fn, object, 'a');
deepEqual(bound(), [object, 'a']);
- bound = _.bind(func, object, 'a');
+ bound = _.bind(fn, object, 'a');
deepEqual(bound('b'), [object, 'a', 'b']);
- bound = _.bind(func, object, 'a', 'b');
+ bound = _.bind(fn, object, 'a', 'b');
deepEqual(bound(), [object, 'a', 'b']);
deepEqual(bound('c', 'd'), [object, 'a', 'b', 'c', 'd']);
});
- test('bound functions should have a `length` of `0`', 1, function() {
- var func = function(a, b, c) {},
- bound = _.bind(func, {});
+ test('should support placeholders', 4, function() {
+ var object = {},
+ ph = _.bind.placeholder,
+ bound = _.bind(fn, object, ph, 'b', ph);
+
+ deepEqual(bound('a', 'c'), [object, 'a', 'b', 'c']);
+ deepEqual(bound('a'), [object, 'a', 'b', undefined]);
+ deepEqual(bound('a', 'c', 'd'), [object, 'a', 'b', 'c', 'd']);
+ deepEqual(bound(), [object, undefined, 'b', undefined]);
+ });
+
+ test('should create a function with a `length` of `0`', 2, function() {
+ var fn = function(a, b, c) {},
+ bound = _.bind(fn, {});
+
+ strictEqual(bound.length, 0);
+ bound = _.bind(fn, {}, 1);
strictEqual(bound.length, 0);
});
@@ -641,6 +1244,7 @@
function Foo() {
return this;
}
+
var bound = _.bind(Foo, { 'a': 1 }),
newBound = new bound;
@@ -653,6 +1257,7 @@
function Foo(value) {
return value && object;
}
+
var bound = _.bind(Foo),
object = {};
@@ -662,19 +1267,15 @@
test('should append array arguments to partially applied arguments (test in IE < 9)', 1, function() {
var object = {},
- bound = _.bind(func, object, 'a');
+ bound = _.bind(fn, object, 'a');
deepEqual(bound(['b'], 'c'), [object, 'a', ['b'], 'c']);
});
- test('should throw a TypeError if `func` is not a function', 1, function() {
- raises(function() { _.bind(); }, TypeError);
- });
-
test('should return a wrapped value when chaining', 2, function() {
if (!isNpm) {
var object = {},
- bound = _(func).bind({}, 'a', 'b');
+ bound = _(fn).bind({}, 'a', 'b');
ok(bound instanceof _);
@@ -691,7 +1292,7 @@
object2 = {},
object3 = {};
- var bound1 = _.bind(func, object1),
+ var bound1 = _.bind(fn, object1),
bound2 = _.bind(bound1, object2, 'a'),
bound3 = _.bind(bound1, object3, 'b');
@@ -713,14 +1314,13 @@
this._a = 1;
this._b = 2;
this.a = function() { return this._a; };
- };
-
+ }
Foo.prototype.b = function() { return this._b; };
var object = new Foo;
_.bindAll(object);
- var actual = _.map(_.functions(object), function(methodName) {
+ var actual = _.map(_.functions(object).sort(), function(methodName) {
return object[methodName].call({});
});
@@ -739,7 +1339,7 @@
_.bindAll(object, 'a', 'b');
- var actual = _.map(_.functions(object), function(methodName) {
+ var actual = _.map(_.functions(object).sort(), function(methodName) {
return object[methodName].call({});
});
@@ -760,7 +1360,7 @@
_.bindAll(object, ['a', 'b'], ['c']);
- var actual = _.map(_.functions(object), function(methodName) {
+ var actual = _.map(_.functions(object).sort(), function(methodName) {
return object[methodName].call({});
});
@@ -770,7 +1370,7 @@
test('should work with an array `object` argument', 1, function() {
var array = ['push', 'pop'];
_.bindAll(array);
- strictEqual(array.pop, Array.prototype.pop);
+ strictEqual(array.pop, arrayProto.pop);
});
test('should work with `arguments` objects as secondary arguments', 1, function() {
@@ -781,7 +1381,7 @@
_.bindAll(object, args);
- var actual = _.map(_.functions(object), function(methodName) {
+ var actual = _.map(_.functions(object).sort(), function(methodName) {
return object[methodName].call({});
});
@@ -796,22 +1396,151 @@
(function() {
test('should work when the target function is overwritten', 2, function() {
var object = {
- 'name': 'fred',
+ 'user': 'fred',
'greet': function(greeting) {
- return greeting + ' ' + this.name;
+ return this.user + ' says: ' + greeting;
}
};
- var func = _.bindKey(object, 'greet', 'hi');
- equal(func(), 'hi fred');
+ var bound = _.bindKey(object, 'greet', 'hi');
+ strictEqual(bound(), 'fred says: hi');
object.greet = function(greeting) {
- return greeting + ' ' + this.name + '!';
+ return this.user + ' says: ' + greeting + '!';
+ };
+
+ strictEqual(bound(), 'fred says: hi!');
+ });
+
+ test('should support placeholders', 4, function() {
+ var object = {
+ 'fn': function() {
+ return slice.call(arguments);
+ }
};
- equal(func(), 'hi fred!');
+
+ var ph = _.bindKey.placeholder,
+ bound = _.bindKey(object, 'fn', ph, 'b', ph);
+
+ deepEqual(bound('a', 'c'), ['a', 'b', 'c']);
+ deepEqual(bound('a'), ['a', 'b', undefined]);
+ deepEqual(bound('a', 'c', 'd'), ['a', 'b', 'c', 'd']);
+ deepEqual(bound(), [undefined, 'b', undefined]);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('case methods');
+
+ _.each(['camel', 'kebab', 'snake'], function(caseName) {
+ var methodName = caseName + 'Case',
+ func = _[methodName];
+
+ var strings = [
+ 'foo bar', 'Foo bar', 'foo Bar', 'Foo Bar',
+ 'FOO BAR', 'fooBar', '--foo-bar', '__foo_bar__'
+ ];
+
+ var expected = (function() {
+ switch (caseName) {
+ case 'camel': return 'fooBar';
+ case 'kebab': return 'foo-bar';
+ case 'snake': return 'foo_bar';
+ }
+ }());
+
+ test('`_.' + methodName + '` should convert `string` to ' + caseName + ' case', 1, function() {
+ var actual = _.map(strings, function(string) {
+ return func(string) === expected;
+ });
+
+ deepEqual(actual, _.map(strings, _.constant(true)));
+ });
+
+ test('`_.' + methodName + '` should handle double-converting strings', 1, function() {
+ var actual = _.map(strings, function(string) {
+ return func(func(string)) === expected;
+ });
+
+ deepEqual(actual, _.map(strings, _.constant(true)));
+ });
+
+ test('`_.' + methodName + '` should deburr letters', 1, function() {
+ var actual = _.map(burredLetters, function(burred, index) {
+ return func(burred) === deburredLetters[index].toLowerCase();
+ });
+
+ deepEqual(actual, _.map(burredLetters, _.constant(true)));
+ });
+
+ test('should trim latin-1 mathematical operators', 1, function() {
+ var actual = _.map(['\xd7', '\xf7'], func);
+ deepEqual(actual, ['', '']);
+ });
+
+ test('`_.' + methodName + '` should coerce `string` to a string', 2, function() {
+ var string = 'Foo Bar';
+ strictEqual(func(Object(string)), expected);
+ strictEqual(func({ 'toString': _.constant(string) }), expected);
+ });
+
+ test('`_.' + methodName + '` should return an unwrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ strictEqual(_('foo bar')[methodName](), expected);
+ }
+ else {
+ skipTest();
+ }
+ });
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.camelCase');
+
+ (function() {
+ test('should work with numbers', 3, function() {
+ strictEqual(_.camelCase('too legit 2 quit'), 'tooLegit2Quit');
+ strictEqual(_.camelCase('walk 500 miles'), 'walk500Miles');
+ strictEqual(_.camelCase('xhr2 request'), 'xhr2Request');
+ });
+
+ test('should handle acronyms', 6, function() {
+ _.each(['safe HTML', 'safeHTML'], function(string) {
+ strictEqual(_.camelCase(string), 'safeHtml');
+ });
+
+ _.each(['escape HTML entities', 'escapeHTMLEntities'], function(string) {
+ strictEqual(_.camelCase(string), 'escapeHtmlEntities');
+ });
+
+ _.each(['XMLHttpRequest', 'XmlHTTPRequest'], function(string) {
+ strictEqual(_.camelCase(string), 'xmlHttpRequest');
+ });
});
}());
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.capitalize');
+
+ (function() {
+ test('should capitalize the first character of a string', 3, function() {
+ strictEqual(_.capitalize('fred'), 'Fred');
+ strictEqual(_.capitalize('Fred'), 'Fred');
+ strictEqual(_.capitalize(' fred'), ' fred');
+ });
+
+ test('should return an unwrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ strictEqual(_('fred').capitalize(), 'Fred');
+ }
+ else {
+ skipTest();
+ }
+ });
+ }());
/*--------------------------------------------------------------------------*/
@@ -828,13 +1557,14 @@
}
});
- test('should return the existing wrapper when chaining', 1, function() {
+ test('should return existing wrapped values', 2, function() {
if (!isNpm) {
- var wrapper = _({ 'a': 0 });
- equal(wrapper.chain(), wrapper);
+ var wrapped = _({ 'a': 0 });
+ strictEqual(_.chain(wrapped), wrapped);
+ strictEqual(wrapped.chain(), wrapped);
}
else {
- skipTest();
+ skipTest(2);
}
});
@@ -861,9 +1591,9 @@
_.times(2, function(index) {
var array = ['one two three four', 'five six seven eight', 'nine ten eleven twelve'],
expected = { ' ': 9, 'e': 14, 'f': 2, 'g': 1, 'h': 2, 'i': 4, 'l': 2, 'n': 6, 'o': 3, 'r': 2, 's': 2, 't': 5, 'u': 1, 'v': 4, 'w': 2, 'x': 1 },
- wrapper = index ? _(array).chain() : _.chain(array);
+ wrapped = index ? _(array).chain() : _.chain(array);
- var actual = wrapper
+ var actual = wrapped
.chain()
.map(function(value) { return value.split(''); })
.flatten()
@@ -877,8 +1607,8 @@
deepEqual(actual, expected);
array = [1, 2, 3, 4, 5, 6];
- wrapper = index ? _(array).chain() : _.chain(array);
- actual = wrapper
+ wrapped = index ? _(array).chain() : _.chain(array);
+ actual = wrapped
.chain()
.filter(function(n) { return n % 2; })
.reject(function(n) { return n % 3 == 0; })
@@ -888,8 +1618,8 @@
deepEqual(actual, [5, 1]);
array = [3, 4];
- wrapper = index ? _(array).chain() : _.chain(array);
- actual = wrapper
+ wrapped = index ? _(array).chain() : _.chain(array);
+ actual = wrapped
.reverse()
.concat([2, 1])
.unshift(5)
@@ -908,106 +1638,204 @@
/*--------------------------------------------------------------------------*/
- QUnit.module('cloning');
+ QUnit.module('lodash.chunk');
+
+ (function() {
+ var array = [0, 1, 2, 3, 4, 5];
+
+ test('should return chunked arrays', 1, function() {
+ var actual = _.chunk(array, 3);
+ deepEqual(actual, [[0, 1, 2], [3, 4, 5]]);
+ });
+
+ test('should return the last chunk as remaining elements', 1, function() {
+ var actual = _.chunk(array, 4);
+ deepEqual(actual, [[0, 1, 2, 3], [4, 5]]);
+ });
+
+ test('should ensure the minimum `chunkSize` is `1`', 1, function() {
+ var values = falsey.concat(-1, -Infinity),
+ expected = _.map(values, _.constant([[0], [1], [2], [3], [4], [5]]));
+
+ var actual = _.map(values, function(value, index) {
+ return index ? _.chunk(array, value) : _.chunk(array);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var actual = _.map([[1, 2], [3, 4]], _.chunk);
+ deepEqual(actual, [[[1], [2]], [[3], [4]]]);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('clone methods');
(function() {
function Klass() { this.a = 1; }
Klass.prototype = { 'b': 1 };
+ Klass.foo = function() {};
- var nonCloneable = {
- 'an element': body,
- 'a function': Klass
+ var objects = {
+ '`arguments` objects': arguments,
+ 'arrays': ['a', ''],
+ 'array-like-objects': { '0': 'a', '1': '', 'length': 3 },
+ 'booleans': false,
+ 'boolean objects': Object(false),
+ 'Klass instances': new Klass,
+ 'objects': { 'a': 0, 'b': 1, 'c': 3 },
+ 'objects with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } },
+ 'objects from another document': _._object || {},
+ 'null values': null,
+ 'numbers': 3,
+ 'number objects': Object(3),
+ 'regexes': /a/gim,
+ 'strings': 'a',
+ 'string objects': Object('a'),
+ 'undefined values': undefined
};
- var objects = {
- 'an `arguments` object': arguments,
- 'an array': ['a', 'b', 'c', ''],
- 'an array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 },
- 'boolean': false,
- 'boolean object': Object(false),
- 'a Klass instance': new Klass,
- 'an object': { 'a': 0, 'b': 1, 'c': 3 },
- 'an object with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } },
- 'an object from another document': _._object || {},
- 'null': null,
- 'a number': 3,
- 'a number object': Object(3),
- 'a regexp': /a/gim,
- 'a string': 'a',
- 'a string object': Object('a'),
- 'undefined': undefined
+ objects['arrays'].length = 3;
+
+ var uncloneable = {
+ 'DOM elements': body,
+ 'functions': Klass
};
- objects['an array'].length = 5;
+ _.each(errors, function(error) {
+ uncloneable[error.name + 's'] = error;
+ });
- test('`_.clone` should shallow clone by default', 2, function() {
+ test('`_.clone` should perform a shallow clone', 2, function() {
var expected = [{ 'a': 0 }, { 'b': 1 }],
actual = _.clone(expected);
deepEqual(actual, expected);
- ok(actual != expected && actual[0] === expected[0]);
+ ok(actual !== expected && actual[0] === expected[0]);
});
- test('`_.clone` should perform a shallow clone when used as `callback` for `_.map`', 1, function() {
- var expected = [{ 'a': [0] }, { 'b': [1] }],
- actual = _.map(expected, _.clone);
+ test('`_.clone` should work with `isDeep`', 2, function() {
+ var expected = [{ 'a': 0 }, { 'b': 1 }],
+ actual = _.clone(expected, true);
- ok(actual[0] != expected[0] && actual[0].a === expected[0].a && actual[1].b === expected[1].b);
+ deepEqual(actual, expected);
+ ok(actual !== expected && actual[0] !== expected[0]);
});
test('`_.cloneDeep` should deep clone objects with circular references', 1, function() {
var object = {
- 'foo': { 'b': { 'foo': { 'c': { } } } },
- 'bar': { }
+ 'foo': { 'b': { 'c': { 'd': {} } } },
+ 'bar': {}
};
- object.foo.b.foo.c = object;
+ object.foo.b.c.d = object;
object.bar.b = object.foo.b;
var clone = _.cloneDeep(object);
- ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c && clone !== object);
+ ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.c.d && clone !== object);
});
- _.forEach([
- 'clone',
- 'cloneDeep'
- ],
- function(methodName) {
+ _.each(['clone', 'cloneDeep'], function(methodName, index) {
var func = _[methodName],
- klass = new Klass;
+ isDeep = !!index;
_.forOwn(objects, function(object, key) {
test('`_.' + methodName + '` should clone ' + key, 2, function() {
- var clone = func(object);
- strictEqual(_.isEqual(object, clone), true);
+ var actual = func(object);
+ ok(_.isEqual(actual, object));
if (_.isObject(object)) {
- notStrictEqual(clone, object);
+ notStrictEqual(actual, object);
} else {
- strictEqual(clone, object);
+ strictEqual(actual, object);
}
});
});
- _.forOwn(nonCloneable, function(object, key) {
- test('`_.' + methodName + '` should not clone ' + key, 1, function() {
- strictEqual(func(object), object);
+ _.forOwn(uncloneable, function(value, key) {
+ test('`_.' + methodName + '` should not clone ' + key, 3, function() {
+ var object = { 'a': value, 'b': { 'c': value } },
+ actual = func(object);
+
+ notStrictEqual(actual, object);
+ deepEqual(actual, object);
+
+ var expected = typeof value == 'function' ? { 'foo': Klass.foo } : (value && {});
+ deepEqual(func(value), expected);
+ });
+
+ test('`_.' + methodName + '` should work with a `customizer` callback and ' + key, 4, function() {
+ var customizer = function(value) {
+ return _.isPlainObject(value) ? undefined : value;
+ };
+
+ var actual = func(value, customizer);
+
+ deepEqual(actual, value);
+ strictEqual(actual, value);
+
+ var object = { 'a': value, 'b': { 'c': value } };
+ actual = func(object, customizer);
+
+ deepEqual(actual, object);
+ notStrictEqual(actual, object);
+ });
+ });
+
+ test('`_.' + methodName + '` should clone array buffers', 2, function() {
+ if (ArrayBuffer) {
+ var buffer = new ArrayBuffer(10),
+ actual = func(buffer);
+
+ strictEqual(actual.byteLength, buffer.byteLength);
+ notStrictEqual(actual, buffer);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+
+ _.each(typedArrays, function(type) {
+ test('`_.' + methodName + '` should clone ' + type + ' arrays', 10, function() {
+ var Ctor = root[type];
+
+ _.times(2, function(index) {
+ if (Ctor) {
+ var buffer = new ArrayBuffer(24),
+ array = index ? new Ctor(buffer, 8, 1) : new Ctor(buffer),
+ actual = func(array);
+
+ deepEqual(actual, array);
+ notStrictEqual(actual, array);
+ strictEqual(actual.buffer === array.buffer, !isDeep);
+ strictEqual(actual.byteOffset, array.byteOffset);
+ strictEqual(actual.length, array.length);
+ }
+ else {
+ skipTest(5);
+ }
+ });
});
});
test('`_.' + methodName + '` should clone problem JScript properties (test in IE < 9)', 2, function() {
- deepEqual(func(shadowedObject), shadowedObject);
- notStrictEqual(func(shadowedObject), shadowedObject);
+ var actual = func(shadowObject);
+ deepEqual(actual, shadowObject);
+ notStrictEqual(actual, shadowObject);
});
- test('`_.' + methodName + '` should pass the correct `callback` arguments', 1, function() {
- var args;
+ test('`_.' + methodName + '` should provide the correct `customizer` arguments', 1, function() {
+ var argsList = [],
+ klass = new Klass;
func(klass, function() {
- args || (args = slice.call(arguments));
+ argsList.push(slice.call(arguments));
});
- deepEqual(args, [klass]);
+ deepEqual(argsList, isDeep ? [[klass], [1, 'a', klass]] : [[klass]]);
});
test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() {
@@ -1015,152 +1843,240 @@
return this[value];
}, { 'a': 'A' });
- equal(actual, 'A');
+ strictEqual(actual, 'A');
});
- test('`_.' + methodName + '` should handle cloning if `callback` returns `undefined`', 1, function() {
- var actual = func({ 'a': { 'b': 'c' } }, function() {});
+ test('`_.' + methodName + '` should handle cloning if `customizer` returns `undefined`', 1, function() {
+ var actual = func({ 'a': { 'b': 'c' } }, _.noop);
deepEqual(actual, { 'a': { 'b': 'c' } });
});
- test('`_.' + methodName + '` should deep clone `index` and `input` array properties', 2, function() {
+ test('`_.' + methodName + '` should clone `index` and `input` array properties', 2, function() {
var array = /x/.exec('vwxyz'),
actual = func(array);
strictEqual(actual.index, 2);
- equal(actual.input, 'vwxyz');
+ strictEqual(actual.input, 'vwxyz');
});
- test('`_.' + methodName + '` should deep clone `lastIndex` regexp property', 1, function() {
- // avoid a regexp literal for older Opera and use `exec` for older Safari
+ test('`_.' + methodName + '` should clone `lastIndex` regexp property', 1, function() {
+ // Avoid a regexp literal for older Opera and use `exec` for older Safari.
var regexp = RegExp('x', 'g');
regexp.exec('vwxyz');
var actual = func(regexp);
- equal(actual.lastIndex, 3);
+ strictEqual(actual.lastIndex, 3);
});
- });
- }(1, 2, 3));
- /*--------------------------------------------------------------------------*/
+ test('`_.' + methodName + '` should not error on DOM elements', 1, function() {
+ if (document) {
+ var element = document.createElement('div');
- QUnit.module('lodash.compact');
+ try {
+ deepEqual(func(element), {});
+ } catch(e) {
+ ok(false, e.message);
+ }
+ }
+ else {
+ skipTest();
+ }
+ });
- (function() {
- test('should filter falsey values', 1, function() {
- var array = ['0', '1', '2'];
- deepEqual(_.compact(falsey.concat(array)), array);
- });
- }());
+ test('`_.' + methodName + '` should perform a ' + (isDeep ? 'deep' : 'shallow') + ' clone when used as an iteratee for `_.map`', 3, function() {
+ var expected = [{ 'a': [0] }, { 'b': [1] }],
+ actual = _.map(expected, func);
- /*--------------------------------------------------------------------------*/
+ deepEqual(actual, expected);
- QUnit.module('lodash.compose');
+ if (isDeep) {
+ ok(actual[0] !== expected[0] && actual[0].a !== expected[0].a && actual[1].b !== expected[1].b);
+ } else {
+ ok(actual[0] !== expected[0] && actual[0].a === expected[0].a && actual[1].b === expected[1].b);
+ }
+ actual = _.map(isDeep ? Object('abc') : 'abc', func);
+ deepEqual(actual, ['a', 'b', 'c']);
+ });
- (function() {
- test('should create a function that is the composition of the provided functions', 1, function() {
- var realNameMap = {
- 'pebbles': 'penelope'
- };
+ test('`_.' + methodName + '` should create an object from the same realm as `value`', 1, function() {
+ var objects = _.transform(_, function(result, value, key) {
+ if (_.startsWith(key, '_') && _.isObject(value) && !_.isArguments(value) && !_.isElement(value) && !_.isFunction(value)) {
+ result.push(value);
+ }
+ }, []);
- var format = function(name) {
- name = realNameMap[name.toLowerCase()] || name;
- return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
- };
+ var expected = _.times(objects.length, _.constant(true));
- var greet = function(formatted) {
- return 'Hiya ' + formatted + '!';
- };
+ var actual = _.map(objects, function(object) {
+ var Ctor = object.constructor,
+ result = func(object);
- var welcome = _.compose(greet, format);
- equal(welcome('pebbles'), 'Hiya Penelope!');
- });
- }());
+ return result !== object && (result instanceof Ctor || !(new Ctor instanceof Ctor));
+ });
- /*--------------------------------------------------------------------------*/
+ deepEqual(actual, expected);
+ });
- QUnit.module('lodash.constant');
+ test('`_.' + methodName + '` should return a unwrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var object = objects['objects'],
+ actual = _(object)[methodName]();
+
+ deepEqual(actual, object);
+ notStrictEqual(actual, object);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+ });
+ }(1, 2, 3));
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.compact');
(function() {
- test('should create a function that always returns `value`', 1, function() {
- var object = { 'a': 1 },
- values = falsey.concat(1, 'a'),
- constant = _.constant(object),
- expected = _.map(values, function() { return object; });
+ test('should filter falsey values', 1, function() {
+ var array = ['0', '1', '2'];
+ deepEqual(_.compact(falsey.concat(array)), array);
+ });
- var actual = _.map(values, function(value, index) {
- return index ? constant(value) : constant();
- });
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(falsey).compact();
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), []);
+ }
+ else {
+ skipTest(2);
+ }
+ });
- deepEqual(actual, expected);
+ test('should work when in between lazy operators', 2, function() {
+ if (!isNpm) {
+ var actual = _(falsey).slice().compact().slice().value();
+ deepEqual(actual, []);
+
+ actual = _(falsey).slice().push(true, 1).compact().push('a').slice().value();
+ deepEqual(actual, [true, 1, 'a']);
+ }
+ else {
+ skipTest(2);
+ }
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.contains');
+ QUnit.module('lodash.flowRight');
(function() {
- _.forEach({
- 'an `arguments` object': arguments,
- 'an array': [1, 2, 3, 1, 2, 3],
- 'an object': { 'a': 1, 'b': 2, 'c': 3, 'd': 1, 'e': 2, 'f': 3 },
- 'a string': '123123'
- },
- function(collection, key) {
- test('should work with ' + key + ' and return `true` for matched values', 1, function() {
- strictEqual(_.contains(collection, 3), true);
- });
+ test('should be aliased', 2, function() {
+ strictEqual(_.backflow, _.flowRight);
+ strictEqual(_.compose, _.flowRight);
+ });
+ }());
- test('should work with ' + key + ' and return `false` for unmatched values', 1, function() {
- strictEqual(_.contains(collection, 4), false);
- });
+ /*--------------------------------------------------------------------------*/
- test('should work with ' + key + ' and a positive `fromIndex`', 1, function() {
- strictEqual(_.contains(collection, 1, 2), true);
- });
+ QUnit.module('flow methods');
- test('should work with ' + key + ' and a `fromIndex` >= collection\'s length', 4, function() {
- strictEqual(_.contains(collection, 1, 6), false);
- strictEqual(_.contains(collection, undefined, 6), false);
- strictEqual(_.contains(collection, 1, 8), false);
- strictEqual(_.contains(collection, undefined, 8), false);
- });
+ _.each(['flow', 'flowRight'], function(methodName, index) {
+ var func = _[methodName],
+ isFlow = !index;
- test('should work with ' + key + ' and a negative `fromIndex`', 1, function() {
- strictEqual(_.contains(collection, 2, -3), true);
- });
+ test('`_.' + methodName + '` should supply each function with the return value of the previous', 1, function() {
+ function add(x, y) {
+ return x + y;
+ }
- test('should work with ' + key + ' and a negative `fromIndex` <= negative collection\'s length', 2, function() {
- strictEqual(_.contains(collection, 1, -6), true);
- strictEqual(_.contains(collection, 2, -8), true);
- });
+ function square(n) {
+ return n * n;
+ }
- test('should work with ' + key + ' and return an unwrapped value when chaining', 1, function() {
- if (!isNpm) {
- strictEqual(_(collection).contains(3), true);
- }
- else {
- skipTest();
+ function fixed(n) {
+ return n.toFixed(1);
+ }
+
+ var combined = isFlow ? func(add, square, fixed) : func(fixed, square, add);
+ strictEqual(combined(1, 2), '9.0');
+ });
+
+ test('`_.' + methodName + '` should return a new function', 1, function() {
+ notStrictEqual(func(_.noop), _.noop);
+ });
+
+ test('`_.' + methodName + '` should return a noop function when no arguments are provided', 2, function() {
+ var combined = func();
+
+ try {
+ strictEqual(combined(), undefined);
+ } catch(e) {
+ ok(false, e.message);
+ }
+ notStrictEqual(combined, _.noop);
+ });
+
+ test('`_.' + methodName + '` should return a wrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ var wrapped = _(_.noop)[methodName]();
+ ok(wrapped instanceof _);
+ }
+ else {
+ skipTest();
+ }
+ });
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.constant');
+
+ (function() {
+ test('should create a function that returns `value`', 1, function() {
+ var object = { 'a': 1 },
+ values = Array(2).concat(empties, true, 1, 'a'),
+ constant = _.constant(object),
+ expected = _.map(values, function() { return true; });
+
+ var actual = _.map(values, function(value, index) {
+ if (index == 0) {
+ var result = constant();
+ } else if (index == 1) {
+ result = constant.call({});
+ } else {
+ result = constant(value);
}
+ return result === object;
});
+
+ deepEqual(actual, expected);
});
- _.forEach({
- 'literal': 'abc',
- 'object': Object('abc')
- },
- function(collection, key) {
- test('should work with a string ' + key + ' for `collection`', 2, function() {
- strictEqual(_.contains(collection, 'bc'), true);
- strictEqual(_.contains(collection, 'd'), false);
+ test('should work with falsey values', 1, function() {
+ var expected = _.map(falsey, function() { return true; });
+
+ var actual = _.map(falsey, function(value, index) {
+ var constant = index ? _.constant(value) : _.constant(),
+ result = constant();
+
+ return result === value || (_.isNaN(result) && _.isNaN(value));
});
+
+ deepEqual(actual, expected);
});
- test('should be aliased', 1, function() {
- strictEqual(_.include, _.contains);
+ test('should return a wrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ var wrapped = _(true).constant();
+ ok(wrapped instanceof _);
+ }
+ else {
+ skipTest();
+ }
});
- }(1, 2, 3, 1, 2, 3));
+ }());
/*--------------------------------------------------------------------------*/
@@ -1169,7 +2085,7 @@
(function() {
var array = [4.2, 6.1, 6.4];
- test('should work with a `callback`', 1, function() {
+ test('should work with an iteratee', 1, function() {
var actual = _.countBy(array, function(num) {
return Math.floor(num);
}, Math);
@@ -1177,12 +2093,19 @@
deepEqual(actual, { '4': 1, '6': 2 });
});
- test('should use `_.identity` when no `callback` is provided', 1, function() {
- var actual = _.countBy([4, 6, 6]);
- deepEqual(actual, { '4': 1, '6': 2 });
+ test('should use `_.identity` when `iteratee` is nullish', 1, function() {
+ var array = [4, 6, 6],
+ values = [, null, undefined],
+ expected = _.map(values, _.constant({ '4': 1, '6': 2 }));
+
+ var actual = _.map(values, function(value, index) {
+ return index ? _.countBy(array, value) : _.countBy(array);
+ });
+
+ deepEqual(actual, expected);
});
- test('should pass the correct `callback` arguments', 1, function() {
+ test('should provide the correct `iteratee` arguments', 1, function() {
var args;
_.countBy(array, function() {
@@ -1209,11 +2132,22 @@
deepEqual(actual.hasOwnProperty, 2);
});
- test('should work with a string for `callback`', 1, function() {
+ test('should work with a "_.pluck" style `iteratee`', 1, function() {
var actual = _.countBy(['one', 'two', 'three'], 'length');
deepEqual(actual, { '3': 2, '5': 1 });
});
+ test('should work with a number for `iteratee`', 2, function() {
+ var array = [
+ [1, 'a'],
+ [2, 'a'],
+ [2, 'b']
+ ];
+
+ deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 });
+ deepEqual(_.countBy(array, 1), { 'a': 2, 'b': 1 });
+ });
+
test('should work with an object for `collection`', 1, function() {
var actual = _.countBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) {
return Math.floor(num);
@@ -1222,15 +2156,17 @@
deepEqual(actual, { '4': 1, '6': 2 });
});
- test('should work with a number for `callback`', 2, function() {
- var array = [
- [1, 'a'],
- [2, 'a'],
- [2, 'b']
- ];
+ test('should work in a lazy chain sequence', 1, function() {
+ if (!isNpm) {
+ var array = [1, 2, 1, 3],
+ predicate = function(value) { return value > 1; },
+ actual = _(array).countBy(_.identity).map(String).filter(predicate).take().value();
- deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 });
- deepEqual(_.countBy(array, 1), { 'a': 2, 'b': 1 });
+ deepEqual(actual, ['2']);
+ }
+ else {
+ skipTest();
+ }
});
}());
@@ -1279,8 +2215,18 @@
deepEqual(Circle.prototype, expected);
});
+ test('should assign own properties', 1, function() {
+ function Foo() {
+ this.a = 1;
+ this.c = 3;
+ }
+ Foo.prototype.b = 2;
+
+ deepEqual(_.create({}, new Foo), { 'a': 1, 'c': 3 });
+ });
+
test('should accept a falsey `prototype` argument', 1, function() {
- var expected = _.map(falsey, function() { return {}; });
+ var expected = _.map(falsey, _.constant({}));
var actual = _.map(falsey, function(value, index) {
return index ? _.create(value) : _.create();
@@ -1291,7 +2237,7 @@
test('should ignore primitive `prototype` arguments and use an empty object instead', 1, function() {
var primitives = [true, null, 1, 'a', undefined],
- expected = _.map(primitives, function() { return true; });
+ expected = _.map(primitives, _.constant(true));
var actual = _.map(primitives, function(value, index) {
return _.isPlainObject(index ? _.create(value) : _.create());
@@ -1299,49 +2245,135 @@
deepEqual(actual, expected);
});
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }],
+ expected = _.map(array, _.constant(true)),
+ objects = _.map(array, _.create);
+
+ var actual = _.map(objects, function(object) {
+ return object.a === 1 && !_.keys(object).length;
+ });
+
+ deepEqual(actual, expected);
+ });
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.createCallback');
+ QUnit.module('lodash.callback');
(function() {
- test('should work with functions created by `_.partial` and `_.partialRight`', 2, function() {
- function func() {
- var result = [this.x];
+ test('should provide arguments to `func`', 3, function() {
+ function fn() {
+ var result = [this];
push.apply(result, arguments);
return result;
}
- var expected = [1, 2, 3],
- object = { 'x': 1 },
- callback = _.createCallback(_.partial(func, 2), object);
- deepEqual(callback(3), expected);
+ var callback = _.callback(fn),
+ actual = callback('a', 'b', 'c', 'd', 'e', 'f');
- callback = _.createCallback(_.partialRight(func, 3), object);
- deepEqual(callback(2), expected);
+ ok(actual[0] === null || actual[0] && actual[0].Array);
+ deepEqual(actual.slice(1), ['a', 'b', 'c', 'd', 'e', 'f']);
+
+ var object = {};
+ callback = _.callback(fn, object);
+ actual = callback('a', 'b');
+
+ deepEqual(actual, [object, 'a', 'b']);
});
- test('should work without an `argCount`', 1, function() {
- var args,
- expected = ['a', 'b', 'c', 'd', 'e'];
+ test('should return `_.identity` when `func` is nullish', 1, function() {
+ var object = {},
+ values = [, null, undefined],
+ expected = _.map(values, _.constant(object));
- var callback = _.createCallback(function() {
- args = slice.call(arguments);
+ var actual = _.map(values, function(value, index) {
+ var callback = index ? _.callback(value) : _.callback();
+ return callback(object);
});
- callback.apply(null, expected);
- deepEqual(args, expected);
+ deepEqual(actual, expected);
});
- test('should return the function provided if already bound with `Function#bind`', 1, function() {
- function a() {}
+ test('should not error when `func` is nullish and a `thisArg` is provided', 2, function() {
var object = {};
- var bound = a.bind && a.bind(object);
- if (bound && !('prototype' in bound)) {
- var bound = a.bind(object);
- strictEqual(_.createCallback(bound, object), bound);
+ _.each([null, undefined], function(value) {
+ try {
+ var callback = _.callback(value, {});
+ strictEqual(callback(object), object);
+ } catch(e) {
+ ok(false, e.message);
+ }
+ });
+ });
+
+ test('should create a callback with a falsey `thisArg`', 1, function() {
+ var fn = function() { return this; },
+ object = {};
+
+ var expected = _.map(falsey, function(value) {
+ var result = fn.call(value);
+ return (result && result.Array) ? object : result;
+ });
+
+ var actual = _.map(falsey, function(value) {
+ var callback = _.callback(fn, value),
+ result = callback();
+
+ return (result && result.Array) ? object : result;
+ });
+
+ ok(_.isEqual(actual, expected));
+ });
+
+ test('should return a callback created by `_.matches` when `func` is an object', 2, function() {
+ var callback = _.callback({ 'a': 1 });
+ strictEqual(callback({ 'a': 1, 'b': 2 }), true);
+ strictEqual(callback({}), false);
+ });
+
+ test('should return a callback created by `_.property` when `func` is a number or string', 2, function() {
+ var array = ['a'],
+ callback = _.callback(0);
+
+ strictEqual(callback(array), 'a');
+
+ callback = _.callback('0');
+ strictEqual(callback(array), 'a');
+ });
+
+ test('should work with functions created by `_.partial` and `_.partialRight`', 2, function() {
+ function fn() {
+ var result = [this.a];
+ push.apply(result, arguments);
+ return result;
+ }
+
+ var expected = [1, 2, 3],
+ object = { 'a': 1 },
+ callback = _.callback(_.partial(fn, 2), object);
+
+ deepEqual(callback(3), expected);
+
+ callback = _.callback(_.partialRight(fn, 3), object);
+ deepEqual(callback(2), expected);
+ });
+
+ test('should support binding built-in methods', 2, function() {
+ var object = { 'a': 1 },
+ callback = _.callback(hasOwnProperty, object);
+
+ strictEqual(callback('a'), true);
+
+ var fn = function() {},
+ bound = fn.bind && fn.bind(object);
+
+ if (bound) {
+ callback = _.callback(bound, object);
+ notStrictEqual(callback, bound);
}
else {
skipTest();
@@ -1355,2786 +2387,4992 @@
var object = {};
if (_.support.funcDecomp) {
- strictEqual(_.createCallback(a, object), a);
- notStrictEqual(_.createCallback(b, object), b);
+ strictEqual(_.callback(a, object), a);
+ notStrictEqual(_.callback(b, object), b);
}
else {
skipTest(2);
}
});
- test('should only write `__bindData__` to named functions', 3, function() {
- function a() {};
- function c() {};
-
- var b = function() {},
- object = {};
+ test('should work with bizarro `_.support.funcNames`', 6, function() {
+ function a() {}
- if (defineProperty && _.support.funcDecomp) {
- _.createCallback(a, object);
- ok('__bindData__' in a)
+ var b = function() {};
- _.createCallback(b, object);
- ok(!('__bindData__' in b));
+ function c() {
+ return this;
+ }
- if (_.support.funcNames) {
- _.support.funcNames = false;
- _.createCallback(c, object);
- ok('__bindData__' in c);
- _.support.funcNames = true;
+ var object = {},
+ supportBizarro = lodashBizarro ? lodashBizarro.support : {},
+ funcDecomp = supportBizarro.funcDecomp,
+ funcNames = supportBizarro.funcNames;
+
+ supportBizarro.funcNames = !supportBizarro.funcNames;
+ supportBizarro.funcDecomp = true;
+
+ _.each([a, b, c], function(fn) {
+ if (lodashBizarro && _.support.funcDecomp) {
+ var callback = lodashBizarro.callback(fn, object);
+ strictEqual(callback(), fn === c ? object : undefined);
+ strictEqual(callback === fn, _.support.funcNames && fn === a);
}
else {
- skipTest();
+ skipTest(2);
}
- }
- else {
- skipTest(3);
- }
- });
- }());
-
- /*--------------------------------------------------------------------------*/
-
- QUnit.module('lodash.curry');
-
- (function() {
- function func(a, b, c) {
- return a + b + c;
- }
-
- test('should curry based on the number of arguments provided', 3, function() {
- var curried = _.curry(func);
-
- equal(curried(1)(2)(3), 6);
- equal(curried(1, 2)(3), 6);
- equal(curried(1, 2, 3), 6);
- });
-
- test('should work with partial methods', 2, function() {
- var curried = _.curry(func),
- a = _.partial(curried, 1),
- b = _.partialRight(a, 3),
- c = _.partialRight(a(2), 3);
+ });
- equal(b(2), 6);
- equal(c(), 6);
+ supportBizarro.funcDecomp = funcDecomp;
+ supportBizarro.funcNames = funcNames;
});
- test('should return a function with a `length` of `0`', 6, function() {
- _.times(2, function(index) {
- var curried = index ? _.curry(func, 4) : _.curry(func);
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var fn = function() { return this instanceof Number; },
+ array = [fn, fn, fn],
+ expected = _.map(array, _.constant(false)),
+ callbacks = _.map(array, _.callback);
- strictEqual(curried.length, 0);
- strictEqual(curried(1).length, 0);
- strictEqual(curried(1, 2).length, 0);
+ var actual = _.map(callbacks, function(callback) {
+ return callback();
});
- });
-
- test('ensure `new bound` is an instance of `func`', 2, function() {
- function Foo(value) {
- return value && object;
- }
- var bound = _.curry(Foo),
- object = {};
- ok(new bound(false) instanceof Foo);
- strictEqual(new bound(true), object);
+ deepEqual(actual, expected);
});
- test('should not alter the `this` binding', 9, function() {
- function func(a, b, c) {
- var value = this || {};
- return value[a] + value[b] + value[c];
- }
-
- var object = { 'a': 1, 'b': 2, 'c': 3 };
-
- equal(_.curry(_.bind(func, object), 3)('a')('b')('c'), 6);
- equal(_.curry(_.bind(func, object), 3)('a', 'b')('c'), 6);
- equal(_.curry(_.bind(func, object), 3)('a', 'b', 'c'), 6);
-
- ok(_.isEqual(_.bind(_.curry(func), object)('a')('b')('c'), NaN));
- ok(_.isEqual(_.bind(_.curry(func), object)('a', 'b')('c'), NaN));
- equal(_.bind(_.curry(func), object)('a', 'b', 'c'), 6);
-
- object.func = _.curry(func);
-
- ok(_.isEqual(object.func('a')('b')('c'), NaN));
- ok(_.isEqual(object.func('a', 'b')('c'), NaN));
- equal(object.func('a', 'b', 'c'), 6);
+ test('should be aliased', 1, function() {
+ strictEqual(_.iteratee, _.callback);
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.debounce');
+ QUnit.module('custom `_.callback` methods');
(function() {
- asyncTest('should debounce a function', 2, function() {
- if (!(isRhino && isModularize)) {
- var count = 0,
- debounced = _.debounce(function() { count++; }, 32);
-
- debounced();
- debounced();
- debounced();
+ var array = ['one', 'two', 'three'],
+ callback = _.callback,
+ getPropA = _.partial(_.property, 'a'),
+ getPropB = _.partial(_.property, 'b'),
+ getLength = _.partial(_.property, 'length');
+
+ var getSum = function() {
+ return function(result, object) {
+ return result + object.a;
+ };
+ };
- equal(count, 0);
+ var objects = [
+ { 'a': 0, 'b': 0 },
+ { 'a': 1, 'b': 0 },
+ { 'a': 1, 'b': 1 }
+ ];
- setTimeout(function() {
- equal(count, 1);
- QUnit.start();
- }, 96);
+ test('`_.countBy` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getLength;
+ deepEqual(_.countBy(array), { '3': 2, '5': 1 });
+ _.callback = callback;
}
else {
- skipTest(2);
- QUnit.start();
+ skipTest();
}
});
- asyncTest('subsequent debounced calls return the last `func` result', 2, function() {
- if (!(isRhino && isModularize)) {
- var debounced = _.debounce(_.identity, 32);
- debounced('x');
-
- setTimeout(function() {
- notEqual(debounced('y'), 'y');
- }, 64);
-
- setTimeout(function() {
- notEqual(debounced('z'), 'z');
- QUnit.start();
- }, 128);
+ test('`_.dropRightWhile` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ deepEqual(_.dropRightWhile(objects), objects.slice(0, 2));
+ _.callback = callback;
}
else {
- skipTest(2);
- QUnit.start();
+ skipTest();
}
});
- asyncTest('subsequent "immediate" debounced calls return the last `func` result', 2, function() {
- if (!(isRhino && isModularize)) {
- var debounced = _.debounce(_.identity, 32, true),
- result = [debounced('x'), debounced('y')];
-
- deepEqual(result, ['x', 'x']);
-
- setTimeout(function() {
- var result = [debounced('a'), debounced('b')];
- deepEqual(result, ['a', 'a']);
- QUnit.start();
- }, 64);
+ test('`_.dropWhile` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2));
+ _.callback = callback;
}
else {
- skipTest(2);
- QUnit.start();
+ skipTest();
}
});
- asyncTest('should apply default options correctly', 2, function() {
- if (!(isRhino && isModularize)) {
- var count = 0;
-
- var debounced = _.debounce(function(value) {
- count++;
- return value;
- }, 32, {});
-
- strictEqual(debounced('x'), undefined);
-
- setTimeout(function() {
- strictEqual(count, 1);
- QUnit.start();
- }, 64);
+ test('`_.every` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropA;
+ strictEqual(_.every(objects.slice(1)), true);
+ _.callback = callback;
}
else {
- skipTest(2);
- QUnit.start();
+ skipTest();
}
});
- asyncTest('should work with `leading` option', 7, function() {
- if (!(isRhino && isModularize)) {
- var withLeading,
- counts = [0, 0, 0];
-
- _.forEach([true, { 'leading': true }], function(options, index) {
- var debounced = _.debounce(function(value) {
- counts[index]++;
- return value;
- }, 32, options);
-
- if (index == 1) {
- withLeading = debounced;
- }
- equal(debounced('x'), 'x');
- });
-
- _.forEach([false, { 'leading': false }], function(options) {
- var withoutLeading = _.debounce(_.identity, 32, options);
- strictEqual(withoutLeading('x'), undefined);
- });
-
- var withLeadingAndTrailing = _.debounce(function() {
- counts[2]++;
- }, 32, { 'leading': true });
-
- withLeadingAndTrailing();
- withLeadingAndTrailing();
-
- strictEqual(counts[2], 1);
-
- setTimeout(function() {
- deepEqual(counts, [1, 1, 2]);
-
- withLeading('x');
- equal(counts[1], 2);
+ test('`_.filter` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ var objects = [{ 'a': 0 }, { 'a': 1 }];
- QUnit.start();
- }, 64);
+ _.callback = getPropA;
+ deepEqual(_.filter(objects), [objects[1]]);
+ _.callback = callback;
}
else {
- skipTest(7);
- QUnit.start();
+ skipTest();
}
});
- asyncTest('should work with `trailing` option', 4, function() {
- if (!(isRhino && isModularize)) {
- var withCount = 0,
- withoutCount = 0;
-
- var withTrailing = _.debounce(function(value) {
- withCount++;
- return value;
- }, 32, { 'trailing': true });
-
- var withoutTrailing = _.debounce(function(value) {
- withoutCount++;
- return value;
- }, 32, { 'trailing': false });
-
- strictEqual(withTrailing('x'), undefined);
- strictEqual(withoutTrailing('x'), undefined);
-
- setTimeout(function() {
- strictEqual(withCount, 1);
- strictEqual(withoutCount, 0);
- QUnit.start();
- }, 64);
+ test('`_.find` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropA;
+ strictEqual(_.find(objects), objects[1]);
+ _.callback = callback;
}
else {
- skipTest(4);
- QUnit.start();
+ skipTest();
}
});
- test('should work with `maxWait` option', 2, function() {
- if (!(isRhino && isModularize)) {
- var limit = argv ? 1000 : 500,
- withCount = 0,
- withoutCount = 0;
-
- var withMaxWait = _.debounce(function() {
- withCount++;
- }, 64, { 'maxWait': 128 });
-
- var withoutMaxWait = _.debounce(function() {
- withoutCount++;
- }, 96);
-
- var start = +new Date;
- while ((new Date - start) < limit) {
- withMaxWait();
- withoutMaxWait();
- }
- ok(withCount > 0);
- ok(!withoutCount);
+ test('`_.findIndex` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropA;
+ strictEqual(_.findIndex(objects), 1);
+ _.callback = callback;
}
else {
- skipTest(2);
+ skipTest();
}
});
- asyncTest('should cancel `maxDelayed` when `delayed` is executed', 1, function() {
- if (!(isRhino && isModularize)) {
- var count = 0;
-
- var debounced = _.debounce(function() {
- count++;
- }, 32, { 'maxWait': 64 });
-
- debounced();
-
- setTimeout(function() {
- strictEqual(count, 1);
- QUnit.start();
- }, 128);
+ test('`_.findLast` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropA;
+ strictEqual(_.findLast(objects), objects[2]);
+ _.callback = callback;
}
else {
- skipTest(1);
- QUnit.start();
+ skipTest();
}
});
- asyncTest('should execute the `trailing` call with the correct arguments and `this` binding', 2, function() {
- if (!(isRhino && isModularize)) {
- var args,
- count = 0,
- object = {};
-
- var debounced = _.debounce(function(value) {
- args = [this];
- push.apply(args, arguments);
- return ++count != 2;
- }, 32, { 'leading': true, 'maxWait': 64 });
-
- while (true) {
- if (!debounced.call(object, 'a')) {
- break;
- }
- }
- setTimeout(function() {
- equal(count, 2);
- deepEqual(args, [object, 'a']);
- QUnit.start();
- }, 64);
+ test('`_.findLastIndex` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropA;
+ strictEqual(_.findLastIndex(objects), 2);
+ _.callback = callback;
}
else {
- skipTest(2);
- QUnit.start();
+ skipTest();
}
});
- }());
-
- /*--------------------------------------------------------------------------*/
-
- QUnit.module('lodash.defaults');
-
- (function() {
- test('should assign properties of a source object if missing on the destination object', 1, function() {
- deepEqual(_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 }), { 'a': 1, 'b': 2 });
- });
- test('should assign own source properties', 1, function() {
- function Foo() {
- this.a = 1;
- this.c = 3;
+ test('`_.findLastKey` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ strictEqual(_.findKey(objects), '2');
+ _.callback = callback;
+ }
+ else {
+ skipTest();
}
-
- Foo.prototype.b = 2;
- deepEqual(_.defaults({ 'c': 2 }, new Foo), { 'a': 1, 'c': 2 });
});
- test('should accept multiple source objects', 2, function() {
- var expected = { 'a': 1, 'b': 2, 'c': 3 };
- deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 }), expected);
- deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 }), expected);
+ test('`_.findKey` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ strictEqual(_.findLastKey(objects), '2');
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
});
- test('should not overwrite `null` values', 1, function() {
- var actual = _.defaults({ 'a': null }, { 'a': 1 });
- strictEqual(actual.a, null);
+ test('`_.groupBy` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getLength;
+ deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] });
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
});
- test('should overwrite `undefined` values', 1, function() {
- var actual = _.defaults({ 'a': undefined }, { 'a': 1 });
- strictEqual(actual.a, 1);
+ test('`_.indexBy` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getLength;
+ deepEqual(_.indexBy(array), { '3': 'two', '5': 'three' });
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
});
- test('should not error on `null` or `undefined` sources (test in IE < 9)', 1, function() {
- try {
- deepEqual(_.defaults({ 'a': 1 }, null, undefined, { 'a': 2, 'b': 2 }), { 'a': 1, 'b': 2 });
- } catch(e) {
- ok(false);
+ test('`_.map` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropA;
+ deepEqual(_.map(objects), [0, 1, 1]);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
}
});
- }());
-
- /*--------------------------------------------------------------------------*/
-
- QUnit.module('lodash.defer');
-
- (function() {
- asyncTest('should defer `func` execution', 1, function() {
- if (!(isRhino && isModularize)) {
- var pass = false;
- _.defer(function(){ pass = true; });
- setTimeout(function() {
- ok(pass);
- QUnit.start();
- }, 128);
+ test('`_.mapValues` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ deepEqual(_.mapValues({ 'a': { 'b': 1 } }), { 'a': 1 });
+ _.callback = callback;
}
else {
skipTest();
- QUnit.start();
}
});
- asyncTest('should accept additional arguments', 1, function() {
- if (!(isRhino && isModularize)) {
- var args;
+ test('`_.max` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ deepEqual(_.max(objects), objects[2]);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- _.defer(function() {
- args = slice.call(arguments);
- }, 1, 2, 3);
+ test('`_.min` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ deepEqual(_.min(objects), objects[0]);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- setTimeout(function() {
- deepEqual(args, [1, 2, 3]);
- QUnit.start();
- }, 128);
+ test('`_.partition` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }];
+
+ _.callback = getPropA;
+ deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]);
+ _.callback = callback;
}
else {
skipTest();
- QUnit.start();
}
});
- asyncTest('should be cancelable', 1, function() {
- if (!(isRhino && isModularize)) {
- var pass = true;
+ test('`_.reduce` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getSum;
+ strictEqual(_.reduce(objects, undefined, 0), 2);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- var timerId = _.defer(function() {
- pass = false;
- });
+ test('`_.reduceRight` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getSum;
+ strictEqual(_.reduceRight(objects, undefined, 0), 2);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- clearTimeout(timerId);
+ test('`_.reject` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ var objects = [{ 'a': 0 }, { 'a': 1 }];
- setTimeout(function() {
- ok(pass);
- QUnit.start();
- }, 128);
+ _.callback = getPropA;
+ deepEqual(_.reject(objects), [objects[0]]);
+ _.callback = callback;
}
else {
skipTest();
- QUnit.start();
}
});
- }());
- /*--------------------------------------------------------------------------*/
+ test('`_.remove` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ var objects = [{ 'a': 0 }, { 'a': 1 }];
- QUnit.module('lodash.delay');
+ _.callback = getPropA;
+ _.remove(objects);
+ deepEqual(objects, [{ 'a': 0 }]);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- (function() {
- asyncTest('should delay `func` execution', 2, function() {
- if (!(isRhino && isModularize)) {
- var pass = false;
- _.delay(function(){ pass = true; }, 96);
+ test('`_.some` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ strictEqual(_.some(objects), true);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- setTimeout(function() {
- ok(!pass);
- }, 32);
+ test('`_.sortBy` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropA;
+ deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- setTimeout(function() {
- ok(pass);
- QUnit.start();
- }, 160);
+ test('`_.sortedIndex` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ var objects = [{ 'a': 30 }, { 'a': 50 }];
+
+ _.callback = getPropA;
+ strictEqual(_.sortedIndex(objects, { 'a': 40 }), 1);
+ _.callback = callback;
}
else {
- skipTest(2);
- QUnit.start();
+ skipTest();
}
});
- asyncTest('should accept additional arguments', 1, function() {
- if (!(isRhino && isModularize)) {
- var args;
+ test('`_.sortedLastIndex` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ var objects = [{ 'a': 30 }, { 'a': 50 }];
- _.delay(function() {
- args = slice.call(arguments);
- }, 32, 1, 2, 3);
+ _.callback = getPropA;
+ strictEqual(_.sortedLastIndex(objects, { 'a': 40 }), 1);
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- setTimeout(function() {
- deepEqual(args, [1, 2, 3]);
- QUnit.start();
- }, 128);
+ test('`_.takeRightWhile` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ deepEqual(_.takeRightWhile(objects), objects.slice(2));
+ _.callback = callback;
}
else {
skipTest();
- QUnit.start();
}
});
- asyncTest('should be cancelable', 1, function() {
- if (!(isRhino && isModularize)) {
- var pass = true;
+ test('`_.takeWhile` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2));
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- var timerId = _.delay(function() {
- pass = false;
- }, 32);
+ test('`_.transform` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = function() {
+ return function(result, object) {
+ result.sum += object.a;
+ };
+ };
- clearTimeout(timerId);
+ deepEqual(_.transform(objects, undefined, { 'sum': 0 }), { 'sum': 2 });
+ _.callback = callback;
+ }
+ else {
+ skipTest();
+ }
+ });
- setTimeout(function() {
- ok(pass);
- QUnit.start();
- }, 128);
+ test('`_.uniq` should use `_.callback` internally', 1, function() {
+ if (!isModularize) {
+ _.callback = getPropB;
+ deepEqual(_.uniq(objects), [objects[0], objects[2]]);
+ _.callback = callback;
}
else {
skipTest();
- QUnit.start();
}
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.difference');
+ QUnit.module('lodash.curry');
(function() {
- test('should return the difference of the given arrays', 2, function() {
- var actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
- deepEqual(actual, [1, 3, 4]);
+ function fn(a, b, c, d) {
+ return slice.call(arguments);
+ }
- actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10], [8, 4]);
- deepEqual(actual, [1, 3]);
- });
+ test('should curry based on the number of arguments provided', 3, function() {
+ var curried = _.curry(fn),
+ expected = [1, 2, 3, 4];
- test('should work with large arrays', 1, function() {
- var array1 = _.range(largeArraySize),
- array2 = array1.slice(),
- a = {},
- b = {},
- c = {};
+ deepEqual(curried(1)(2)(3)(4), expected);
+ deepEqual(curried(1, 2)(3, 4), expected);
+ deepEqual(curried(1, 2, 3, 4), expected);
+ });
- array1.push(a, b, c);
- array2.push(b, c, a);
+ test('should allow specifying `arity`', 3, function() {
+ var curried = _.curry(fn, 3),
+ expected = [1, 2, 3];
- deepEqual(_.difference(array1, array2), []);
+ deepEqual(curried(1)(2, 3), expected);
+ deepEqual(curried(1, 2)(3), expected);
+ deepEqual(curried(1, 2, 3), expected);
});
- test('should work with large arrays of objects', 1, function() {
- var object = {};
+ test('should coerce `arity` to a number', 2, function() {
+ var values = ['0', 'xyz'],
+ expected = _.map(values, _.constant([]));
- var largeArray = _.times(largeArraySize, function() {
- return object;
+ var actual = _.map(values, function(arity) {
+ return _.curry(fn, arity)();
});
- deepEqual(_.difference(largeArray, [object]), []);
+ deepEqual(actual, expected);
+ deepEqual(_.curry(fn, '2')(1)(2), [1, 2]);
});
- test('should ignore individual secondary values', 1, function() {
- var array = [1, null, 3];
- deepEqual(_.difference(array, null, 3), array);
+ test('should support placeholders', 4, function() {
+ var curried = _.curry(fn),
+ ph = curried.placeholder;
+
+ deepEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]);
+ deepEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]);
+ deepEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]);
+ deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]);
});
- }());
- /*--------------------------------------------------------------------------*/
+ test('should work with partialed methods', 2, function() {
+ var curried = _.curry(fn),
+ expected = [1, 2, 3, 4];
- QUnit.module('lodash.escape');
+ var a = _.partial(curried, 1),
+ b = _.bind(a, null, 2),
+ c = _.partialRight(b, 4),
+ d = _.partialRight(b(3), 4);
- (function() {
- var escaped = '&<>"'\/',
- unescaped = '&<>"\'\/';
+ deepEqual(c(3), expected);
+ deepEqual(d(), expected);
+ });
- test('should not escape the "/" character', 1, function() {
- equal(_.escape('/'), '/');
+ test('should provide additional arguments after reaching the target arity', 3, function() {
+ var curried = _.curry(fn, 3);
+ deepEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]);
+ deepEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]);
+ deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]);
});
- test('should escape values', 1, function() {
- equal(_.escape(unescaped), escaped);
+ test('should return a function with a `length` of `0`', 6, function() {
+ _.times(2, function(index) {
+ var curried = index ? _.curry(fn, 4) : _.curry(fn);
+ strictEqual(curried.length, 0);
+ strictEqual(curried(1).length, 0);
+ strictEqual(curried(1, 2).length, 0);
+ });
+ });
+
+ test('ensure `new curried` is an instance of `func`', 2, function() {
+ var Foo = function(value) {
+ return value && object;
+ };
+
+ var curried = _.curry(Foo),
+ object = {};
+
+ ok(new curried(false) instanceof Foo);
+ strictEqual(new curried(true), object);
});
- test('should return an empty string when provided `null` or `undefined`', 2, function() {
- equal(_.escape(null), '');
- equal(_.escape(undefined), '');
+ test('should not set a `this` binding', 9, function() {
+ var fn = function(a, b, c) {
+ var value = this || {};
+ return [value[a], value[b], value[c]];
+ };
+
+ var object = { 'a': 1, 'b': 2, 'c': 3 },
+ expected = [1, 2, 3];
+
+ deepEqual(_.curry(_.bind(fn, object), 3)('a')('b')('c'), expected);
+ deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b')('c'), expected);
+ deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b', 'c'), expected);
+
+ deepEqual(_.bind(_.curry(fn), object)('a')('b')('c'), Array(3));
+ deepEqual(_.bind(_.curry(fn), object)('a', 'b')('c'), Array(3));
+ deepEqual(_.bind(_.curry(fn), object)('a', 'b', 'c'), expected);
+
+ object.curried = _.curry(fn);
+ deepEqual(object.curried('a')('b')('c'), Array(3));
+ deepEqual(object.curried('a', 'b')('c'), Array(3));
+ deepEqual(object.curried('a', 'b', 'c'), expected);
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.every');
+ QUnit.module('lodash.curryRight');
(function() {
- test('should return `true` for empty or falsey collections', 1, function() {
- var expected = _.map(empties, function() { return true; });
+ function fn(a, b, c, d) {
+ return slice.call(arguments);
+ }
- var actual = _.map(empties, function(value) {
- try {
- return _.every(value, _.identity);
- } catch(e) { }
- });
+ test('should curry based on the number of arguments provided', 3, function() {
+ var curried = _.curryRight(fn),
+ expected = [1, 2, 3, 4];
- deepEqual(actual, expected);
+ deepEqual(curried(4)(3)(2)(1), expected);
+ deepEqual(curried(3, 4)(1, 2), expected);
+ deepEqual(curried(1, 2, 3, 4), expected);
});
- test('should return `true` if the callback returns truey for all elements in the collection', 1, function() {
- strictEqual(_.every([true, 1, 'x'], _.identity), true);
- });
+ test('should allow specifying `arity`', 3, function() {
+ var curried = _.curryRight(fn, 3),
+ expected = [1, 2, 3];
- test('should return `false` as soon as the callback result is falsey', 1, function() {
- strictEqual(_.every([true, null, true], _.identity), false);
+ deepEqual(curried(3)(1, 2), expected);
+ deepEqual(curried(2, 3)(1), expected);
+ deepEqual(curried(1, 2, 3), expected);
});
- test('should work with collections of `undefined` values (test in IE < 9)', 1, function() {
- strictEqual(_.every([undefined, undefined, undefined], _.identity), false);
- });
+ test('should work with partialed methods', 2, function() {
+ var curried = _.curryRight(fn),
+ expected = [1, 2, 3, 4];
- test('should use `_.identity` when no callback is provided', 2, function() {
- strictEqual(_.every([0]), false);
- strictEqual(_.every([1]), true);
- });
+ var a = _.partialRight(curried, 4),
+ b = _.partialRight(a, 3),
+ c = _.bind(b, null, 1),
+ d = _.partial(b(2), 1);
- test('should be aliased', 1, function() {
- strictEqual(_.all, _.every);
+ deepEqual(c(2), expected);
+ deepEqual(d(), expected);
});
- }());
- /*--------------------------------------------------------------------------*/
+ test('should support placeholders', 4, function() {
+ var curried = _.curryRight(fn),
+ expected = [1, 2, 3, 4],
+ ph = curried.placeholder;
- QUnit.module('source property checks');
+ deepEqual(curried(4)(2, ph)(1, ph)(3), expected);
+ deepEqual(curried(3, ph)(4)(1, ph)(2), expected);
+ deepEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected);
+ deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected);
+ });
- _.forEach(['assign', 'defaults', 'merge'], function(methodName) {
- var func = _[methodName];
+ test('should provide additional arguments after reaching the target arity', 3, function() {
+ var curried = _.curryRight(fn, 3);
+ deepEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]);
+ deepEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]);
+ deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]);
+ });
- test('`_.' + methodName + '` should not assign inherited `source` properties', 1, function() {
- function Foo() {}
- Foo.prototype = { 'a': 1 };
- deepEqual(func({}, new Foo), {});
+ test('should return a function with a `length` of `0`', 6, function() {
+ _.times(2, function(index) {
+ var curried = index ? _.curryRight(fn, 4) : _.curryRight(fn);
+ strictEqual(curried.length, 0);
+ strictEqual(curried(4).length, 0);
+ strictEqual(curried(3, 4).length, 0);
+ });
});
- test('should work when used as `callback` for `_.reduce`', 1, function() {
- var array = [{ 'a': 1 }, { 'b': 2 }, { 'c': 3 }],
- actual = _.reduce(array, _.merge);
+ test('ensure `new curried` is an instance of `func`', 2, function() {
+ var Foo = function(value) {
+ return value && object;
+ };
+
+ var curried = _.curryRight(Foo),
+ object = {};
- deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
+ ok(new curried(false) instanceof Foo);
+ strictEqual(new curried(true), object);
});
- if (methodName == 'merge') {
- test('`_.' + methodName + '` should treat sparse arrays as dense', 2, function() {
- var array = Array(3);
- array[0] = 1;
- array[2] = 3;
+ test('should not set a `this` binding', 9, function() {
+ var fn = function(a, b, c) {
+ var value = this || {};
+ return [value[a], value[b], value[c]];
+ };
- var actual = func([], array),
- expected = array.slice();
+ var object = { 'a': 1, 'b': 2, 'c': 3 },
+ expected = [1, 2, 3];
- expected[1] = undefined;
+ deepEqual(_.curryRight(_.bind(fn, object), 3)('c')('b')('a'), expected);
+ deepEqual(_.curryRight(_.bind(fn, object), 3)('b', 'c')('a'), expected);
+ deepEqual(_.curryRight(_.bind(fn, object), 3)('a', 'b', 'c'), expected);
- ok(1 in actual);
- deepEqual(actual, expected);
- });
- }
- });
+ deepEqual(_.bind(_.curryRight(fn), object)('c')('b')('a'), Array(3));
+ deepEqual(_.bind(_.curryRight(fn), object)('b', 'c')('a'), Array(3));
+ deepEqual(_.bind(_.curryRight(fn), object)('a', 'b', 'c'), expected);
+
+ object.curried = _.curryRight(fn);
+ deepEqual(object.curried('c')('b')('a'), Array(3));
+ deepEqual(object.curried('b', 'c')('a'), Array(3));
+ deepEqual(object.curried('a', 'b', 'c'), expected);
+ });
+ }());
/*--------------------------------------------------------------------------*/
- QUnit.module('strict mode checks');
+ QUnit.module('curry methods');
- _.forEach(['assign', 'bindAll', 'defaults'], function(methodName) {
+ _.each(['curry', 'curryRight'], function(methodName) {
var func = _[methodName];
- test('`_.' + methodName + '` should not throw strict mode errors', 1, function() {
- var object = { 'a': null, 'b': function(){} },
- pass = true;
+ test('`_.' + methodName + '` should work as an iteratee for `_.map`', 1, function() {
+ var array = [_.identity, _.identity, _.identity],
+ curries = _.map(array, func);
- if (freeze) {
- freeze(object);
- try {
- if (methodName == 'bindAll') {
- func(object);
- } else {
- func(object, { 'a': 1 });
- }
- } catch(e) {
- pass = false;
- }
- ok(pass);
- }
- else {
- skipTest();
- }
+ var actual = _.map(curries, function(curried, index) {
+ return curried(index);
+ });
+
+ deepEqual(actual, [0, 1, 2]);
});
});
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.filter');
+ QUnit.module('lodash.debounce');
(function() {
- test('should return elements the `callback` returns truey for', 1, function() {
- var actual = _.filter([1, 2, 3], function(num) {
- return num % 2;
- });
-
+ asyncTest('should debounce a function', 2, function() {
+ if (!(isRhino && isModularize)) {
+ var count = 0,
+ debounced = _.debounce(function() { count++; }, 32);
+
+ debounced();
+ debounced();
+ debounced();
+
+ strictEqual(count, 0);
+
+ setTimeout(function() {
+ strictEqual(count, 1);
+ QUnit.start();
+ }, 96);
+ }
+ else {
+ skipTest(2);
+ QUnit.start();
+ }
+ });
+
+ asyncTest('subsequent debounced calls return the last `func` result', 2, function() {
+ if (!(isRhino && isModularize)) {
+ var debounced = _.debounce(_.identity, 32);
+ debounced('x');
+
+ setTimeout(function() {
+ notEqual(debounced('y'), 'y');
+ }, 64);
+
+ setTimeout(function() {
+ notEqual(debounced('z'), 'z');
+ QUnit.start();
+ }, 128);
+ }
+ else {
+ skipTest(2);
+ QUnit.start();
+ }
+ });
+
+ asyncTest('subsequent "immediate" debounced calls return the last `func` result', 2, function() {
+ if (!(isRhino && isModularize)) {
+ var debounced = _.debounce(_.identity, 32, true),
+ result = [debounced('x'), debounced('y')];
+
+ deepEqual(result, ['x', 'x']);
+
+ setTimeout(function() {
+ var result = [debounced('a'), debounced('b')];
+ deepEqual(result, ['a', 'a']);
+ QUnit.start();
+ }, 64);
+ }
+ else {
+ skipTest(2);
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should apply default options correctly', 2, function() {
+ if (!(isRhino && isModularize)) {
+ var count = 0;
+
+ var debounced = _.debounce(function(value) {
+ count++;
+ return value;
+ }, 32, {});
+
+ strictEqual(debounced('x'), undefined);
+
+ setTimeout(function() {
+ strictEqual(count, 1);
+ QUnit.start();
+ }, 64);
+ }
+ else {
+ skipTest(2);
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should support a `leading` option', 7, function() {
+ if (!(isRhino && isModularize)) {
+ var withLeading,
+ counts = [0, 0, 0];
+
+ _.each([true, { 'leading': true }], function(options, index) {
+ var debounced = _.debounce(function(value) {
+ counts[index]++;
+ return value;
+ }, 32, options);
+
+ if (index == 1) {
+ withLeading = debounced;
+ }
+ strictEqual(debounced('x'), 'x');
+ });
+
+ _.each([false, { 'leading': false }], function(options) {
+ var withoutLeading = _.debounce(_.identity, 32, options);
+ strictEqual(withoutLeading('x'), undefined);
+ });
+
+ var withLeadingAndTrailing = _.debounce(function() {
+ counts[2]++;
+ }, 32, { 'leading': true });
+
+ withLeadingAndTrailing();
+ withLeadingAndTrailing();
+
+ strictEqual(counts[2], 1);
+
+ setTimeout(function() {
+ deepEqual(counts, [1, 1, 2]);
+
+ withLeading('x');
+ strictEqual(counts[1], 2);
+
+ QUnit.start();
+ }, 64);
+ }
+ else {
+ skipTest(7);
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should support a `trailing` option', 4, function() {
+ if (!(isRhino && isModularize)) {
+ var withCount = 0,
+ withoutCount = 0;
+
+ var withTrailing = _.debounce(function(value) {
+ withCount++;
+ return value;
+ }, 32, { 'trailing': true });
+
+ var withoutTrailing = _.debounce(function(value) {
+ withoutCount++;
+ return value;
+ }, 32, { 'trailing': false });
+
+ strictEqual(withTrailing('x'), undefined);
+ strictEqual(withoutTrailing('x'), undefined);
+
+ setTimeout(function() {
+ strictEqual(withCount, 1);
+ strictEqual(withoutCount, 0);
+ QUnit.start();
+ }, 64);
+ }
+ else {
+ skipTest(4);
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should support a `maxWait` option', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var limit = (argv || isPhantom) ? 1000 : 320,
+ withCount = 0,
+ withoutCount = 0;
+
+ var withMaxWait = _.debounce(function() {
+ withCount++;
+ }, 64, { 'maxWait': 128 });
+
+ var withoutMaxWait = _.debounce(function() {
+ withoutCount++;
+ }, 96);
+
+ var start = +new Date;
+ while ((new Date - start) < limit) {
+ withMaxWait();
+ withoutMaxWait();
+ }
+ var actual = [Boolean(withCount), Boolean(withoutCount)];
+
+ setTimeout(function() {
+ deepEqual(actual, [true, false]);
+ QUnit.start();
+ }, 1);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should cancel `maxDelayed` when `delayed` is invoked', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var count = 0;
+
+ var debounced = _.debounce(function() {
+ count++;
+ }, 32, { 'maxWait': 64 });
+
+ debounced();
+
+ setTimeout(function() {
+ strictEqual(count, 1);
+ QUnit.start();
+ }, 128);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should invoke the `trailing` call with the correct arguments and `this` binding', 2, function() {
+ if (!(isRhino && isModularize)) {
+ var actual,
+ count = 0,
+ object = {};
+
+ var debounced = _.debounce(function(value) {
+ actual = [this];
+ push.apply(actual, arguments);
+ return ++count != 2;
+ }, 32, { 'leading': true, 'maxWait': 64 });
+
+ while (true) {
+ if (!debounced.call(object, 'a')) {
+ break;
+ }
+ }
+ setTimeout(function() {
+ strictEqual(count, 2);
+ deepEqual(actual, [object, 'a']);
+ QUnit.start();
+ }, 64);
+ }
+ else {
+ skipTest(2);
+ QUnit.start();
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.deburr');
+
+ (function() {
+ test('should convert latin-1 supplementary letters to basic latin', 1, function() {
+ var actual = _.map(burredLetters, _.deburr);
+ deepEqual(actual, deburredLetters);
+ });
+
+ test('should not deburr latin-1 mathematical operators', 1, function() {
+ var operators = ['\xd7', '\xf7'],
+ actual = _.map(operators, _.deburr);
+
+ deepEqual(actual, operators);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.defaults');
+
+ (function() {
+ test('should assign properties of a source object if missing on the destination object', 1, function() {
+ deepEqual(_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 }), { 'a': 1, 'b': 2 });
+ });
+
+ test('should accept multiple source objects', 2, function() {
+ var expected = { 'a': 1, 'b': 2, 'c': 3 };
+ deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 }), expected);
+ deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 }), expected);
+ });
+
+ test('should not overwrite `null` values', 1, function() {
+ var actual = _.defaults({ 'a': null }, { 'a': 1 });
+ strictEqual(actual.a, null);
+ });
+
+ test('should overwrite `undefined` values', 1, function() {
+ var actual = _.defaults({ 'a': undefined }, { 'a': 1 });
+ strictEqual(actual.a, 1);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.defer');
+
+ (function() {
+ asyncTest('should defer `func` execution', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var pass = false;
+ _.defer(function() { pass = true; });
+
+ setTimeout(function() {
+ ok(pass);
+ QUnit.start();
+ }, 128);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should accept additional arguments', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var args;
+
+ _.defer(function() {
+ args = slice.call(arguments);
+ }, 1, 2, 3);
+
+ setTimeout(function() {
+ deepEqual(args, [1, 2, 3]);
+ QUnit.start();
+ }, 128);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should be cancelable', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var pass = true;
+
+ var timerId = _.defer(function() {
+ pass = false;
+ });
+
+ clearTimeout(timerId);
+
+ setTimeout(function() {
+ ok(pass);
+ QUnit.start();
+ }, 128);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.delay');
+
+ (function() {
+ asyncTest('should delay `func` execution', 2, function() {
+ if (!(isRhino && isModularize)) {
+ var pass = false;
+ _.delay(function() { pass = true; }, 96);
+
+ setTimeout(function() {
+ ok(!pass);
+ }, 32);
+
+ setTimeout(function() {
+ ok(pass);
+ QUnit.start();
+ }, 160);
+ }
+ else {
+ skipTest(2);
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should accept additional arguments', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var args;
+
+ _.delay(function() {
+ args = slice.call(arguments);
+ }, 32, 1, 2, 3);
+
+ setTimeout(function() {
+ deepEqual(args, [1, 2, 3]);
+ QUnit.start();
+ }, 128);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+
+ asyncTest('should be cancelable', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var pass = true;
+
+ var timerId = _.delay(function() {
+ pass = false;
+ }, 32);
+
+ clearTimeout(timerId);
+
+ setTimeout(function() {
+ ok(pass);
+ QUnit.start();
+ }, 128);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.difference');
+
+ (function() {
+ var args = arguments;
+
+ test('should return the difference of the given arrays', 2, function() {
+ var actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
+ deepEqual(actual, [1, 3, 4]);
+
+ actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10], [8, 4]);
+ deepEqual(actual, [1, 3]);
+ });
+
+ test('should match `NaN`', 1, function() {
+ deepEqual(_.difference([1, NaN, 3], [NaN, 5, NaN]), [1, 3]);
+ });
+
+ test('should work with large arrays', 1, function() {
+ var array1 = _.range(LARGE_ARRAY_SIZE + 1),
+ array2 = _.range(LARGE_ARRAY_SIZE),
+ a = {},
+ b = {},
+ c = {};
+
+ array1.push(a, b, c);
+ array2.push(b, c, a);
+
+ deepEqual(_.difference(array1, array2), [LARGE_ARRAY_SIZE]);
+ });
+
+ test('should work with large arrays of objects', 1, function() {
+ var object1 = {},
+ object2 = {},
+ largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(object1));
+
+ deepEqual(_.difference([object1, object2], largeArray), [object2]);
+ });
+
+ test('should work with large arrays of `NaN`', 1, function() {
+ var largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(NaN));
+ deepEqual(_.difference([1, NaN, 3], largeArray), [1, 3]);
+ });
+
+ test('should ignore values that are not arrays or `arguments` objects', 3, function() {
+ var array = [0, 1, null, 3];
+ deepEqual(_.difference(array, 3, null, { '0': 1 }), array);
+ deepEqual(_.difference(null, array, null, [2, 1]), [0, null, 3]);
+ deepEqual(_.difference(null, array, null, args), [0, null]);
+ });
+ }(1, 2, 3));
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.drop');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ test('should drop the first two elements', 1, function() {
+ deepEqual(_.drop(array, 2), [3]);
+ });
+
+ test('should treat falsey `n` values, except nullish, as `0`', 1, function() {
+ var expected = _.map(falsey, function(value) {
+ return value == null ? [2, 3] : array;
+ });
+
+ var actual = _.map(falsey, function(n) {
+ return _.drop(array, n);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return all elements when `n` < `1`', 3, function() {
+ _.each([0, -1, -Infinity], function(n) {
+ deepEqual(_.drop(array, n), array);
+ });
+ });
+
+ test('should return an empty array when `n` >= `array.length`', 4, function() {
+ _.each([3, 4, Math.pow(2, 32), Infinity], function(n) {
+ deepEqual(_.drop(array, n), []);
+ });
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ actual = _.map(array, _.drop);
+
+ deepEqual(actual, [[2, 3], [5, 6], [8, 9]]);
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).drop(2);
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [3]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+
+ test('should work in a lazy chain sequence', 4, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3, 4, 5, 6, 7, 8],
+ predicate = function(value) { return value > 1; },
+ actual = _(array).drop(2).drop().value();
+
+ deepEqual(actual, [4, 5, 6, 7, 8]);
+
+ actual = _(array).filter(predicate).drop(2).drop().value();
+ deepEqual(actual, [5, 6, 7, 8]);
+
+ actual = _(array).drop(2).dropRight().drop().dropRight(2).value();
+ deepEqual(actual, [4, 5]);
+
+ actual = _(array).filter(predicate).drop(2).dropRight().drop().dropRight(2).value();
+ deepEqual(actual, [5]);
+ }
+ else {
+ skipTest(4);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.dropRight');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ test('should drop the last two elements', 1, function() {
+ deepEqual(_.dropRight(array, 2), [1]);
+ });
+
+ test('should treat falsey `n` values, except nullish, as `0`', 1, function() {
+ var expected = _.map(falsey, function(value) {
+ return value == null ? [1, 2] : array;
+ });
+
+ var actual = _.map(falsey, function(n) {
+ return _.dropRight(array, n);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return all elements when `n` < `1`', 3, function() {
+ _.each([0, -1, -Infinity], function(n) {
+ deepEqual(_.dropRight(array, n), array);
+ });
+ });
+
+ test('should return an empty array when `n` >= `array.length`', 4, function() {
+ _.each([3, 4, Math.pow(2, 32), Infinity], function(n) {
+ deepEqual(_.dropRight(array, n), []);
+ });
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ actual = _.map(array, _.dropRight);
+
+ deepEqual(actual, [[1, 2], [4, 5], [7, 8]]);
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).dropRight(2);
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [1]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+
+ test('should work in a lazy chain sequence', 4, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3, 4, 5, 6, 7, 8],
+ predicate = function(value) { return value < 8; },
+ actual = _(array).dropRight(2).dropRight().value();
+
+ deepEqual(actual, [1, 2, 3, 4, 5]);
+
+ actual = _(array).filter(predicate).dropRight(2).dropRight().value();
+ deepEqual(actual, [1, 2, 3, 4]);
+
+ actual = _(array).dropRight(2).drop().dropRight().drop(2).value();
+ deepEqual(actual, [4, 5]);
+
+ actual = _(array).filter(predicate).dropRight(2).drop().dropRight().drop(2).value();
+ deepEqual(actual, [4]);
+ }
+ else {
+ skipTest(4);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.dropRightWhile');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ var objects = [
+ { 'a': 0, 'b': 0 },
+ { 'a': 1, 'b': 1 },
+ { 'a': 2, 'b': 2 }
+ ];
+
+ test('should drop elements while `predicate` returns truthy', 1, function() {
+ var actual = _.dropRightWhile(array, function(num) {
+ return num > 1;
+ });
+
+ deepEqual(actual, [1]);
+ });
+
+ test('should provide the correct `predicate` arguments', 1, function() {
+ var args;
+
+ _.dropRightWhile(array, function() {
+ args = slice.call(arguments);
+ });
+
+ deepEqual(args, [3, 2, array]);
+ });
+
+ test('should support the `thisArg` argument', 1, function() {
+ var actual = _.dropRightWhile(array, function(num, index) {
+ return this[index] > 1;
+ }, array);
+
+ deepEqual(actual, [1]);
+ });
+
+ test('should work with a "_.pluck" style `predicate`', 1, function() {
+ deepEqual(_.dropRightWhile(objects, 'b'), objects.slice(0, 1));
+ });
+
+ test('should work with a "_.where" style `predicate`', 1, function() {
+ deepEqual(_.dropRightWhile(objects, { 'b': 2 }), objects.slice(0, 2));
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).dropRightWhile(function(num) {
+ return num > 1;
+ });
+
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [1]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.dropWhile');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ var objects = [
+ { 'a': 2, 'b': 2 },
+ { 'a': 1, 'b': 1 },
+ { 'a': 0, 'b': 0 }
+ ];
+
+ test('should drop elements while `predicate` returns truthy', 1, function() {
+ var actual = _.dropWhile(array, function(num) {
+ return num < 3;
+ });
+
+ deepEqual(actual, [3]);
+ });
+
+ test('should provide the correct `predicate` arguments', 1, function() {
+ var args;
+
+ _.dropWhile(array, function() {
+ args = slice.call(arguments);
+ });
+
+ deepEqual(args, [1, 0, array]);
+ });
+
+ test('should support the `thisArg` argument', 1, function() {
+ var actual = _.dropWhile(array, function(num, index) {
+ return this[index] < 3;
+ }, array);
+
+ deepEqual(actual, [3]);
+ });
+
+ test('should work with a "_.pluck" style `predicate`', 1, function() {
+ deepEqual(_.dropWhile(objects, 'b'), objects.slice(2));
+ });
+
+ test('should work with a "_.where" style `predicate`', 1, function() {
+ deepEqual(_.dropWhile(objects, { 'b': 2 }), objects.slice(1));
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).dropWhile(function(num) {
+ return num < 3;
+ });
+
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [3]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.endsWith');
+
+ (function() {
+ var string = 'abc';
+
+ test('should return `true` if a string ends with `target`', 1, function() {
+ strictEqual(_.endsWith(string, 'c'), true);
+ });
+
+ test('should return `false` if a string does not end with `target`', 1, function() {
+ strictEqual(_.endsWith(string, 'b'), false);
+ });
+
+ test('should work with a `position` argument', 1, function() {
+ strictEqual(_.endsWith(string, 'b', 2), true);
+ });
+
+ test('should work with `position` >= `string.length`', 4, function() {
+ _.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) {
+ strictEqual(_.endsWith(string, 'c', position), true);
+ });
+ });
+
+ test('should treat falsey `position` values, except `undefined`, as `0`', 1, function() {
+ var expected = _.map(falsey, _.constant(true));
+
+ var actual = _.map(falsey, function(position) {
+ return _.endsWith(string, position === undefined ? 'c' : '', position);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should treat a negative `position` as `0`', 6, function() {
+ _.each([-1, -3, -Infinity], function(position) {
+ ok(_.every(string, function(chr) {
+ return _.endsWith(string, chr, position) === false;
+ }));
+ strictEqual(_.endsWith(string, '', position), true);
+ });
+ });
+
+ test('should return `true` when `target` is an empty string regardless of `position`', 1, function() {
+ ok(_.every([-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity], function(position) {
+ return _.endsWith(string, '', position, true);
+ }));
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.escape');
+
+ (function() {
+ var escaped = '&<>"'`\/',
+ unescaped = '&<>"\'`\/';
+
+ escaped += escaped;
+ unescaped += unescaped;
+
+ test('should escape values', 1, function() {
+ strictEqual(_.escape(unescaped), escaped);
+ });
+
+ test('should not escape the "/" character', 1, function() {
+ strictEqual(_.escape('/'), '/');
+ });
+
+ test('should handle strings with nothing to escape', 1, function() {
+ strictEqual(_.escape('abc'), 'abc');
+ });
+
+ test('should escape the same characters unescaped by `_.unescape`', 1, function() {
+ strictEqual(_.escape(_.unescape(escaped)), escaped);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.escapeRegExp');
+
+ (function() {
+ var escaped = '\\.\\*\\+\\?\\^\\$\\{\\}\\(\\)\\|\\[\\]\\/\\\\',
+ unescaped = '.*+?^${}()|[\]\/\\';
+
+ escaped += escaped;
+ unescaped += unescaped;
+
+ test('should escape values', 1, function() {
+ strictEqual(_.escapeRegExp(unescaped), escaped);
+ });
+
+ test('should handle strings with nothing to escape', 1, function() {
+ strictEqual(_.escapeRegExp('abc'), 'abc');
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.every');
+
+ (function() {
+ test('should return `true` for empty collections', 1, function() {
+ var expected = _.map(empties, _.constant(true));
+
+ var actual = _.map(empties, function(value) {
+ try {
+ return _.every(value, _.identity);
+ } catch(e) {}
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return `true` if `predicate` returns truthy for all elements in the collection', 1, function() {
+ strictEqual(_.every([true, 1, 'a'], _.identity), true);
+ });
+
+ test('should return `false` as soon as `predicate` returns falsey', 1, function() {
+ strictEqual(_.every([true, null, true], _.identity), false);
+ });
+
+ test('should work with collections of `undefined` values (test in IE < 9)', 1, function() {
+ strictEqual(_.every([undefined, undefined, undefined], _.identity), false);
+ });
+
+ test('should work with a "_.pluck" style `predicate`', 2, function() {
+ var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }];
+ strictEqual(_.every(objects, 'a'), false);
+ strictEqual(_.every(objects, 'b'), true);
+ });
+
+ test('should work with a "_where" style `predicate`', 2, function() {
+ var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }];
+ strictEqual(_.every(objects, { 'a': 0 }), true);
+ strictEqual(_.every(objects, { 'b': 1 }), false);
+ });
+
+ test('should use `_.identity` when `predicate` is nullish', 2, function() {
+ var values = [, null, undefined],
+ expected = _.map(values, _.constant(false));
+
+ var actual = _.map(values, function(value, index) {
+ var array = [0];
+ return index ? _.every(array, value) : _.every(array);
+ });
+
+ deepEqual(actual, expected);
+
+ expected = _.map(values, _.constant(true));
+ actual = _.map(values, function(value, index) {
+ var array = [1];
+ return index ? _.every(array, value) : _.every(array);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should be aliased', 1, function() {
+ strictEqual(_.all, _.every);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('strict mode checks');
+
+ _.each(['assign', 'bindAll', 'defaults'], function(methodName) {
+ var func = _[methodName];
+
+ test('`_.' + methodName + '` should ' + (isStrict ? '' : 'not ') + 'throw strict mode errors', 1, function() {
+ if (freeze) {
+ var object = { 'a': undefined, 'b': function() {} },
+ pass = !isStrict;
+
+ freeze(object);
+ try {
+ if (methodName == 'bindAll') {
+ func(object);
+ } else {
+ func(object, { 'a': 1 });
+ }
+ } catch(e) {
+ pass = !pass;
+ }
+ ok(pass);
+ }
+ else {
+ skipTest();
+ }
+ });
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.filter');
+
+ (function() {
+ test('should return elements `predicate` returns truthy for', 1, function() {
+ var actual = _.filter([1, 2, 3], function(num) {
+ return num % 2;
+ });
+
deepEqual(actual, [1, 3]);
});
- test('should not modify wrapped values', 2, function() {
- if (!isNpm) {
- var wrapped = _([1, 2, 3, 4]);
+ test('should iterate correctly over an object with numeric keys (test in Mobile Safari 8)', 1, function() {
+ // Trigger a Mobile Safari 8 JIT bug.
+ // See https://github.com/lodash/lodash/issues/799.
+ var counter = 0,
+ object = { '1': 'foo', '8': 'bar', '50': 'baz' };
+
+ _.times(1000, function() {
+ _.filter([], _.constant(true));
+ });
+
+ _.filter(object, function() {
+ counter++;
+ return true;
+ });
+
+ strictEqual(counter, 3);
+ });
+
+ test('should be aliased', 1, function() {
+ strictEqual(_.select, _.filter);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ _.each(['find', 'findLast', 'findIndex', 'findLastIndex', 'findKey', 'findLastKey'], function(methodName) {
+ QUnit.module('lodash.' + methodName);
+
+ var func = _[methodName];
+
+ (function() {
+ var objects = [
+ { 'a': 0, 'b': 0 },
+ { 'a': 1, 'b': 1 },
+ { 'a': 2, 'b': 2 }
+ ];
+
+ var expected = ({
+ 'find': [objects[1], undefined, objects[2], objects[1]],
+ 'findLast': [objects[2], undefined, objects[2], objects[2]],
+ 'findIndex': [1, -1, 2, 1],
+ 'findLastIndex': [2, -1, 2, 2],
+ 'findKey': ['1', undefined, '2', '1'],
+ 'findLastKey': ['2', undefined, '2', '2']
+ })[methodName];
+
+ test('should return the correct value', 1, function() {
+ strictEqual(func(objects, function(object) { return object.a; }), expected[0]);
+ });
+
+ test('should work with a `thisArg`', 1, function() {
+ strictEqual(func(objects, function(object, index) { return this[index].a; }, objects), expected[0]);
+ });
+
+ test('should return `' + expected[1] + '` if value is not found', 1, function() {
+ strictEqual(func(objects, function(object) { return object.a === 3; }), expected[1]);
+ });
+
+ test('should work with a "_.pluck" style `predicate`', 1, function() {
+ strictEqual(func(objects, 'b'), expected[3]);
+ });
+
+ test('should work with a "_.where" style `predicate`', 1, function() {
+ strictEqual(func(objects, { 'b': 2 }), expected[2]);
+ });
+
+ test('should return `' + expected[1] + '` for empty collections', 1, function() {
+ var actual = [],
+ emptyValues = _.endsWith(methodName, 'Index') ? _.reject(empties, _.isPlainObject) : empties,
+ expecting = _.map(emptyValues, function() { return expected[1]; });
+
+ _.each(emptyValues, function(value) {
+ try {
+ actual.push(func(value, { 'a': 3 }));
+ } catch(e) {}
+ });
+
+ deepEqual(actual, expecting);
+ });
+ }());
+
+ (function() {
+ var expected = ({
+ 'find': 1,
+ 'findLast': 2,
+ 'findKey': 'a',
+ 'findLastKey': 'b'
+ })[methodName];
+
+ if (expected != null) {
+ test('should work with an object for `collection`', 1, function() {
+ var actual = func({ 'a': 1, 'b': 2, 'c': 3 }, function(num) {
+ return num < 3;
+ });
+
+ strictEqual(actual, expected);
+ });
+ }
+ }());
+
+ (function() {
+ var expected = ({
+ 'find': 'a',
+ 'findLast': 'b',
+ 'findIndex': 0,
+ 'findLastIndex': 1
+ })[methodName];
+
+ if (expected != null) {
+ test('should work with a string for `collection`', 1, function() {
+ var actual = func('abc', function(chr, index) {
+ return index < 2;
+ });
+
+ strictEqual(actual, expected);
+ });
+ }
+ if (methodName == 'find') {
+ test('should be aliased', 1, function() {
+ strictEqual(_.detect, func);
+ });
+ }
+ }());
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.findWhere');
+
+ (function() {
+ var objects = [
+ { 'a': 1 },
+ { 'a': 1 },
+ { 'a': 1, 'b': 2 },
+ { 'a': 2, 'b': 2 },
+ { 'a': 3 }
+ ];
+
+ test('should filter by `source` properties', 6, function() {
+ strictEqual(_.findWhere(objects, { 'a': 1 }), objects[0]);
+ strictEqual(_.findWhere(objects, { 'a': 2 }), objects[3]);
+ strictEqual(_.findWhere(objects, { 'a': 3 }), objects[4]);
+ strictEqual(_.findWhere(objects, { 'b': 1 }), undefined);
+ strictEqual(_.findWhere(objects, { 'b': 2 }), objects[2]);
+ strictEqual(_.findWhere(objects, { 'a': 1, 'b': 2 }), objects[2]);
+ });
+
+ test('should work with a function for `source`', 1, function() {
+ function source() {}
+ source.a = 2;
+
+ strictEqual(_.findWhere(objects, source), objects[3]);
+ });
+
+ test('should match all elements when provided an empty `source`', 1, function() {
+ var expected = _.map(empties, _.constant(true));
+
+ var actual = _.map(empties, function(value) {
+ return _.findWhere(objects, value) === objects[0];
+ });
+
+ deepEqual(actual, expected);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.first');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ test('should return the first element', 1, function() {
+ strictEqual(_.first(array), 1);
+ });
+
+ test('should return `undefined` when querying empty arrays', 1, function() {
+ var array = [];
+ array['-1'] = 1;
+ strictEqual(_.first(array), undefined);
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ actual = _.map(array, _.first);
+
+ deepEqual(actual, [1, 4, 7]);
+ });
+
+ test('should return an unwrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ strictEqual(_(array).first(), 1);
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ test('should work in a lazy chain sequence', 1, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3, 4];
+
+ var wrapped = _(array).filter(function(value) {
+ return value % 2 == 0;
+ });
+
+ strictEqual(wrapped.first(), 2);
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ test('should be aliased', 1, function() {
+ strictEqual(_.head, _.first);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.take');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ test('should take the first two elements', 1, function() {
+ deepEqual(_.take(array, 2), [1, 2]);
+ });
+
+ test('should treat falsey `n` values, except nullish, as `0`', 1, function() {
+ var expected = _.map(falsey, function(value) {
+ return value == null ? [1] : [];
+ });
+
+ var actual = _.map(falsey, function(n) {
+ return _.take(array, n);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return an empty array when `n` < `1`', 3, function() {
+ _.each([0, -1, -Infinity], function(n) {
+ deepEqual(_.take(array, n), []);
+ });
+ });
+
+ test('should return all elements when `n` >= `array.length`', 4, function() {
+ _.each([3, 4, Math.pow(2, 32), Infinity], function(n) {
+ deepEqual(_.take(array, n), array);
+ });
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ actual = _.map(array, _.take);
+
+ deepEqual(actual, [[1], [4], [7]]);
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).take(2);
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [1, 2]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+
+ test('should work in a lazy chain sequence', 4, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3, 4, 5, 6, 7, 8],
+ predicate = function(value) { return value > 1; },
+ actual = _(array).take(2).take().value();
+
+ deepEqual(actual, [1]);
+
+ actual = _(array).filter(predicate).take(2).take().value();
+ deepEqual(actual, [2]);
+
+ actual = _(array).take(6).takeRight(4).take(2).takeRight().value();
+ deepEqual(actual, [4]);
+
+ actual = _(array).filter(predicate).take(6).takeRight(4).take(2).takeRight().value();
+ deepEqual(actual, [5]);
+ }
+ else {
+ skipTest(4);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.takeRight');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ test('should take the last two elements', 1, function() {
+ deepEqual(_.takeRight(array, 2), [2, 3]);
+ });
+
+ test('should treat falsey `n` values, except nullish, as `0`', 1, function() {
+ var expected = _.map(falsey, function(value) {
+ return value == null ? [3] : [];
+ });
+
+ var actual = _.map(falsey, function(n) {
+ return _.takeRight(array, n);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return an empty array when `n` < `1`', 3, function() {
+ _.each([0, -1, -Infinity], function(n) {
+ deepEqual(_.takeRight(array, n), []);
+ });
+ });
+
+ test('should return all elements when `n` >= `array.length`', 4, function() {
+ _.each([3, 4, Math.pow(2, 32), Infinity], function(n) {
+ deepEqual(_.takeRight(array, n), array);
+ });
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ actual = _.map(array, _.takeRight);
+
+ deepEqual(actual, [[3], [6], [9]]);
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).takeRight(2);
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [2, 3]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+
+ test('should work in a lazy chain sequence', 4, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3, 4, 5, 6, 7, 8],
+ predicate = function(value) { return value < 8; },
+ actual = _(array).takeRight(2).takeRight().value();
+
+ deepEqual(actual, [8]);
+
+ actual = _(array).filter(predicate).takeRight(2).takeRight().value();
+ deepEqual(actual, [7]);
+
+ actual = _(array).takeRight(6).take(4).takeRight(2).take().value();
+ deepEqual(actual, [5]);
+
+ actual = _(array).filter(predicate).takeRight(6).take(4).takeRight(2).take().value();
+ deepEqual(actual, [4]);
+ }
+ else {
+ skipTest(4);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.takeRightWhile');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ var objects = [
+ { 'a': 0, 'b': 0 },
+ { 'a': 1, 'b': 1 },
+ { 'a': 2, 'b': 2 }
+ ];
+
+ test('should take elements while `predicate` returns truthy', 1, function() {
+ var actual = _.takeRightWhile(array, function(num) {
+ return num > 1;
+ });
+
+ deepEqual(actual, [2, 3]);
+ });
+
+ test('should provide the correct `predicate` arguments', 1, function() {
+ var args;
+
+ _.takeRightWhile(array, function() {
+ args = slice.call(arguments);
+ });
+
+ deepEqual(args, [3, 2, array]);
+ });
+
+ test('should support the `thisArg` argument', 1, function() {
+ var actual = _.takeRightWhile(array, function(num, index) {
+ return this[index] > 1;
+ }, array);
+
+ deepEqual(actual, [2, 3]);
+ });
+
+ test('should work with a "_.pluck" style `predicate`', 1, function() {
+ deepEqual(_.takeRightWhile(objects, 'b'), objects.slice(1));
+ });
+
+ test('should work with a "_.where" style `predicate`', 1, function() {
+ deepEqual(_.takeRightWhile(objects, { 'b': 2 }), objects.slice(2));
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).takeRightWhile(function(num) {
+ return num > 1;
+ });
+
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [2, 3]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.takeWhile');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ var objects = [
+ { 'a': 2, 'b': 2 },
+ { 'a': 1, 'b': 1 },
+ { 'a': 0, 'b': 0 }
+ ];
+
+ test('should take elements while `predicate` returns truthy', 1, function() {
+ var actual = _.takeWhile(array, function(num) {
+ return num < 3;
+ });
+
+ deepEqual(actual, [1, 2]);
+ });
+
+ test('should provide the correct `predicate` arguments', 1, function() {
+ var args;
+
+ _.takeWhile(array, function() {
+ args = slice.call(arguments);
+ });
+
+ deepEqual(args, [1, 0, array]);
+ });
+
+ test('should support the `thisArg` argument', 1, function() {
+ var actual = _.takeWhile(array, function(num, index) {
+ return this[index] < 3;
+ }, array);
+
+ deepEqual(actual, [1, 2]);
+ });
+
+ test('should work with a "_.pluck" style `predicate`', 1, function() {
+ deepEqual(_.takeWhile(objects, 'b'), objects.slice(0, 2));
+ });
+
+ test('should work with a "_.where" style `predicate`', 1, function() {
+ deepEqual(_.takeWhile(objects, { 'b': 2 }), objects.slice(0, 1));
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).takeWhile(function(num) {
+ return num < 3;
+ });
+
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [1, 2]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('flatten methods');
+
+ (function() {
+ var args = arguments;
+
+ test('should perform a shallow flatten', 1, function() {
+ var array = [[['a']], [['b']]];
+ deepEqual(_.flatten(array), [['a'], ['b']]);
+ });
+
+ test('should work with `isDeep`', 2, function() {
+ var array = [[['a']], [['b']]],
+ expected = ['a', 'b'];
+
+ deepEqual(_.flatten(array, true), expected);
+ deepEqual(_.flattenDeep(array), expected);
+ });
+
+ test('should flatten `arguments` objects', 3, function() {
+ var array = [args, [args]],
+ expected = [1, 2, 3, args];
+
+ deepEqual(_.flatten(array), expected);
+
+ expected = [1, 2, 3, 1, 2, 3];
+ deepEqual(_.flatten(array, true), expected);
+ deepEqual(_.flattenDeep(array), expected);
+ });
+
+ test('should work as an iteratee for `_.map`', 2, function() {
+ var array = [[[['a']]], [[['b']]]];
+
+ deepEqual(_.map(array, _.flatten), [[['a']], [['b']]]);
+ deepEqual(_.map(array, _.flattenDeep), [['a'], ['b']]);
+ });
+
+ test('should treat sparse arrays as dense', 6, function() {
+ var array = [[1, 2, 3], Array(3)],
+ expected = [1, 2, 3];
+
+ expected.push(undefined, undefined, undefined);
+
+ _.each([_.flatten(array), _.flatten(array, true), _.flattenDeep(array)], function(actual) {
+ deepEqual(actual, expected);
+ ok('4' in actual);
+ });
+ });
+
+ test('should work with extremely large arrays', 3, function() {
+ // Test in modern browsers only to avoid browser hangs.
+ _.times(3, function(index) {
+ if (freeze) {
+ var expected = Array(5e5);
+
+ try {
+ if (index) {
+ var actual = actual == 1 ? _.flatten([expected], true) : _.flattenDeep([expected]);
+ } else {
+ actual = _.flatten(expected);
+ }
+ deepEqual(actual, expected);
+ } catch(e) {
+ ok(false, e.message);
+ }
+ }
+ else {
+ skipTest();
+ }
+ });
+ });
+
+ test('should work with empty arrays', 3, function() {
+ var array = [[], [[]], [[], [[[]]]]],
+ expected = [[], [], [[[]]]];
+
+ deepEqual(_.flatten(array), expected);
+
+ expected = [];
+ deepEqual(_.flatten(array, true), expected);
+ deepEqual(_.flattenDeep(array), expected);
+ });
+
+ test('should support flattening of nested arrays', 3, function() {
+ var array = [1, [2], [3, [4]]],
+ expected = [1, 2, 3, [4]];
+
+ deepEqual(_.flatten(array), expected);
+
+ expected = [1, 2, 3, 4];
+ deepEqual(_.flatten(array, true), expected);
+ deepEqual(_.flattenDeep(array), expected);
+ });
+
+ test('should return an empty array for non array-like objects', 3, function() {
+ var expected = [];
+
+ deepEqual(_.flatten({ 'a': 1 }), expected);
+ deepEqual(_.flatten({ 'a': 1 }, true), expected);
+ deepEqual(_.flattenDeep({ 'a': 1 }), expected);
+ });
+
+ test('should return a wrapped value when chaining', 6, function() {
+ if (!isNpm) {
+ var wrapped = _([1, [2], [3, [4]]]),
+ actual = wrapped.flatten(),
+ expected = [1, 2, 3, [4]];
+
+ ok(actual instanceof _);
+ deepEqual(actual.value(), expected);
+
+ expected = [1, 2, 3, 4];
+ actual = wrapped.flatten(true);
+
+ ok(actual instanceof _);
+ deepEqual(actual.value(), expected);
+
+ actual = wrapped.flattenDeep();
+
+ ok(actual instanceof _);
+ deepEqual(actual.value(), expected);
+ }
+ else {
+ skipTest(6);
+ }
+ });
+ }(1, 2, 3));
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.forEach');
+
+ (function() {
+ test('should be aliased', 1, function() {
+ strictEqual(_.each, _.forEach);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.forEachRight');
+
+ (function() {
+ test('should be aliased', 1, function() {
+ strictEqual(_.eachRight, _.forEachRight);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('forIn methods');
+
+ _.each(['forIn', 'forInRight'], function(methodName) {
+ var func = _[methodName];
+
+ test('`_.' + methodName + '` iterates over inherited properties', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
+
+ var keys = [];
+ func(new Foo, function(value, key) { keys.push(key); });
+ deepEqual(keys.sort(), ['a', 'b']);
+ });
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('forOwn methods');
+
+ _.each(['forOwn', 'forOwnRight'], function(methodName) {
+ var func = _[methodName];
+
+ test('iterates over the `length` property', 1, function() {
+ var object = { '0': 'zero', '1': 'one', 'length': 2 },
+ props = [];
+
+ func(object, function(value, prop) { props.push(prop); });
+ deepEqual(props.sort(), ['0', '1', 'length']);
+ });
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('iteration methods');
+
+ (function() {
+ var methods = [
+ 'countBy',
+ 'every',
+ 'filter',
+ 'find',
+ 'findIndex',
+ 'findKey',
+ 'findLast',
+ 'findLastIndex',
+ 'findLastKey',
+ 'forEachRight',
+ 'forIn',
+ 'forInRight',
+ 'forOwn',
+ 'forOwnRight',
+ 'groupBy',
+ 'indexBy',
+ 'map',
+ 'max',
+ 'min',
+ 'partition',
+ 'reject',
+ 'some'
+ ];
+
+ var arrayMethods = [
+ 'findIndex',
+ 'findLastIndex'
+ ];
+
+ var collectionMethods = [
+ 'countBy',
+ 'every',
+ 'filter',
+ 'find',
+ 'findLast',
+ 'forEach',
+ 'forEachRight',
+ 'groupBy',
+ 'indexBy',
+ 'map',
+ 'max',
+ 'min',
+ 'partition',
+ 'reduce',
+ 'reduceRight',
+ 'reject',
+ 'some'
+ ];
+
+ var forInMethods = [
+ 'forIn',
+ 'forInRight'
+ ];
+
+ var iterationMethods = [
+ 'forEach',
+ 'forEachRight',
+ 'forIn',
+ 'forInRight',
+ 'forOwn',
+ 'forOwnRight'
+ ]
+
+ var objectMethods = [
+ 'findKey',
+ 'findLastKey',
+ 'forIn',
+ 'forInRight',
+ 'forOwn',
+ 'forOwnRight'
+ ];
+
+ var rightMethods = [
+ 'findLast',
+ 'findLastIndex',
+ 'findLastKey',
+ 'forEachRight',
+ 'forInRight',
+ 'forOwnRight'
+ ];
+
+ var unwrappedMethods = [
+ 'every',
+ 'find',
+ 'findIndex',
+ 'findKey',
+ 'findLast',
+ 'findLastIndex',
+ 'findLastKey',
+ 'max',
+ 'min',
+ 'some'
+ ];
+
+ _.each(methods, function(methodName) {
+ var array = [1, 2, 3],
+ func = _[methodName];
+
+ test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() {
+ var args,
+ expected = [1, 0, array];
+
+ func(array, function() {
+ args || (args = slice.call(arguments));
+ });
+
+ if (_.includes(rightMethods, methodName)) {
+ expected[0] = 3;
+ expected[1] = 2;
+ }
+ if (_.includes(objectMethods, methodName)) {
+ expected[1] += '';
+ }
+ deepEqual(args, expected);
+ });
+
+ test('`_.' + methodName + '` should support the `thisArg` argument', 2, function() {
+ var actual;
+
+ function callback(num, index) {
+ actual = this[index];
+ }
+ func([1], callback, [2]);
+ strictEqual(actual, 2);
+
+ func({ 'a': 1 }, callback, { 'a': 2 });
+ strictEqual(actual, 2);
+ });
+ });
+
+ _.each(_.difference(methods, objectMethods), function(methodName) {
+ var array = [1, 2, 3],
+ func = _[methodName],
+ isEvery = methodName == 'every';
+
+ array.a = 1;
+
+ test('`_.' + methodName + '` should not iterate custom properties on arrays', 1, function() {
+ var keys = [];
+ func(array, function(value, key) {
+ keys.push(key);
+ return isEvery;
+ });
+
+ ok(!_.includes(keys, 'a'));
+ });
+ });
+
+ _.each(_.difference(methods, unwrappedMethods), function(methodName) {
+ var array = [1, 2, 3],
+ func = _[methodName];
+
+ test('`_.' + methodName + '` should return a wrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ var wrapped = _(array)[methodName](_.noop);
+ ok(wrapped instanceof _);
+ }
+ else {
+ skipTest();
+ }
+ });
+ });
+
+ _.each(unwrappedMethods, function(methodName) {
+ var array = [1, 2, 3],
+ func = _[methodName];
+
+ test('`_.' + methodName + '` should return an unwrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ var wrapped = _(array)[methodName](_.noop);
+ ok(!(wrapped instanceof _));
+ }
+ else {
+ skipTest();
+ }
+ });
+ });
+
+ _.each(_.difference(methods, arrayMethods, forInMethods), function(methodName) {
+ var array = [1, 2, 3],
+ func = _[methodName];
+
+ test('`_.' + methodName + '` iterates over own properties of objects', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
+
+ var keys = [];
+ func(new Foo, function(value, key) { keys.push(key); });
+ deepEqual(keys, ['a']);
+ });
+ });
+
+ _.each(iterationMethods, function(methodName) {
+ var array = [1, 2, 3],
+ func = _[methodName],
+ isEach = !_.includes(objectMethods, methodName),
+ isRight = _.includes(rightMethods, methodName);
+
+ test('`_.' + methodName + '` should return the collection', 1, function() {
+ strictEqual(func(array, Boolean), array);
+ });
+
+ test('`_.' + methodName + '` should not return the existing wrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ var wrapped = _(array);
+ notStrictEqual(wrapped[methodName](_.noop), wrapped);
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ _.each({
+ 'literal': 'abc',
+ 'object': Object('abc')
+ },
+ function(collection, key) {
+ test('`_.' + methodName + '` should work with a string ' + key + ' for `collection` (test in IE < 9)', 6, function() {
+ var args,
+ values = [],
+ expectedChars = ['a', 'b', 'c'];
+
+ var expectedArgs = isEach
+ ? (isRight ? ['c', 2, collection] : ['a', 0, collection])
+ : (isRight ? ['c', '2', collection] : ['a', '0', collection])
+
+ var actual = func(collection, function(value) {
+ args || (args = slice.call(arguments));
+ values.push(value);
+ });
+
+ var stringObject = args[2];
+
+ ok(_.isString(stringObject));
+ ok(_.isObject(stringObject));
+
+ deepEqual([stringObject[0], stringObject[1], stringObject[2]], expectedChars);
+ deepEqual(args, expectedArgs);
+ deepEqual(values, isRight ? ['c', 'b', 'a'] : expectedChars);
+
+ strictEqual(actual, collection);
+ });
+ });
+ });
+
+ _.each(collectionMethods, function(methodName) {
+ var func = _[methodName];
+
+ test('`_.' + methodName + '` should use `isLength` to determine whether a value is array-like', 2, function() {
+ function isIteratedAsObject(length) {
+ var result = false;
+ func({ 'length': length }, function() { result = true; }, 0);
+ return result;
+ }
+
+ var values = [-1, '1', 1.1, Object(1), MAX_SAFE_INTEGER + 1],
+ expected = _.map(values, _.constant(true)),
+ actual = _.map(values, isIteratedAsObject);
- var actual = wrapped.filter(function(num) {
- return num < 3;
- });
+ deepEqual(actual, expected);
+ ok(!isIteratedAsObject(0));
+ });
+ });
- deepEqual(actual.value(), [1, 2]);
+ _.each(collectionMethods.concat(objectMethods), function(methodName) {
+ var func = _[methodName];
- actual = wrapped.filter(function(num) {
- return num > 2;
- });
+ test('`_.' + methodName + '` should compute length before iteration', 2, function() {
+ _.each([[0], { 'a': 0 }], function(collection) {
+ var count = 0;
- deepEqual(actual.value(), [3, 4]);
- }
- else {
- skipTest(2);
- }
- });
+ func(collection, function() {
+ collection[++count] = count;
+ if (count > 1) {
+ return false;
+ }
+ }, 0);
- test('should be aliased', 1, function() {
- strictEqual(_.select, _.filter);
+ strictEqual(count, 1);
+ });
+ });
});
}());
/*--------------------------------------------------------------------------*/
- (function() {
- var objects = [
- { 'a': 0, 'b': 0 },
- { 'a': 1, 'b': 1 },
- { 'a': 2, 'b': 2 }
- ];
-
- _.forEach({
- 'find': [objects[1], undefined, objects[2], objects[1]],
- 'findLast': [objects[2], undefined, objects[2], objects[2]],
- 'findIndex': [1, -1, 2, 1],
- 'findLastIndex': [2, -1, 2, 2],
- 'findKey': ['1', undefined, '2', '1'],
- 'findLastKey': ['2', undefined, '2', '2']
- },
- function(expected, methodName) {
- QUnit.module('lodash.' + methodName);
-
- var func = _[methodName];
+ QUnit.module('collection iteration bugs');
- test('should return the correct value', 1, function() {
- strictEqual(func(objects, function(object) { return object.a; }), expected[0]);
- });
+ _.each(['forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight'], function(methodName) {
+ var func = _[methodName];
- test('should work with a `thisArg`', 1, function() {
- strictEqual(func(objects, function(object, index) { return this[index].a; }, objects), expected[0]);
- });
+ test('`_.' + methodName + '` fixes the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() {
+ var props = [];
+ func(shadowObject, function(value, prop) { props.push(prop); });
+ deepEqual(props.sort(), shadowProps);
+ });
- test('should return `' + expected[1] + '` if value is not found', 1, function() {
- strictEqual(func(objects, function(object) { return object.a == 3; }), expected[1]);
- });
+ test('`_.' + methodName + '` skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
+ function Foo() {}
+ Foo.prototype.a = 1;
- test('should work with an object for `collection`', 1, function() {
- var actual = _.find({ 'a': 1, 'b': 2, 'c': 3 }, function(num) {
- return num > 2;
- });
+ var props = [];
+ function callback(value, prop) { props.push(prop); }
- equal(actual, 3);
- });
+ func(Foo, callback);
+ deepEqual(props, []);
+ props.length = 0;
- test('should work with an object for `callback`', 1, function() {
- strictEqual(func(objects, { 'b': 2 }), expected[2]);
- });
+ Foo.prototype = { 'a': 1 };
+ func(Foo, callback);
+ deepEqual(props, []);
+ });
+ });
- test('should work with a string for `callback`', 1, function() {
- strictEqual(func(objects, 'b'), expected[3]);
- });
+ /*--------------------------------------------------------------------------*/
- test('should return `' + expected[1] + '` for empty or falsey collections', 1, function() {
- var actual = [],
- emptyValues = /Index/.test(methodName) ? _.reject(empties, _.isPlainObject) : empties,
- expecting = _.map(emptyValues, function() { return expected[1]; });
+ QUnit.module('object assignments');
- _.forEach(emptyValues, function(value) {
- try {
- actual.push(func(value, { 'a': 3 }));
- } catch(e) { }
- });
+ _.each(['assign', 'defaults', 'merge'], function(methodName) {
+ var func = _[methodName];
- deepEqual(actual, expecting);
+ test('`_.' + methodName + '` should pass thru falsey `object` values', 1, function() {
+ var actual = _.map(falsey, function(value, index) {
+ return index ? func(value) : func();
});
- if (methodName == 'find') {
- test('should be aliased', 2, function() {
- strictEqual(_.detect, func);
- strictEqual(_.findWhere, func);
- });
+ deepEqual(actual, falsey);
+ });
+
+ test('`_.' + methodName + '` should assign own source properties', 1, function() {
+ function Foo() {
+ this.a = 1;
+ this.c = 3;
}
+ Foo.prototype.b = 2;
+
+ deepEqual(func({}, new Foo), { 'a': 1, 'c': 3 });
});
- }());
- /*--------------------------------------------------------------------------*/
+ test('`_.' + methodName + '` should assign problem JScript properties (test in IE < 9)', 1, function() {
+ var object = {
+ 'constructor': '0',
+ 'hasOwnProperty': '1',
+ 'isPrototypeOf': '2',
+ 'propertyIsEnumerable': undefined,
+ 'toLocaleString': undefined,
+ 'toString': undefined,
+ 'valueOf': undefined
+ };
- QUnit.module('lodash.first');
+ var source = {
+ 'propertyIsEnumerable': '3',
+ 'toLocaleString': '4',
+ 'toString': '5',
+ 'valueOf': '6'
+ };
- (function() {
- var array = [1, 2, 3];
+ deepEqual(func(object, source), shadowObject);
+ });
- var objects = [
- { 'a': 2, 'b': 2 },
- { 'a': 1, 'b': 1 },
- { 'a': 0, 'b': 0 }
- ];
+ test('`_.' + methodName + '` skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
+ function Foo() {}
+ Foo.a = 1;
+ Foo.b = 2;
+ Foo.prototype.c = 3;
- test('should return the first element', 1, function() {
- strictEqual(_.first(array), 1);
+ var expected = { 'a': 1, 'b': 2 };
+ deepEqual(func({}, Foo), expected);
+
+ Foo.prototype = { 'c': 3 };
+ deepEqual(func({}, Foo), expected);
});
- test('should return the first two elements', 1, function() {
- deepEqual(_.first(array, 2), [1, 2]);
+ test('`_.' + methodName + '` should not error on nullish sources (test in IE < 9)', 1, function() {
+ try {
+ deepEqual(func({ 'a': 1 }, undefined, { 'b': 2 }, null), { 'a': 1, 'b': 2 });
+ } catch(e) {
+ ok(false, e.message);
+ }
});
- test('should return an empty array when `n` < `1`', 3, function() {
- _.forEach([0, -1, -2], function(n) {
- deepEqual(_.first(array, n), []);
+ test('`_.' + methodName + '` should not error when `object` is nullish and source objects are provided', 1, function() {
+ var expected = _.times(2, _.constant(true));
+
+ var actual = _.map([null, undefined], function(value) {
+ try {
+ return _.isEqual(func(value, { 'a': 1 }), value);
+ } catch(e) {
+ return false;
+ }
});
+
+ deepEqual(actual, expected);
});
- test('should return all elements when `n` >= `array.length`', 2, function() {
- _.forEach([3, 4], function(n) {
- deepEqual(_.first(array, n), array);
- });
+ test('`_.' + methodName + '` should work as an iteratee for `_.reduce`', 1, function() {
+ var array = [{ 'b': 2 }, { 'c': 3 }];
+ deepEqual(_.reduce(array, func, { 'a': 1}), { 'a': 1, 'b': 2, 'c': 3 });
});
- test('should return `undefined` when querying empty arrays', 1, function() {
- strictEqual(_.first([]), undefined);
+ test('`_.' + methodName + '` should not return the existing wrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ var wrapped = _({ 'a': 1 });
+ notStrictEqual(wrapped[methodName]({ 'b': 2 }), wrapped);
+ }
+ else {
+ skipTest();
+ }
});
+ });
- test('should work when used as `callback` for `_.map`', 1, function() {
- var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
- actual = _.map(array, _.first);
+ _.each(['assign', 'merge'], function(methodName, index) {
+ var func = _[methodName],
+ isMerge = !!index;
- deepEqual(actual, [1, 4, 7]);
- });
+ test('`_.' + methodName + '` should provide the correct `customizer` arguments', 3, function() {
+ var args,
+ object = { 'a': 1 },
+ source = { 'a': 2 };
- test('should work with a `callback`', 1, function() {
- var actual = _.first(array, function(num) {
- return num < 3;
+ func(object, source, function() {
+ args || (args = slice.call(arguments));
});
- deepEqual(actual, [1, 2]);
- });
+ deepEqual(args, [1, 2, 'a', object, source], 'primitive property values');
- test('should pass the correct `callback` arguments', 1, function() {
- var args;
+ args = null;
+ object = { 'a': 1 };
+ source = { 'b': 2 };
- _.first(array, function() {
+ func(object, source, function() {
args || (args = slice.call(arguments));
});
- deepEqual(args, [1, 0, array]);
+ deepEqual(args, [undefined, 2, 'b', object, source], 'missing destination property');
+
+ var argsList = [],
+ objectValue = [1, 2],
+ sourceValue = { 'b': 2 };
+
+ object = { 'a': objectValue };
+ source = { 'a': sourceValue };
+
+ func(object, source, function() {
+ argsList.push(slice.call(arguments));
+ });
+
+ var expected = [[objectValue, sourceValue, 'a', object, source]];
+ if (isMerge) {
+ expected.push([undefined, 2, 'b', sourceValue, sourceValue]);
+ }
+ deepEqual(argsList, expected, 'non-primitive property values');
});
- test('should support the `thisArg` argument', 1, function() {
- var actual = _.first(array, function(num, index) {
- return this[index] < 3;
- }, array);
+ test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() {
+ var actual = func({}, { 'a': 0 }, function(a, b) {
+ return this[b];
+ }, [2]);
- deepEqual(actual, [1, 2]);
+ deepEqual(actual, { 'a': 2 });
});
- test('should chain when passing `n`, `callback`, or `thisArg`', 3, function() {
- if (!isNpm) {
- var actual = _(array).first(2);
+ test('`_.' + methodName + '` should not treat the second argument as a `customizer` callback', 2, function() {
+ function callback() {}
+ callback.b = 2;
- ok(actual instanceof _);
+ var actual = func({ 'a': 1 }, callback);
+ deepEqual(actual, { 'a': 1, 'b': 2 });
- actual = _(array).first(function(num) {
- return num < 3;
- });
+ actual = func({ 'a': 1 }, callback, { 'c': 3 });
+ deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
+ });
- ok(actual instanceof _);
+ test('`_.' + methodName + '` should not assign the `customizer` result if it is the same as the destination value', 4, function() {
+ _.each(['a', ['a'], { 'a': 1 }, NaN], function(value) {
+ if (defineProperty) {
+ var object = {},
+ pass = true;
- actual = _(array).first(function(num, index) {
- return this[index] < 3;
- }, array);
+ defineProperty(object, 'a', {
+ 'get': _.constant(value),
+ 'set': function() { pass = false; }
+ });
- ok(actual instanceof _);
- }
- else {
- skipTest(3);
- }
+ func(object, { 'a': value }, _.identity);
+ ok(pass);
+ }
+ else {
+ skipTest();
+ }
+ });
});
+ });
- test('should not chain when arguments are not provided', 1, function() {
- if (!isNpm) {
- var actual = _(array).first();
- strictEqual(actual, 1);
- }
- else {
- skipTest();
- }
- });
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('exit early');
+
+ _.each(['_baseEach', 'forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'transform'], function(methodName) {
+ var func = _[methodName];
+ if (!func) {
+ return;
+ }
+ test('`_.' + methodName + '` can exit early when iterating arrays', 1, function() {
+ var array = [1, 2, 3],
+ values = [];
+
+ func(array, function(value, other) {
+ values.push(_.isArray(value) ? other : value);
+ return false;
+ });
- test('should work with an object for `callback`', 1, function() {
- deepEqual(_.first(objects, { 'b': 2 }), objects.slice(0, 1));
+ deepEqual(values, [_.endsWith(methodName, 'Right') ? 3 : 1]);
});
- test('should work with a string for `callback`', 1, function() {
- deepEqual(_.first(objects, 'b'), objects.slice(0, 2));
+ test('`_.' + methodName + '` can exit early when iterating objects', 1, function() {
+ var object = { 'a': 1, 'b': 2, 'c': 3 },
+ values = [];
+
+ func(object, function(value, other) {
+ values.push(_.isArray(value) ? other : value);
+ return false;
+ });
+
+ strictEqual(values.length, 1);
});
+ });
- test('should be aliased', 2, function() {
- strictEqual(_.head, _.first);
- strictEqual(_.take, _.first);
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('`__proto__` property bugs');
+
+ (function() {
+ test('internal data objects should work with the `__proto__` key', 4, function() {
+ var stringLiteral = '__proto__',
+ stringObject = Object(stringLiteral),
+ expected = [stringLiteral, stringObject];
+
+ var largeArray = _.times(LARGE_ARRAY_SIZE, function(count) {
+ return count % 2 ? stringObject : stringLiteral;
+ });
+
+ deepEqual(_.difference(largeArray, largeArray), []);
+ deepEqual(_.intersection(largeArray, largeArray), expected);
+ deepEqual(_.uniq(largeArray), expected);
+ deepEqual(_.without.apply(_, [largeArray].concat(largeArray)), []);
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.flatten');
+ QUnit.module('lodash.functions');
(function() {
- var args = arguments,
- array = [{ 'a': [1, [2]] }, { 'a': [3] }];
+ test('should return the function names of an object', 1, function() {
+ var object = { 'a': 'a', 'b': _.identity, 'c': /x/, 'd': _.each };
+ deepEqual(_.functions(object).sort(), ['b', 'd']);
+ });
+
+ test('should include inherited functions', 1, function() {
+ function Foo() {
+ this.a = _.identity;
+ this.b = 'b';
+ }
+ Foo.prototype.c = _.noop;
+ deepEqual(_.functions(new Foo).sort(), ['a', 'c']);
+ });
- test('should flatten `arguments` objects', 1, function() {
- var actual = _.flatten([args, args]);
- deepEqual(actual, [1, 2, 3, 1, 2, 3]);
+ test('should be aliased', 1, function() {
+ strictEqual(_.methods, _.functions);
});
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.groupBy');
- test('should work with a `callback`', 1, function() {
- var actual = _.flatten(array, function(object) {
- return object.a;
- });
+ (function() {
+ var array = [4.2, 6.1, 6.4];
- deepEqual(actual, [1, 2, 3]);
- });
+ test('should use `_.identity` when `iteratee` is nullish', 1, function() {
+ var array = [4, 6, 6],
+ values = [, null, undefined],
+ expected = _.map(values, _.constant({ '4': [4], '6': [6, 6] }));
- test('should work with `isShallow` and `callback`', 1, function() {
- var actual = _.flatten(array, true, function(object) {
- return object.a;
+ var actual = _.map(values, function(value, index) {
+ return index ? _.groupBy(array, value) : _.groupBy(array);
});
- deepEqual(actual, [1, [2], 3]);
+ deepEqual(actual, expected);
});
- test('should pass the correct `callback` arguments', 1, function() {
+ test('should provide the correct `iteratee` arguments', 1, function() {
var args;
- _.flatten(array, function() {
+ _.groupBy(array, function() {
args || (args = slice.call(arguments));
});
- deepEqual(args, [{ 'a': [1, [2]] }, 0, array]);
+ deepEqual(args, [4.2, 0, array]);
});
test('should support the `thisArg` argument', 1, function() {
- var actual = _.flatten(array, function(object, index) {
- return this[index].a;
- }, array);
+ var actual = _.groupBy(array, function(num) {
+ return this.floor(num);
+ }, Math);
- deepEqual(actual, [1, 2, 3]);
+ deepEqual(actual, { '4': [4.2], '6': [6.1, 6.4] });
});
- test('should work with a string for `callback`', 1, function() {
- deepEqual(_.flatten(array, 'a'), [1, 2, 3]);
- });
+ test('should only add values to own, not inherited, properties', 2, function() {
+ var actual = _.groupBy([4.2, 6.1, 6.4], function(num) {
+ return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
+ });
- test('should perform a deep flatten when used as `callback` for `_.map`', 1, function() {
- var array = [[[['a']]], [[['b']]]],
- actual = _.map(array, _.flatten);
+ deepEqual(actual.constructor, [4.2]);
+ deepEqual(actual.hasOwnProperty, [6.1, 6.4]);
+ });
- deepEqual(actual, [['a'], ['b']]);
+ test('should work with a "_.pluck" style `iteratee`', 1, function() {
+ var actual = _.groupBy(['one', 'two', 'three'], 'length');
+ deepEqual(actual, { '3': ['one', 'two'], '5': ['three'] });
});
- test('should treat sparse arrays as dense', 4, function() {
- var array = [[1, 2, 3], Array(3)],
- expected = [1, 2, 3],
- actual1 = _.flatten(array),
- actual2 = _.flatten(array, true);
+ test('should work with a number for `iteratee`', 2, function() {
+ var array = [
+ [1, 'a'],
+ [2, 'a'],
+ [2, 'b']
+ ];
- expected.push(undefined, undefined, undefined);
+ deepEqual(_.groupBy(array, 0), { '1': [[1, 'a']], '2': [[2, 'a'], [2, 'b']] });
+ deepEqual(_.groupBy(array, 1), { 'a': [[1, 'a'], [2, 'a']], 'b': [[2, 'b']] });
+ });
- deepEqual(actual1, expected);
- ok(4 in actual1);
+ test('should work with an object for `collection`', 1, function() {
+ var actual = _.groupBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) {
+ return Math.floor(num);
+ });
- deepEqual(actual2, expected);
- ok(4 in actual2);
+ deepEqual(actual, { '4': [4.2], '6': [6.1, 6.4] });
});
- test('should work with extremely large arrays', 1, function() {
- var expected = Array(5e5),
- pass = true;
+ test('should work in a lazy chain sequence', 1, function() {
+ if (!isNpm) {
+ var array = [1, 2, 1, 3],
+ iteratee = function(value) { value.push(value[0]); return value; },
+ predicate = function(value, index) { return index; },
+ actual = _(array).groupBy(_.identity).map(iteratee).filter(predicate).take().value();
- if (freeze) {
- try {
- var actual = _.flatten([expected]);
- } catch(e) {
- pass = false;
- }
- if (pass) {
- deepEqual(actual, expected);
- } else {
- ok(pass);
- }
- } else {
+ deepEqual(actual, [[2, 2]]);
+ }
+ else {
skipTest();
}
});
+ }());
- test('should work with empty arrays', 1, function() {
- var actual = _.flatten([[], [[]], [[], [[[]]]]]);
- deepEqual(actual, []);
- });
+ /*--------------------------------------------------------------------------*/
- test('should flatten nested arrays', 1, function() {
- var array = [1, [2], [3, [[4]]]],
- expected = [1, 2, 3, 4];
+ QUnit.module('lodash.has');
- deepEqual(_.flatten(array), expected);
+ (function() {
+ test('should check for own properties', 2, function() {
+ var object = { 'a': 1 };
+ strictEqual(_.has(object, 'a'), true);
+ strictEqual(_.has(object, 'b'), false);
});
- test('should support shallow flattening nested arrays', 1, function() {
- var array = [1, [2], [3, [4]]],
- expected = [1, 2, 3, [4]];
+ test('should not use the `hasOwnProperty` method of the object', 1, function() {
+ var object = { 'hasOwnProperty': null, 'a': 1 };
+ strictEqual(_.has(object, 'a'), true);
+ });
- deepEqual(_.flatten(array, true), expected);
+ test('should not check for inherited properties', 1, function() {
+ function Foo() {}
+ Foo.prototype.a = 1;
+ strictEqual(_.has(new Foo, 'a'), false);
});
- test('should support shallow flattening arrays of other arrays', 1, function() {
- var array = [[1], [2], [3], [[4]]],
- expected = [1, 2, 3, [4]];
+ test('should work with functions', 1, function() {
+ function Foo() {}
+ strictEqual(_.has(Foo, 'prototype'), true);
+ });
- deepEqual(_.flatten(array, true), expected);
+ test('should return `false` for primitives', 1, function() {
+ var values = falsey.concat(true, 1, 'a'),
+ expected = _.map(values, _.constant(false));
+
+ var actual = _.map(values, function(value) {
+ return _.has(value, 'valueOf');
+ });
+
+ deepEqual(actual, expected);
});
- }(1, 2, 3));
+ }());
/*--------------------------------------------------------------------------*/
- QUnit.module('forEach methods');
+ QUnit.module('lodash.identity');
- _.forEach(['forEach', 'forEachRight'], function(methodName) {
- var func = _[methodName];
+ (function() {
+ test('should return the first argument provided', 1, function() {
+ var object = { 'name': 'fred' };
+ strictEqual(_.identity(object), object);
+ });
+ }());
- _.forEach({
- 'literal': 'abc',
- 'object': Object('abc')
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.includes');
+
+ (function() {
+ _.each({
+ 'an `arguments` object': arguments,
+ 'an array': [1, 2, 3, 4],
+ 'an object': { 'a': 1, 'b': 2, 'c': 3, 'd': 4 },
+ 'a string': '1234'
},
function(collection, key) {
- test('`_.' + methodName + '` should work with a string ' + key + ' for `collection` (test in IE < 9)', 2, function() {
- var args,
- values = [];
+ var values = _.toArray(collection);
- func(collection, function(value) {
- args || (args = slice.call(arguments));
- values.push(value);
- });
+ test('should work with ' + key + ' and return `true` for matched values', 1, function() {
+ strictEqual(_.includes(collection, 3), true);
+ });
- if (methodName == 'forEach') {
- deepEqual(args, ['a', 0, collection]);
- deepEqual(values, ['a', 'b', 'c']);
- } else {
- deepEqual(args, ['c', 2, collection]);
- deepEqual(values, ['c', 'b', 'a']);
- }
+ test('should work with ' + key + ' and return `false` for unmatched values', 1, function() {
+ strictEqual(_.includes(collection, 5), false);
});
- });
- test('`_.' + methodName + '` should be aliased', 1, function() {
- if (methodName == 'forEach') {
- strictEqual(_.each, _.forEach);
- } else {
- strictEqual(_.eachRight, _.forEachRight);
- }
- });
- });
+ test('should work with ' + key + ' and a positive `fromIndex`', 2, function() {
+ strictEqual(_.includes(collection, values[2], 2), true);
+ strictEqual(_.includes(collection, values[1], 2), false);
+ });
- /*--------------------------------------------------------------------------*/
+ test('should work with ' + key + ' and a `fromIndex` >= `collection.length`', 12, function() {
+ _.each([4, 6, Math.pow(2, 32), Infinity], function(fromIndex) {
+ strictEqual(_.includes(collection, 1, fromIndex), false);
+ strictEqual(_.includes(collection, undefined, fromIndex), false);
+ strictEqual(_.includes(collection, '', fromIndex), false);
+ });
+ });
- QUnit.module('forIn methods');
+ test('should work with ' + key + ' and treat falsey `fromIndex` values as `0`', 1, function() {
+ var expected = _.map(falsey, _.constant(true));
- _.forEach(['forIn', 'forInRight'], function(methodName) {
- var func = _[methodName];
+ var actual = _.map(falsey, function(fromIndex) {
+ return _.includes(collection, values[0], fromIndex);
+ });
- test('`_.' + methodName + '` iterates over inherited properties', 1, function() {
- function Foo() { this.a = 1; }
- Foo.prototype.b = 2;
+ deepEqual(actual, expected);
+ });
- var keys = [];
- func(new Foo, function(value, key) { keys.push(key); });
- deepEqual(keys.sort(), ['a', 'b']);
- });
+ test('should work with ' + key + ' and treat non-number `fromIndex` values as `0`', 1, function() {
+ strictEqual(_.includes(collection, values[0], '1'), true);
+ });
- test('`_.' + methodName + '` fixes the JScript [[DontEnum]] bug with inherited properties (test in IE < 9)', 1, function() {
- function Foo() {}
- Foo.prototype = shadowedObject;
+ test('should work with ' + key + ' and a negative `fromIndex`', 2, function() {
+ strictEqual(_.includes(collection, values[2], -2), true);
+ strictEqual(_.includes(collection, values[1], -2), false);
+ });
- function Bar() {}
- Bar.prototype = new Foo;
- Bar.prototype.constructor = Bar;
+ test('should work with ' + key + ' and a negative `fromIndex` <= negative `collection.length`', 3, function() {
+ _.each([-4, -6, -Infinity], function(fromIndex) {
+ strictEqual(_.includes(collection, values[0], fromIndex), true);
+ });
+ });
- var keys = [];
- func(shadowedObject, function(value, key) { keys.push(key); });
- deepEqual(keys.sort(), shadowedProps);
+ test('should work with ' + key + ' and return an unwrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ strictEqual(_(collection).includes(3), true);
+ }
+ else {
+ skipTest();
+ }
+ });
});
- });
- /*--------------------------------------------------------------------------*/
+ _.each({
+ 'literal': 'abc',
+ 'object': Object('abc')
+ },
+ function(collection, key) {
+ test('should work with a string ' + key + ' for `collection`', 2, function() {
+ strictEqual(_.includes(collection, 'bc'), true);
+ strictEqual(_.includes(collection, 'd'), false);
+ });
+ });
- QUnit.module('forOwn methods');
+ test('should return `false` for empty collections', 1, function() {
+ var expected = _.map(empties, _.constant(false));
- _.forEach(['forOwn', 'forOwnRight'], function(methodName) {
- var func = _[methodName];
+ var actual = _.map(empties, function(value) {
+ try {
+ return _.includes(value);
+ } catch(e) {}
+ });
- test('iterates over the `length` property', 1, function() {
- var object = { '0': 'zero', '1': 'one', 'length': 2 },
- props = [];
+ deepEqual(actual, expected);
+ });
- func(object, function(value, prop) { props.push(prop); });
- deepEqual(props.sort(), ['0', '1', 'length']);
+ test('should not be possible to perform a binary search', 1, function() {
+ strictEqual(_.includes([3, 2, 1], 3, true), true);
});
- });
+
+ test('should match `NaN`', 1, function() {
+ strictEqual(_.includes([1, NaN, 3], NaN), true);
+ });
+
+ test('should be aliased', 2, function() {
+ strictEqual(_.contains, _.includes);
+ strictEqual(_.include, _.includes);
+ });
+ }(1, 2, 3, 4));
/*--------------------------------------------------------------------------*/
- QUnit.module('iteration methods');
+ QUnit.module('lodash.indexBy');
(function() {
- var methods = [
- 'every',
- 'filter',
- 'forEach',
- 'forEachRight',
- 'forIn',
- 'forInRight',
- 'forOwn',
- 'forOwnRight',
- 'map',
- 'reject',
- 'some'
- ];
+ test('should use `_.identity` when `iteratee` is nullish', 1, function() {
+ var array = [4, 6, 6],
+ values = [, null, undefined],
+ expected = _.map(values, _.constant({ '4': 4, '6': 6 }));
- var boolMethods = [
- 'every',
- 'some'
- ];
-
- var forInMethods = [
- 'forIn',
- 'forInRight'
- ];
+ var actual = _.map(values, function(value, index) {
+ return index ? _.indexBy(array, value) : _.indexBy(array);
+ });
- var iterationMethods = [
- 'forEach',
- 'forEachRight',
- 'forIn',
- 'forInRight',
- 'forOwn',
- 'forOwnRight'
- ]
+ deepEqual(actual, expected);
+ });
- var objectMethods = [
- 'forIn',
- 'forInRight',
- 'forOwn',
- 'forOwnRight'
- ];
+ test('should support the `thisArg` argument', 1, function() {
+ var actual = _.indexBy([4.2, 6.1, 6.4], function(num) {
+ return this.floor(num);
+ }, Math);
- var rightMethods = [
- 'forEachRight',
- 'forInRight',
- 'forOwnRight'
- ];
+ deepEqual(actual, { '4': 4.2, '6': 6.4 });
+ });
- _.forEach(methods, function(methodName) {
- var array = [1, 2, 3],
- func = _[methodName];
+ test('should only add values to own, not inherited, properties', 2, function() {
+ var actual = _.indexBy([4.2, 6.1, 6.4], function(num) {
+ return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
+ });
- test('`_.' + methodName + '` should pass the correct `callback` arguments', 1, function() {
- var args,
- expected = [1, 0, array];
+ deepEqual(actual.constructor, 4.2);
+ deepEqual(actual.hasOwnProperty, 6.4);
+ });
- func(array, function() {
- args || (args = slice.call(arguments));
- });
+ test('should work with a "_.pluck" style `iteratee`', 1, function() {
+ var actual = _.indexBy(['one', 'two', 'three'], 'length');
+ deepEqual(actual, { '3': 'two', '5': 'three' });
+ });
- if (_.contains(rightMethods, methodName)) {
- expected[0] = 3;
- expected[1] = 2;
- }
- if (_.contains(objectMethods, methodName)) {
- expected[1] += '';
- }
- deepEqual(args, expected);
- });
+ test('should work with a number for `iteratee`', 2, function() {
+ var array = [
+ [1, 'a'],
+ [2, 'a'],
+ [2, 'b']
+ ];
- test('`_.' + methodName + '` should support the `thisArg` argument', 2, function() {
- var actual;
+ deepEqual(_.indexBy(array, 0), { '1': [1, 'a'], '2': [2, 'b'] });
+ deepEqual(_.indexBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] });
+ });
- function callback(num, index) {
- actual = this[index];
- }
+ test('should work with an object for `collection`', 1, function() {
+ var actual = _.indexBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) {
+ return Math.floor(num);
+ });
- func([1], callback, [2]);
- equal(actual, 2);
+ deepEqual(actual, { '4': 4.2, '6': 6.4 });
+ });
- func({ 'a': 1 }, callback, { 'a': 2 });
- equal(actual, 2);
- });
+ test('should work in a lazy chain sequence', 1, function() {
+ if (!isNpm) {
+ var array = [1, 2, 1, 3],
+ predicate = function(value) { return value > 1; },
+ actual = _(array).indexBy(_.identity).map(String).filter(predicate).take().value();
+
+ deepEqual(actual, ['2']);
+ }
+ else {
+ skipTest();
+ }
});
+ }());
- _.forEach(_.difference(methods, boolMethods), function(methodName) {
- var array = [1, 2, 3],
- func = _[methodName];
+ /*--------------------------------------------------------------------------*/
- test('`_.' + methodName + '` should return a wrapped value when chaining', 1, function() {
- if (!isNpm) {
- var actual = _(array)[methodName](noop);
- ok(actual instanceof _);
- }
- else {
- skipTest();
- }
- });
+ QUnit.module('lodash.indexOf');
+
+ (function() {
+ var array = [1, 2, 3, 1, 2, 3];
+
+ test('should return the index of the first matched value', 1, function() {
+ strictEqual(_.indexOf(array, 3), 2);
});
- _.forEach(_.difference(methods, forInMethods), function(methodName) {
- var array = [1, 2, 3],
- func = _[methodName];
+ test('should work with a positive `fromIndex`', 1, function() {
+ strictEqual(_.indexOf(array, 1, 2), 3);
+ });
- test('`_.' + methodName + '` iterates over own properties of objects', 1, function() {
- function Foo() { this.a = 1; }
- Foo.prototype.b = 2;
+ test('should work with `fromIndex` >= `array.length`', 1, function() {
+ var values = [6, 8, Math.pow(2, 32), Infinity],
+ expected = _.map(values, _.constant([-1, -1, -1]));
- var keys = [];
- func(new Foo, function(value, key) { keys.push(key); });
- deepEqual(keys, ['a']);
+ var actual = _.map(values, function(fromIndex) {
+ return [
+ _.indexOf(array, undefined, fromIndex),
+ _.indexOf(array, 1, fromIndex),
+ _.indexOf(array, '', fromIndex)
+ ];
});
+
+ deepEqual(actual, expected);
});
- _.forEach(iterationMethods, function(methodName) {
- var array = [1, 2, 3],
- func = _[methodName];
+ test('should treat falsey `fromIndex` values as `0`', 1, function() {
+ var expected = _.map(falsey, _.constant(0));
- test('`_.' + methodName + '` should return the collection', 1, function() {
- equal(func(array, Boolean), array);
+ var actual = _.map(falsey, function(fromIndex) {
+ return _.indexOf(array, 1, fromIndex);
});
- test('`_.' + methodName + '` should return the existing wrapper when chaining', 1, function() {
- if (!isNpm) {
- var wrapper = _(array);
- equal(wrapper[methodName](noop), wrapper);
- }
- else {
- skipTest();
- }
- });
+ deepEqual(actual, expected);
});
- }());
- /*--------------------------------------------------------------------------*/
-
- QUnit.module('collection iteration bugs');
+ test('should perform a binary search when `fromIndex` is a non-number truthy value', 1, function() {
+ var sorted = [4, 4, 5, 5, 6, 6],
+ values = [true, '1', {}],
+ expected = _.map(values, _.constant(2));
- _.forEach(['forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight'], function(methodName) {
- var func = _[methodName];
+ var actual = _.map(values, function(value) {
+ return _.indexOf(sorted, 5, value);
+ });
- test('`_.' + methodName + '` fixes the JScript [[DontEnum]] bug (test in IE < 9)', 1, function() {
- var props = [];
- func(shadowedObject, function(value, prop) { props.push(prop); });
- deepEqual(props.sort(), shadowedProps);
+ deepEqual(actual, expected);
});
- test('`_.' + methodName + '` does not iterate over non-enumerable properties (test in IE < 9)', 10, function() {
- _.forOwn({
- 'Array': Array.prototype,
- 'Boolean': Boolean.prototype,
- 'Date': Date.prototype,
- 'Error': Error.prototype,
- 'Function': Function.prototype,
- 'Object': Object.prototype,
- 'Number': Number.prototype,
- 'TypeError': TypeError.prototype,
- 'RegExp': RegExp.prototype,
- 'String': String.prototype
- },
- function(object, builtin) {
- var message = 'non-enumerable properties on ' + builtin + '.prototype',
- props = [];
+ test('should work with a negative `fromIndex`', 1, function() {
+ strictEqual(_.indexOf(array, 2, -3), 4);
+ });
- func(object, function(value, prop) { props.push(prop); });
+ test('should work with a negative `fromIndex` <= `-array.length`', 1, function() {
+ var values = [-6, -8, -Infinity],
+ expected = _.map(values, _.constant(0));
- if (/Error/.test(builtin)) {
- ok(_.every(['constructor', 'toString'], function(prop) {
- return !_.contains(props, prop);
- }), message);
- }
- else {
- deepEqual(props, [], message);
- }
+ var actual = _.map(values, function(fromIndex) {
+ return _.indexOf(array, 1, fromIndex);
});
+
+ deepEqual(actual, expected);
});
+ }());
- test('`_.' + methodName + '` skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
- function Foo() {}
- Foo.prototype.a = 1;
+ /*--------------------------------------------------------------------------*/
- var props = [];
- function callback(value, prop) { props.push(prop); }
+ QUnit.module('custom `_.indexOf` methods');
- func(Foo, callback);
- deepEqual(props, []);
- props.length = 0;
+ (function() {
+ function Foo() {}
- Foo.prototype = { 'a': 1 };
- func(Foo, callback);
- deepEqual(props, []);
- });
- });
+ function custom(array, value, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array.length;
- /*--------------------------------------------------------------------------*/
+ while (++index < length) {
+ var other = array[index];
+ if (other === value || (value instanceof Foo && other instanceof Foo)) {
+ return index;
+ }
+ }
+ return -1;
+ }
- QUnit.module('object assignments');
+ var array = [1, new Foo, 3, new Foo],
+ indexOf = _.indexOf;
- _.forEach(['assign', 'defaults', 'merge'], function(methodName) {
- var func = _[methodName];
+ var largeArray = _.times(LARGE_ARRAY_SIZE, function() {
+ return new Foo;
+ });
- test('`_.' + methodName + '` should return the existing wrapper when chaining', 1, function() {
- if (!isNpm) {
- var wrapper = _({ 'a': 1 });
- equal(wrapper[methodName]({ 'b': 2 }), wrapper);
+ test('`_.includes` should work with a custom `_.indexOf` method', 2, function() {
+ if (!isModularize) {
+ _.indexOf = custom;
+ ok(_.includes(array, new Foo));
+ ok(_.includes({ 'a': 1, 'b': new Foo, 'c': 3 }, new Foo));
+ _.indexOf = indexOf;
}
else {
- skipTest();
+ skipTest(2);
}
});
- test('`_.' + methodName + '` should assign problem JScript properties (test in IE < 9)', 1, function() {
- var object = {
- 'constructor': '0',
- 'hasOwnProperty': '1',
- 'isPrototypeOf': '2',
- 'propertyIsEnumerable': undefined,
- 'toLocaleString': undefined,
- 'toString': undefined,
- 'valueOf': undefined
- };
+ test('`_.difference` should work with a custom `_.indexOf` method', 2, function() {
+ if (!isModularize) {
+ _.indexOf = custom;
+ deepEqual(_.difference(array, [new Foo]), [1, 3]);
+ deepEqual(_.difference(array, largeArray), [1, 3]);
+ _.indexOf = indexOf;
+ }
+ else {
+ skipTest(2);
+ }
+ });
- var source = {
- 'propertyIsEnumerable': '3',
- 'toLocaleString': '4',
- 'toString': '5',
- 'valueOf': '6'
- };
+ test('`_.intersection` should work with a custom `_.indexOf` method', 2, function() {
+ if (!isModularize) {
+ _.indexOf = custom;
+ deepEqual(_.intersection(array, [new Foo]), [array[1]]);
+ deepEqual(_.intersection(largeArray, [new Foo]), [array[1]]);
+ _.indexOf = indexOf;
+ }
+ else {
+ skipTest(2);
+ }
+ });
- deepEqual(func(object, source), shadowedObject);
+ test('`_.uniq` should work with a custom `_.indexOf` method', 6, function() {
+ _.each([false, true, _.identity], function(param) {
+ if (!isModularize) {
+ _.indexOf = custom;
+ deepEqual(_.uniq(array, param), array.slice(0, 3));
+ deepEqual(_.uniq(largeArray, param), [largeArray[0]]);
+ _.indexOf = indexOf;
+ }
+ else {
+ skipTest(2);
+ }
+ });
});
+ }());
- test('`_.' + methodName + '` skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
- function Foo() {}
- Foo.prototype.c = 3;
+ /*--------------------------------------------------------------------------*/
- Foo.a = 1;
- Foo.b = 2;
+ QUnit.module('lodash.initial');
- var expected = { 'a': 1, 'b': 2 };
- deepEqual(func({}, Foo), expected);
+ (function() {
+ var array = [1, 2, 3];
- Foo.prototype = { 'c': 3 };
- deepEqual(func({}, Foo), expected);
- });
+ test('should accept a falsey `array` argument', 1, function() {
+ var expected = _.map(falsey, _.constant([]));
- test('`_.' + methodName + '` should work with `_.reduce`', 1, function() {
- var actual = { 'a': 1},
- array = [{ 'b': 2 }, { 'c': 3 }];
+ var actual = _.map(falsey, function(value, index) {
+ try {
+ return index ? _.initial(value) : _.initial();
+ } catch(e) {}
+ });
- _.reduce(array, func, actual);
- deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3});
+ deepEqual(actual, expected);
});
- });
- _.forEach(['assign', 'merge'], function(methodName) {
- var func = _[methodName];
+ test('should exclude last element', 1, function() {
+ deepEqual(_.initial(array), [1, 2]);
+ });
- test('`_.' + methodName + '` should pass the correct `callback` arguments', 2, function() {
- var args;
+ test('should return an empty when querying empty arrays', 1, function() {
+ deepEqual(_.initial([]), []);
+ });
- func({ 'a': 1 }, { 'a': 2 }, function() {
- args || (args = slice.call(arguments));
- });
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ actual = _.map(array, _.initial);
- deepEqual(args, [1, 2], 'primitive property values');
+ deepEqual(actual, [[1, 2], [4, 5], [7, 8]]);
+ });
- var array = [1, 2],
- object = { 'b': 2 };
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).initial();
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [1, 2]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+ }());
- args = null;
- func({ 'a': array }, { 'a': object }, function() {
- args || (args = slice.call(arguments));
- });
+ /*--------------------------------------------------------------------------*/
- deepEqual(args, [array, object], 'non-primitive property values');
- });
+ QUnit.module('lodash.intersection');
- test('`_.' + methodName + '`should support the `thisArg` argument', 1, function() {
- var actual = func({}, { 'a': 0 }, function(a, b) {
- return this[b];
- }, [2]);
+ (function() {
+ var args = arguments;
- deepEqual(actual, { 'a': 2 });
+ test('should return the intersection of the given arrays', 1, function() {
+ var actual = _.intersection([1, 3, 2], [5, 2, 1, 4], [2, 1]);
+ deepEqual(actual, [1, 2]);
});
- test('`_.' + methodName + '` should not treat the second argument as a `callback`', 2, function() {
- function callback() {}
- callback.b = 2;
-
- var actual = func({ 'a': 1 }, callback);
- deepEqual(actual, { 'a': 1, 'b': 2 });
+ test('should return an array of unique values', 2, function() {
+ var array = [1, 1, 3, 2, 2];
+ deepEqual(_.intersection(array, [5, 2, 2, 1, 4], [2, 1, 1]), [1, 2]);
+ deepEqual(_.intersection(array), [1, 3, 2]);
+ });
- actual = func({ 'a': 1 }, callback, { 'c': 3 });
- deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
+ test('should match `NaN`', 1, function() {
+ deepEqual(_.intersection([1, NaN, 3], [NaN, 5, NaN]), [NaN]);
});
- });
- /*--------------------------------------------------------------------------*/
+ test('should work with large arrays of objects', 1, function() {
+ var object = {},
+ largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(object));
- QUnit.module('exit early');
+ deepEqual(_.intersection([object], largeArray), [object]);
+ });
- _.forEach(['forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight'], function(methodName) {
- var func = _[methodName];
+ test('should work with large arrays of objects', 2, function() {
+ var object = {},
+ largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(object));
- test('`_.' + methodName + '` can exit early when iterating arrays', 1, function() {
- var array = [1, 2, 3],
- values = [];
+ deepEqual(_.intersection([object], largeArray), [object]);
+ deepEqual(_.intersection(_.range(LARGE_ARRAY_SIZE), null, [1]), [1]);
+ });
- func(array, function(value) { values.push(value); return false; });
- deepEqual(values, [/Right/.test(methodName) ? 3 : 1]);
+ test('should work with large arrays of `NaN`', 1, function() {
+ var largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(NaN));
+ deepEqual(_.intersection([1, NaN, 3], largeArray), [NaN]);
});
- test('`_.' + methodName + '` can exit early when iterating objects', 1, function() {
- var object = { 'a': 1, 'b': 2, 'c': 3 },
- values = [];
+ test('should ignore values that are not arrays or `arguments` objects', 3, function() {
+ var array = [0, 1, null, 3];
+ deepEqual(_.intersection(array, 3, null, { '0': 1 }), array);
+ deepEqual(_.intersection(null, array, null, [2, 1]), [1]);
+ deepEqual(_.intersection(null, array, null, args), [1, 3]);
+ });
- func(object, function(value) { values.push(value); return false; });
- equal(values.length, 1);
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _([1, 3, 2]).intersection([5, 2, 1, 4]);
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [1, 2]);
+ }
+ else {
+ skipTest(2);
+ }
});
- });
+ }(1, 2, 3));
/*--------------------------------------------------------------------------*/
- QUnit.module('`__proto__` property bugs');
+ QUnit.module('lodash.invert');
(function() {
- test('internal data objects should work with the `__proto__` key', 4, function() {
- var stringLiteral = '__proto__',
- stringObject = Object(stringLiteral),
- expected = [stringLiteral, stringObject];
-
- var largeArray = _.times(largeArraySize, function(count) {
- return count % 2 ? stringObject : stringLiteral;
- });
+ test('should invert an object', 2, function() {
+ var object = { 'a': 1, 'b': 2 },
+ actual = _.invert(object);
- deepEqual(_.difference(largeArray, largeArray), []);
- deepEqual(_.intersection(largeArray, largeArray), expected);
- deepEqual(_.uniq(largeArray), expected);
- deepEqual(_.without.apply(_, [largeArray].concat(largeArray)), []);
+ deepEqual(actual, { '1': 'a', '2': 'b' });
+ deepEqual(_.invert(actual), { 'a': '1', 'b': '2' });
});
- test('lodash.memoize should memoize values resolved to the `__proto__` key', 1, function() {
- var count = 0,
- memoized = _.memoize(function() { return ++count; });
-
- memoized('__proto__');
- memoized('__proto__');
- strictEqual(count, 1);
+ test('should work with an object that has a `length` property', 1, function() {
+ var object = { '0': 'a', '1': 'b', 'length': 2 };
+ deepEqual(_.invert(object), { 'a': '0', 'b': '1', '2': 'length' });
});
- }());
- /*--------------------------------------------------------------------------*/
+ test('should accept a `multiValue` flag', 1, function() {
+ var object = { 'a': 1, 'b': 2, 'c': 1 };
+ deepEqual(_.invert(object, true), { '1': ['a', 'c'], '2': ['b'] });
+ });
- QUnit.module('lodash.functions');
+ test('should only add multiple values to own, not inherited, properties', 2, function() {
+ var object = { 'a': 'hasOwnProperty', 'b': 'constructor' };
- (function() {
- test('should return the function names of an object', 1, function() {
- var object = { 'a': 'a', 'b': _.identity, 'c': /x/, 'd': _.each };
- deepEqual(_.functions(object), ['b', 'd']);
+ deepEqual(_.invert(object), { 'hasOwnProperty': 'a', 'constructor': 'b' });
+ ok(_.isEqual(_.invert(object, true), { 'hasOwnProperty': ['a'], 'constructor': ['b'] }));
});
- test('should include inherited functions', 1, function() {
- function Foo() {
- this.a = _.identity;
- this.b = 'b'
- }
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var inverted = { '1': 'c', '2': 'b' },
+ object = { 'a': 1, 'b': 2, 'c': 1 },
+ actual = _.map([object, object, object], _.invert);
- Foo.prototype.c = noop;
- deepEqual(_.functions(new Foo), ['a', 'c']);
+ deepEqual(actual, [inverted, inverted, inverted]);
});
- test('should be aliased', 1, function() {
- strictEqual(_.methods, _.functions);
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var object = { 'a': 1, 'b': 2 },
+ wrapped = _(object).invert();
+
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), { '1': 'a', '2': 'b' });
+ }
+ else {
+ skipTest(2);
+ }
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.groupBy');
+ QUnit.module('lodash.invoke');
(function() {
- var array = [4.2, 6.1, 6.4];
+ test('should invoke a methods on each element of a collection', 1, function() {
+ var array = ['a', 'b', 'c'];
+ deepEqual(_.invoke(array, 'toUpperCase'), ['A', 'B', 'C']);
+ });
+
+ test('should support invoking with arguments', 1, function() {
+ var array = [function() { return slice.call(arguments); }],
+ actual = _.invoke(array, 'call', null, 'a', 'b', 'c');
- test('should use `_.identity` when no `callback` is provided', 1, function() {
- var actual = _.groupBy([4, 6, 6]);
- deepEqual(actual, { '4': [4], '6': [6, 6] });
+ deepEqual(actual, [['a', 'b', 'c']]);
});
- test('should pass the correct `callback` arguments', 1, function() {
- var args;
+ test('should work with a function `methodName` argument', 1, function() {
+ var array = ['a', 'b', 'c'];
- _.groupBy(array, function() {
- args || (args = slice.call(arguments));
- });
+ var actual = _.invoke(array, function(left, right) {
+ return left + this.toUpperCase() + right;
+ }, '(', ')');
- deepEqual(args, [4.2, 0, array]);
+ deepEqual(actual, ['(A)', '(B)', '(C)']);
});
- test('should support the `thisArg` argument', 1, function() {
- var actual = _.groupBy(array, function(num) {
- return this.floor(num);
- }, Math);
+ test('should work with an object for `collection`', 1, function() {
+ var object = { 'a': 1, 'b': 2, 'c': 3 };
+ deepEqual(_.invoke(object, 'toFixed', 1), ['1.0', '2.0', '3.0']);
+ });
- deepEqual(actual, { '4': [4.2], '6': [6.1, 6.4] });
+ test('should treat number values for `collection` as empty', 1, function() {
+ deepEqual(_.invoke(1), []);
});
- test('should only add values to own, not inherited, properties', 2, function() {
- var actual = _.groupBy([4.2, 6.1, 6.4], function(num) {
- return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
- });
+ test('should not error on nullish elements', 1, function() {
+ var array = ['a', null, undefined, 'd'];
- deepEqual(actual.constructor, [4.2]);
- deepEqual(actual.hasOwnProperty, [6.1, 6.4]);
+ try {
+ var actual = _.invoke(array, 'toUpperCase');
+ } catch(e) {}
+
+ deepEqual(_.invoke(array, 'toUpperCase'), ['A', undefined, undefined, 'D']);
});
- test('should work with an object for `collection`', 1, function() {
- var actual = _.groupBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) {
- return Math.floor(num);
+ test('should not error on elements with missing properties', 1, function() {
+ var objects = _.map(falsey.concat(_.constant(1)), function(value) {
+ return { 'a': value };
});
- deepEqual(actual, { '4': [4.2], '6': [6.1, 6.4] });
- });
-
- test('should work with a number for `callback`', 2, function() {
- var array = [
- [1, 'a'],
- [2, 'a'],
- [2, 'b']
- ];
+ var expected = _.times(objects.length - 1, _.constant(undefined)).concat(1);
- deepEqual(_.groupBy(array, 0), { '1': [[1 , 'a']], '2': [[2, 'a'], [2, 'b']] });
- deepEqual(_.groupBy(array, 1), { 'a': [[1 , 'a'], [2, 'a']], 'b': [[2, 'b']] });
- });
+ try {
+ var actual = _.invoke(objects, 'a');
+ } catch(e) {}
- test('should work with a string for `callback`', 1, function() {
- var actual = _.groupBy(['one', 'two', 'three'], 'length');
- deepEqual(actual, { '3': ['one', 'two'], '5': ['three'] });
+ deepEqual(actual, expected);
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.has');
+ QUnit.module('lodash.isArguments');
(function() {
- test('should check for own properties', 2, function() {
- var object = { 'a': 1 };
- strictEqual(_.has(object, 'a'), true);
- strictEqual(_.has(object, 'b'), false);
- });
-
- test('should not use the `hasOwnProperty` method of the object', 1, function() {
- var object = { 'hasOwnProperty': null, 'a': 1 };
- strictEqual(_.has(object, 'a'), true);
- });
-
- test('should not check for inherited properties', 1, function() {
- function Foo() {}
- Foo.prototype.a = 1;
- strictEqual(_.has(new Foo, 'a'), false);
- });
+ var args = arguments;
- test('should work with functions', 1, function() {
- function Foo() {}
- strictEqual(_.has(Foo, 'prototype'), true);
+ test('should return `true` for `arguments` objects', 1, function() {
+ strictEqual(_.isArguments(args), true);
});
- test('should return `false` for primitives', 1, function() {
- var values = falsey.concat(1, 'a'),
- expected = _.map(values, function() { return false; });
+ test('should return `false` for non `arguments` objects', 12, function() {
+ var expected = _.map(falsey, _.constant(false));
- var actual = _.map(values, function(value) {
- return _.has(value, 'valueOf');
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.isArguments(value) : _.isArguments();
});
deepEqual(actual, expected);
- });
- }());
- /*--------------------------------------------------------------------------*/
-
- QUnit.module('lodash.identity');
+ strictEqual(_.isArguments([1, 2, 3]), false);
+ strictEqual(_.isArguments(true), false);
+ strictEqual(_.isArguments(new Date), false);
+ strictEqual(_.isArguments(new Error), false);
+ strictEqual(_.isArguments(_), false);
+ strictEqual(_.isArguments(slice), false);
+ strictEqual(_.isArguments({ '0': 1, 'callee': _.noop, 'length': 1 }), false);
+ strictEqual(_.isArguments(1), false);
+ strictEqual(_.isArguments(NaN), false);
+ strictEqual(_.isArguments(/x/), false);
+ strictEqual(_.isArguments('a'), false);
+ });
- (function() {
- test('should return the first argument provided', 1, function() {
- var object = { 'name': 'fred' };
- strictEqual(_.identity(object), object);
+ test('should work with an `arguments` object from another realm', 1, function() {
+ if (_._object) {
+ strictEqual(_.isArguments(_._arguments), true);
+ }
+ else {
+ skipTest();
+ }
});
- }())
+ }(1, 2, 3));
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.indexBy');
+ QUnit.module('lodash.isArray');
(function() {
- test('should use `_.identity` when no `callback` is provided', 1, function() {
- var actual = _.indexBy([4, 6, 6]);
- deepEqual(actual, { '4': 4, '6': 6 });
- });
-
- test('should support the `thisArg` argument', 1, function() {
- var actual = _.indexBy([4.2, 6.1, 6.4], function(num) {
- return this.floor(num);
- }, Math);
+ var args = arguments;
- deepEqual(actual, { '4': 4.2, '6': 6.4 });
+ test('should return `true` for arrays', 1, function() {
+ strictEqual(_.isArray([1, 2, 3]), true);
});
- test('should only add values to own, not inherited, properties', 2, function() {
- var actual = _.indexBy([4.2, 6.1, 6.4], function(num) {
- return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
- });
-
- deepEqual(actual.constructor, 4.2);
- deepEqual(actual.hasOwnProperty, 6.4);
- });
+ test('should return `false` for non arrays', 12, function() {
+ var expected = _.map(falsey, _.constant(false));
- test('should work with an object for `collection`', 1, function() {
- var actual = _.indexBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) {
- return Math.floor(num);
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.isArray(value) : _.isArray();
});
- deepEqual(actual, { '4': 4.2, '6': 6.4 });
- });
+ deepEqual(actual, expected);
- test('should work with a number for `callback`', 2, function() {
- var array = [
- [1, 'a'],
- [2, 'a'],
- [2, 'b']
- ];
+ strictEqual(_.isArray(args), false);
+ strictEqual(_.isArray(true), false);
+ strictEqual(_.isArray(new Date), false);
+ strictEqual(_.isArray(new Error), false);
+ strictEqual(_.isArray(_), false);
+ strictEqual(_.isArray(slice), false);
+ strictEqual(_.isArray({ '0': 1, 'length': 1 }), false);
+ strictEqual(_.isArray(1), false);
+ strictEqual(_.isArray(NaN), false);
+ strictEqual(_.isArray(/x/), false);
+ strictEqual(_.isArray('a'), false);
+ });
- deepEqual(_.indexBy(array, 0), { '1': [1 , 'a'], '2': [2, 'b'] });
- deepEqual(_.indexBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] });
+ test('should work with an array from another realm', 1, function() {
+ if (_._object) {
+ strictEqual(_.isArray(_._array), true);
+ }
+ else {
+ skipTest();
+ }
});
- }());
+ }(1, 2, 3));
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.indexOf');
+ QUnit.module('lodash.isBoolean');
(function() {
- var array = [1, 2, 3, 1, 2, 3];
-
- test('should return the index of the first matched value', 1, function() {
- equal(_.indexOf(array, 3), 2);
- });
-
- test('should return `-1` for an unmatched value', 1, function() {
- equal(_.indexOf(array, 4), -1);
- });
+ var args = arguments;
- test('should work with a positive `fromIndex`', 1, function() {
- equal(_.indexOf(array, 1, 2), 3);
+ test('should return `true` for booleans', 4, function() {
+ strictEqual(_.isBoolean(true), true);
+ strictEqual(_.isBoolean(false), true);
+ strictEqual(_.isBoolean(Object(true)), true);
+ strictEqual(_.isBoolean(Object(false)), true);
});
- test('should work with `fromIndex` >= `array.length`', 4, function() {
- equal(_.indexOf(array, 1, 6), -1);
- equal(_.indexOf(array, undefined, 6), -1);
- equal(_.indexOf(array, 1, 8), -1);
- equal(_.indexOf(array, undefined, 8), -1);
- });
+ test('should return `false` for non booleans', 12, function() {
+ var expected = _.map(falsey, function(value) { return value === false; });
- test('should work with a negative `fromIndex`', 1, function() {
- equal(_.indexOf(array, 2, -3), 4);
- });
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.isBoolean(value) : _.isBoolean();
+ });
- test('should work with a negative `fromIndex` <= `-array.length`', 2, function() {
- strictEqual(_.indexOf(array, 1, -6), 0);
- strictEqual(_.indexOf(array, 2, -8), 1);
- });
+ deepEqual(actual, expected);
- test('should ignore non-number `fromIndex` values', 1, function() {
- strictEqual(_.indexOf([1, 2, 3], 1, '1'), 0);
+ strictEqual(_.isBoolean(args), false);
+ strictEqual(_.isBoolean([1, 2, 3]), false);
+ strictEqual(_.isBoolean(new Date), false);
+ strictEqual(_.isBoolean(new Error), false);
+ strictEqual(_.isBoolean(_), false);
+ strictEqual(_.isBoolean(slice), false);
+ strictEqual(_.isBoolean({ 'a': 1 }), false);
+ strictEqual(_.isBoolean(1), false);
+ strictEqual(_.isBoolean(NaN), false);
+ strictEqual(_.isBoolean(/x/), false);
+ strictEqual(_.isBoolean('a'), false);
});
- test('should work with `isSorted`', 1, function() {
- strictEqual(_.indexOf([1, 2, 3], 1, true), 0);
+ test('should work with a boolean from another realm', 1, function() {
+ if (_._object) {
+ strictEqual(_.isBoolean(_._boolean), true);
+ }
+ else {
+ skipTest();
+ }
});
- }());
+ }(1, 2, 3));
/*--------------------------------------------------------------------------*/
- QUnit.module('custom `_.indexOf` methods');
+ QUnit.module('lodash.isDate');
(function() {
- function custom(array, value, fromIndex) {
- var index = (fromIndex || 0) - 1,
- length = array.length;
+ var args = arguments;
- while (++index < length) {
- var other = array[index];
- if (other === value || (value instanceof Foo && other instanceof Foo)) {
- return index;
- }
- }
- return -1;
- }
+ test('should return `true` for dates', 1, function() {
+ strictEqual(_.isDate(new Date), true);
+ });
- function Foo() {}
+ test('should return `false` for non dates', 12, function() {
+ var expected = _.map(falsey, _.constant(false));
- var array = [1, new Foo, 3, new Foo],
- indexOf = _.indexOf;
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.isDate(value) : _.isDate();
+ });
+
+ deepEqual(actual, expected);
+
+ strictEqual(_.isDate(args), false);
+ strictEqual(_.isDate([1, 2, 3]), false);
+ strictEqual(_.isDate(true), false);
+ strictEqual(_.isDate(new Error), false);
+ strictEqual(_.isDate(_), false);
+ strictEqual(_.isDate(slice), false);
+ strictEqual(_.isDate({ 'a': 1 }), false);
+ strictEqual(_.isDate(1), false);
+ strictEqual(_.isDate(NaN), false);
+ strictEqual(_.isDate(/x/), false);
+ strictEqual(_.isDate('a'), false);
+ });
- test('`_.contains` should work with a custom `_.indexOf` method', 1, function() {
- if (!isModularize) {
- _.indexOf = custom;
- ok(_.contains(array, new Foo));
- _.indexOf = indexOf;
+ test('should work with a date object from another realm', 1, function() {
+ if (_._object) {
+ strictEqual(_.isDate(_._date), true);
}
else {
skipTest();
}
});
+ }(1, 2, 3));
- test('`_.difference` should work with a custom `_.indexOf` method', 1, function() {
- if (!isModularize) {
- _.indexOf = custom;
- deepEqual(_.difference(array, [new Foo]), [1, 3]);
- _.indexOf = indexOf;
- }
- else {
- skipTest();
- }
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.isElement');
+
+ (function() {
+ var args = arguments;
+
+ function Element() {
+ this.nodeType = 1;
+ }
+
+ test('should use robust check', 7, function() {
+ var element = body || new Element;
+
+ strictEqual(_.isElement(element), true);
+ strictEqual(_.isElement({ 'nodeType': 1 }), false);
+ strictEqual(_.isElement({ 'nodeType': Object(1) }), false);
+ strictEqual(_.isElement({ 'nodeType': true }), false);
+ strictEqual(_.isElement({ 'nodeType': [1] }), false);
+ strictEqual(_.isElement({ 'nodeType': '1' }), false);
+ strictEqual(_.isElement({ 'nodeType': '001' }), false);
});
- test('`_.intersection` should work with a custom `_.indexOf` method', 1, function() {
- if (!isModularize) {
- _.indexOf = custom;
- deepEqual(_.intersection(array, [new Foo]), [array[1]]);
- _.indexOf = indexOf;
+ test('should use a stronger check in browsers', 2, function() {
+ var expected = !_.support.dom;
+
+ strictEqual(_.isElement(new Element), expected);
+
+ if (lodashBizarro) {
+ expected = !lodashBizarro.support.dom;
+ strictEqual(lodashBizarro.isElement(new Element), expected);
}
else {
skipTest();
}
});
- test('`_.uniq` should work with a custom `_.indexOf` method', 2, function() {
- if (!isModularize) {
- _.indexOf = custom;
- deepEqual(_.uniq(array), array.slice(0, 3));
+ test('should return `false` for non DOM elements', 13, function() {
+ var expected = _.map(falsey, _.constant(false));
- var largeArray = _.times(largeArraySize, function() {
- return new Foo;
- });
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.isElement(value) : _.isElement();
+ });
- deepEqual(_.uniq(largeArray), [largeArray[0]]);
- _.indexOf = indexOf;
+ deepEqual(actual, expected);
+
+ strictEqual(_.isElement(args), false);
+ strictEqual(_.isElement([1, 2, 3]), false);
+ strictEqual(_.isElement(true), false);
+ strictEqual(_.isElement(new Date), false);
+ strictEqual(_.isElement(new Error), false);
+ strictEqual(_.isElement(_), false);
+ strictEqual(_.isElement(slice), false);
+ strictEqual(_.isElement({ 'a': 1 }), false);
+ strictEqual(_.isElement(1), false);
+ strictEqual(_.isElement(NaN), false);
+ strictEqual(_.isElement(/x/), false);
+ strictEqual(_.isElement('a'), false);
+ });
+
+ test('should work with a DOM element from another realm', 1, function() {
+ if (_._element) {
+ strictEqual(_.isElement(_._element), true);
}
else {
- skipTest(2);
+ skipTest();
}
});
- }());
+ }(1, 2, 3));
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.initial');
+ QUnit.module('lodash.isEmpty');
(function() {
- var array = [1, 2, 3];
-
- var objects = [
- { 'a': 0, 'b': 0 },
- { 'a': 1, 'b': 1 },
- { 'a': 2, 'b': 2 }
- ];
+ var args = arguments;
- test('should accept a falsey `array` argument', 1, function() {
- var expected = _.map(falsey, function() { return []; });
+ test('should return `true` for empty values', 7, function() {
+ var expected = _.map(empties, _.constant(true));
- var actual = _.map(falsey, function(value, index) {
- try {
- return index ? _.initial(value) : _.initial();
- } catch(e) { }
+ var actual = _.map(empties, function(value) {
+ return _.isEmpty(value);
});
deepEqual(actual, expected);
- });
- test('should exclude last element', 1, function() {
- deepEqual(_.initial(array), [1, 2]);
+ strictEqual(_.isEmpty(true), true);
+ strictEqual(_.isEmpty(slice), true);
+ strictEqual(_.isEmpty(1), true);
+ strictEqual(_.isEmpty(NaN), true);
+ strictEqual(_.isEmpty(/x/), true);
+ strictEqual(_.isEmpty(), true);
});
- test('should exclude the last two elements', 1, function() {
- deepEqual(_.initial(array, 2), [1]);
+ test('should return `false` for non empty values', 3, function() {
+ strictEqual(_.isEmpty([0]), false);
+ strictEqual(_.isEmpty({ 'a': 0 }), false);
+ strictEqual(_.isEmpty('a'), false);
});
- test('should return an empty when querying empty arrays', 1, function() {
- deepEqual(_.initial([]), []);
+ test('should work with an object that has a `length` property', 1, function() {
+ strictEqual(_.isEmpty({ 'length': 0 }), false);
});
- test('should return all elements when `n` < `1`', 3, function() {
- _.forEach([0, -1, -2], function(n) {
- deepEqual(_.initial(array, n), array);
- });
+ test('should work with `arguments` objects (test in IE < 9)', 1, function() {
+ strictEqual(_.isEmpty(args), false);
});
- test('should return an empty array when `n` >= `array.length`', 2, function() {
- _.forEach([3, 4], function(n) {
- deepEqual(_.initial(array, n), []);
- });
+ test('should work with jQuery/MooTools DOM query collections', 1, function() {
+ function Foo(elements) { push.apply(this, elements); }
+ Foo.prototype = { 'length': 0, 'splice': arrayProto.splice };
+
+ strictEqual(_.isEmpty(new Foo([])), true);
});
- test('should work when used as `callback` for `_.map`', 1, function() {
- var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
- actual = _.map(array, _.initial);
+ test('should not treat objects with negative lengths as array-like', 1, function() {
+ function Foo() {}
+ Foo.prototype.length = -1;
- deepEqual(actual, [[1, 2], [4, 5], [7, 8]]);
+ strictEqual(_.isEmpty(new Foo), true);
});
- test('should work with a `callback`', 1, function() {
- var actual = _.initial(array, function(num) {
- return num > 1;
- });
+ test('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', 1, function() {
+ function Foo() {}
+ Foo.prototype.length = MAX_SAFE_INTEGER + 1;
- deepEqual(actual, [1]);
+ strictEqual(_.isEmpty(new Foo), true);
});
- test('should pass the correct `callback` arguments', 1, function() {
- var args;
-
- _.initial(array, function() {
- args || (args = slice.call(arguments));
- });
+ test('should not treat objects with non-number lengths as array-like', 1, function() {
+ strictEqual(_.isEmpty({ 'length': '0' }), false);
+ });
- deepEqual(args, [3, 2, array]);
+ test('fixes the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() {
+ strictEqual(_.isEmpty(shadowObject), false);
});
- test('should support the `thisArg` argument', 1, function() {
- var actual = _.initial(array, function(num, index) {
- return this[index] > 1;
- }, array);
+ test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
+ function Foo() {}
+ Foo.prototype.a = 1;
- deepEqual(actual, [1]);
+ strictEqual(_.isEmpty(Foo), true);
+
+ Foo.prototype = { 'a': 1 };
+ strictEqual(_.isEmpty(Foo), true);
});
- test('should work with an object for `callback`', 1, function() {
- deepEqual(_.initial(objects, { 'b': 2 }), objects.slice(0, 2));
+ test('should return an unwrapped value when intuitively chaining', 1, function() {
+ if (!isNpm) {
+ strictEqual(_({}).isEmpty(), true);
+ }
+ else {
+ skipTest();
+ }
});
- test('should work with a string for `callback`', 1, function() {
- deepEqual(_.initial(objects, 'b'), objects.slice(0, 1));
+ test('should return a wrapped value when explicitly chaining', 1, function() {
+ if (!isNpm) {
+ ok(_({}).chain().isEmpty() instanceof _);
+ }
+ else {
+ skipTest();
+ }
});
- }());
+ }(1, 2, 3));
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.intersection');
+ QUnit.module('lodash.isEqual');
(function() {
- test('should return the intersection of the given arrays', 1, function() {
- var actual = _.intersection([1, 3, 2], [5, 2, 1, 4], [2, 1]);
- deepEqual(actual, [1, 2]);
- });
-
- test('should return an array of unique values', 1, function() {
- var actual = _.intersection([1, 1, 3, 2, 2], [5, 2, 2, 1, 4], [2, 1, 1]);
- deepEqual(actual, [1, 2]);
- });
+ test('should perform comparisons between primitive values', 1, function() {
+ var pairs = [
+ [1, 1, true], [1, Object(1), true], [1, '1', false], [1, 2, false],
+ [-0, -0, true], [0, 0, true], [0, Object(0), true], [Object(0), Object(0), true], [-0, 0, false], [0, '0', false], [0, null, false],
+ [NaN, NaN, true], [NaN, Object(NaN), true], [Object(NaN), Object(NaN), true], [NaN, 'a', false], [NaN, Infinity, false],
+ ['a', 'a', true], ['a', Object('a'), true], [Object('a'), Object('a'), true], ['a', 'b', false], ['a', ['a'], false],
+ [true, true, true], [true, Object(true), true], [Object(true), Object(true), true], [true, 1, false], [true, 'a', false],
+ [false, false, true], [false, Object(false), true], [Object(false), Object(false), true], [false, 0, false], [false, '', false],
+ [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false],
+ [undefined, undefined, true], [undefined, null, false], [undefined, '', false]
+ ];
- test('should work with large arrays of objects', 1, function() {
- var object = {},
- expected = [object];
+ var expected = _.map(pairs, function(pair) {
+ return pair[2];
+ });
- var largeArray = _.times(largeArraySize, function() {
- return object;
+ var actual = _.map(pairs, function(pair) {
+ return _.isEqual(pair[0], pair[1]);
});
- deepEqual(_.intersection(expected, largeArray), expected);
+ deepEqual(actual, expected);
});
- test('should return a wrapped value when chaining', 2, function() {
- if (!isNpm) {
- var actual = _([1, 3, 2]).intersection([5, 2, 1, 4]);
- ok(actual instanceof _);
- deepEqual(actual.value(), [1, 2]);
- }
- else {
- skipTest(2);
- }
- });
+ test('should perform comparisons between arrays', 6, function() {
+ var array1 = [true, null, 1, 'a', undefined],
+ array2 = [true, null, 1, 'a', undefined];
- test('should ignore individual secondary values', 1, function() {
- deepEqual(_.intersection([1, null, 3], 3, null), []);
- });
- }());
+ strictEqual(_.isEqual(array1, array2), true);
- /*--------------------------------------------------------------------------*/
+ array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }];
+ array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }];
- QUnit.module('lodash.invert');
+ strictEqual(_.isEqual(array1, array2), true);
- (function() {
- test('should invert an object', 2, function() {
- var object = { 'a': 1, 'b': 2 },
- actual = _.invert(object);
+ array1 = [1];
+ array1[2] = 3;
- deepEqual(actual, { '1': 'a', '2': 'b' });
- deepEqual(_.invert(actual), { 'a': '1', 'b': '2' });
- });
+ array2 = [1];
+ array2[1] = undefined;
+ array2[2] = 3;
- test('should work with an object that has a `length` property', 1, function() {
- var object = { '0': 'a', '1': 'b', 'length': 2 };
- deepEqual(_.invert(object), { 'a': '0', 'b': '1', '2': 'length' });
- });
- }());
+ strictEqual(_.isEqual(array1, array2), true);
- /*--------------------------------------------------------------------------*/
+ array1 = [Object(1), false, Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [Object('c')]], { 'a': 1 }];
+ array2 = [1, Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', Object('b'), ['c']], { 'a': 1 }];
- QUnit.module('lodash.invoke');
+ strictEqual(_.isEqual(array1, array2), true);
- (function() {
- test('should invoke a methods on each element of a collection', 1, function() {
- var actual = _.invoke(['a', 'b', 'c'], 'toUpperCase');
- deepEqual(actual, ['A', 'B', 'C']);
+ array1 = [1, 2, 3];
+ array2 = [3, 2, 1];
+
+ strictEqual(_.isEqual(array1, array2), false);
+
+ array1 = [1, 2];
+ array2 = [1, 2, 3];
+
+ strictEqual(_.isEqual(array1, array2), false);
});
- test('should work with a function `methodName` argument', 1, function() {
- var actual = _.invoke(['a', 'b', 'c'], function() {
- return this.toUpperCase();
- });
+ test('should treat arrays with identical values but different non-numeric properties as equal', 3, function() {
+ var array1 = [1, 2, 3],
+ array2 = [1, 2, 3];
+
+ array1.every = array1.filter = array1.forEach = array1.indexOf = array1.lastIndexOf = array1.map = array1.some = array1.reduce = array1.reduceRight = null;
+ array2.concat = array2.join = array2.pop = array2.reverse = array2.shift = array2.slice = array2.sort = array2.splice = array2.unshift = null;
+
+ strictEqual(_.isEqual(array1, array2), true);
+
+ array1 = [1, 2, 3];
+ array1.a = 1;
+
+ array2 = [1, 2, 3];
+ array2.b = 1;
+
+ strictEqual(_.isEqual(array1, array2), true);
+
+ array1 = /x/.exec('vwxyz');
+ array2 = ['x'];
- deepEqual(actual, ['A', 'B', 'C']);
+ strictEqual(_.isEqual(array1, array2), true);
});
- test('should work with an object for `collection`', 1, function() {
- var object = { 'a': 1, 'b': 2, 'c': 3 };
- deepEqual(_.invoke(object, 'toFixed', 1), ['1.0', '2.0', '3.0']);
+ test('should work with sparse arrays', 3, function() {
+ var array = Array(1);
+
+ strictEqual(_.isEqual(array, Array(1)), true);
+ strictEqual(_.isEqual(array, [undefined]), true);
+ strictEqual(_.isEqual(array, Array(2)), false);
});
- }());
- /*--------------------------------------------------------------------------*/
+ test('should perform comparisons between plain objects', 5, function() {
+ var object1 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined },
+ object2 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined };
- QUnit.module('lodash.isArguments');
+ strictEqual(_.isEqual(object1, object2), true);
- (function() {
- var args = arguments;
+ object1 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } };
+ object2 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } };
- test('should return `true` for `arguments` objects', 1, function() {
- strictEqual(_.isArguments(args), true);
- });
+ strictEqual(_.isEqual(object1, object2), true);
+
+ object1 = { 'a': 1, 'b': 2, 'c': 3 };
+ object2 = { 'a': 3, 'b': 2, 'c': 1 };
+
+ strictEqual(_.isEqual(object1, object2), false);
+
+ object1 = { 'a': 1, 'b': 2, 'c': 3 };
+ object2 = { 'd': 1, 'e': 2, 'f': 3 };
+
+ strictEqual(_.isEqual(object1, object2), false);
- test('should return `false` for non `arguments` objects', 9, function() {
- var expected = _.map(falsey, function() { return false; });
+ object1 = { 'a': 1, 'b': 2 };
+ object2 = { 'a': 1, 'b': 2, 'c': 3 };
- var actual = _.map(falsey, function(value, index) {
- return index ? _.isArguments(value) : _.isArguments();
- });
+ strictEqual(_.isEqual(object1, object2), false);
+ });
- strictEqual(_.isArguments([1, 2, 3]), false);
- strictEqual(_.isArguments(true), false);
- strictEqual(_.isArguments(new Date), false);
- strictEqual(_.isArguments(_), false);
- strictEqual(_.isArguments({ '0': 1, 'callee': noop, 'length': 1 }), false);
- strictEqual(_.isArguments(0), false);
- strictEqual(_.isArguments(/x/), false);
- strictEqual(_.isArguments('a'), false);
+ test('should perform comparisons of nested objects', 1, function() {
+ var object1 = {
+ 'a': [1, 2, 3],
+ 'b': true,
+ 'c': Object(1),
+ 'd': 'a',
+ 'e': {
+ 'f': ['a', Object('b'), 'c'],
+ 'g': Object(false),
+ 'h': new Date(2012, 4, 23),
+ 'i': _.noop,
+ 'j': 'a'
+ }
+ };
- deepEqual(actual, expected);
- });
+ var object2 = {
+ 'a': [1, Object(2), 3],
+ 'b': Object(true),
+ 'c': 1,
+ 'd': Object('a'),
+ 'e': {
+ 'f': ['a', 'b', 'c'],
+ 'g': false,
+ 'h': new Date(2012, 4, 23),
+ 'i': _.noop,
+ 'j': 'a'
+ }
+ };
- test('should work with `arguments` objects from another realm', 1, function() {
- if (_._object) {
- strictEqual(_.isArguments(_._arguments), true);
- }
- else {
- skipTest();
- }
+ strictEqual(_.isEqual(object1, object2), true);
});
- }(1, 2, 3));
- /*--------------------------------------------------------------------------*/
+ test('should perform comparisons between object instances', 4, function() {
+ function Foo() { this.value = 1; }
+ Foo.prototype.value = 1;
- QUnit.module('lodash.isArray');
+ function Bar() {
+ this.value = 1;
+ }
+ Bar.prototype.value = 2;
- (function() {
- var args = arguments;
+ strictEqual(_.isEqual(new Foo, new Foo), true);
+ strictEqual(_.isEqual(new Foo, new Bar), false);
+ strictEqual(_.isEqual({ 'value': 1 }, new Foo), false);
+ strictEqual(_.isEqual({ 'value': 2 }, new Bar), false);
+ });
- test('should return `true` for arrays', 1, function() {
- strictEqual(_.isArray([1, 2, 3]), true);
+ test('should perform comparisons between objects with constructor properties', 5, function() {
+ strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': 1 }), true);
+ strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': '1' }), false);
+ strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': [1] }), true);
+ strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': ['1'] }), false);
+ strictEqual(_.isEqual({ 'constructor': Object }, {}), false);
});
- test('should return `false` for non arrays', 9, function() {
- var expected = _.map(falsey, function() { return false; });
+ test('should perform comparisons between arrays with circular references', 4, function() {
+ var array1 = [],
+ array2 = [];
- var actual = _.map(falsey, function(value, index) {
- return index ? _.isArray(value) : _.isArray();
- });
+ array1.push(array1);
+ array2.push(array2);
- strictEqual(_.isArray(args), false);
- strictEqual(_.isArray(true), false);
- strictEqual(_.isArray(new Date), false);
- strictEqual(_.isArray(_), false);
- strictEqual(_.isArray({ '0': 1, 'length': 1 }), false);
- strictEqual(_.isArray(0), false);
- strictEqual(_.isArray(/x/), false);
- strictEqual(_.isArray('a'), false);
+ strictEqual(_.isEqual(array1, array2), true);
- deepEqual(actual, expected);
- });
+ array1.push('b');
+ array2.push('b');
- test('should work with arrays from another realm', 1, function() {
- if (_._object) {
- strictEqual(_.isArray(_._array), true);
- }
- else {
- skipTest();
- }
- });
- }(1, 2, 3));
+ strictEqual(_.isEqual(array1, array2), true);
- /*--------------------------------------------------------------------------*/
+ array1.push('c');
+ array2.push('d');
- QUnit.module('lodash.isBoolean');
+ strictEqual(_.isEqual(array1, array2), false);
- (function() {
- var args = arguments;
+ array1 = ['a', 'b', 'c'];
+ array1[1] = array1;
+ array2 = ['a', ['a', 'b', 'c'], 'c'];
- test('should return `true` for booleans', 4, function() {
- strictEqual(_.isBoolean(true), true);
- strictEqual(_.isBoolean(false), true);
- strictEqual(_.isBoolean(new Boolean(true)), true);
- strictEqual(_.isBoolean(new Boolean(false)), true);
+ strictEqual(_.isEqual(array1, array2), false);
});
- test('should return `false` for non booleans', 9, function() {
- var expected = _.map(falsey, function(value) { return value === false; });
+ test('should perform comparisons between objects with circular references', 4, function() {
+ var object1 = {},
+ object2 = {};
- var actual = _.map(falsey, function(value, index) {
- return index ? _.isBoolean(value) : _.isBoolean();
- });
+ object1.a = object1;
+ object2.a = object2;
- strictEqual(_.isBoolean(args), false);
- strictEqual(_.isBoolean([1, 2, 3]), false);
- strictEqual(_.isBoolean(new Date), false);
- strictEqual(_.isBoolean(_), false);
- strictEqual(_.isBoolean({ 'a': 1 }), false);
- strictEqual(_.isBoolean(0), false);
- strictEqual(_.isBoolean(/x/), false);
- strictEqual(_.isBoolean('a'), false);
+ strictEqual(_.isEqual(object1, object2), true);
- deepEqual(actual, expected);
- });
+ object1.b = 0;
+ object2.b = Object(0);
- test('should work with booleans from another realm', 1, function() {
- if (_._object) {
- strictEqual(_.isBoolean(_._boolean), true);
- }
- else {
- skipTest();
- }
- });
- }(1, 2, 3));
+ strictEqual(_.isEqual(object1, object2), true);
- /*--------------------------------------------------------------------------*/
+ object1.c = Object(1);
+ object2.c = Object(2);
- QUnit.module('lodash.isDate');
+ strictEqual(_.isEqual(object1, object2), false);
- (function() {
- var args = arguments;
+ object1 = { 'a': 1, 'b': 2, 'c': 3 };
+ object1.b = object1;
+ object2 = { 'a': 1, 'b': { 'a': 1, 'b': 2, 'c': 3 }, 'c': 3 };
- test('should return `true` for dates', 1, function() {
- strictEqual(_.isDate(new Date), true);
+ strictEqual(_.isEqual(object1, object2), false);
});
- test('should return `false` for non dates', 9, function() {
- var expected = _.map(falsey, function() { return false; });
+ test('should perform comparisons between objects with multiple circular references', 3, function() {
+ var array1 = [{}],
+ array2 = [{}];
- var actual = _.map(falsey, function(value, index) {
- return index ? _.isDate(value) : _.isDate();
- });
+ (array1[0].a = array1).push(array1);
+ (array2[0].a = array2).push(array2);
- strictEqual(_.isDate(args), false);
- strictEqual(_.isDate([1, 2, 3]), false);
- strictEqual(_.isDate(true), false);
- strictEqual(_.isDate(_), false);
- strictEqual(_.isDate({ 'a': 1 }), false);
- strictEqual(_.isDate(0), false);
- strictEqual(_.isDate(/x/), false);
- strictEqual(_.isDate('a'), false);
+ strictEqual(_.isEqual(array1, array2), true);
- deepEqual(actual, expected);
- });
+ array1[0].b = 0;
+ array2[0].b = Object(0);
- test('should work with dates from another realm', 1, function() {
- if (_._object) {
- strictEqual(_.isDate(_._date), true);
- }
- else {
- skipTest();
- }
- });
- }(1, 2, 3));
+ strictEqual(_.isEqual(array1, array2), true);
- /*--------------------------------------------------------------------------*/
+ array1[0].c = Object(1);
+ array2[0].c = Object(2);
- QUnit.module('lodash.isElement');
+ strictEqual(_.isEqual(array1, array2), false);
+ });
- (function() {
- test('should use strict equality in its duck type check', 6, function() {
- var element = body || { 'nodeType': 1 };
+ test('should perform comparisons between objects with complex circular references', 1, function() {
+ var object1 = {
+ 'foo': { 'b': { 'c': { 'd': {} } } },
+ 'bar': { 'a': 2 }
+ };
- strictEqual(_.isElement(element), true);
- strictEqual(_.isElement({ 'nodeType': new Number(1) }), false);
- strictEqual(_.isElement({ 'nodeType': true }), false);
- strictEqual(_.isElement({ 'nodeType': [1] }), false);
- strictEqual(_.isElement({ 'nodeType': '1' }), false);
- strictEqual(_.isElement({ 'nodeType': '001' }), false);
- });
+ var object2 = {
+ 'foo': { 'b': { 'c': { 'd': {} } } },
+ 'bar': { 'a': 2 }
+ };
- test('should work with elements from another realm', 1, function() {
- if (_._element) {
- strictEqual(_.isElement(_._element), true);
- }
- else {
- skipTest();
- }
- });
- }());
+ object1.foo.b.c.d = object1;
+ object1.bar.b = object1.foo.b;
- /*--------------------------------------------------------------------------*/
+ object2.foo.b.c.d = object2;
+ object2.bar.b = object2.foo.b;
- QUnit.module('lodash.isEmpty');
+ strictEqual(_.isEqual(object1, object2), true);
+ });
- (function() {
- var args = arguments;
+ test('should perform comparisons between objects with shared property values', 1, function() {
+ var object1 = {
+ 'a': [1, 2]
+ };
- test('should return `true` for empty or falsey values', 3, function() {
- var expected = _.map(empties, function() { return true; });
+ var object2 = {
+ 'a': [1, 2],
+ 'b': [1, 2]
+ };
- var actual = _.map(empties, function(value) {
- return _.isEmpty(value);
- });
+ object1.b = object1.a;
- strictEqual(_.isEmpty(), true);
- strictEqual(_.isEmpty(/x/), true);
- deepEqual(actual, expected);
+ strictEqual(_.isEqual(object1, object2), true);
});
- test('should return `false` for non-empty values', 3, function() {
- strictEqual(_.isEmpty([0]), false);
- strictEqual(_.isEmpty({ 'a': 0 }), false);
- strictEqual(_.isEmpty('a'), false);
- });
+ test('should work with `arguments` objects (test in IE < 9)', 2, function() {
+ var args1 = (function() { return arguments; }(1, 2, 3)),
+ args2 = (function() { return arguments; }(1, 2, 3)),
+ args3 = (function() { return arguments; }(1, 2));
- test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', 1, function() {
- equal(_.isEmpty(shadowedObject), false);
+ strictEqual(_.isEqual(args1, args2), true);
+ strictEqual(_.isEqual(args1, args3), false);
});
- test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
+ test('should treat `arguments` objects like `Object` objects', 4, function() {
+ var args = (function() { return arguments; }(1, 2, 3)),
+ object = { '0': 1, '1': 2, '2': 3 };
+
function Foo() {}
- Foo.prototype.a = 1;
- strictEqual(_.isEmpty(Foo), true);
+ Foo.prototype = object;
- Foo.prototype = { 'a': 1 };
- strictEqual(_.isEmpty(Foo), true);
- });
+ strictEqual(_.isEqual(args, object), true);
+ strictEqual(_.isEqual(object, args), true);
- test('should work with an object that has a `length` property', 1, function() {
- strictEqual(_.isEmpty({ 'length': 0 }), false);
+ strictEqual(_.isEqual(args, new Foo), false);
+ strictEqual(_.isEqual(new Foo, args), false);
});
- test('should work with jQuery/MooTools DOM query collections', 1, function() {
- function Foo(elements) { push.apply(this, elements); }
- Foo.prototype = { 'length': 0, 'splice': Array.prototype.splice };
-
- strictEqual(_.isEmpty(new Foo([])), true);
+ test('should perform comparisons between date objects', 4, function() {
+ strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2012, 4, 23)), true);
+ strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2013, 3, 25)), false);
+ strictEqual(_.isEqual(new Date(2012, 4, 23), { 'getTime': function() { return 1337756400000; } }), false);
+ strictEqual(_.isEqual(new Date('a'), new Date('a')), false);
});
- test('should work with `arguments` objects (test in IE < 9)', 1, function() {
- if (!isPhantomPage) {
- strictEqual(_.isEmpty(args), false);
- } else {
- skipTest();
- }
- });
+ test('should perform comparisons between error objects', 1, function() {
+ var pairs = _.map([
+ 'Error',
+ 'EvalError',
+ 'RangeError',
+ 'ReferenceError',
+ 'SyntaxError',
+ 'TypeError',
+ 'URIError'
+ ], function(type, index, errorTypes) {
+ var otherType = errorTypes[++index % errorTypes.length],
+ CtorA = root[type],
+ CtorB = root[otherType];
- test('should return an unwrapped value when intuitively chaining', 1, function() {
- if (!isNpm) {
- strictEqual(_({}).isEmpty(), true);
- }
- else {
- skipTest();
- }
- });
+ return [new CtorA('a'), new CtorA('a'), new CtorB('a'), new CtorB('b')];
+ });
- test('should return a wrapped value when explicitly chaining', 1, function() {
- if (!isNpm) {
- ok(_({}).chain().isEmpty() instanceof _);
- }
- else {
- skipTest();
- }
+ var expected = _.times(pairs.length, _.constant([true, false, false]));
+
+ var actual = _.map(pairs, function(pair) {
+ return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])];
+ });
+
+ deepEqual(actual, expected);
});
- }(1, 2, 3));
- /*--------------------------------------------------------------------------*/
+ test('should perform comparisons between functions', 2, function() {
+ function a() { return 1 + 2; }
+ function b() { return 1 + 2; }
- QUnit.module('lodash.isEqual');
+ strictEqual(_.isEqual(a, a), true);
+ strictEqual(_.isEqual(a, b), false);
+ });
- (function() {
- test('should perform comparisons between primitive values', 1, function() {
- var pairs = [
- [1, 1, true], [1, new Number(1), true], [1, '1', false], [1, 2, false],
- [-0, -0, true], [0, 0, true], [0, new Number(0), true], [new Number(0), new Number(0), true], [-0, 0, false], [0, '0', false], [0, null, false],
- [NaN, NaN, true], [NaN, new Number(NaN), true], [new Number(NaN), new Number(NaN), true], [NaN, 'a', false], [NaN, Infinity, false],
- ['a', 'a', true], ['a', new String('a'), true], [new String('a'), new String('a'), true], ['a', 'b', false], ['a', ['a'], false],
- [true, true, true], [true, new Boolean(true), true], [new Boolean(true), new Boolean(true), true], [true, 1, false], [true, 'a', false],
- [false, false, true], [false, new Boolean(false), true], [new Boolean(false), new Boolean(false), true], [false, 0, false], [false, '', false],
- [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false],
- [undefined, undefined, true], [undefined, null, false], [undefined, '', false]
- ];
+ test('should perform comparisons between regexes', 5, function() {
+ strictEqual(_.isEqual(/x/gim, /x/gim), true);
+ strictEqual(_.isEqual(/x/gim, /x/mgi), true);
+ strictEqual(_.isEqual(/x/gi, /x/g), false);
+ strictEqual(_.isEqual(/x/, /y/), false);
+ strictEqual(_.isEqual(/x/g, { 'global': true, 'ignoreCase': false, 'multiline': false, 'source': 'x' }), false);
+ });
- var expected = _.map(pairs, function(pair) {
- return pair[2];
+ test('should perform comparisons between typed arrays', 1, function() {
+ var pairs = _.map(typedArrays, function(type, index) {
+ var otherType = typedArrays[(index + 1) % typedArrays.length],
+ CtorA = root[type] || function(n) { this.n = n; },
+ CtorB = root[otherType] || function(n) { this.n = n; },
+ bufferA = root[type] ? new ArrayBuffer(8) : 8,
+ bufferB = root[otherType] ? new ArrayBuffer(8) : 8,
+ bufferC = root[otherType] ? new ArrayBuffer(16) : 16;
+
+ return [new CtorA(bufferA), new CtorA(bufferA), new CtorB(bufferB), new CtorB(bufferC)];
});
+ var expected = _.times(pairs.length, _.constant([true, false, false]));
+
var actual = _.map(pairs, function(pair) {
- return _.isEqual(pair[0], pair[1]);
- })
+ return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])];
+ });
deepEqual(actual, expected);
});
+ test('should avoid common type coercions', 9, function() {
+ strictEqual(_.isEqual(true, Object(false)), false);
+ strictEqual(_.isEqual(Object(false), Object(0)), false);
+ strictEqual(_.isEqual(false, Object('')), false);
+ strictEqual(_.isEqual(Object(36), Object('36')), false);
+ strictEqual(_.isEqual(0, ''), false);
+ strictEqual(_.isEqual(1, true), false);
+ strictEqual(_.isEqual(1337756400000, new Date(2012, 4, 23)), false);
+ strictEqual(_.isEqual('36', 36), false);
+ strictEqual(_.isEqual(36, '36'), false);
+ });
+
+ test('fixes the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() {
+ strictEqual(_.isEqual(shadowObject, {}), false);
+ });
+
test('should return `false` for objects with custom `toString` methods', 1, function() {
var primitive,
object = { 'toString': function() { return primitive; } },
values = [true, null, 1, 'a', undefined],
- expected = _.map(values, function() { return false; });
+ expected = _.map(values, _.constant(false));
var actual = _.map(values, function(value) {
primitive = value;
return _.isEqual(object, value);
});
- ok(actual, expected);
+ deepEqual(actual, expected);
});
- test('should perform comparisons between arrays', 6, function() {
- var array1 = [true, null, 1, 'a', undefined],
- array2 = [true, null, 1, 'a', undefined];
+ test('should provide the correct `customizer` arguments', 1, function() {
+ var argsList = [],
+ object1 = { 'a': [1, 2], 'b': null },
+ object2 = { 'a': [1, 2], 'b': null };
+
+ object1.b = object2;
+ object2.b = object1;
+
+ var expected = [
+ [object1, object2],
+ [object1.a, object2.a, 'a'],
+ [object1.a[0], object2.a[0], 0],
+ [object1.a[1], object2.a[1], 1],
+ [object1.b, object2.b, 'b'],
+ [object1.b.a, object2.b.a, 'a'],
+ [object1.b.a[0], object2.b.a[0], 0],
+ [object1.b.a[1], object2.b.a[1], 1],
+ [object1.b.b, object2.b.b, 'b']
+ ];
- strictEqual(_.isEqual(array1, array2), true);
+ _.isEqual(object1, object2, function() {
+ argsList.push(slice.call(arguments));
+ });
- array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }];
- array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }];
+ deepEqual(argsList, expected);
+ });
- strictEqual(_.isEqual(array1, array2), true);
+ test('should correctly set the `this` binding', 1, function() {
+ var actual = _.isEqual('a', 'b', function(a, b) {
+ return this[a] == this[b];
+ }, { 'a': 1, 'b': 1 });
- array1 = [1];
- array1[2] = 3;
+ strictEqual(actual, true);
+ });
- array2 = [1];
- array2[1] = undefined;
- array2[2] = 3;
+ test('should handle comparisons if `customizer` returns `undefined`', 1, function() {
+ strictEqual(_.isEqual('a', 'a', _.noop), true);
+ });
- strictEqual(_.isEqual(array1, array2), true);
+ test('should return a boolean value even if `customizer` does not', 2, function() {
+ var actual = _.isEqual('a', 'a', _.constant('a'));
+ strictEqual(actual, true);
- array1 = [new Number(1), false, new String('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [new String('c')]], { 'a': 1 }];
- array2 = [1, new Boolean(false), 'a', /x/, new Date(2012, 4, 23), ['a', new String('b'), ['c']], { 'a': 1 }];
+ var expected = _.map(falsey, _.constant(false));
- strictEqual(_.isEqual(array1, array2), true);
+ actual = [];
+ _.each(falsey, function(value) {
+ actual.push(_.isEqual('a', 'b', _.constant(value)));
+ });
- array1 = [1, 2, 3];
- array2 = [3, 2, 1];
+ deepEqual(actual, expected);
+ });
- strictEqual(_.isEqual(array1, array2), false);
+ test('should ensure `customizer` is a function', 1, function() {
+ var array = [1, 2, 3],
+ eq = _.partial(_.isEqual, array),
+ actual = _.map([array, [1, 0, 3]], eq);
- array1 = [1, 2];
- array2 = [1, 2, 3];
+ deepEqual(actual, [true, false]);
+ });
- strictEqual(_.isEqual(array1, array2), false);
+ test('should work as an iteratee for `_.every`', 1, function() {
+ var actual = _.every([1, 1, 1], _.partial(_.isEqual, 1));
+ ok(actual);
});
- test('should treat arrays with identical values but different non-numeric properties as equal', 3, function() {
- var array1 = [1, 2, 3],
- array2 = [1, 2, 3];
+ test('should treat objects created by `Object.create(null)` like any other plain object', 2, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.constructor = null;
- array1.every = array1.filter = array1.forEach = array1.indexOf = array1.lastIndexOf = array1.map = array1.some = array1.reduce = array1.reduceRight = null;
- array2.concat = array2.join = array2.pop = array2.reverse = array2.shift = array2.slice = array2.sort = array2.splice = array2.unshift = null;
+ var object2 = { 'a': 1 };
+ strictEqual(_.isEqual(new Foo, object2), false);
- strictEqual(_.isEqual(array1, array2), true);
+ if (create) {
+ var object1 = create(null);
+ object1.a = 1;
+ strictEqual(_.isEqual(object1, object2), true);
+ }
+ else {
+ skipTest();
+ }
+ });
- array1 = [1, 2, 3];
- array1.a = 1;
+ test('should return `true` for like-objects from different documents', 4, function() {
+ // Ensure `_._object` is assigned (unassigned in Opera 10.00).
+ if (_._object) {
+ strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 3 }, _._object), true);
+ strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 2 }, _._object), false);
+ strictEqual(_.isEqual([1, 2, 3], _._array), true);
+ strictEqual(_.isEqual([1, 2, 2], _._array), false);
+ }
+ else {
+ skipTest(4);
+ }
+ });
- array2 = [1, 2, 3];
- array2.b = 1;
+ test('should not error on DOM elements', 1, function() {
+ if (document) {
+ var element1 = document.createElement('div'),
+ element2 = element1.cloneNode(true);
- strictEqual(_.isEqual(array1, array2), true);
+ try {
+ strictEqual(_.isEqual(element1, element2), false);
+ } catch(e) {
+ ok(false, e.message);
+ }
+ }
+ else {
+ skipTest();
+ }
+ });
- array1 = /x/.exec('vwxyz');
- array2 = ['x'];
+ test('should perform comparisons between wrapped values', 32, function() {
+ var stamp = +new Date;
- strictEqual(_.isEqual(array1, array2), true);
- });
+ var values = [
+ [[1, 2], [1, 2], [1, 2, 3]],
+ [true, true, false],
+ [new Date(stamp), new Date(stamp), new Date(stamp - 100)],
+ [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 2 }, { 'a': 1, 'b': 1 }],
+ [1, 1, 2],
+ [NaN, NaN, Infinity],
+ [/x/, /x/, /x/i],
+ ['a', 'a', 'A']
+ ];
- test('should perform comparisons between date objects', 4, function() {
- strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2012, 4, 23)), true);
- strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2013, 3, 25)), false);
- strictEqual(_.isEqual(new Date(2012, 4, 23), { 'getTime': function() { return 1337756400000; } }), false);
- strictEqual(_.isEqual(new Date('a'), new Date('a')), false);
- });
+ _.each(values, function(vals) {
+ if (!isNpm) {
+ var wrapped1 = _(vals[0]),
+ wrapped2 = _(vals[1]),
+ actual = wrapped1.isEqual(wrapped2);
- test('should perform comparisons between functions', 2, function() {
- function a() { return 1 + 2; }
- function b() { return 1 + 2; }
+ strictEqual(actual, true);
+ strictEqual(_.isEqual(_(actual), _(true)), true);
- strictEqual(_.isEqual(a, a), true);
- strictEqual(_.isEqual(a, b), false);
- });
+ wrapped1 = _(vals[0]);
+ wrapped2 = _(vals[2]);
- test('should perform comparisons between plain objects', 5, function() {
- var object1 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined },
- object2 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined };
+ actual = wrapped1.isEqual(wrapped2);
+ strictEqual(actual, false);
+ strictEqual(_.isEqual(_(actual), _(false)), true);
+ }
+ else {
+ skipTest(4);
+ }
+ });
+ });
- strictEqual(_.isEqual(object1, object2), true);
+ test('should perform comparisons between wrapped and non-wrapped values', 4, function() {
+ if (!isNpm) {
+ var object1 = _({ 'a': 1, 'b': 2 }),
+ object2 = { 'a': 1, 'b': 2 };
- object1 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } };
- object2 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } };
+ strictEqual(object1.isEqual(object2), true);
+ strictEqual(_.isEqual(object1, object2), true);
- strictEqual(_.isEqual(object1, object2), true);
+ object1 = _({ 'a': 1, 'b': 2 });
+ object2 = { 'a': 1, 'b': 1 };
- object1 = { 'a': 1, 'b': 2, 'c': 3 };
- object2 = { 'a': 3, 'b': 2, 'c': 1 };
+ strictEqual(object1.isEqual(object2), false);
+ strictEqual(_.isEqual(object1, object2), false);
+ }
+ else {
+ skipTest(4);
+ }
+ });
- strictEqual(_.isEqual(object1, object2), false);
+ test('should return an unwrapped value when intuitively chaining', 1, function() {
+ if (!isNpm) {
+ strictEqual(_('a').isEqual('a'), true);
+ }
+ else {
+ skipTest();
+ }
+ });
- object1 = { 'a': 1, 'b': 2, 'c': 3 };
- object2 = { 'd': 1, 'e': 2, 'f': 3 };
+ test('should return a wrapped value when explicitly chaining', 1, function() {
+ if (!isNpm) {
+ ok(_('a').chain().isEqual('a') instanceof _);
+ }
+ else {
+ skipTest();
+ }
+ });
+ }());
- strictEqual(_.isEqual(object1, object2), false);
+ /*--------------------------------------------------------------------------*/
- object1 = { 'a': 1, 'b': 2 };
- object2 = { 'a': 1, 'b': 2, 'c': 3 };
+ QUnit.module('lodash.isError');
- strictEqual(_.isEqual(object1, object2), false);
- });
+ (function() {
+ var args = arguments;
- test('should perform comparisons of nested objects', 1, function() {
- var object1 = {
- 'a': [1, 2, 3],
- 'b': true,
- 'c': new Number(1),
- 'd': 'a',
- 'e': {
- 'f': ['a', new String('b'), 'c'],
- 'g': new Boolean(false),
- 'h': new Date(2012, 4, 23),
- 'i': noop,
- 'j': 'a'
- }
- };
+ test('should return `true` for error objects', 1, function() {
+ var expected = _.map(errors, _.constant(true));
- var object2 = {
- 'a': [1, new Number(2), 3],
- 'b': new Boolean(true),
- 'c': 1,
- 'd': new String('a'),
- 'e': {
- 'f': ['a', 'b', 'c'],
- 'g': false,
- 'h': new Date(2012, 4, 23),
- 'i': noop,
- 'j': 'a'
- }
- };
+ var actual = _.map(errors, function(error) {
+ return _.isError(error) === true;
+ });
- strictEqual(_.isEqual(object1, object2), true);
+ deepEqual(actual, expected);
});
- test('should perform comparisons between object instances', 4, function() {
- function Foo() {
- this.value = 1;
- }
- Foo.prototype.value = 1;
+ test('should return `false` for non error objects', 12, function() {
+ var expected = _.map(falsey, _.constant(false));
- function Bar() {
- this.value = 1;
- }
- Bar.prototype.value = 2;
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.isError(value) : _.isError();
+ });
- strictEqual(_.isEqual(new Foo, new Foo), true);
- strictEqual(_.isEqual(new Foo, new Bar), false);
- strictEqual(_.isEqual({ 'value': 1 }, new Foo), false);
- strictEqual(_.isEqual({ 'value': 2 }, new Bar), false);
- });
+ deepEqual(actual, expected);
- test('should perform comparisons between regexes', 4, function() {
- strictEqual(_.isEqual(/x/gim, /x/gim), true);
- strictEqual(_.isEqual(/x/gi, /x/g), false);
- strictEqual(_.isEqual(/x/, /y/), false);
- strictEqual(_.isEqual(/x/g, { 'global': true, 'ignoreCase': false, 'multiline': false, 'source': 'x' }), false);
+ strictEqual(_.isError(args), false);
+ strictEqual(_.isError([1, 2, 3]), false);
+ strictEqual(_.isError(true), false);
+ strictEqual(_.isError(new Date), false);
+ strictEqual(_.isError(_), false);
+ strictEqual(_.isError(slice), false);
+ strictEqual(_.isError({ 'a': 1 }), false);
+ strictEqual(_.isError(1), false);
+ strictEqual(_.isError(NaN), false);
+ strictEqual(_.isError(/x/), false);
+ strictEqual(_.isError('a'), false);
});
- test('should avoid common type coercions', 9, function() {
- strictEqual(_.isEqual(true, new Boolean(false)), false);
- strictEqual(_.isEqual(new Boolean(false), new Number(0)), false);
- strictEqual(_.isEqual(false, new String('')), false);
- strictEqual(_.isEqual(new Number(36), new String(36)), false);
- strictEqual(_.isEqual(0, ''), false);
- strictEqual(_.isEqual(1, true), false);
- strictEqual(_.isEqual(1337756400000, new Date(2012, 4, 23)), false);
- strictEqual(_.isEqual('36', 36), false);
- strictEqual(_.isEqual(36, '36'), false);
+ test('should work with an error object from another realm', 1, function() {
+ if (_._object) {
+ var expected = _.map(_._errors, _.constant(true));
+
+ var actual = _.map(_._errors, function(error) {
+ return _.isError(error) === true;
+ });
+
+ deepEqual(actual, expected);
+ }
+ else {
+ skipTest();
+ }
});
+ }(1, 2, 3));
- test('should work with sparse arrays', 2, function() {
- strictEqual(_.isEqual(Array(3), Array(3)), true);
- strictEqual(_.isEqual(Array(3), Array(6)), false);
- });
+ /*--------------------------------------------------------------------------*/
- test('should work with `arguments` objects (test in IE < 9)', 2, function() {
- var args1 = (function() { return arguments; }(1, 2, 3)),
- args2 = (function() { return arguments; }(1, 2, 3)),
- args3 = (function() { return arguments; }(1, 2));
+ QUnit.module('lodash.isFinite');
- if (!isPhantomPage) {
- strictEqual(_.isEqual(args1, args2), true);
- strictEqual(_.isEqual(args1, args3), false);
- } else {
- skipTest(2);
- }
- });
+ (function() {
+ var args = arguments;
- test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', 1, function() {
- strictEqual(_.isEqual(shadowedObject, {}), false);
- });
+ test('should return `true` for finite values', 1, function() {
+ var values = [0, 1, 3.14, -1],
+ expected = _.map(values, _.constant(true));
- test('should perform comparisons between arrays with circular references', 4, function() {
- var array1 = [],
- array2 = [];
+ var actual = _.map(values, function(value) {
+ return _.isFinite(value);
+ });
- array1.push(array1);
- array2.push(array2);
+ deepEqual(actual, expected);
+ });
- strictEqual(_.isEqual(array1, array2), true);
+ test('should return `false` for non finite values', 9, function() {
+ var values = [NaN, Infinity, -Infinity, Object(1)],
+ expected = _.map(values, _.constant(false));
- array1.push('a');
- array2.push('a');
+ var actual = _.map(values, function(value) {
+ return _.isFinite(value);
+ });
- strictEqual(_.isEqual(array1, array2), true);
+ deepEqual(actual, expected);
- array1.push('b');
- array2.push('c');
+ strictEqual(_.isFinite(args), false);
+ strictEqual(_.isFinite([1, 2, 3]), false);
+ strictEqual(_.isFinite(true), false);
+ strictEqual(_.isFinite(new Date), false);
+ strictEqual(_.isFinite(new Error), false);
+ strictEqual(_.isFinite({ 'a': 1 }), false);
+ strictEqual(_.isFinite(/x/), false);
+ strictEqual(_.isFinite('a'), false);
+ });
- strictEqual(_.isEqual(array1, array2), false);
+ test('should return `false` for non numeric values', 1, function() {
+ var values = [undefined, [], true, new Date, new Error, '', ' ', '2px'],
+ expected = _.map(values, _.constant(false));
- array1 = ['a', 'b', 'c'];
- array1[1] = array1;
- array2 = ['a', ['a', 'b', 'c'], 'c'];
+ var actual = _.map(values, function(value) {
+ return _.isFinite(value);
+ });
- strictEqual(_.isEqual(array1, array2), false);
+ deepEqual(actual, expected);
});
- test('should perform comparisons between objects with circular references', 4, function() {
- var object1 = {},
- object2 = {};
+ test('should return `false` for numeric string values', 1, function() {
+ var values = ['2', '0', '08'],
+ expected = _.map(values, _.constant(false));
- object1.a = object1;
- object2.a = object2;
+ var actual = _.map(values, function(value) {
+ return _.isFinite(value);
+ });
- strictEqual(_.isEqual(object1, object2), true);
+ deepEqual(actual, expected);
+ });
+ }(1, 2, 3));
- object1.b = 0;
- object2.b = new Number(0);
+ /*--------------------------------------------------------------------------*/
- strictEqual(_.isEqual(object1, object2), true);
+ QUnit.module('lodash.isFunction');
- object1.c = new Number(1);
- object2.c = new Number(2);
+ (function() {
+ var args = arguments;
- strictEqual(_.isEqual(object1, object2), false);
+ test('should return `true` for functions', 2, function() {
+ strictEqual(_.isFunction(_), true);
+ strictEqual(_.isFunction(slice), true);
+ });
- object1 = { 'a': 1, 'b': 2, 'c': 3 };
- object1.b = object1;
- object2 = { 'a': 1, 'b': { 'a': 1, 'b': 2, 'c': 3 }, 'c': 3 };
+ test('should return `true` for typed array constructors', 1, function() {
+ var expected = _.map(typedArrays, function(type) {
+ return objToString.call(root[type]) == funcTag;
+ });
- strictEqual(_.isEqual(object1, object2), false);
+ var actual = _.map(typedArrays, function(type) {
+ return _.isFunction(root[type]);
+ });
+
+ deepEqual(actual, expected);
});
- test('should perform comparisons between objects with multiple circular references', 3, function() {
- var array1 = [{}],
- array2 = [{}];
+ test('should return `false` for non functions', 11, function() {
+ var expected = _.map(falsey, _.constant(false));
- (array1[0].a = array1).push(array1);
- (array2[0].a = array2).push(array2);
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.isFunction(value) : _.isFunction();
+ });
- strictEqual(_.isEqual(array1, array2), true);
+ deepEqual(actual, expected);
- array1[0].b = 0;
- array2[0].b = new Number(0);
+ strictEqual(_.isFunction(args), false);
+ strictEqual(_.isFunction([1, 2, 3]), false);
+ strictEqual(_.isFunction(true), false);
+ strictEqual(_.isFunction(new Date), false);
+ strictEqual(_.isFunction(new Error), false);
+ strictEqual(_.isFunction({ 'a': 1 }), false);
+ strictEqual(_.isFunction(1), false);
+ strictEqual(_.isFunction(NaN), false);
+ strictEqual(_.isFunction(/x/), false);
+ strictEqual(_.isFunction('a'), false);
+ });
- strictEqual(_.isEqual(array1, array2), true);
+ test('should work using its fallback', 3, function() {
+ if (!isModularize) {
+ // Simulate native `Uint8Array` constructor with a `toStringTag`
+ // of 'Function' and a `typeof` result of 'object'.
+ var lodash = _.runInContext({
+ 'Function': {
+ 'prototype': {
+ 'toString': function() {
+ return _.has(this, 'toString') ? this.toString() : fnToString.call(this);
+ }
+ }
+ },
+ 'Object': _.assign(function(value) {
+ return Object(value);
+ }, {
+ 'prototype': {
+ 'toString': _.assign(function() {
+ return _.has(this, '@@toStringTag') ? this['@@toStringTag'] : objToString.call(this);
+ }, {
+ 'toString': function() {
+ return String(toString);
+ }
+ })
+ }
+ }),
+ 'Uint8Array': {
+ '@@toStringTag': funcTag,
+ 'toString': function() {
+ return String(Uint8Array || Array);
+ }
+ }
+ });
- array1[0].c = new Number(1);
- array2[0].c = new Number(2);
+ strictEqual(lodash.isFunction(slice), true);
+ strictEqual(lodash.isFunction(/x/), false);
+ strictEqual(lodash.isFunction(Uint8Array), objToString.call(Uint8Array) == funcTag);
+ }
+ else {
+ skipTest(3);
+ }
+ });
- strictEqual(_.isEqual(array1, array2), false);
+ test('should work with host objects in IE 8 document mode (test in IE 11)', 2, function() {
+ // Trigger a Chakra JIT bug.
+ // See https://github.com/jashkenas/underscore/issues/1621.
+ _.each([body, xml], function(object) {
+ if (object) {
+ _.times(100, _.isFunction);
+ strictEqual(_.isFunction(object), false);
+ }
+ else {
+ skipTest();
+ }
+ });
});
- test('should perform comparisons between objects with complex circular references', 1, function() {
- var object1 = {
- 'foo': { 'b': { 'foo': { 'c': { } } } },
- 'bar': { 'a': 2 }
- };
+ test('should work with a function from another realm', 1, function() {
+ if (_._object) {
+ strictEqual(_.isFunction(_._function), true);
+ }
+ else {
+ skipTest();
+ }
+ });
+ }(1, 2, 3));
- var object2 = {
- 'foo': { 'b': { 'foo': { 'c': { } } } },
- 'bar': { 'a': 2 }
- };
+ /*--------------------------------------------------------------------------*/
- object1.foo.b.foo.c = object1;
- object1.bar.b = object1.foo.b;
+ QUnit.module('lodash.isMatch');
- object2.foo.b.foo.c = object2;
- object2.bar.b = object2.foo.b;
+ (function() {
+ test('should perform a deep comparison between `object` and `source`', 5, function() {
+ var object = { 'a': 1, 'b': 2, 'c': 3 };
+ strictEqual(_.isMatch(object, { 'a': 1 }), true);
+ strictEqual(_.isMatch(object, { 'b': 1 }), false);
+ strictEqual(_.isMatch(object, { 'a': 1, 'c': 3 }), true);
+ strictEqual(_.isMatch(object, { 'c': 3, 'd': 4 }), false);
- strictEqual(_.isEqual(object1, object2), true);
+ object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 };
+ strictEqual(_.isMatch(object, { 'a': { 'b': { 'c': 1 } } }), true);
});
- test('should perform comparisons between objects with shared property values', function() {
- var object1 = {
- 'a': [1, 2]
- };
+ test('should compare a variety of `source` values', 2, function() {
+ var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } },
+ object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } };
- var object2 = {
- 'a': [1, 2],
- 'b': [1, 2]
- };
+ strictEqual(_.isMatch(object1, object1), true);
+ strictEqual(_.isMatch(object1, object2), false);
+ });
- object1.b = object1.a;
+ test('should return `true` when comparing an empty `source`', 1, function() {
+ var object = { 'a': 1 },
+ expected = _.map(empties, _.constant(true));
- strictEqual(_.isEqual(object1, object2), true);
+ var actual = _.map(empties, function(value) {
+ return _.isMatch(object, value);
+ });
+
+ deepEqual(actual, expected);
});
- test('should pass the correct `callback` arguments', 1, function() {
- var args;
+ test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() {
+ var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }],
+ source = { 'a': [], 'b': {} };
- _.isEqual('a', 'b', function() {
- args || (args = slice.call(arguments));
+ var actual = _.filter(objects, function(object) {
+ return _.isMatch(object, source);
});
- deepEqual(args, ['a', 'b']);
+ deepEqual(actual, objects);
});
- test('should correctly set the `this` binding', 1, function() {
- var actual = _.isEqual('a', 'b', function(a, b) {
- return this[a] == this[b];
- }, { 'a': 1, 'b': 1 });
+ test('should not error for falsey `object` values', 1, function() {
+ var values = falsey.slice(1),
+ expected = _.map(values, _.constant(false)),
+ source = { 'a': 1 };
- strictEqual(actual, true);
- });
+ var actual = _.map(values, function(value) {
+ try {
+ return _.isMatch(value, source);
+ } catch(e) {}
+ });
- test('should handle comparisons if `callback` returns `undefined`', 1, function() {
- var actual = _.isEqual('a', 'a', function() {});
- strictEqual(actual, true);
+ deepEqual(actual, expected);
});
- test('should return a boolean value even if `callback` does not', 2, function() {
- var actual = _.isEqual('a', 'a', function() { return 'a'; });
- strictEqual(actual, true);
-
- var expected = _.map(falsey, function() { return false; });
- actual = [];
+ test('should return `true` when comparing an empty `source` to a falsey `object`', 1, function() {
+ var values = falsey.slice(1),
+ expected = _.map(values, _.constant(true)),
+ source = {};
- _.forEach(falsey, function(value) {
- actual.push(_.isEqual('a', 'b', function() { return value; }));
+ var actual = _.map(values, function(value) {
+ try {
+ return _.isMatch(value, source);
+ } catch(e) {}
});
deepEqual(actual, expected);
});
- test('should ensure `callback` is a function', 1, function() {
- var array = [1, 2, 3],
- eq = _.partial(_.isEqual, array),
- actual = _.every([array, [1, 0, 3]], eq);
+ test('should search arrays of `source` for values', 3, function() {
+ var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }],
+ source = { 'a': ['d'] },
+ predicate = function(object) { return _.isMatch(object, source); },
+ actual = _.filter(objects, predicate);
- strictEqual(actual, false);
- });
+ deepEqual(actual, [objects[1]]);
- test('should treat objects created by `Object.create(null)` like any other plain object', 2, function() {
- function Foo() { this.a = 1; }
- Foo.prototype.constructor = null;
+ source = { 'a': ['b', 'd'] };
+ actual = _.filter(objects, predicate);
- var other = { 'a': 1 };
- strictEqual(_.isEqual(new Foo, other), false);
+ deepEqual(actual, []);
- if (create) {
- var object = Object.create(null);
- object.a = 1;
- strictEqual(_.isEqual(object, other), true);
- }
- else {
- skipTest();
- }
+ source = { 'a': ['d', 'b'] };
+ actual = _.filter(objects, predicate);
+ deepEqual(actual, []);
});
- test('should return an unwrapped value when intuitively chaining', 1, function() {
- if (!isNpm) {
- strictEqual(_('a').isEqual('a'), true);
- }
- else {
- skipTest();
- }
+ test('should perform a partial comparison of all objects within arrays of `source`', 1, function() {
+ var source = { 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] };
+
+ var objects = [
+ { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] },
+ { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] }
+ ];
+
+ var actual = _.filter(objects, function(object) {
+ return _.isMatch(object, source);
+ });
+
+ deepEqual(actual, [objects[0]]);
});
- test('should return a wrapped value when explicitly chaining', 1, function() {
- if (!isNpm) {
- ok(_('a').chain().isEqual('a') instanceof _);
- }
- else {
- skipTest();
- }
+ test('should handle a `source` with `undefined` values', 2, function() {
+ var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }],
+ source = { 'b': undefined },
+ predicate = function(object) { return _.isMatch(object, source); },
+ actual = _.map(objects, predicate),
+ expected = [false, false, true];
+
+ deepEqual(actual, expected);
+
+ source = { 'a': { 'c': undefined } };
+ objects = [{ 'a': { 'b': 1 } }, { 'a':{ 'b':1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }];
+ actual = _.map(objects, predicate);
+
+ deepEqual(actual, expected);
});
- test('should perform comparisons between wrapped values', 4, function() {
- if (!isNpm) {
- var object1 = _({ 'a': 1, 'b': 2 }),
- object2 = _({ 'a': 1, 'b': 2 }),
- actual = object1.isEqual(object2);
+ test('should not match by inherited `source` properties', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
- strictEqual(actual, true);
- strictEqual(_.isEqual(_(actual), _(true)), true);
+ var objects = [{ 'a': 1 }, { 'a': 1, 'b': 2 }],
+ source = new Foo,
+ expected = _.map(objects, _.constant(true));
- object1 = _({ 'a': 1, 'b': 2 });
- object2 = _({ 'a': 1, 'b': 1 });
+ var actual = _.map(objects, function(object) {
+ return _.isMatch(object, source);
+ });
- actual = object1.isEqual(object2);
- strictEqual(actual, false);
- strictEqual(_.isEqual(_(actual), _(false)), true);
- }
- else {
- skipTest(4);
- }
+ deepEqual(actual, expected);
});
- test('should perform comparisons between wrapped and non-wrapped values', 4, function() {
- if (!isNpm) {
- var object1 = _({ 'a': 1, 'b': 2 }),
- object2 = { 'a': 1, 'b': 2 };
+ test('should work with a function for `source`', 1, function() {
+ function source() {}
- strictEqual(object1.isEqual(object2), true);
- strictEqual(_.isEqual(object1, object2), true);
+ source.a = 1;
+ source.b = function() {};
+ source.c = 3;
- object1 = _({ 'a': 1, 'b': 2 });
- object2 = { 'a': 1, 'b': 1 };
+ var objects = [{ 'a': 1 }, { 'a': 1, 'b': source.b, 'c': 3 }];
- strictEqual(object1.isEqual(object2), false);
- strictEqual(_.isEqual(object1, object2), false);
- }
- else {
- skipTest(4);
- }
+ var actual = _.map(objects, function(object) {
+ return _.isMatch(object, source);
+ });
+
+ deepEqual(actual, [false, true]);
});
- test('should return `true` for like-objects from different documents', 1, function() {
- // ensure `_._object` is assigned (unassigned in Opera 10.00)
- if (_._object) {
- var object = { 'a': 1, 'b': 2, 'c': 3 };
- strictEqual(_.isEqual(object, _._object), true);
- }
- else {
- skipTest();
- }
+ test('should match problem JScript properties (test in IE < 9)', 1, function() {
+ var objects = [{}, shadowObject];
+
+ var actual = _.map(objects, function(object) {
+ return _.isMatch(object, shadowObject);
+ });
+
+ deepEqual(actual, [false, true]);
});
- }());
- /*--------------------------------------------------------------------------*/
+ test('should provide the correct `customizer` arguments', 1, function() {
+ var argsList = [],
+ object1 = { 'a': [1, 2], 'b': null },
+ object2 = { 'a': [1, 2], 'b': null };
+
+ object1.b = object2;
+ object2.b = object1;
+
+ var expected = [
+ [object1.a, object2.a, 'a'],
+ [object1.a[0], object2.a[0], 0],
+ [object1.a[1], object2.a[1], 1],
+ [object1.b, object2.b, 'b'],
+ [object1.b.a, object2.b.a, 'a'],
+ [object1.b.a[0], object2.b.a[0], 0],
+ [object1.b.a[1], object2.b.a[1], 1],
+ [object1.b.b, object2.b.b, 'b'],
+ [object1.b.b.a, object2.b.b.a, 'a'],
+ [object1.b.b.a[0], object2.b.b.a[0], 0],
+ [object1.b.b.a[1], object2.b.b.a[1], 1],
+ [object1.b.b.b, object2.b.b.b, 'b']
+ ];
- QUnit.module('lodash.isFinite');
+ _.isMatch(object1, object2, function() {
+ argsList.push(slice.call(arguments));
+ });
- (function() {
- test('should return `true` for finite values', 5, function() {
- strictEqual(_.isFinite(0), true);
- strictEqual(_.isFinite(1), true);
- strictEqual(_.isFinite(3.14), true);
- strictEqual(_.isFinite(-1), true);
- strictEqual(_.isFinite(new Number(0)), true);
+ deepEqual(argsList, expected);
+ });
+
+ test('should correctly set the `this` binding', 1, function() {
+ var actual = _.isMatch({ 'a': 1 }, { 'a': 2 }, function(a, b) {
+ return this[a] == this[b];
+ }, { 'a': 1, 'b': 1 });
+
+ strictEqual(actual, true);
});
- test('should return `false` for non-finite values', 3, function() {
- strictEqual(_.isFinite(NaN), false);
- strictEqual(_.isFinite(Infinity), false);
- strictEqual(_.isFinite(-Infinity), false);
+ test('should handle comparisons if `customizer` returns `undefined`', 1, function() {
+ strictEqual(_.isMatch({ 'a': 1 }, { 'a': 1 }, _.noop), true);
});
- test('should return `false` for non-numeric values', 8, function() {
- strictEqual(_.isFinite(null), false);
- strictEqual(_.isFinite(undefined), false);
- strictEqual(_.isFinite([]), false);
- strictEqual(_.isFinite(true), false);
- strictEqual(_.isFinite(new Date), false);
- strictEqual(_.isFinite(''), false);
- strictEqual(_.isFinite(' '), false);
- strictEqual(_.isFinite('2px'), false);
+ test('should return a boolean value even if `customizer` does not', 2, function() {
+ var object = { 'a': 1 },
+ actual = _.isMatch(object, { 'a': 1 }, _.constant('a'));
+
+ strictEqual(actual, true);
+
+ var expected = _.map(falsey, _.constant(false));
+
+ actual = [];
+ _.each(falsey, function(value) {
+ actual.push(_.isMatch(object, { 'a': 2 }, _.constant(value)));
+ });
+
+ deepEqual(actual, expected);
});
- test('should return `true` for numeric string values', 3, function() {
- strictEqual(_.isFinite('2'), true);
- strictEqual(_.isFinite('0'), true);
- strictEqual(_.isFinite('08'), true);
- });
+ test('should ensure `customizer` is a function', 1, function() {
+ var object = { 'a': 1 },
+ matches = _.partial(_.isMatch, object),
+ actual = _.map([object, { 'a': 2 }], matches);
- test('should work with numbers from another realm', 1, function() {
- if (_._object) {
- strictEqual(_.isFinite(_._number), true);
- }
- else {
- skipTest();
- }
+ deepEqual(actual, [true, false]);
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.isFunction');
+ QUnit.module('lodash.isNaN');
(function() {
var args = arguments;
- test('should return `true` for functions', 1, function() {
- strictEqual(_.isFunction(_), true);
+ test('should return `true` for NaNs', 2, function() {
+ strictEqual(_.isNaN(NaN), true);
+ strictEqual(_.isNaN(Object(NaN)), true);
});
- test('should return `false` for non functions', 9, function() {
- var expected = _.map(falsey, function() { return false; });
+ test('should return `false` for non NaNs', 12, function() {
+ var expected = _.map(falsey, function(value) { return value !== value; });
var actual = _.map(falsey, function(value, index) {
- return index ? _.isFunction(value) : _.isFunction();
+ return index ? _.isNaN(value) : _.isNaN();
});
- strictEqual(_.isFunction(args), false);
- strictEqual(_.isFunction([1, 2, 3]), false);
- strictEqual(_.isFunction(true), false);
- strictEqual(_.isFunction(new Date), false);
- strictEqual(_.isFunction({ 'a': 1 }), false);
- strictEqual(_.isFunction(0), false);
- strictEqual(_.isFunction(/x/), false);
- strictEqual(_.isFunction('a'), false);
-
deepEqual(actual, expected);
+
+ strictEqual(_.isNaN(args), false);
+ strictEqual(_.isNaN([1, 2, 3]), false);
+ strictEqual(_.isNaN(true), false);
+ strictEqual(_.isNaN(new Date), false);
+ strictEqual(_.isNaN(new Error), false);
+ strictEqual(_.isNaN(_), false);
+ strictEqual(_.isNaN(slice), false);
+ strictEqual(_.isNaN({ 'a': 1 }), false);
+ strictEqual(_.isNaN(1), false);
+ strictEqual(_.isNaN(/x/), false);
+ strictEqual(_.isNaN('a'), false);
});
- test('should work with functions from another realm', 1, function() {
+ test('should work with `NaN` from another realm', 1, function() {
if (_._object) {
- strictEqual(_.isFunction(_._function), true);
+ strictEqual(_.isNaN(_._nan), true);
}
else {
skipTest();
@@ -4144,39 +7382,60 @@
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.isNaN');
+ QUnit.module('lodash.isNative');
(function() {
var args = arguments;
- test('should return `true` for NaNs', 2, function() {
- strictEqual(_.isNaN(NaN), true);
- strictEqual(_.isNaN(new Number(NaN)), true);
+ test('should return `true` for native methods', 6, function() {
+ _.each([Array, create, root.encodeURI, slice, Uint8Array], function(func) {
+ if (func) {
+ strictEqual(_.isNative(func), true);
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ if (body) {
+ strictEqual(_.isNative(body.cloneNode), true);
+ }
+ else {
+ skipTest();
+ }
});
- test('should return `false` for non NaNs', 10, function() {
- var expected = _.map(falsey, function(value) { return value !== value; });
+ test('should return `false` for non native methods', 12, function() {
+ var expected = _.map(falsey, _.constant(false));
var actual = _.map(falsey, function(value, index) {
- return index ? _.isNaN(value) : _.isNaN();
+ return index ? _.isNative(value) : _.isNative();
});
- strictEqual(_.isNaN(args), false);
- strictEqual(_.isNaN([1, 2, 3]), false);
- strictEqual(_.isNaN(true), false);
- strictEqual(_.isNaN(new Date), false);
- strictEqual(_.isNaN(_), false);
- strictEqual(_.isNaN({ 'a': 1 }), false);
- strictEqual(_.isNaN(0), false);
- strictEqual(_.isNaN(/x/), false);
- strictEqual(_.isNaN('a'), false);
-
deepEqual(actual, expected);
+
+ strictEqual(_.isNative(args), false);
+ strictEqual(_.isNative([1, 2, 3]), false);
+ strictEqual(_.isNative(true), false);
+ strictEqual(_.isNative(new Date), false);
+ strictEqual(_.isNative(new Error), false);
+ strictEqual(_.isNative(_), false);
+ strictEqual(_.isNative({ 'a': 1 }), false);
+ strictEqual(_.isNative(1), false);
+ strictEqual(_.isNative(NaN), false);
+ strictEqual(_.isNative(/x/), false);
+ strictEqual(_.isNative('a'), false);
});
- test('should work with NaNs from another realm', 1, function() {
+ test('should work with native functions from another realm', 2, function() {
+ if (_._element) {
+ strictEqual(_.isNative(_._element.cloneNode), true);
+ }
+ else {
+ skipTest();
+ }
if (_._object) {
- strictEqual(_.isNaN(_._nan), true);
+ strictEqual(_.isNative(_._object.valueOf), true);
}
else {
skipTest();
@@ -4195,24 +7454,27 @@
strictEqual(_.isNull(null), true);
});
- test('should return `false` for non nulls', 10, function() {
+ test('should return `false` for non nulls', 13, function() {
var expected = _.map(falsey, function(value) { return value === null; });
var actual = _.map(falsey, function(value, index) {
return index ? _.isNull(value) : _.isNull();
});
+ deepEqual(actual, expected);
+
strictEqual(_.isNull(args), false);
strictEqual(_.isNull([1, 2, 3]), false);
strictEqual(_.isNull(true), false);
strictEqual(_.isNull(new Date), false);
+ strictEqual(_.isNull(new Error), false);
strictEqual(_.isNull(_), false);
+ strictEqual(_.isNull(slice), false);
strictEqual(_.isNull({ 'a': 1 }), false);
- strictEqual(_.isNull(0), false);
+ strictEqual(_.isNull(1), false);
+ strictEqual(_.isNull(NaN), false);
strictEqual(_.isNull(/x/), false);
strictEqual(_.isNull('a'), false);
-
- deepEqual(actual, expected);
});
test('should work with nulls from another realm', 1, function() {
@@ -4232,28 +7494,31 @@
(function() {
var args = arguments;
- test('should return `true` for numbers', 2, function() {
+ test('should return `true` for numbers', 3, function() {
strictEqual(_.isNumber(0), true);
- strictEqual(_.isNumber(new Number(0)), true);
+ strictEqual(_.isNumber(Object(0)), true);
+ strictEqual(_.isNumber(NaN), true);
});
- test('should return `false` for non numbers', 9, function() {
+ test('should return `false` for non numbers', 11, function() {
var expected = _.map(falsey, function(value) { return typeof value == 'number'; });
var actual = _.map(falsey, function(value, index) {
return index ? _.isNumber(value) : _.isNumber();
});
+ deepEqual(actual, expected);
+
strictEqual(_.isNumber(args), false);
strictEqual(_.isNumber([1, 2, 3]), false);
strictEqual(_.isNumber(true), false);
strictEqual(_.isNumber(new Date), false);
+ strictEqual(_.isNumber(new Error), false);
strictEqual(_.isNumber(_), false);
+ strictEqual(_.isNumber(slice), false);
strictEqual(_.isNumber({ 'a': 1 }), false);
strictEqual(_.isNumber(/x/), false);
strictEqual(_.isNumber('a'), false);
-
- deepEqual(actual, expected);
});
test('should work with numbers from another realm', 1, function() {
@@ -4277,27 +7542,29 @@
(function() {
var args = arguments;
- test('should return `true` for objects', 10, function() {
+ test('should return `true` for objects', 12, function() {
strictEqual(_.isObject(args), true);
strictEqual(_.isObject([1, 2, 3]), true);
- strictEqual(_.isObject(new Boolean(false)), true);
+ strictEqual(_.isObject(Object(false)), true);
strictEqual(_.isObject(new Date), true);
+ strictEqual(_.isObject(new Error), true);
strictEqual(_.isObject(_), true);
+ strictEqual(_.isObject(slice), true);
strictEqual(_.isObject({ 'a': 1 }), true);
- strictEqual(_.isObject(new Number(0)), true);
+ strictEqual(_.isObject(Object(0)), true);
strictEqual(_.isObject(/x/), true);
- strictEqual(_.isObject(new String('a')), true);
+ strictEqual(_.isObject(Object('a')), true);
if (document) {
strictEqual(_.isObject(body), true);
} else {
- skipTest(1);
+ skipTest();
}
});
test('should return `false` for non objects', 1, function() {
- var values = falsey.concat('a', true),
- expected = _.map(values, function() { return false; });
+ var values = falsey.concat(true, 1, 'a'),
+ expected = _.map(values, _.constant(false));
var actual = _.map(values, function(value, index) {
return index ? _.isObject(value) : _.isObject();
@@ -4327,18 +7594,18 @@
}
});
- test('should avoid V8 bug #2291', 1, function() {
- // trigger V8 bug
- // http://code.google.com/p/v8/issues/detail?id=2291
- var obj = {},
- str = 'foo';
+ test('should avoid V8 bug #2291 (test in Chrome 19-20)', 1, function() {
+ // Trigger a V8 JIT bug.
+ // See http://code.google.com/p/v8/issues/detail?id=2291.
+ var object = {};
+
+ // 1: Useless comparison statement, this is half the trigger.
+ object == object;
- // 1: Useless comparison statement, this is half the trigger
- obj == obj;
- // 2: Initial check with object, this is the other half of the trigger
- _.isObject(obj);
+ // 2: Initial check with object, this is the other half of the trigger.
+ _.isObject(object);
- equal(_.isObject(str), false);
+ strictEqual(_.isObject('x'), false);
});
}(1, 2, 3));
@@ -4353,21 +7620,19 @@
function Foo(a) {
this.a = 1;
}
-
- strictEqual(_.isPlainObject(new Foo(1)), false);
- strictEqual(_.isPlainObject([1, 2, 3]), false);
+ strictEqual(_.isPlainObject({}), true);
strictEqual(_.isPlainObject({ 'a': 1 }), true);
+ strictEqual(_.isPlainObject({ 'constructor': Foo }), true);
+ strictEqual(_.isPlainObject([1, 2, 3]), false);
+ strictEqual(_.isPlainObject(new Foo(1)), false);
+ });
+ test('should return `true` for objects with a `[[Prototype]]` of `null`', 1, function() {
if (create) {
strictEqual(_.isPlainObject(create(null)), true);
} else {
skipTest();
}
- if (element) {
- strictEqual(_.isPlainObject(element), false);
- } else {
- skipTest();
- }
});
test('should return `true` for plain objects with a custom `valueOf` property', 2, function() {
@@ -4376,6 +7641,7 @@
if (element) {
var valueOf = element.valueOf;
element.valueOf = 0;
+
strictEqual(_.isPlainObject(element), false);
element.valueOf = valueOf;
}
@@ -4384,27 +7650,31 @@
}
});
- test('should return `true` for empty objects', 1, function() {
- strictEqual(_.isPlainObject({}), true);
+ test('should return `false` for DOM elements', 1, function() {
+ if (element) {
+ strictEqual(_.isPlainObject(element), false);
+ } else {
+ skipTest();
+ }
});
- test('should return `false` for Object objects without a [[Class]] of "Object"', 4, function() {
+ test('should return `false` for Object objects without a `toStringTag` of "Object"', 3, function() {
strictEqual(_.isPlainObject(arguments), false);
strictEqual(_.isPlainObject(Error), false);
strictEqual(_.isPlainObject(Math), false);
- strictEqual(_.isPlainObject(root), false);
});
test('should return `false` for non objects', 3, function() {
- var expected = _.map(falsey, function() { return false; });
+ var expected = _.map(falsey, _.constant(false));
var actual = _.map(falsey, function(value, index) {
return index ? _.isPlainObject(value) : _.isPlainObject();
});
+ deepEqual(actual, expected);
+
strictEqual(_.isPlainObject(true), false);
strictEqual(_.isPlainObject('a'), false);
- deepEqual(actual, expected);
});
test('should work with objects from another realm', 1, function() {
@@ -4429,23 +7699,26 @@
strictEqual(_.isRegExp(RegExp('x')), true);
});
- test('should return `false` for non regexes', 9, function() {
- var expected = _.map(falsey, function(value) { return false; });
+ test('should return `false` for non regexes', 12, function() {
+ var expected = _.map(falsey, _.constant(false));
var actual = _.map(falsey, function(value, index) {
return index ? _.isRegExp(value) : _.isRegExp();
});
+ deepEqual(actual, expected);
+
strictEqual(_.isRegExp(args), false);
strictEqual(_.isRegExp([1, 2, 3]), false);
strictEqual(_.isRegExp(true), false);
strictEqual(_.isRegExp(new Date), false);
+ strictEqual(_.isRegExp(new Error), false);
strictEqual(_.isRegExp(_), false);
+ strictEqual(_.isRegExp(slice), false);
strictEqual(_.isRegExp({ 'a': 1 }), false);
- strictEqual(_.isRegExp(0), false);
+ strictEqual(_.isRegExp(1), false);
+ strictEqual(_.isRegExp(NaN), false);
strictEqual(_.isRegExp('a'), false);
-
- deepEqual(actual, expected);
});
test('should work with regexes from another realm', 1, function() {
@@ -4467,26 +7740,29 @@
test('should return `true` for strings', 2, function() {
strictEqual(_.isString('a'), true);
- strictEqual(_.isString(new String('a')), true);
+ strictEqual(_.isString(Object('a')), true);
});
- test('should return `false` for non strings', 9, function() {
+ test('should return `false` for non strings', 12, function() {
var expected = _.map(falsey, function(value) { return value === ''; });
var actual = _.map(falsey, function(value, index) {
return index ? _.isString(value) : _.isString();
});
+ deepEqual(actual, expected);
+
strictEqual(_.isString(args), false);
strictEqual(_.isString([1, 2, 3]), false);
strictEqual(_.isString(true), false);
strictEqual(_.isString(new Date), false);
+ strictEqual(_.isString(new Error), false);
strictEqual(_.isString(_), false);
+ strictEqual(_.isString(slice), false);
strictEqual(_.isString({ '0': 1, 'length': 1 }), false);
- strictEqual(_.isString(0), false);
+ strictEqual(_.isString(1), false);
+ strictEqual(_.isString(NaN), false);
strictEqual(_.isString(/x/), false);
-
- deepEqual(actual, expected);
});
test('should work with strings from another realm', 1, function() {
@@ -4501,6 +7777,72 @@
/*--------------------------------------------------------------------------*/
+ QUnit.module('lodash.isTypedArray');
+
+ (function() {
+ var args = arguments;
+
+ test('should return `true` for typed arrays', 1, function() {
+ var expected = _.map(typedArrays, function(type) {
+ return type in root;
+ });
+
+ var actual = _.map(typedArrays, function(type) {
+ var Ctor = root[type];
+ return Ctor ? _.isTypedArray(new Ctor(new ArrayBuffer(8))) : false;
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return `false` for non typed arrays', 13, function() {
+ var expected = _.map(falsey, _.constant(false));
+
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.isTypedArray(value) : _.isTypedArray();
+ });
+
+ deepEqual(actual, expected);
+
+ strictEqual(_.isTypedArray(args), false);
+ strictEqual(_.isTypedArray([1, 2, 3]), false);
+ strictEqual(_.isTypedArray(true), false);
+ strictEqual(_.isTypedArray(new Date), false);
+ strictEqual(_.isTypedArray(new Error), false);
+ strictEqual(_.isTypedArray(_), false);
+ strictEqual(_.isTypedArray(slice), false);
+ strictEqual(_.isTypedArray({ 'a': 1 }), false);
+ strictEqual(_.isTypedArray(1), false);
+ strictEqual(_.isTypedArray(NaN), false);
+ strictEqual(_.isTypedArray(/x/), false);
+ strictEqual(_.isTypedArray('a'), false);
+ });
+
+ test('should work with typed arrays from another realm', 1, function() {
+ if (_._object) {
+ var props = _.map(typedArrays, function(type) {
+ return '_' + type.toLowerCase();
+ });
+
+ var expected = _.map(props, function(key) {
+ return key in _;
+ });
+
+ var actual = _.map(props, function(key) {
+ var value = _[key];
+ return value ? _.isTypedArray(value) : false;
+ });
+
+ deepEqual(actual, expected);
+ }
+ else {
+ skipTest();
+ }
+ });
+ }(1, 2, 3));
+
+ /*--------------------------------------------------------------------------*/
+
QUnit.module('lodash.isUndefined');
(function() {
@@ -4511,24 +7853,27 @@
strictEqual(_.isUndefined(undefined), true);
});
- test('should return `false` for non `undefined` values', 10, function() {
+ test('should return `false` for non `undefined` values', 13, function() {
var expected = _.map(falsey, function(value) { return value === undefined; });
var actual = _.map(falsey, function(value, index) {
- return _.isUndefined(value);
+ return index ? _.isUndefined(value) : _.isUndefined();
});
+ deepEqual(actual, expected);
+
strictEqual(_.isUndefined(args), false);
strictEqual(_.isUndefined([1, 2, 3]), false);
strictEqual(_.isUndefined(true), false);
strictEqual(_.isUndefined(new Date), false);
+ strictEqual(_.isUndefined(new Error), false);
strictEqual(_.isUndefined(_), false);
+ strictEqual(_.isUndefined(slice), false);
strictEqual(_.isUndefined({ 'a': 1 }), false);
- strictEqual(_.isUndefined(0), false);
+ strictEqual(_.isUndefined(1), false);
+ strictEqual(_.isUndefined(NaN), false);
strictEqual(_.isUndefined(/x/), false);
strictEqual(_.isUndefined('a'), false);
-
- deepEqual(actual, expected);
});
test('should work with `undefined` from another realm', 1, function() {
@@ -4546,18 +7891,18 @@
QUnit.module('isType checks');
(function() {
- test('should return `false` for subclassed values', 7, function() {
+ test('should return `false` for subclassed values', 8, function() {
var funcs = [
- 'isArray', 'isBoolean', 'isDate', 'isFunction',
- 'isNumber', 'isRegExp', 'isString'
+ 'isArray', 'isBoolean', 'isDate', 'isError',
+ 'isFunction', 'isNumber', 'isRegExp', 'isString'
];
- _.forEach(funcs, function(methodName) {
+ _.each(funcs, function(methodName) {
function Foo() {}
Foo.prototype = root[methodName.slice(2)].prototype;
var object = new Foo;
- if (toString.call(object) == '[object Object]') {
+ if (objToString.call(object) == objectTag) {
strictEqual(_[methodName](object), false, '`_.' + methodName + '` returns `false`');
} else {
skipTest();
@@ -4565,192 +7910,278 @@
});
});
- test('should not error on host objects (test in IE)', 12, function() {
- try {
- var xml = new ActiveXObject('Microsoft.XMLDOM');
- } catch(e) { }
-
- if (xml) {
- var funcs = [
- 'isArray', 'isArguments', 'isBoolean', 'isDate', 'isElement', 'isFunction',
- 'isObject', 'isNull', 'isNumber', 'isRegExp', 'isString', 'isUndefined'
- ];
+ test('should not error on host objects (test in IE)', 15, function() {
+ var funcs = [
+ 'isArguments', 'isArray', 'isBoolean', 'isDate', 'isElement',
+ 'isError', 'isFinite', 'isFunction', 'isNaN', 'isNull', 'isNumber',
+ 'isObject', 'isRegExp', 'isString', 'isUndefined'
+ ];
- _.forEach(funcs, function(methodName) {
+ _.each(funcs, function(methodName) {
+ if (xml) {
var pass = true;
+
try {
_[methodName](xml);
} catch(e) {
pass = false;
}
ok(pass, '`_.' + methodName + '` should not error');
- });
- }
- else {
- skipTest(12)
- }
+ }
+ else {
+ skipTest();
+ }
+ });
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.keys');
+ QUnit.module('keys methods');
- (function() {
- var args = arguments;
+ _.each(['keys', 'keysIn'], function(methodName, index) {
+ var args = arguments,
+ func = _[methodName],
+ isKeys = !index;
+
+ test('`_.' + methodName + '` should return the keys of an object', 1, function() {
+ deepEqual(func({ 'a': 1, 'b': 1 }).sort(), ['a', 'b']);
+ });
- test('should return the keys of an object', 1, function() {
- var object = { 'a': 1, 'b': 1 };
- deepEqual(_.keys(object), ['a', 'b']);
+ test('`_.' + methodName + '` should coerce primitives to objects (test in IE 9)', 2, function() {
+ deepEqual(func('abc').sort(), ['0', '1', '2']);
+
+ if (!isKeys) {
+ // IE 9 doesn't box numbers in for-in loops.
+ Number.prototype.a = 1;
+ deepEqual(func(0).sort(), ['a']);
+ delete Number.prototype.a;
+ }
+ else {
+ skipTest();
+ }
});
- test('should work with sparse arrays', 1, function() {
+ test('`_.' + methodName + '` should treat sparse arrays as dense', 1, function() {
var array = [1];
array[2] = 3;
- deepEqual(_.keys(array), ['0', '2']);
+
+ deepEqual(func(array).sort(), ['0', '1', '2']);
});
- test('should work with `arguments` objects (test in IE < 9)', 1, function() {
- if (!isPhantomPage) {
- deepEqual(_.keys(args), ['0', '1', '2']);
- } else {
+ test('`_.' + methodName + '` should return an empty array for `null` or `undefined` values', 2, function() {
+ objectProto.a = 1;
+ _.each([null, undefined], function(value) {
+ deepEqual(func(value), []);
+ });
+ delete objectProto.a;
+ });
+
+ test('`_.' + methodName + '` should return keys for custom properties on arrays', 1, function() {
+ var array = [1];
+ array.a = 1;
+
+ deepEqual(func(array).sort(), ['0', 'a']);
+ });
+
+ test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of arrays', 1, function() {
+ var expected = isKeys ? ['0'] : ['0', 'a'];
+
+ arrayProto.a = 1;
+ deepEqual(func([1]).sort(), expected);
+ delete arrayProto.a;
+ });
+
+ test('`_.' + methodName + '` should work with `arguments` objects (test in IE < 9)', 1, function() {
+ if (!(isPhantom || isStrict)) {
+ deepEqual(func(args).sort(), ['0', '1', '2']);
+ }
+ else {
skipTest();
}
});
- test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', 2, function() {
- function Foo() {}
- Foo.prototype.a = 1;
+ test('`_.' + methodName + '` should return keys for custom properties on `arguments` objects', 1, function() {
+ if (!(isPhantom || isStrict)) {
+ args.a = 1;
+ deepEqual(func(args).sort(), ['0', '1', '2', 'a']);
+ delete args.a;
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of `arguments` objects', 1, function() {
+ if (!(isPhantom || isStrict)) {
+ var expected = isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a'];
+
+ objectProto.a = 1;
+ deepEqual(func(args).sort(), expected);
+ delete objectProto.a;
+ }
+ else {
+ skipTest();
+ }
+ });
- deepEqual(_.keys(Foo.prototype), ['a']);
- deepEqual(_.keys(shadowedObject).sort(), shadowedProps);
+ test('`_.' + methodName + '` should work with string objects (test in IE < 9)', 1, function() {
+ deepEqual(func(Object('abc')).sort(), ['0', '1', '2']);
});
- test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
+ test('`_.' + methodName + '` should return keys for custom properties on string objects', 1, function() {
+ var object = Object('a');
+ object.a = 1;
+
+ deepEqual(func(object).sort(), ['0', 'a']);
+ });
+
+ test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of string objects', 1, function() {
+ var expected = isKeys ? ['0'] : ['0', 'a'];
+
+ stringProto.a = 1;
+ deepEqual(func(Object('a')).sort(), expected);
+ delete stringProto.a;
+ });
+
+ test('`_.' + methodName + '` fixes the JScript `[[DontEnum]]` bug (test in IE < 9)', 3, function() {
function Foo() {}
- Foo.prototype.c = 3;
+ Foo.prototype = _.create(shadowObject);
+
+ deepEqual(func(shadowObject).sort(), shadowProps);
+
+ var actual = isKeys ? [] : _.without(shadowProps, 'constructor');
+ deepEqual(func(new Foo).sort(), actual);
+
+ Foo.prototype.constructor = Foo;
+ deepEqual(func(new Foo).sort(), actual);
+ });
+
+ test('`_.' + methodName + '` skips non-enumerable properties (test in IE < 9)', 50, function() {
+ _.forOwn({
+ 'Array': arrayProto,
+ 'Boolean': Boolean.prototype,
+ 'Date': Date.prototype,
+ 'Error': errorProto,
+ 'Function': funcProto,
+ 'Object': objectProto,
+ 'Number': Number.prototype,
+ 'TypeError': TypeError.prototype,
+ 'RegExp': RegExp.prototype,
+ 'String': stringProto
+ },
+ function(proto, key) {
+ _.each([proto, _.create(proto)], function(object, index) {
+ var actual = func(proto),
+ isErr = _.endsWith(key, 'Error'),
+ message = 'enumerable properties ' + (index ? 'inherited from' : 'on') + ' `' + key + '.prototype`',
+ props = isErr ? ['constructor', 'toString'] : ['constructor'];
+
+ actual = isErr ? _.difference(props, actual) : actual;
+ strictEqual(_.isEmpty(actual), !isErr, 'skips non-' + message);
+
+ proto.a = 1;
+ actual = func(object);
+ delete proto.a;
+
+ strictEqual(_.includes(actual, 'a'), !(isKeys && index), 'includes ' + message);
+
+ if (index) {
+ object.constructor = 1;
+ if (isErr) {
+ object.toString = 2;
+ }
+ actual = func(object);
+ ok(_.isEmpty(_.difference(props, actual)), 'includes properties on objects that shadow those on `' + key + '.prototype`');
+ }
+ });
+ });
+ });
+ test('`_.' + methodName + '` skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() {
+ function Foo() {}
Foo.a = 1;
Foo.b = 2;
+ Foo.prototype.c = 3;
var expected = ['a', 'b'];
- deepEqual(_.keys(Foo), expected);
+ deepEqual(func(Foo).sort(), expected);
Foo.prototype = { 'c': 3 };
- deepEqual(_.keys(Foo), expected);
+ deepEqual(func(Foo).sort(), expected);
});
- }(1, 2, 3));
-
- /*--------------------------------------------------------------------------*/
- QUnit.module('lodash.last');
+ test('`_.' + methodName + '` skips the `constructor` property on prototype objects', 3, function() {
+ function Foo() {}
+ Foo.prototype.a = 1;
- (function() {
- var array = [1, 2, 3];
+ var expected = ['a'];
+ deepEqual(func(Foo.prototype), ['a']);
- var objects = [
- { 'a': 0, 'b': 0 },
- { 'a': 1, 'b': 1 },
- { 'a': 2, 'b': 2 }
- ];
+ Foo.prototype = { 'constructor': Foo, 'a': 1 };
+ deepEqual(func(Foo.prototype), ['a']);
- test('should return the last element', 1, function() {
- equal(_.last(array), 3);
+ var Fake = { 'prototype': {} };
+ Fake.prototype.constructor = Fake;
+ deepEqual(func(Fake.prototype), ['constructor']);
});
- test('should return the last two elements', 1, function() {
- deepEqual(_.last(array, 2), [2, 3]);
- });
+ test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
- test('should return an empty array when `n` < `1`', 3, function() {
- _.forEach([0, -1, -2], function(n) {
- deepEqual(_.last(array, n), []);
- });
+ var expected = isKeys ? ['a'] : ['a', 'b'];
+ deepEqual(func(new Foo).sort(), expected);
});
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.last');
+
+ (function() {
+ var array = [1, 2, 3];
- test('should return all elements when `n` >= `array.length`', 2, function() {
- _.forEach([3, 4], function(n) {
- deepEqual(_.last(array, n), array);
- });
+ test('should return the last element', 1, function() {
+ strictEqual(_.last(array), 3);
});
test('should return `undefined` when querying empty arrays', 1, function() {
+ var array = [];
+ array['-1'] = 1;
strictEqual(_.last([]), undefined);
});
- test('should work when used as `callback` for `_.map`', 1, function() {
+ test('should work as an iteratee for `_.map`', 1, function() {
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
actual = _.map(array, _.last);
deepEqual(actual, [3, 6, 9]);
});
- test('should work with a `callback`', 1, function() {
- var actual = _.last(array, function(num) {
- return num > 1;
- });
-
- deepEqual(actual, [2, 3]);
- });
-
- test('should pass the correct `callback` arguments', 1, function() {
- var args;
-
- _.last(array, function() {
- args || (args = slice.call(arguments));
- });
-
- deepEqual(args, [3, 2, array]);
- });
-
- test('should support the `thisArg` argument', 1, function() {
- var actual = _.last(array, function(num, index) {
- return this[index] > 1;
- }, array);
-
- deepEqual(actual, [2, 3]);
- });
-
- test('should chain when passing `n`, `callback`, or `thisArg`', 3, function() {
+ test('should return an unwrapped value when chaining', 1, function() {
if (!isNpm) {
- var actual = _(array).last(2);
-
- ok(actual instanceof _);
-
- actual = _(array).last(function(num) {
- return num > 1;
- });
-
- ok(actual instanceof _);
-
- actual = _(array).last(function(num, index) {
- return this[index] > 1;
- }, array);
-
- ok(actual instanceof _);
+ strictEqual(_(array).last(), 3);
}
else {
- skipTest(3);
+ skipTest();
}
});
- test('should not chain when arguments are not provided', 1, function() {
+ test('should work in a lazy chain sequence', 1, function() {
if (!isNpm) {
- var actual = _(array).last();
- equal(actual, 3);
+ var array = [1, 2, 3, 4];
+
+ var wrapped = _(array).filter(function(value) {
+ return value % 2;
+ });
+
+ strictEqual(wrapped.last(), 3);
}
else {
skipTest();
}
});
-
- test('should work with an object for `callback`', 1, function() {
- deepEqual(_.last(objects, { 'b': 2 }), objects.slice(-1));
- });
-
- test('should work with a string for `callback`', 1, function() {
- deepEqual(_.last(objects, 'b'), objects.slice(-2));
- });
}());
/*--------------------------------------------------------------------------*/
@@ -4761,36 +8192,65 @@
var array = [1, 2, 3, 1, 2, 3];
test('should return the index of the last matched value', 1, function() {
- equal(_.lastIndexOf(array, 3), 5);
- });
-
- test('should return `-1` for an unmatched value', 1, function() {
- equal(_.lastIndexOf(array, 4), -1);
+ strictEqual(_.lastIndexOf(array, 3), 5);
});
test('should work with a positive `fromIndex`', 1, function() {
strictEqual(_.lastIndexOf(array, 1, 2), 0);
});
- test('should work with `fromIndex` >= `array.length`', 4, function() {
- equal(_.lastIndexOf(array, undefined, 6), -1);
- equal(_.lastIndexOf(array, 1, 6), 3);
- equal(_.lastIndexOf(array, undefined, 8), -1);
- equal(_.lastIndexOf(array, 1, 8), 3);
+ test('should work with `fromIndex` >= `array.length`', 1, function() {
+ var values = [6, 8, Math.pow(2, 32), Infinity],
+ expected = _.map(values, _.constant([-1, 3, -1]));
+
+ var actual = _.map(values, function(fromIndex) {
+ return [
+ _.lastIndexOf(array, undefined, fromIndex),
+ _.lastIndexOf(array, 1, fromIndex),
+ _.lastIndexOf(array, '', fromIndex)
+ ];
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`', 1, function() {
+ var expected = _.map(falsey, function(value) {
+ return typeof value == 'number' ? -1 : 5;
+ });
+
+ var actual = _.map(falsey, function(fromIndex) {
+ return _.lastIndexOf(array, 3, fromIndex);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should perform a binary search when `fromIndex` is a non-number truthy value', 1, function() {
+ var sorted = [4, 4, 5, 5, 6, 6],
+ values = [true, '1', {}],
+ expected = _.map(values, _.constant(3));
+
+ var actual = _.map(values, function(value) {
+ return _.lastIndexOf(sorted, 5, value);
+ });
+
+ deepEqual(actual, expected);
});
test('should work with a negative `fromIndex`', 1, function() {
strictEqual(_.lastIndexOf(array, 2, -3), 1);
});
- test('should work with a negative `fromIndex` <= `-array.length`', 2, function() {
- strictEqual(_.lastIndexOf(array, 1, -6), 0);
- equal(_.lastIndexOf(array, 2, -8), -1);
- });
+ test('should work with a negative `fromIndex` <= `-array.length`', 1, function() {
+ var values = [-6, -8, -Infinity],
+ expected = _.map(values, _.constant(0));
+
+ var actual = _.map(values, function(fromIndex) {
+ return _.lastIndexOf(array, 1, fromIndex);
+ });
- test('should ignore non-number `fromIndex` values', 2, function() {
- equal(_.lastIndexOf([1, 2, 3], 3, '1'), 2);
- equal(_.lastIndexOf([1, 2, 3], 3, true), 2);
+ deepEqual(actual, expected);
});
}());
@@ -4798,23 +8258,45 @@
QUnit.module('indexOf methods');
- (function() {
- _.forEach(['indexOf', 'lastIndexOf'], function(methodName) {
- var func = _[methodName];
-
- test('`_.' + methodName + '` should accept a falsey `array` argument', 1, function() {
- var expected = _.map(falsey, function() { return -1; });
+ _.each(['indexOf', 'lastIndexOf'], function(methodName) {
+ var func = _[methodName];
- var actual = _.map(falsey, function(value, index) {
- try {
- return index ? func(value) : func();
- } catch(e) { }
- });
+ test('`_.' + methodName + '` should accept a falsey `array` argument', 1, function() {
+ var expected = _.map(falsey, _.constant(-1));
- deepEqual(actual, expected);
+ var actual = _.map(falsey, function(value, index) {
+ try {
+ return index ? func(value) : func();
+ } catch(e) {}
});
+
+ deepEqual(actual, expected);
});
- }());
+
+ test('`_.' + methodName + '` should return `-1` for an unmatched value', 4, function() {
+ var array = [1, 2, 3],
+ empty = [];
+
+ strictEqual(func(array, 4), -1);
+ strictEqual(func(array, 4, true), -1);
+
+ strictEqual(func(empty, undefined), -1);
+ strictEqual(func(empty, undefined, true), -1);
+ });
+
+ test('`_.' + methodName + '` should not match values on empty arrays', 2, function() {
+ var array = [];
+ array[-1] = 0;
+
+ strictEqual(func(array, undefined), -1);
+ strictEqual(func(array, 0, true), -1);
+ });
+
+ test('`_.' + methodName + '` should match `NaN`', 2, function() {
+ strictEqual(func([1, NaN, 3], NaN), 1);
+ strictEqual(func([1, 3, NaN], NaN, true), 2);
+ });
+ });
/*--------------------------------------------------------------------------*/
@@ -4823,7 +8305,7 @@
(function() {
var array = [1, 2, 3];
- test('should pass the correct `callback` arguments', 1, function() {
+ test('should provide the correct `iteratee` arguments', 1, function() {
var args;
_.map(array, function() {
@@ -4845,6 +8327,11 @@
deepEqual(actual, [3]);
});
+ test('should work with a "_.pluck" style `iteratee`', 1, function() {
+ var objects = [{ 'a': 'x' }, { 'a': 'y' }];
+ deepEqual(_.map(objects, 'a'), ['x', 'y']);
+ });
+
test('should iterate over own properties of objects', 1, function() {
function Foo() { this.a = 1; }
Foo.prototype.b = 2;
@@ -4853,28 +8340,16 @@
deepEqual(actual, ['a']);
});
- test('should work on an object with no `callback`', 1, function() {
+ test('should work on an object with no `iteratee`', 1, function() {
var actual = _.map({ 'a': 1, 'b': 2, 'c': 3 });
deepEqual(actual, array);
});
test('should handle object arguments with non-numeric length properties', 1, function() {
- if (defineProperty) {
- var object = {};
- defineProperty(object, 'length', { 'value': 'x' });
- deepEqual(_.map(object, _.identity), []);
- } else {
- skipTest();
- }
- });
+ var value = { 'value': 'x' },
+ object = { 'length': { 'value': 'x' } };
- test('should return a wrapped value when chaining', 1, function() {
- if (!isNpm) {
- ok(_(array).map(noop) instanceof _);
- }
- else {
- skipTest();
- }
+ deepEqual(_.map(object, _.identity), [value]);
});
test('should treat a nodelist as an array-like object', 1, function() {
@@ -4890,18 +8365,31 @@
}
});
- test('should accept a falsey `array` argument', 1, function() {
- var expected = _.map(falsey, function() { return []; });
+ test('should accept a falsey `collection` argument', 1, function() {
+ var expected = _.map(falsey, _.constant([]));
var actual = _.map(falsey, function(value, index) {
try {
return index ? _.map(value) : _.map();
- } catch(e) { }
+ } catch(e) {}
});
deepEqual(actual, expected);
});
+ test('should treat number values for `collection` as empty', 1, function() {
+ deepEqual(_.map(1), []);
+ });
+
+ test('should return a wrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ ok(_(array).map(_.noop) instanceof _);
+ }
+ else {
+ skipTest();
+ }
+ });
+
test('should be aliased', 1, function() {
strictEqual(_.collect, _.map);
});
@@ -4914,7 +8402,7 @@
(function() {
var object = { 'a': 1, 'b': 2, 'c': 3 };
- test('should pass the correct `callback` arguments', 1, function() {
+ test('should provide the correct `iteratee` arguments', 1, function() {
var args;
_.mapValues(object, function() {
@@ -4936,6 +8424,11 @@
deepEqual(actual, { '0': 3 });
});
+ test('should work with a "_.pluck" style `iteratee`', 1, function() {
+ var actual = _.mapValues({ 'a': { 'b': 1 } }, 'b');
+ deepEqual(actual, { 'a': 1 });
+ });
+
test('should iterate over own properties of objects', 1, function() {
function Foo() { this.a = 1; }
Foo.prototype.b = 2;
@@ -4944,31 +8437,213 @@
deepEqual(actual, { 'a': 'a' });
});
- test('should work on an object with no `callback`', 1, function() {
+ test('should work on an object with no `iteratee`', 1, function() {
var actual = _.mapValues({ 'a': 1, 'b': 2, 'c': 3 });
deepEqual(actual, object);
});
+ test('should accept a falsey `object` argument', 1, function() {
+ var expected = _.map(falsey, _.constant({}));
+
+ var actual = _.map(falsey, function(value, index) {
+ try {
+ return index ? _.mapValues(value) : _.mapValues();
+ } catch(e) {}
+ });
+
+ deepEqual(actual, expected);
+ });
+
test('should return a wrapped value when chaining', 1, function() {
if (!isNpm) {
- ok(_(object).mapValues(noop) instanceof _);
+ ok(_(object).mapValues(_.noop) instanceof _);
}
else {
skipTest();
}
});
+ }());
- test('should accept a falsey `object` argument', 1, function() {
- var expected = _.map(falsey, function() { return {}; });
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.matches');
+
+ (function() {
+ test('should create a function that performs a deep comparison between a given object and `source`', 6, function() {
+ var object = { 'a': 1, 'b': 2, 'c': 3 },
+ matches = _.matches({ 'a': 1 });
+
+ strictEqual(matches.length, 1);
+ strictEqual(matches(object), true);
+
+ matches = _.matches({ 'b': 1 });
+ strictEqual(matches(object), false);
+
+ matches = _.matches({ 'a': 1, 'c': 3 });
+ strictEqual(matches(object), true);
+
+ matches = _.matches({ 'c': 3, 'd': 4 });
+ strictEqual(matches(object), false);
+
+ object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 };
+ matches = _.matches({ 'a': { 'b': { 'c': 1 } } });
+
+ strictEqual(matches(object), true);
+ });
+
+ test('should compare a variety of `source` values', 2, function() {
+ var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } },
+ object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } },
+ matches = _.matches(object1);
+
+ strictEqual(matches(object1), true);
+ strictEqual(matches(object2), false);
+ });
+
+ test('should not change match behavior if `source` is augmented', 9, function() {
+ _.each([{ 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 }], function(source, index) {
+ var object = _.cloneDeep(source),
+ matches = _.matches(source);
+
+ strictEqual(matches(object), true);
+
+ if (index) {
+ source.a = 2;
+ source.b = 1;
+ source.c = 3;
+ } else {
+ source.a.b = 1;
+ source.a.c = 2;
+ source.a.d = 3;
+ }
+ strictEqual(matches(object), true);
+ strictEqual(matches(source), false);
+ });
+ });
+
+ test('should return `true` when comparing an empty `source`', 1, function() {
+ var object = { 'a': 1 },
+ expected = _.map(empties, _.constant(true));
+
+ var actual = _.map(empties, function(value) {
+ var matches = _.matches(value);
+ return matches(object);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() {
+ var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }],
+ matches = _.matches({ 'a': [], 'b': {} }),
+ actual = _.filter(objects, matches);
+
+ deepEqual(actual, objects);
+ });
+
+ test('should not error for falsey `object` values', 1, function() {
+ var expected = _.map(falsey, _.constant(false)),
+ matches = _.matches({ 'a': 1 });
var actual = _.map(falsey, function(value, index) {
try {
- return index ? _.mapValues(value) : _.mapValues();
- } catch(e) { }
+ return index ? matches(value) : matches();
+ } catch(e) {}
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return `true` when comparing an empty `source` to a falsey `object`', 1, function() {
+ var expected = _.map(falsey, _.constant(true)),
+ matches = _.matches({});
+
+ var actual = _.map(falsey, function(value, index) {
+ try {
+ return index ? matches(value) : matches();
+ } catch(e) {}
});
deepEqual(actual, expected);
});
+
+ test('should search arrays of `source` for values', 3, function() {
+ var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }],
+ matches = _.matches({ 'a': ['d'] }),
+ actual = _.filter(objects, matches);
+
+ deepEqual(actual, [objects[1]]);
+
+ matches = _.matches({ 'a': ['b', 'd'] });
+ actual = _.filter(objects, matches);
+ deepEqual(actual, []);
+
+ matches = _.matches({ 'a': ['d', 'b'] });
+ actual = _.filter(objects, matches);
+ deepEqual(actual, []);
+ });
+
+ test('should perform a partial comparison of all objects within arrays of `source`', 1, function() {
+ var objects = [
+ { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] },
+ { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] }
+ ];
+
+ var matches = _.matches({ 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] }),
+ actual = _.filter(objects, matches);
+
+ deepEqual(actual, [objects[0]]);
+ });
+
+ test('should handle a `source` with `undefined` values', 2, function() {
+ var matches = _.matches({ 'b': undefined }),
+ objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }],
+ actual = _.map(objects, matches),
+ expected = [false, false, true];
+
+ deepEqual(actual, expected);
+
+ matches = _.matches({ 'a': { 'c': undefined } });
+ objects = [{ 'a': { 'b': 1 } }, { 'a':{ 'b':1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }];
+ actual = _.map(objects, matches);
+
+ deepEqual(actual, expected);
+ });
+
+ test('should not match by inherited `source` properties', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
+
+ var objects = [{ 'a': 1 }, { 'a': 1, 'b': 2 }],
+ source = new Foo,
+ matches = _.matches(source),
+ actual = _.map(objects, matches),
+ expected = _.map(objects, _.constant(true));
+
+ deepEqual(actual, expected);
+ });
+
+ test('should work with a function for `source`', 1, function() {
+ function source() {}
+
+ source.a = 1;
+ source.b = function() {};
+ source.c = 3;
+
+ var matches = _.matches(source),
+ objects = [{ 'a': 1 }, { 'a': 1, 'b': source.b, 'c': 3 }],
+ actual = _.map(objects, matches);
+
+ deepEqual(actual, [false, true]);
+ });
+
+ test('should match problem JScript properties (test in IE < 9)', 1, function() {
+ var matches = _.matches(shadowObject),
+ objects = [{}, shadowObject],
+ actual = _.map(objects, matches);
+
+ deepEqual(actual, [false, true]);
+ });
}());
/*--------------------------------------------------------------------------*/
@@ -4977,7 +8652,7 @@
(function() {
test('should return the largest value from a collection', 1, function() {
- equal(3, _.max([1, 2, 3]));
+ strictEqual(3, _.max([1, 2, 3]));
});
test('should return `-Infinity` for empty collections', 1, function() {
@@ -4986,7 +8661,7 @@
var actual = _.map(empties, function(value) {
try {
return _.max(value);
- } catch(e) { }
+ } catch(e) {}
});
deepEqual(actual, expected);
@@ -4999,7 +8674,7 @@
var actual = _.map(collections, function(value) {
try {
return _.max(value);
- } catch(e) { }
+ } catch(e) {}
});
deepEqual(actual, expected);
@@ -5011,54 +8686,160 @@
QUnit.module('lodash.memoize');
(function() {
- test('should memoize results based on the first argument passed', 2, function() {
+ test('should memoize results based on the first argument provided', 2, function() {
var memoized = _.memoize(function(a, b, c) {
return a + b + c;
});
- equal(memoized(1, 2, 3), 6);
- equal(memoized(1, 3, 5), 6);
+ strictEqual(memoized(1, 2, 3), 6);
+ strictEqual(memoized(1, 3, 5), 6);
+ });
+
+ test('should support a `resolver` argument', 2, function() {
+ var fn = function(a, b, c) { return a + b + c; },
+ memoized = _.memoize(fn, fn);
+
+ strictEqual(memoized(1, 2, 3), 6);
+ strictEqual(memoized(1, 3, 5), 9);
+ });
+
+ test('should not set a `this` binding', 2, function() {
+ var memoized = _.memoize(function(a, b, c) {
+ return a + this.b + this.c;
+ });
+
+ var object = { 'b': 2, 'c': 3, 'memoized': memoized };
+ strictEqual(object.memoized(1), 6);
+ strictEqual(object.memoized(2), 7);
+ });
+
+ test('should throw a TypeError if `resolve` is truthy and not a function', function() {
+ raises(function() { _.memoize(_.noop, {}); }, TypeError);
+ });
+
+ test('should not error if `resolve` is falsey', function() {
+ var expected = _.map(falsey, _.constant(true));
+
+ var actual = _.map(falsey, function(value, index) {
+ try {
+ return _.isFunction(index ? _.memoize(_.noop, value) : _.memoize(_.noop));
+ } catch(e) {}
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should check cache for own properties', 1, function() {
+ var actual = [],
+ memoized = _.memoize(_.identity);
+
+ _.each(shadowProps, function(value) {
+ actual.push(memoized(value));
+ });
+
+ deepEqual(actual, shadowProps);
+ });
+
+ test('should expose a `cache` object on the `memoized` function which implements `Map` interface', 18, function() {
+ _.times(2, function(index) {
+ var resolver = index ? _.identity : null,
+ memoized = _.memoize(function(value) { return 'value:' + value; }, resolver),
+ cache = memoized.cache;
+
+ memoized('a');
+
+ strictEqual(cache.has('a'), true);
+ strictEqual(cache.get('a'), 'value:a');
+ strictEqual(cache['delete']('a'), true);
+ strictEqual(cache['delete']('b'), false);
+
+ strictEqual(cache.set('b', 'value:b'), cache);
+ strictEqual(cache.has('b'), true);
+ strictEqual(cache.get('b'), 'value:b');
+ strictEqual(cache['delete']('b'), true);
+ strictEqual(cache['delete']('a'), false);
+ });
+ });
+
+ test('should skip the `__proto__` key', 8, function() {
+ _.times(2, function(index) {
+ var count = 0,
+ key = '__proto__',
+ resolver = index && _.identity;
+
+ var memoized = _.memoize(function() {
+ count++;
+ return [];
+ }, resolver);
+
+ var cache = memoized.cache;
+
+ memoized(key);
+ memoized(key);
+
+ strictEqual(count, 2);
+ strictEqual(cache.get(key), undefined);
+ strictEqual(cache['delete'](key), false);
+ ok(!(cache.__data__ instanceof Array));
+ });
});
- test('should support a `resolver` argument', 2, function() {
- function func(a, b, c) {
- return a + b + c;
+ test('should allow `_.memoize.Cache` to be customized', 4, function() {
+ var oldCache = _.memoize.Cache
+
+ function Cache() {
+ this.__data__ = [];
}
- var memoized = _.memoize(func, func);
- equal(memoized(1, 2, 3), 6);
- equal(memoized(1, 3, 5), 9);
- });
+ Cache.prototype = {
+ 'delete': function(key) {
+ var data = this.__data__;
- test('should not set a `this` binding', 2, function() {
- var memoized = _.memoize(function(a, b, c) {
- return a + this.b + this.c;
- });
+ var index = _.findIndex(data, function(entry) {
+ return key === entry.key;
+ });
- var object = { 'b': 2, 'c': 3, 'memoized': memoized };
- equal(object.memoized(1), 6);
- equal(object.memoized(2), 7);
- });
+ if (index < 0) {
+ return false;
+ }
+ data.splice(index, 1);
+ return true;
+ },
+ 'get': function(key) {
+ return _.find(this.__data__, function(entry) {
+ return key === entry.key;
+ }).value;
+ },
+ 'has': function(key) {
+ return _.some(this.__data__, function(entry) {
+ return key === entry.key;
+ });
+ },
+ 'set': function(key, value) {
+ this.__data__.push({ 'key': key, 'value': value });
+ }
+ };
- test('should check cache for own properties', 1, function() {
- var actual = [],
- memoized = _.memoize(_.identity);
+ _.memoize.Cache = Cache;
- _.forEach(shadowedProps, function(value) {
- actual.push(memoized(value));
+ var memoized = _.memoize(function(object) {
+ return '`id` is "' + object.id + '"';
});
- deepEqual(actual, shadowedProps);
- });
+ var actual = memoized({ 'id': 'a' });
+ strictEqual(actual, '`id` is "a"');
- test('should expose a `cache` object on the `memoized` function', 2, function() {
- var memoized = _.memoize(_.identity, _.identity);
+ var key = { 'id': 'b' };
+ actual = memoized(key);
+ strictEqual(actual, '`id` is "b"');
- memoized('x');
- equal(memoized.cache.x, 'x');
+ var cache = memoized.cache;
+ strictEqual(cache.has(key), true);
- memoized.cache.x = 'y';
- equal(memoized('x'), 'y');
+ cache['delete'](key);
+ strictEqual(cache.has(key), false);
+
+ _.memoize.Cache = oldCache;
});
}());
@@ -5108,28 +8889,88 @@
};
var source = {
- 'foo': { 'b': { 'foo': { 'c': { } } } },
- 'bar': { }
+ 'foo': { 'b': { 'c': { 'd': {} } } },
+ 'bar': {}
};
- source.foo.b.foo.c = source;
+ source.foo.b.c.d = source;
source.bar.b = source.foo.b;
var actual = _.merge(object, source);
- ok(actual.bar.b === actual.foo.b && actual.foo.b.foo.c === actual.foo.b.foo.c.foo.b.foo.c);
+ ok(actual.bar.b === actual.foo.b && actual.foo.b.c.d === actual.foo.b.c.d.foo.b.c.d);
});
- test('should not treat `arguments` objects as plain objects', 1, function() {
- var object = {
- 'args': args
- };
+ test('should treat sources that are sparse arrays as dense', 2, function() {
+ var array = Array(3);
+ array[0] = 1;
+ array[2] = 3;
- var source = {
- 'args': { '3': 4 }
- };
+ var actual = _.merge([], array),
+ expected = array.slice();
- var actual = _.merge(object, source);
- equal(_.isArguments(actual.args), false);
+ expected[1] = undefined;
+
+ ok('1' in actual);
+ deepEqual(actual, expected);
+ });
+
+ test('should merge `arguments` objects', 3, function() {
+ var object1 = { 'value': args },
+ object2 = { 'value': { '3': 4 } },
+ expected = { '0': 1, '1': 2, '2': 3, '3': 4 },
+ actual = _.merge(object1, object2);
+
+ ok(!_.isArguments(actual.value));
+ deepEqual(actual.value, expected);
+ delete object1.value[3];
+
+ actual = _.merge(object2, object1);
+ deepEqual(actual.value, expected);
+ });
+
+ test('should merge typed arrays', 4, function() {
+ var array1 = [0],
+ array2 = [0, 0],
+ array3 = [0, 0, 0, 0],
+ array4 = _.range(0, 8, 0);
+
+ var arrays = [array2, array1, array4, array3, array2, array4, array4, array3, array2],
+ buffer = ArrayBuffer && new ArrayBuffer(8);
+
+ // juggle for `Float64Array` shim
+ if (root.Float64Array && (new Float64Array(buffer)).length == 8) {
+ arrays[1] = array4;
+ }
+ var expected = _.map(typedArrays, function(type, index) {
+ var array = arrays[index].slice();
+ array[0] = 1;
+ return root[type] ? { 'value': array } : false;
+ });
+
+ var actual = _.map(typedArrays, function(type) {
+ var Ctor = root[type];
+ return Ctor ? _.merge({ 'value': new Ctor(buffer) }, { 'value': [1] }) : false;
+ });
+
+ ok(_.isArray(actual));
+ deepEqual(actual, expected);
+
+ expected = _.map(typedArrays, function(type, index) {
+ var array = arrays[index].slice();
+ array.push(1);
+ return root[type] ? { 'value': array } : false;
+ });
+
+ actual = _.map(typedArrays, function(type, index) {
+ var Ctor = root[type],
+ array = _.range(arrays[index].length);
+
+ array.push(1);
+ return Ctor ? _.merge({ 'value': array }, { 'value': new Ctor(buffer) }) : false;
+ });
+
+ ok(_.isArray(actual));
+ deepEqual(actual, expected);
});
test('should work with four arguments', 1, function() {
@@ -5143,32 +8984,24 @@
});
test('should not assign `undefined` values', 1, function() {
- var actual = _.merge({ 'a': 1 }, { 'a': undefined });
- strictEqual(actual.a, 1);
+ var actual = _.merge({ 'a': 1 }, { 'a': undefined, 'b': undefined });
+ deepEqual(actual, { 'a': 1 });
});
- test('should handle merging if `callback` returns `undefined`', 1, function() {
- var actual = _.merge({ 'a': { 'b': [1, 1] } }, { 'a': { 'b': [0] } }, function() {});
+ test('should handle merging if `customizer` returns `undefined`', 2, function() {
+ var actual = _.merge({ 'a': { 'b': [1, 1] } }, { 'a': { 'b': [0] } }, _.noop);
deepEqual(actual, { 'a': { 'b': [0, 1] } });
+
+ actual = _.merge([], [undefined], _.identity);
+ deepEqual(actual, [undefined]);
});
- test('should defer to `callback` when it returns a value other than `undefined`', 1, function() {
+ test('should defer to `customizer` when it returns a value other than `undefined`', 1, function() {
var actual = _.merge({ 'a': { 'b': [0, 1] } }, { 'a': { 'b': [2] } }, function(a, b) {
return _.isArray(a) ? a.concat(b) : undefined;
});
- deepEqual(actual, { 'a': { 'b': [0, 1, 2] } });
- });
-
- test('should pass the correct values to `callback`', 1, function() {
- var argsList = [],
- array = [1, 2],
- object = { 'b': 2 };
-
- _.merge({ 'a': array }, { 'a': object }, function(a, b) {
- argsList.push(slice.call(arguments));
- });
- deepEqual(argsList, [[array, object], [undefined, 2]]);
+ deepEqual(actual, { 'a': { 'b': [0, 1, 2] } });
});
}(1, 2, 3));
@@ -5178,7 +9011,7 @@
(function() {
test('should return the smallest value from a collection', 1, function() {
- equal(1, _.min([1, 2, 3]));
+ strictEqual(1, _.min([1, 2, 3]));
});
test('should return `Infinity` for empty collections', 1, function() {
@@ -5187,7 +9020,7 @@
var actual = _.map(empties, function(value) {
try {
return _.min(value);
- } catch(e) { }
+ } catch(e) {}
});
deepEqual(actual, expected);
@@ -5200,7 +9033,7 @@
var actual = _.map(collections, function(value) {
try {
return _.min(value);
- } catch(e) { }
+ } catch(e) {}
});
deepEqual(actual, expected);
@@ -5211,26 +9044,27 @@
QUnit.module('lodash.max and lodash.min');
- _.forEach(['max', 'min'], function(methodName) {
+ _.each(['max', 'min'], function(methodName, index) {
var array = [1, 2, 3],
- func = _[methodName];
+ func = _[methodName],
+ isMax = !index;
test('`_.' + methodName + '` should work with Date objects', 1, function() {
- var now = new Date,
+ var curr = new Date,
past = new Date(0);
- equal(func([now, past]), methodName == 'max' ? now : past);
+ strictEqual(func([curr, past]), isMax ? curr : past);
});
- test('`_.' + methodName + '` should work with a `callback` argument', 1, function() {
+ test('`_.' + methodName + '` should work with a `iteratee` argument', 1, function() {
var actual = func(array, function(num) {
return -num;
});
- equal(actual, methodName == 'max' ? 1 : 3);
+ strictEqual(actual, isMax ? 1 : 3);
});
- test('`_.' + methodName + '` should pass the correct `callback` arguments when iterating an array', 1, function() {
+ test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an array', 1, function() {
var args;
func(array, function() {
@@ -5240,7 +9074,7 @@
deepEqual(args, [1, 0, array]);
});
- test('`_.' + methodName + '` should pass the correct `callback` arguments when iterating an object', 1, function() {
+ test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an object', 1, function() {
var args,
object = { 'a': 1, 'b': 2 },
firstKey = _.first(_.keys(object));
@@ -5261,42 +9095,68 @@
return -this[index];
}, array);
- equal(actual, methodName == 'max' ? 1 : 3);
+ strictEqual(actual, isMax ? 1 : 3);
});
- test('`_.' + methodName + '` should work when used as `callback` for `_.map`', 1, function() {
- var array = [[2, 3, 1], [5, 6, 4], [8, 9, 7]],
- actual = _.map(array, func);
+ test('should work with a "_.pluck" style `iteratee`', 2, function() {
+ var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }],
+ actual = func(objects, 'a');
- deepEqual(actual, methodName == 'max' ? [3, 6, 9] : [1, 4, 7]);
+ deepEqual(actual, objects[isMax ? 1 : 2]);
+
+ var arrays = [[2], [3], [1]];
+ actual = func(arrays, 0);
+
+ deepEqual(actual, arrays[isMax ? 1 : 2]);
+ });
+
+ test('`_.' + methodName + '` should work when `iteratee` returns +/-Infinity', 1, function() {
+ var value = isMax ? -Infinity : Infinity,
+ object = { 'a': value };
+
+ var actual = func([object, { 'a': value }], function(object) {
+ return object.a;
+ });
+
+ strictEqual(actual, object);
});
test('`_.' + methodName + '` should iterate an object', 1, function() {
var actual = func({ 'a': 1, 'b': 2, 'c': 3 });
- equal(actual, methodName == 'max' ? 3 : 1);
+ strictEqual(actual, isMax ? 3 : 1);
});
test('`_.' + methodName + '` should iterate a string', 2, function() {
- _.forEach(['abc', Object('abc')], function(value) {
+ _.each(['abc', Object('abc')], function(value) {
var actual = func(value);
- equal(actual, methodName == 'max' ? 'c' : 'a');
+ strictEqual(actual, isMax ? 'c' : 'a');
});
});
- test('`_.' + methodName + '` should resolve the correct value when provided an array containing only one value', 1, function() {
+ test('`_.' + methodName + '` should work with extremely large arrays', 1, function() {
+ var array = _.range(0, 5e5);
+ strictEqual(func(array), isMax ? 499999 : 0);
+ });
+
+ test('`_.' + methodName + '` should work as an iteratee for `_.map`', 2, function() {
+ var array = [[2, 3, 1], [5, 6, 4], [8, 9, 7]],
+ actual = _.map(array, func);
+
+ deepEqual(actual, isMax ? [3, 6, 9] : [1, 4, 7]);
+
+ actual = _.map('abc', func);
+ deepEqual(actual, ['a', 'b', 'c']);
+ });
+
+ test('`_.' + methodName + '` should work when chaining on an array with only one value', 1, function() {
if (!isNpm) {
- var actual = _([40])[methodName]().value();
+ var actual = _([40])[methodName]();
strictEqual(actual, 40);
}
else {
skipTest();
}
});
-
- test('`_.' + methodName + '` should work with extremely large arrays', 1, function() {
- var array = _.range(0, 5e5);
- equal(func(array), methodName == 'max' ? 499999 : 0);
- });
});
/*--------------------------------------------------------------------------*/
@@ -5304,88 +9164,156 @@
QUnit.module('lodash.mixin');
(function() {
- function wrapper(value) {
- if (!(this instanceof wrapper)) {
- return new wrapper(value);
+ function Wrapper(value) {
+ if (!(this instanceof Wrapper)) {
+ return new Wrapper(value);
+ }
+ if (_.has(value, '__wrapped__')) {
+ var actions = _.slice(value.__actions__),
+ chain = value.__chain__;
+
+ value = value.__wrapped__;
}
+ this.__actions__ = actions || [];
+ this.__chain__ = chain || false;
this.__wrapped__ = value;
}
- var value = ['a'],
- source = { 'a': function(array) { return array[0]; } };
+ Wrapper.prototype.value = function() {
+ return getUnwrappedValue(this);
+ };
- test('should accept an `object` argument', 1, function() {
- var lodash = {};
- _.mixin(lodash, source);
- strictEqual(lodash.a(value), 'a');
- });
+ var array = ['a'],
+ source = { 'a': function(array) { return array[0]; }, 'b': 'B' };
- test('should accept a function `object` argument', 2, function() {
- _.mixin(wrapper, source);
+ test('should mixin `source` methods into lodash', 4, function() {
+ if (!isNpm) {
+ _.mixin(source);
- var wrapped = wrapper(value),
- actual = wrapped.a();
+ strictEqual(_.a(array), 'a');
+ strictEqual(_(array).a().value(), 'a');
+
+ delete _.a;
+ delete _.prototype.a;
- strictEqual(actual.__wrapped__, 'a');
- ok(actual instanceof wrapper);
+ ok(!('b' in _));
+ ok(!('b' in _.prototype));
- delete wrapper.a;
- delete wrapper.prototype.a;
+ delete _.b;
+ delete _.prototype.b;
+ }
+ else {
+ skipTest(4);
+ }
});
- test('should mixin `source` methods into lodash', 4, function() {
+ test('should mixin chaining methods by reference', 2, function() {
if (!isNpm) {
- _.mixin({
- 'a': 'a',
- 'A': function(string) { return string.toUpperCase(); }
- });
+ _.mixin(source);
+ _.a = _.constant('b');
- equal('a' in _, false);
- equal('a' in _.prototype, false);
+ strictEqual(_.a(array), 'b');
+ strictEqual(_(array).a().value(), 'a');
delete _.a;
delete _.prototype.a;
-
- equal(_.A('a'), 'A');
- equal(_('a').A().value(), 'A');
-
- delete _.A;
- delete _.prototype.A;
}
else {
- skipTest(4);
+ skipTest(2);
}
});
+ test('should use `this` as the default `object` value', 3, function() {
+ var object = _.create(_);
+ object.mixin(source);
+
+ strictEqual(object.a(array), 'a');
+
+ ok(!('a' in _));
+ ok(!('a' in _.prototype));
+
+ delete Wrapper.a;
+ delete Wrapper.prototype.a;
+ delete Wrapper.b;
+ delete Wrapper.prototype.b;
+ });
+
+ test('should accept an `object` argument', 1, function() {
+ var object = {};
+ _.mixin(object, source);
+ strictEqual(object.a(array), 'a');
+ });
+
+ test('should return `object`', 2, function() {
+ var object = {};
+ strictEqual(_.mixin(object, source), object);
+ strictEqual(_.mixin(), _);
+ });
+
+ test('should work with a function for `object`', 2, function() {
+ _.mixin(Wrapper, source);
+
+ var wrapped = Wrapper(array),
+ actual = wrapped.a();
+
+ strictEqual(actual.value(), 'a');
+ ok(actual instanceof Wrapper);
+
+ delete Wrapper.a;
+ delete Wrapper.prototype.a;
+ delete Wrapper.b;
+ delete Wrapper.prototype.b;
+ });
+
+ test('should not assign inherited `source` properties', 1, function() {
+ function Foo() {}
+ Foo.prototype.a = _.noop;
+
+ deepEqual(_.mixin({}, new Foo, {}), {});
+ });
+
test('should accept an `options` argument', 16, function() {
function message(func, chain) {
return (func === _ ? 'lodash' : 'provided') + ' function should ' + (chain ? '' : 'not ') + 'chain';
}
- _.forEach([_, wrapper], function(func) {
- _.forEach([false, true, { 'chain': false }, { 'chain': true }], function(options) {
- if (func === _) {
- _.mixin(source, options);
- } else {
- _.mixin(func, source, options);
+ _.each([_, Wrapper], function(func) {
+ _.each([false, true, { 'chain': false }, { 'chain': true }], function(options) {
+ if (!isNpm) {
+ if (func === _) {
+ _.mixin(source, options);
+ } else {
+ _.mixin(func, source, options);
+ }
+ var wrapped = func(array),
+ actual = wrapped.a();
+
+ if (options === true || (options && options.chain)) {
+ strictEqual(actual.value(), 'a', message(func, true));
+ ok(actual instanceof func, message(func, true));
+ } else {
+ strictEqual(actual, 'a', message(func, false));
+ ok(!(actual instanceof func), message(func, false));
+ }
+ delete func.a;
+ delete func.prototype.a;
+ delete func.b;
+ delete func.prototype.b;
}
- var wrapped = func(value),
- actual = wrapped.a();
-
- if (options && (options === true || options.chain)) {
- strictEqual(actual.__wrapped__, 'a', message(func, true));
- ok(actual instanceof func, message(func, true));
- } else {
- strictEqual(actual, 'a', message(func, false));
- equal(actual instanceof func, false, message(func, false));
+ else {
+ skipTest(2);
}
- delete func.a;
- delete func.prototype.a;
});
});
});
- test('should not error when passed non-object `options` values', 2, function() {
+ test('should not extend lodash when an `object` is provided with an empty `options` object', 1, function() {
+ _.mixin({ 'a': _.noop }, {});
+ ok(!('a' in _));
+ delete _.a;
+ });
+
+ test('should not error for non-object `options` values', 2, function() {
var pass = true;
try {
@@ -5404,9 +9332,69 @@
}
delete _.a;
delete _.prototype.a;
+ delete _.b;
+ delete _.prototype.b;
ok(pass);
});
+
+ test('should not return the existing wrapped value when chaining', 2, function() {
+ _.each([_, Wrapper], function(func) {
+ if (!isNpm) {
+ if (func === _) {
+ var wrapped = _(source),
+ actual = wrapped.mixin();
+
+ strictEqual(actual.value(), _);
+ }
+ else {
+ wrapped = _(func);
+ actual = wrapped.mixin(source);
+ notStrictEqual(actual, wrapped);
+ }
+ delete func.a;
+ delete func.prototype.a;
+ delete func.b;
+ delete func.prototype.b;
+ }
+ else {
+ skipTest();
+ }
+ });
+ });
+
+ test('should produce methods that work in a lazy chain sequence', 1, function() {
+ if (!isNpm) {
+ var predicate = function(value) { return value > 1; };
+ _.mixin({ 'a': _.countBy, 'b': _.filter });
+
+ var actual = _([1, 2, 1, 3]).a(_.identity).map(String).b(predicate).take().value();
+ deepEqual(actual, ['2']);
+
+ delete _.a;
+ delete _.prototype.a;
+ delete _.b;
+ delete _.prototype.b;
+ }
+ else {
+ skipTest();
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.negate');
+
+ (function() {
+ test('should create a function that negates the result of `func`', 2, function() {
+ var negate = _.negate(function(n) {
+ return n % 2 == 0;
+ });
+
+ strictEqual(negate(1), true);
+ strictEqual(negate(2), false);
+ });
}());
/*--------------------------------------------------------------------------*/
@@ -5414,9 +9402,9 @@
QUnit.module('lodash.noop');
(function() {
- test('should always return `undefined`', 1, function() {
- var values = falsey.concat([], true, new Date, _, {}, /x/, 'a'),
- expected = _.map(values, function() { return undefined; });
+ test('should return `undefined`', 1, function() {
+ var values = empties.concat(true, new Date, _, 1, /x/, 'a'),
+ expected = _.map(values, _.constant());
var actual = _.map(values, function(value, index) {
return index ? _.noop(value) : _.noop();
@@ -5428,6 +9416,23 @@
/*--------------------------------------------------------------------------*/
+ QUnit.module('lodash.noConflict');
+
+ (function() {
+ test('should return the `lodash` function', 1, function() {
+ if (!isModularize) {
+ var oldDash = root._;
+ strictEqual(_.noConflict(), _);
+ root._ = oldDash;
+ }
+ else {
+ skipTest();
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
QUnit.module('lodash.now');
(function() {
@@ -5444,8 +9449,8 @@
}, 32);
}
else {
- skipTest();
- QUnit.start();
+ skipTest();
+ QUnit.start();
}
});
}());
@@ -5479,6 +9484,14 @@
deepEqual(_.omit(new Foo, 'a', 'c'), expected);
});
+ test('should return an empty object when `object` is `null` or `undefined`', 2, function() {
+ objectProto.a = 1;
+ _.each([null, undefined], function(value) {
+ deepEqual(_.omit(value, 'valueOf'), {});
+ });
+ delete objectProto.a;
+ });
+
test('should work with `arguments` objects as secondary arguments', 1, function() {
deepEqual(_.omit(object, args), expected);
});
@@ -5487,7 +9500,17 @@
deepEqual(_.omit([1, 2, 3], '0', '2'), { '1': 2 });
});
- test('should work with a `callback` argument', 1, function() {
+ test('should work with a primitive `object` argument', 1, function() {
+ stringProto.a = 1;
+ stringProto.b = 2;
+
+ deepEqual(_.omit('', 'b'), { 'a': 1 });
+
+ delete stringProto.a;
+ delete stringProto.b;
+ });
+
+ test('should work with a `predicate` argument', 1, function() {
var actual = _.omit(object, function(num) {
return num != 2;
});
@@ -5495,7 +9518,7 @@
deepEqual(actual, expected);
});
- test('should pass the correct `callback` arguments', 1, function() {
+ test('should provide the correct `predicate` arguments', 1, function() {
var args,
object = { 'a': 1, 'b': 2 },
lastKey = _.keys(object).pop();
@@ -5518,67 +9541,170 @@
deepEqual(actual, expected);
});
+
+ test('should coerce property names to strings', 1, function() {
+ deepEqual(_.omit({ '0': 'a' }, 0), {});
+ });
}('a', 'c'));
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.once');
+ QUnit.module('lodash.once');
+
+ (function() {
+ test('should invoke `func` once', 2, function() {
+ var count = 0,
+ once = _.once(function() { return ++count; });
+
+ once();
+ strictEqual(once(), 1);
+ strictEqual(count, 1);
+ });
+
+ test('should not set a `this` binding', 2, function() {
+ var once = _.once(function() { return ++this.count; }),
+ object = { 'count': 0, 'once': once };
+
+ object.once();
+ strictEqual(object.once(), 1);
+ strictEqual(object.count, 1);
+ });
+
+ test('should ignore recursive calls', 2, function() {
+ var count = 0;
+
+ var once = _.once(function() {
+ once();
+ return ++count;
+ });
+
+ strictEqual(once(), 1);
+ strictEqual(count, 1);
+ });
+
+ test('should not throw more than once', 2, function() {
+ var pass = true;
+
+ var once = _.once(function() {
+ throw new Error;
+ });
+
+ raises(function() { once(); }, Error);
+
+ try {
+ once();
+ } catch(e) {
+ pass = false;
+ }
+ ok(pass);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.pad');
+
+ (function() {
+ test('should pad a string to a given length', 1, function() {
+ strictEqual(_.pad('abc', 9), ' abc ');
+ });
+
+ test('should truncate pad characters to fit the pad length', 2, function() {
+ strictEqual(_.pad('abc', 8), ' abc ');
+ strictEqual(_.pad('abc', 8, '_-'), '_-abc_-_');
+ });
+
+ test('should coerce `string` to a string', 2, function() {
+ strictEqual(_.pad(Object('abc'), 4), 'abc ');
+ strictEqual(_.pad({ 'toString': _.constant('abc') }, 5), ' abc ');
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.padLeft');
+
+ (function() {
+ test('should pad a string to a given length', 1, function() {
+ strictEqual(_.padLeft('abc', 6), ' abc');
+ });
+
+ test('should truncate pad characters to fit the pad length', 1, function() {
+ strictEqual(_.padLeft('abc', 6, '_-'), '_-_abc');
+ });
+
+ test('should coerce `string` to a string', 2, function() {
+ strictEqual(_.padLeft(Object('abc'), 4), ' abc');
+ strictEqual(_.padLeft({ 'toString': _.constant('abc') }, 5), ' abc');
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.padRight');
(function() {
- test('should execute `func` once', 1, function() {
- var count = 0,
- func = _.once(function() { count++; });
-
- func();
- func();
- strictEqual(count, 1);
+ test('should pad a string to a given length', 1, function() {
+ strictEqual(_.padRight('abc', 6), 'abc ');
});
- test('should not set a `this` binding', 1, function() {
- var func = _.once(function() { this.count++; }),
- object = { 'count': 0, 'once': func };
+ test('should truncate pad characters to fit the pad length', 1, function() {
+ strictEqual(_.padRight('abc', 6, '_-'), 'abc_-_');
+ });
- object.once();
- object.once();
- strictEqual(object.count, 1);
+ test('should coerce `string` to a string', 2, function() {
+ strictEqual(_.padRight(Object('abc'), 4), 'abc ');
+ strictEqual(_.padRight({ 'toString': _.constant('abc') }, 5), 'abc ');
});
+ }());
- test('should ignore recursive calls', 1, function() {
- var count = 0;
+ /*--------------------------------------------------------------------------*/
- var func = _.once(function() {
- count++;
- func();
- });
+ QUnit.module('pad methods');
- func();
- strictEqual(count, 1);
+ _.each(['pad', 'padLeft', 'padRight'], function(methodName) {
+ var func = _[methodName],
+ isPadLeft = methodName == 'padLeft';
+
+ test('`_.' + methodName + '` should not pad is string is >= `length`', 2, function() {
+ strictEqual(func('abc', 2), 'abc');
+ strictEqual(func('abc', 3), 'abc');
});
- test('should not throw more than once', 2, function() {
- var pass = true;
+ test('`_.' + methodName + '` should treat negative `length` as `0`', 2, function() {
+ _.each([0, -2], function(length) {
+ strictEqual(func('abc', length), 'abc');
+ });
+ });
- var func = _.once(function() {
- throw new Error;
+ test('`_.' + methodName + '` should coerce `length` to a number', 2, function() {
+ _.each(['', '4'], function(length) {
+ var actual = length ? (isPadLeft ? ' abc' : 'abc ') : 'abc';
+ strictEqual(func('abc', length), actual);
});
+ });
- raises(function() { func(); }, Error);
+ test('`_.' + methodName + '` should return an empty string when provided `null`, `undefined`, or empty string and `chars`', 6, function() {
+ _.each([null, '_-'], function(chars) {
+ strictEqual(func(null, 0, chars), '');
+ strictEqual(func(undefined, 0, chars), '');
+ strictEqual(func('', 0, chars), '');
+ });
+ });
- try {
- func();
- } catch(e) {
- pass = false;
- }
- ok(pass);
+ test('`_.' + methodName + '` should work with `null`, `undefined`, or empty string for `chars`', 3, function() {
+ notStrictEqual(func('abc', 6, null), 'abc');
+ notStrictEqual(func('abc', 6, undefined), 'abc');
+ strictEqual(func('abc', 6, ''), 'abc');
});
- }());
+ });
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.pairs');
(function() {
- test('should create a two dimensional array of an object\'s key-value pairs', 1, function() {
+ test('should create a two dimensional array of key-value pairs', 1, function() {
var object = { 'a': 1, 'b': 2 };
deepEqual(_.pairs(object), [['a', 1], ['b', 2]]);
});
@@ -5594,22 +9720,82 @@
QUnit.module('lodash.parseInt');
(function() {
- test('should parse strings with leading whitespace and zeros with a `radix` of 10 by default (test in Chrome, Firefox, and Opera)', 2, function() {
- var whitespace = ' \x09\x0B\x0C\xA0\ufeff\x0A\x0D\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000';
- equal(_.parseInt('08'), 8);
- equal(_.parseInt(whitespace + '08'), 8);
+ test('should accept a `radix` argument', 1, function() {
+ var expected = _.range(2, 37);
+
+ var actual = _.map(expected, function(radix) {
+ return _.parseInt('10', radix);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should use a radix of `10`, for non-hexadecimals, if `radix` is `undefined` or `0`', 4, function() {
+ strictEqual(_.parseInt('10'), 10);
+ strictEqual(_.parseInt('10', 0), 10);
+ strictEqual(_.parseInt('10', 10), 10);
+ strictEqual(_.parseInt('10', undefined), 10);
+ });
+
+ test('should use a radix of `16`, for hexadecimals, if `radix` is `undefined` or `0`', 8, function() {
+ _.each(['0x20', '0X20'], function(string) {
+ strictEqual(_.parseInt(string), 32);
+ strictEqual(_.parseInt(string, 0), 32);
+ strictEqual(_.parseInt(string, 16), 32);
+ strictEqual(_.parseInt(string, undefined), 32);
+ });
+ });
+
+ test('should use a radix of `10` for string with leading zeros', 2, function() {
+ strictEqual(_.parseInt('08'), 8);
+ strictEqual(_.parseInt('08', 10), 8);
+ });
+
+ test('should parse strings with leading whitespace (test in Chrome, Firefox, and Opera)', 2, function() {
+ var expected = [8, 8, 10, 10, 32, 32, 32, 32];
+
+ _.times(2, function(index) {
+ var actual = [],
+ func = (index ? (lodashBizarro || {}) : _).parseInt;
+
+ if (func) {
+ _.times(2, function(otherIndex) {
+ var string = otherIndex ? '10' : '08';
+ actual.push(
+ func(whitespace + string, 10),
+ func(whitespace + string)
+ );
+ });
+
+ _.each(['0x20', '0X20'], function(string) {
+ actual.push(
+ func(whitespace + string),
+ func(whitespace + string, 16)
+ );
+ });
+
+ deepEqual(actual, expected);
+ }
+ else {
+ skipTest();
+ }
+ });
});
- test('should use a radix of `10`, for non-hexadecimals, if `radix` is `undefined` or `0`', 3, function() {
- equal(_.parseInt('10', 0), 10);
- equal(_.parseInt('10'), 10);
- equal(_.parseInt('10', undefined), 10);
+ test('should coerce `radix` to a number', 2, function() {
+ var object = { 'valueOf': function() { return 0; } };
+ strictEqual(_.parseInt('08', object), 8);
+ strictEqual(_.parseInt('0x20', object), 32);
});
- test('should use a radix of `16`, for hexadecimals, if `radix` is `undefined` or `0`', 3, function() {
- equal(_.parseInt('0x20', 0), 32);
- equal(_.parseInt('0x20'), 32);
- equal(_.parseInt('0x20', undefined), 32);
+ test('should work as an iteratee for `_.map`', 2, function() {
+ var strings = _.map(['6', '08', '10'], Object),
+ actual = _.map(strings, _.parseInt);
+
+ deepEqual(actual, [6, 8, 10]);
+
+ actual = _.map('123', _.parseInt);
+ deepEqual(actual, [1, 2, 3]);
});
}());
@@ -5617,81 +9803,113 @@
QUnit.module('partial methods');
- _.forEach(['partial', 'partialRight'], function(methodName) {
+ _.each(['partial', 'partialRight'], function(methodName, index) {
var func = _[methodName],
- isPartial = methodName == 'partial';
+ isPartial = !index,
+ ph = func.placeholder;
- test('`_.' + methodName + '` partially applies without additional arguments', 1, function() {
- var arg = 'a',
- fn = function(x) { return x; };
+ test('`_.' + methodName + '` partially applies arguments', 1, function() {
+ var par = func(_.identity, 'a');
+ strictEqual(par(), 'a');
+ });
+
+ test('`_.' + methodName + '` creates a function that can be invoked with additional arguments', 1, function() {
+ var expected = ['a', 'b'],
+ fn = function(a, b) { return [a, b]; },
+ par = func(fn, 'a');
- equal(func(fn, arg)(), arg);
+ deepEqual(par('b'), isPartial ? expected : expected.reverse());
});
- test('`_.' + methodName + '` partially applies with additional arguments', 1, function() {
- var arg1 = 'a',
- arg2 = 'b',
- expected = [arg1, arg2],
- fn = function(x, y) { return [x, y]; };
+ test('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked without additional arguments', 1, function() {
+ var fn = function() { return arguments.length; },
+ par = func(fn);
- if (!isPartial) {
- expected.reverse();
- }
- deepEqual(func(fn, arg1)(arg2), expected);
+ strictEqual(par(), 0);
});
- test('`_.' + methodName + '` works without partially applying arguments, without additional arguments', 1, function() {
- var fn = function() { return arguments.length; };
- strictEqual(func(fn)(), 0);
+ test('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked with additional arguments', 1, function() {
+ var par = func(_.identity);
+ strictEqual(par('a'), 'a');
});
- test('`_.' + methodName + '` works without partially applying arguments, with additional arguments', 1, function() {
- var arg = 'a',
- fn = function(x) { return x; };
+ test('`_.' + methodName + '` should support placeholders', 4, function() {
+ var fn = function() { return slice.call(arguments); },
+ par = func(fn, ph, 'b', ph);
+
+ deepEqual(par('a', 'c'), ['a', 'b', 'c']);
+ deepEqual(par('a'), ['a', 'b', undefined]);
+ deepEqual(par(), [undefined, 'b', undefined]);
- equal(func(fn)(arg), arg);
+ if (isPartial) {
+ deepEqual(par('a', 'c', 'd'), ['a', 'b', 'c', 'd']);
+ } else {
+ par = func(fn, ph, 'c', ph);
+ deepEqual(par('a', 'b', 'd'), ['a', 'b', 'c', 'd']);
+ }
});
- test('`_.' + methodName + '` should not alter the `this` binding', 3, function() {
- var object = { 'a': 1 },
- fn = function() { return this.a; };
+ test('`_.' + methodName + '` should not set a `this` binding', 3, function() {
+ var fn = function() { return this.a; },
+ object = { 'a': 1 };
+
+ var par = func(_.bind(fn, object));
+ strictEqual(par(), object.a);
- strictEqual(func(_.bind(fn, object))(), object.a);
- strictEqual(_.bind(func(fn), object)(), object.a);
+ par = _.bind(func(fn), object);
+ strictEqual(par(), object.a);
- object.fn = func(fn);
- strictEqual(object.fn(), object.a);
+ object.par = func(fn);
+ strictEqual(object.par(), object.a);
});
- test('`_.' + methodName + '` returns a function with a `length` of `0`', 1, function() {
+ test('`_.' + methodName + '` creates a function with a `length` of `0`', 1, function() {
var fn = function(a, b, c) {},
- actual = func(fn, 'a');
+ par = func(fn, 'a');
- strictEqual(actual.length, 0);
+ strictEqual(par.length, 0);
});
- test('ensure `new bound` is an instance of `func`', 2, function() {
+ test('`_.' + methodName + '` ensure `new partialed` is an instance of `func`', 2, function() {
function Foo(value) {
return value && object;
}
- var bound = func(Foo),
- object = {};
- ok(new bound instanceof Foo);
- strictEqual(new bound(true), object);
+ var object = {},
+ par = func(Foo);
+
+ ok(new par instanceof Foo);
+ strictEqual(new par(true), object);
});
- test('`_.' + methodName + '` should clone `__bindData__` for created functions', 3, function() {
+ test('`_.' + methodName + '` should clone metadata for created functions', 3, function() {
function greet(greeting, name) {
return greeting + ' ' + name;
}
+
var par1 = func(greet, 'hi'),
par2 = func(par1, 'barney'),
par3 = func(par1, 'pebbles');
- equal(par1('fred'), isPartial ? 'hi fred' : 'fred hi')
- equal(par2(), isPartial ? 'hi barney' : 'barney hi');
- equal(par3(), isPartial ? 'hi pebbles' : 'pebbles hi');
+ strictEqual(par1('fred'), isPartial ? 'hi fred' : 'fred hi');
+ strictEqual(par2(), isPartial ? 'hi barney' : 'barney hi');
+ strictEqual(par3(), isPartial ? 'hi pebbles' : 'pebbles hi');
+ });
+
+ test('`_.' + methodName + '` should work with curried methods', 2, function() {
+ var fn = function(a, b, c) { return a + b + c; },
+ curried = _.curry(func(fn, 1), 2);
+
+ strictEqual(curried(2, 3), 6);
+ strictEqual(curried(2)(3), 6);
+ });
+
+ test('should work with placeholders and curried methods', 1, function() {
+ var fn = function() { return slice.call(arguments); },
+ curried = _.curry(fn),
+ par = func(curried, ph, 'b', ph, 'd');
+
+ deepEqual(par('a', 'c'), ['a', 'b', 'c', 'd']);
});
});
@@ -5705,8 +9923,11 @@
source = { 'a': { 'b': 2, 'c': 3 } },
expected = { 'a': { 'b': 1, 'c': 3 } };
- var deepDefaults = _.partialRight(_.merge, _.defaults);
- deepEqual(deepDefaults(object, source), expected);
+ var defaultsDeep = _.partialRight(_.merge, function deep(value, other) {
+ return _.merge(value, other, deep);
+ });
+
+ deepEqual(defaultsDeep(object, source), expected);
});
}());
@@ -5715,11 +9936,17 @@
QUnit.module('methods using `createWrapper`');
(function() {
+ var ph1 = _.bind.placeholder,
+ ph2 = _.bindKey.placeholder,
+ ph3 = _.partial.placeholder,
+ ph4 = _.partialRight.placeholder;
+
test('combinations of partial functions should work', 1, function() {
- function func() {
+ function fn() {
return slice.call(arguments);
}
- var a = _.partial(func),
+
+ var a = _.partial(fn),
b = _.partialRight(a, 3),
c = _.partial(b, 1);
@@ -5727,43 +9954,246 @@
});
test('combinations of bound and partial functions should work', 3, function() {
- function func() {
- var result = [this.x];
+ function fn() {
+ var result = [this.a];
push.apply(result, arguments);
return result;
}
+
var expected = [1, 2, 3, 4],
- object = { 'func': func, 'x': 1 };
+ object = { 'a': 1, 'fn': fn };
- var a = _.bindKey(object, 'func'),
+ var a = _.bindKey(object, 'fn'),
b = _.partialRight(a, 4),
c = _.partial(b, 2);
deepEqual(c(3), expected);
- a = _.bind(func, object);
+ a = _.bind(fn, object);
b = _.partialRight(a, 4);
c = _.partial(b, 2);
deepEqual(c(3), expected);
- a = _.partial(func, 2);
+ a = _.partial(fn, 2);
b = _.bind(a, object);
c = _.partialRight(b, 4);
deepEqual(c(3), expected);
});
+ test('combinations of functions with placeholders should work', 3, function() {
+ function fn() {
+ return slice.call(arguments);
+ }
+
+ var expected = [1, 2, 3, 4, 5, 6],
+ object = { 'fn': fn };
+
+ var a = _.bindKey(object, 'fn', ph2, 2),
+ b = _.partialRight(a, ph4, 6),
+ c = _.partial(b, 1, ph3, 4);
+
+ deepEqual(c(3, 5), expected);
+
+ a = _.bind(fn, object, ph1, 2);
+ b = _.partialRight(a, ph4, 6);
+ c = _.partial(b, 1, ph3, 4);
+
+ deepEqual(c(3, 5), expected);
+
+ a = _.partial(fn, ph3, 2)
+ b = _.bind(a, object, 1, ph1, 4);
+ c = _.partialRight(b, ph4, 6);
+
+ deepEqual(c(3, 5), expected);
+ });
+
+ test('combinations of functions with overlaping placeholders should work', 3, function() {
+ function fn() {
+ return slice.call(arguments);
+ }
+
+ var expected = [1, 2, 3, 4],
+ object = { 'fn': fn };
+
+ var a = _.bindKey(object, 'fn', ph2, 2),
+ b = _.partialRight(a, ph4, 4),
+ c = _.partial(b, ph3, 3);
+
+ deepEqual(c(1), expected);
+
+ a = _.bind(fn, object, ph1, 2);
+ b = _.partialRight(a, ph4, 4);
+ c = _.partial(b, ph3, 3);
+
+ deepEqual(c(1), expected);
+
+ a = _.partial(fn, ph3, 2)
+ b = _.bind(a, object, ph1, 3);
+ c = _.partialRight(b, ph4, 4);
+
+ deepEqual(c(1), expected);
+ });
+
test('recursively bound functions should work', 1, function() {
- function func() {
- return this.x;
+ function fn() {
+ return this.a;
}
- var a = _.bind(func, { 'x': 1 }),
- b = _.bind(a, { 'x': 2 }),
- c = _.bind(b, { 'x': 3 });
+
+ var a = _.bind(fn, { 'a': 1 }),
+ b = _.bind(a, { 'a': 2 }),
+ c = _.bind(b, { 'a': 3 });
strictEqual(c(), 1);
});
+
+ test('should work when hot', 12, function() {
+ _.times(2, function(index) {
+ function fn() {
+ var result = [this];
+ push.apply(result, arguments);
+ return result;
+ }
+
+ var object = {},
+ bound1 = index ? _.bind(fn, object, 1) : _.bind(fn, object),
+ expected = [object, 1, 2, 3];
+
+ var actual = _.last(_.times(HOT_COUNT, function() {
+ var bound2 = index ? _.bind(bound1, null, 2) : _.bind(bound1);
+ return index ? bound2(3) : bound2(1, 2, 3);
+ }));
+
+ deepEqual(actual, expected);
+
+ actual = _.last(_.times(HOT_COUNT, function() {
+ var bound1 = index ? _.bind(fn, object, 1) : _.bind(fn, object),
+ bound2 = index ? _.bind(bound1, null, 2) : _.bind(bound1);
+
+ return index ? bound2(3) : bound2(1, 2, 3);
+ }));
+
+ deepEqual(actual, expected);
+ });
+
+ _.each(['curry', 'curryRight'], function(methodName, index) {
+ function fn(a, b, c) {
+ return [a, b, c];
+ }
+
+ var curried = _[methodName](fn),
+ expected = index ? [3, 2, 1] : [1, 2, 3];
+
+ var actual = _.last(_.times(HOT_COUNT, function() {
+ return curried(1)(2)(3);
+ }));
+
+ deepEqual(actual, expected);
+
+ actual = _.last(_.times(HOT_COUNT, function() {
+ var curried = _[methodName](fn);
+ return curried(1)(2)(3);
+ }));
+
+ deepEqual(actual, expected);
+ });
+
+ _.each(['partial', 'partialRight'], function(methodName, index) {
+ function fn() {
+ return slice.call(arguments);
+ }
+
+ var func = _[methodName],
+ par1 = func(fn, 1),
+ expected = index ? [3, 2, 1] : [1, 2, 3];
+
+ var actual = _.last(_.times(HOT_COUNT, function() {
+ var par2 = func(par1, 2);
+ return par2(3);
+ }));
+
+ deepEqual(actual, expected);
+
+ actual = _.last(_.times(HOT_COUNT, function() {
+ var par1 = func(fn, 1),
+ par2 = func(par1, 2);
+
+ return par2(3);
+ }));
+
+ deepEqual(actual, expected);
+ });
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.partition');
+
+ (function() {
+ var array = [1, 0, 1];
+
+ test('should return two groups of elements', 3, function() {
+ deepEqual(_.partition([], _.identity), [[], []]);
+ deepEqual(_.partition(array, _.constant(true)), [array, []]);
+ deepEqual(_.partition(array, _.constant(false)), [[], array]);
+ });
+
+ test('should use `_.identity` when `predicate` is nullish', 1, function() {
+ var values = [, null, undefined],
+ expected = _.map(values, _.constant([[1, 1], [0]]));
+
+ var actual = _.map(values, function(value, index) {
+ return index ? _.partition(array, value) : _.partition(array);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should provide the correct `predicate` arguments', 1, function() {
+ var args;
+
+ _.partition(array, function() {
+ args || (args = slice.call(arguments));
+ });
+
+ deepEqual(args, [1, 0, array]);
+ });
+
+ test('should support the `thisArg` argument', 1, function() {
+ var actual = _.partition([1.1, 0.2, 1.3], function(num) {
+ return this.floor(num);
+ }, Math);
+
+ deepEqual(actual, [[1.1, 1.3], [0.2]]);
+ });
+
+ test('should work with a "_.pluck" style `predicate`', 1, function() {
+ var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }],
+ actual = _.partition(objects, 'a');
+
+ deepEqual(actual, [objects.slice(0, 2), objects.slice(2)]);
+ });
+
+ test('should work with a number for `predicate`', 2, function() {
+ var array = [
+ [1, 0],
+ [0, 1],
+ [1, 0]
+ ];
+
+ deepEqual(_.partition(array, 0), [[array[0], array[2]], [array[1]]]);
+ deepEqual(_.partition(array, 1), [[array[1]], [array[0], array[2]]]);
+ });
+
+ test('should work with an object for `collection`', 1, function() {
+ var actual = _.partition({ 'a': 1.1, 'b': 0.2, 'c': 1.3 }, function(num) {
+ return Math.floor(num);
+ });
+
+ deepEqual(actual, [[1.1, 1.3], [0.2]]);
+ })
}());
/*--------------------------------------------------------------------------*/
@@ -5795,6 +10225,12 @@
deepEqual(_.pick(new Foo, 'a', 'c'), expected);
});
+ test('should return an empty object when `object` is `null` or `undefined`', 2, function() {
+ _.each([null, undefined], function(value) {
+ deepEqual(_.pick(value, 'valueOf'), {});
+ });
+ });
+
test('should work with `arguments` objects as secondary arguments', 1, function() {
deepEqual(_.pick(object, args), expected);
});
@@ -5803,7 +10239,11 @@
deepEqual(_.pick([1, 2, 3], '1'), { '1': 2 });
});
- test('should work with a `callback` argument', 1, function() {
+ test('should work with a primitive `object` argument', 1, function() {
+ deepEqual(_.pick('', 'slice'), { 'slice': ''.slice });
+ });
+
+ test('should work with a `predicate` argument', 1, function() {
var actual = _.pick(object, function(num) {
return num != 2;
});
@@ -5811,7 +10251,7 @@
deepEqual(actual, expected);
});
- test('should pass the correct `callback` arguments', 1, function() {
+ test('should provide the correct `predicate` arguments', 1, function() {
var args,
object = { 'a': 1, 'b': 2 },
lastKey = _.keys(object).pop();
@@ -5834,6 +10274,10 @@
deepEqual(actual, expected);
});
+
+ test('should coerce property names to strings', 1, function() {
+ deepEqual(_.pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' });
+ });
}('a', 'c'));
/*--------------------------------------------------------------------------*/
@@ -5842,39 +10286,153 @@
(function() {
test('should return an array of property values from each element of a collection', 1, function() {
- var objects = [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }],
- actual = _.pluck(objects, 'name');
+ var objects = [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }];
+ deepEqual(_.pluck(objects, 'name'), ['barney', 'fred']);
+ });
+
+ test('should pluck inherited property values', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
+
+ deepEqual(_.pluck([new Foo], 'b'), [2]);
+ });
+
+ test('should work with an object for `collection`', 1, function() {
+ var object = { 'a': [1], 'b': [1, 2], 'c': [1, 2, 3] };
+ deepEqual(_.pluck(object, 'length'), [1, 2, 3]);
+ });
+
+ test('should return `undefined` for undefined properties', 1, function() {
+ var array = [{ 'a': 1 }],
+ actual = [_.pluck(array, 'b'), _.pluck(array, 'c')];
+
+ deepEqual(actual, [[undefined], [undefined]]);
+ });
+
+ test('should work with nullish elements', 1, function() {
+ var objects = [{ 'a': 1 }, null, undefined, { 'a': 4 }];
+ deepEqual(_.pluck(objects, 'a'), [1, undefined, undefined, 4]);
+ });
+
+ test('should coerce `key` to a string', 1, function() {
+ function fn() {}
+ fn.toString = _.constant('fn');
+
+ var objects = [{ 'null': 1 }, { 'undefined': 2 }, { 'fn': 3 }, { '[object Object]': 4 }],
+ values = [null, undefined, fn, {}]
+
+ var actual = _.map(objects, function(object, index) {
+ return _.pluck([object], values[index]);
+ });
+
+ deepEqual(actual, [[1], [2], [3], [4]]);
+ });
+
+ test('should work in a lazy chain sequence', 2, function() {
+ if (!isNpm) {
+ var array = [{ 'a': 1 }, null, { 'a': 3 }, { 'a': 4 }],
+ actual = _(array).pluck('a').value();
+
+ deepEqual(actual, [1, undefined, 3, 4]);
+
+ actual = _(array).filter(Boolean).pluck('a').value();
+ deepEqual(actual, [1, 3, 4]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.property');
+
+ (function() {
+ test('should create a function that plucks a property value of a given object', 3, function() {
+ var object = { 'a': 1, 'b': 2 },
+ prop = _.property('a');
+
+ strictEqual(prop.length, 1);
+ strictEqual(prop(object), 1);
+
+ prop = _.property('b');
+ strictEqual(prop(object), 2);
+ });
+
+ test('should work with non-string `prop` arguments', 1, function() {
+ var prop = _.property(1);
+ strictEqual(prop([1, 2, 3]), 2);
+ });
+
+ test('should coerce key to a string', 1, function() {
+ function fn() {}
+ fn.toString = _.constant('fn');
+
+ var objects = [{ 'null': 1 }, { 'undefined': 2 }, { 'fn': 3 }, { '[object Object]': 4 }],
+ values = [null, undefined, fn, {}]
+
+ var actual = _.map(objects, function(object, index) {
+ var prop = _.property(values[index]);
+ return prop(object);
+ });
+
+ deepEqual(actual, [1, 2, 3, 4]);
+ });
+
+ test('should pluck inherited property values', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
- deepEqual(actual, ['barney', 'fred']);
+ var prop = _.property('b');
+ strictEqual(prop(new Foo), 2);
});
- test('should work with an object for `collection`', 1, function() {
- var object = { 'a': [1], 'b': [1, 2], 'c': [1, 2, 3] };
- deepEqual(_.pluck(object, 'length'), [1, 2, 3]);
+ test('should work when `object` is nullish', 1, function() {
+ var values = [, null, undefined],
+ expected = _.map(values, _.constant(undefined));
+
+ var actual = _.map(values, function(value, index) {
+ var prop = _.property('a');
+ return index ? prop(value) : prop();
+ });
+
+ deepEqual(actual, expected);
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.property');
+ QUnit.module('lodash.propertyOf');
(function() {
- test('should create a function that plucks a property value of a given object', 3, function() {
+ test('should create a function that plucks a property value of a given key', 3, function() {
var object = { 'a': 1, 'b': 2 },
- actual = _.property('a');
+ propOf = _.propertyOf(object);
+
+ strictEqual(propOf.length, 1);
+ strictEqual(propOf('a'), 1);
+ strictEqual(propOf('b'), 2);
+ });
- equal(actual.length, 1);
- strictEqual(actual(object), 1);
+ test('should pluck inherited property values', 1, function() {
+ function Foo() { this.a = 1; }
+ Foo.prototype.b = 2;
- actual = _.property('b');
- strictEqual(actual(object), 2);
+ var propOf = _.propertyOf(new Foo);
+ strictEqual(propOf('b'), 2);
});
- test('should work with non-string `prop` arguments', 1, function() {
- var array = [1, 2, 3],
- actual = _.property(1);
+ test('should work when `object` is nullish', 1, function() {
+ var values = [, null, undefined],
+ expected = _.map(values, _.constant(undefined));
- equal(actual(array), 2);
+ var actual = _.map(values, function(value, index) {
+ var propOf = index ? _.propertyOf(value) : _.propertyOf();
+ return propOf('a');
+ });
+
+ deepEqual(actual, expected);
});
}());
@@ -5897,8 +10455,8 @@
delete array[3];
_.pull(array, 1);
- equal(0 in array, false);
- equal(2 in array, false);
+ ok(!('0' in array));
+ ok(!('2' in array));
});
test('should treat holes as `undefined`', 1, function() {
@@ -5908,6 +10466,109 @@
_.pull(array, undefined);
deepEqual(array, [1, 3]);
});
+
+ test('should match `NaN`', 1, function() {
+ var array = [1, NaN, 3, NaN];
+
+ _.pull(array, NaN);
+ deepEqual(array, [1, 3]);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.pullAt');
+
+ (function() {
+ test('should modify the array and return removed elements', 2, function() {
+ var array = [1, 2, 3],
+ actual = _.pullAt(array, [0, 1]);
+
+ deepEqual(array, [3]);
+ deepEqual(actual, [1, 2]);
+ });
+
+ test('should work with unsorted indexes', 2, function() {
+ var array = [1, 2, 3, 4],
+ actual = _.pullAt(array, [1, 3, 0]);
+
+ deepEqual(array, [3]);
+ deepEqual(actual, [2, 4, 1]);
+ });
+
+ test('should work with repeated indexes', 2, function() {
+ var array = [1, 2, 3, 4],
+ actual = _.pullAt(array, [0, 2, 0, 1, 0, 2]);
+
+ deepEqual(array, [4]);
+ deepEqual(actual, [1, 3, 1, 2, 1, 3]);
+ });
+
+ test('should use `undefined` for nonexistent indexes', 2, function() {
+ var array = ['a', 'b', 'c'],
+ actual = _.pullAt(array, [2, 4, 0]);
+
+ deepEqual(array, ['b']);
+ deepEqual(actual, ['c', undefined, 'a']);
+ });
+
+ test('should ignore non-index keys', 2, function() {
+ var array = ['a', 'b', 'c'],
+ clone = array.slice();
+
+ array['1.1'] = array['-1'] = 1;
+
+ var values = _.reject(empties, function(value) {
+ return value === 0 || _.isArray(value);
+ }).concat(-1, 1.1);
+
+ var expected = _.map(values, _.constant(undefined)),
+ actual = _.pullAt(array, values);
+
+ deepEqual(actual, expected);
+ deepEqual(array, clone);
+ });
+
+ test('should return an empty array when no indexes are provided', 4, function() {
+ var array = ['a', 'b', 'c'],
+ actual = _.pullAt(array);
+
+ deepEqual(array, ['a', 'b', 'c']);
+ deepEqual(actual, []);
+
+ actual = _.pullAt(array, [], []);
+
+ deepEqual(array, ['a', 'b', 'c']);
+ deepEqual(actual, []);
+ });
+
+ test('should accept multiple index arguments', 2, function() {
+ var array = ['a', 'b', 'c', 'd'],
+ actual = _.pullAt(array, 3, 0, 2);
+
+ deepEqual(array, ['b']);
+ deepEqual(actual, ['d', 'a', 'c']);
+ });
+
+ test('should accept multiple arrays of indexes', 2, function() {
+ var array = ['a', 'b', 'c', 'd'],
+ actual = _.pullAt(array, [3], [0, 2]);
+
+ deepEqual(array, ['b']);
+ deepEqual(actual, ['d', 'a', 'c']);
+ });
+
+ test('should work with a falsey `array` argument when keys are provided', 1, function() {
+ var expected = _.map(falsey, _.constant([undefined, undefined]));
+
+ var actual = _.map(falsey, function(value) {
+ try {
+ return _.pullAt(value, 0, 1);
+ } catch(e) {}
+ });
+
+ deepEqual(actual, expected);
+ });
}());
/*--------------------------------------------------------------------------*/
@@ -5918,14 +10579,16 @@
var array = Array(1000);
test('should return `0` or `1` when arguments are not provided', 1, function() {
- var actual = _.random();
- ok(actual === 0 || actual === 1);
+ var actual = _.map(array, function() {
+ return _.random();
+ });
+
+ deepEqual(_.uniq(actual).sort(), [0, 1]);
});
- test('supports not passing a `max` argument', 1, function() {
- var actual = _.random(5);
+ test('supports not providing a `max` argument', 1, function() {
ok(_.some(array, function() {
- return _.random(5) != 5;
+ return _.random(5) !== 5;
}));
});
@@ -5955,7 +10618,7 @@
ok(actual >= min && actual <= max);
});
- test('supports passing a `floating` argument', 3, function() {
+ test('supports providing a `floating` argument', 3, function() {
var actual = _.random(true);
ok(actual % 1 && actual >= 0 && actual <= 1);
@@ -5965,6 +10628,18 @@
actual = _.random(2, 4, true);
ok(actual % 1 && actual >= 2 && actual <= 4);
});
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = [1, 2, 3],
+ expected = _.map(array, _.constant(true)),
+ randoms = _.map(array, _.random);
+
+ var actual = _.map(randoms, function(result, index) {
+ return result >= 0 && result <= array[index] && (result % 1) == 0;
+ });
+
+ deepEqual(actual, expected);
+ });
}());
/*--------------------------------------------------------------------------*/
@@ -5972,17 +10647,15 @@
QUnit.module('lodash.range');
(function() {
- var func = _.range;
-
- test('should work when passing a single `end` argument', 1, function() {
+ test('should work with a single `end` argument', 1, function() {
deepEqual(_.range(4), [0, 1, 2, 3]);
});
- test('should work when passing `start` and `end` arguments', 1, function() {
+ test('should work with `start` and `end` arguments', 1, function() {
deepEqual(_.range(1, 5), [1, 2, 3, 4]);
});
- test('should work when passing `start`, `end`, and `step` arguments', 1, function() {
+ test('should work with `start`, `end`, and `step` arguments', 1, function() {
deepEqual(_.range(0, 20, 5), [0, 5, 10, 15]);
});
@@ -5990,17 +10663,17 @@
deepEqual(_.range(1, 4, 0), [1, 1, 1]);
});
- test('should work when passing `step` larger than `end`', 1, function() {
+ test('should work with a `step` larger than `end`', 1, function() {
deepEqual(_.range(1, 5, 20), [1]);
});
- test('should work when passing a negative `step` argument', 2, function() {
+ test('should work with a negative `step` argument', 2, function() {
deepEqual(_.range(0, -4, -1), [0, -1, -2, -3]);
deepEqual(_.range(21, 10, -3), [21, 18, 15, 12]);
});
test('should treat falsey `start` arguments as `0`', 13, function() {
- _.forEach(falsey, function(value, index) {
+ _.each(falsey, function(value, index) {
if (index) {
deepEqual(_.range(value), []);
deepEqual(_.range(value, 1), [0]);
@@ -6010,9 +10683,84 @@
});
});
- test('should coerce arguments to numbers', 1, function() {
- var actual = [func('0',1), func('1'), func(0, 1, '1')];
- deepEqual(actual, [[0], [0], [0]]);
+ test('should coerce arguments to finite numbers', 1, function() {
+ var actual = [_.range('0', 1), _.range('1'), _.range(0, 1, '1'), _.range(NaN), _.range(NaN, NaN)];
+ deepEqual(actual, [[0], [0], [0], [], []]);
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var actual = _.map([1, 2, 3], _.range);
+ deepEqual(actual, [[0], [0, 1], [0, 1, 2]]);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.rearg');
+
+ (function() {
+ function fn() {
+ return slice.call(arguments);
+ }
+
+ test('should reorder arguments provided to `func`', 1, function() {
+ var rearged = _.rearg(fn, [2, 0, 1]);
+ deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']);
+ });
+
+ test('should work with repeated indexes', 1, function() {
+ var rearged = _.rearg(fn, [1, 1, 1]);
+ deepEqual(rearged('c', 'a', 'b'), ['a', 'a', 'a']);
+ });
+
+ test('should use `undefined` for nonexistent indexes', 1, function() {
+ var rearged = _.rearg(fn, [1, 4]);
+ deepEqual(rearged('b', 'a', 'c'), ['a', undefined, 'c']);
+ });
+
+ test('should use `undefined` for non-index values', 1, function() {
+ var values = _.reject(empties, function(value) {
+ return value === 0 || _.isArray(value);
+ }).concat(-1, 1.1);
+
+ var expected = _.map(values, _.constant([undefined, 'b', 'c']));
+
+ var actual = _.map(values, function(value) {
+ var rearged = _.rearg(fn, [value]);
+ return rearged('a', 'b', 'c');
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should not rearrange arguments when no indexes are provided', 2, function() {
+ var rearged = _.rearg(fn);
+ deepEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']);
+
+ rearged = _.rearg(fn, [], []);
+ deepEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']);
+ });
+
+ test('should accept multiple index arguments', 1, function() {
+ var rearged = _.rearg(fn, 2, 0, 1);
+ deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']);
+ });
+
+ test('should accept multiple arrays of indexes', 1, function() {
+ var rearged = _.rearg(fn, [2], [0, 1]);
+ deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']);
+ });
+
+ test('should work with fewer indexes than arguments', 1, function() {
+ var rearged = _.rearg(fn, [1, 0]);
+ deepEqual(rearged('b', 'a', 'c'), ['a', 'b', 'c']);
+ });
+
+ test('should work on functions that have been rearged', 1, function() {
+ var rearged1 = _.rearg(fn, 2, 1, 0),
+ rearged2 = _.rearg(rearged1, 1, 0, 2);
+
+ deepEqual(rearged2('b', 'c', 'a'), ['a', 'b', 'c']);
});
}());
@@ -6027,7 +10775,7 @@
strictEqual(_.reduce(array), 1);
});
- test('should pass the correct `callback` arguments when iterating an array', 2, function() {
+ test('should provide the correct `iteratee` arguments when iterating an array', 2, function() {
var args;
_.reduce(array, function() {
@@ -6044,7 +10792,7 @@
deepEqual(args, [1, 2, 1, array]);
});
- test('should pass the correct `callback` arguments when iterating an object', 2, function() {
+ test('should provide the correct `iteratee` arguments when iterating an object', 2, function() {
var args,
object = { 'a': 1, 'b': 2 },
firstKey = _.first(_.keys(object));
@@ -6071,7 +10819,7 @@
deepEqual(args, expected);
});
- _.forEach({
+ _.each({
'literal': 'abc',
'object': Object('abc')
},
@@ -6085,7 +10833,7 @@
});
deepEqual(args, ['a', 'b', 1, collection]);
- equal(actual, 'abc');
+ strictEqual(actual, 'abc');
});
});
@@ -6103,10 +10851,10 @@
var array = [1, 2, 3];
test('should use the last element of a collection as the default `accumulator`', 1, function() {
- equal(_.reduceRight(array), 3);
+ strictEqual(_.reduceRight(array), 3);
});
- test('should pass the correct `callback` arguments when iterating an array', 2, function() {
+ test('should provide the correct `iteratee` arguments when iterating an array', 2, function() {
var args;
_.reduceRight(array, function() {
@@ -6123,7 +10871,7 @@
deepEqual(args, [3, 2, 1, array]);
});
- test('should pass the correct `callback` arguments when iterating an object', 2, function() {
+ test('should provide the correct `iteratee` arguments when iterating an object', 2, function() {
var args,
object = { 'a': 1, 'b': 2 },
lastKey = _.last(_.keys(object));
@@ -6150,7 +10898,7 @@
deepEqual(args, expected);
});
- _.forEach({
+ _.each({
'literal': 'abc',
'object': Object('abc')
},
@@ -6164,7 +10912,7 @@
});
deepEqual(args, ['c', 'b', 1, collection]);
- equal(actual, 'cba');
+ strictEqual(actual, 'cba');
});
});
@@ -6177,7 +10925,7 @@
QUnit.module('reduce methods');
- _.forEach(['reduce', 'reduceRight'], function(methodName) {
+ _.each(['reduce', 'reduceRight'], function(methodName, index) {
var array = [1, 2, 3],
func = _[methodName];
@@ -6186,7 +10934,7 @@
return accumulator + value;
}, '');
- equal(actual, methodName == 'reduce' ? 'abc' : 'cba');
+ strictEqual(actual, index ? 'cba' : 'abc');
});
test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() {
@@ -6197,48 +10945,62 @@
deepEqual(actual, 6);
});
- test('`_.' + methodName + '` should return an unwrapped value when chaining', 1, function() {
- if (!isNpm) {
- var actual = _(array)[methodName](function(sum, num) {
- return sum + num;
- });
-
- equal(actual, 6);
- }
- else {
- skipTest();
- }
- });
-
- test('`_.' + methodName + '` should support empty or falsey collections without an initial `accumulator` value', 1, function() {
+ test('`_.' + methodName + '` should support empty collections without an initial `accumulator` value', 1, function() {
var actual = [],
- expected = _.map(empties, function() { return undefined; });
+ expected = _.map(empties, _.constant());
- _.forEach(empties, function(value) {
+ _.each(empties, function(value) {
try {
- actual.push(func(value, noop));
- } catch(e) { }
+ actual.push(func(value, _.noop));
+ } catch(e) {}
});
deepEqual(actual, expected);
});
- test('`_.' + methodName + '` should support empty or falsey collections with an initial `accumulator` value', 1, function() {
- var expected = _.map(empties, function() { return 'x'; });
+ test('`_.' + methodName + '` should support empty collections with an initial `accumulator` value', 1, function() {
+ var expected = _.map(empties, _.constant('x'));
var actual = _.map(empties, function(value) {
try {
- return func(value, noop, 'x');
- } catch(e) { }
+ return func(value, _.noop, 'x');
+ } catch(e) {}
});
deepEqual(actual, expected);
});
test('`_.' + methodName + '` should handle an initial `accumulator` value of `undefined`', 1, function() {
- var actual = func([], noop, undefined);
+ var actual = func([], _.noop, undefined);
strictEqual(actual, undefined);
});
+
+ test('`_.' + methodName + '` should return `undefined` for empty collections when no `accumulator` is provided (test in IE > 9 and modern browsers)', 2, function() {
+ var array = [],
+ object = { '0': 1, 'length': 0 };
+
+ if ('__proto__' in array) {
+ array.__proto__ = object;
+ strictEqual(_.reduce(array, _.noop), undefined);
+ }
+ else {
+ skipTest();
+ }
+ strictEqual(_.reduce(object, _.noop), undefined);
+ });
+
+ test('`_.' + methodName + '` should return an unwrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ var actual = _(array)[methodName](function(sum, num) {
+ return sum + num;
+ });
+
+ strictEqual(actual, 6);
+ }
+ else {
+ skipTest();
+ }
+ });
});
/*--------------------------------------------------------------------------*/
@@ -6246,7 +11008,7 @@
QUnit.module('lodash.reject');
(function() {
- test('should return elements the `callback` returns falsey for', 1, function() {
+ test('should return elements the `predicate` returns falsey for', 1, function() {
var actual = _.reject([1, 2, 3], function(num) {
return num % 2;
});
@@ -6259,17 +11021,69 @@
QUnit.module('filter methods');
- _.forEach(['filter', 'reject'], function(methodNames) {
- var func = _[methodNames];
+ _.each(['filter', 'reject'], function(methodName, index) {
+ var func = _[methodName],
+ isFilter = !index;
- test('`_.' + methodNames + '` should not modify the resulting value from within `callback`', 1, function() {
+ test('`_.' + methodName + '` should not modify the resulting value from within `predicate`', 1, function() {
var actual = func([0], function(num, index, array) {
array[index] = 1;
- return methodNames == 'filter';
+ return isFilter;
});
deepEqual(actual, [0]);
});
+
+ test('`_.' + methodName + '` should work with a "_.pluck" style `predicate`', 1, function() {
+ var objects = [{ 'a': 0 }, { 'a': 1 }];
+ deepEqual(func(objects, 'a'), [objects[isFilter ? 1 : 0]]);
+ });
+
+ test('`_.' + methodName + '` should work with a "_where" style `predicate`', 1, function() {
+ var objects = [{ 'a': 0 }, { 'a': 1 }];
+ deepEqual(func(objects, objects[1]), [objects[isFilter ? 1 : 0]]);
+ });
+
+ test('`_.' + methodName + '` should not modify wrapped values', 2, function() {
+ if (!isNpm) {
+ var wrapped = _([1, 2, 3, 4]);
+
+ var actual = wrapped[methodName](function(num) {
+ return num < 3;
+ });
+
+ deepEqual(actual.value(), isFilter ? [1, 2] : [3, 4]);
+
+ actual = wrapped[methodName](function(num) {
+ return num > 2;
+ });
+
+ deepEqual(actual.value(), isFilter ? [3, 4] : [1, 2]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+
+ test('`_.' + methodName + '` should work in a lazy chain sequence', 2, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3],
+ object = { 'a': 1, 'b': 2, 'c': 3 },
+ doubled = function(value) { return value * 2; },
+ predicate = function(value) { return isFilter ? (value > 3) : (value < 3); };
+
+ var expected = [4, 6],
+ actual = _(array).map(doubled)[methodName](predicate).value();
+
+ deepEqual(actual, expected);
+
+ actual = _(object).mapValues(doubled)[methodName](predicate).value();
+ deepEqual(actual, expected);
+ }
+ else {
+ skipTest(2);
+ }
+ });
});
/*--------------------------------------------------------------------------*/
@@ -6288,7 +11102,7 @@
deepEqual(actual, [1, 2]);
});
- test('should pass the correct `callback` arguments', 1, function() {
+ test('should provide the correct `predicate` arguments', 1, function() {
var args,
array = [1, 2, 3];
@@ -6309,14 +11123,26 @@
deepEqual(actual, [1, 2]);
});
+ test('should work with a "_.pluck" style `predicate`', 1, function() {
+ var objects = [{ 'a': 0 }, { 'a': 1 }];
+ _.remove(objects, 'a');
+ deepEqual(objects, [{ 'a': 0 }]);
+ });
+
+ test('should work with a "_.where" style `predicate`', 1, function() {
+ var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }];
+ _.remove(objects, { 'a': 1 });
+ deepEqual(objects, [{ 'a': 0, 'b': 1 }]);
+ });
+
test('should preserve holes in arrays', 2, function() {
var array = [1, 2, 3, 4];
delete array[1];
delete array[3];
_.remove(array, function(num) { return num === 1; });
- equal(0 in array, false);
- equal(2 in array, false);
+ ok(!('0' in array));
+ ok(!('2' in array));
});
test('should treat holes as `undefined`', 1, function() {
@@ -6330,34 +11156,75 @@
/*--------------------------------------------------------------------------*/
+ QUnit.module('lodash.repeat');
+
+ (function() {
+ test('should repeat a string `n` times', 2, function() {
+ strictEqual(_.repeat('*', 3), '***');
+ strictEqual(_.repeat('abc', 2), 'abcabc');
+ });
+
+ test('should return an empty string for negative `n` or `n` of `0`', 2, function() {
+ strictEqual(_.repeat('abc', 0), '');
+ strictEqual(_.repeat('abc', -2), '');
+ });
+
+ test('should coerce `n` to a number', 3, function() {
+ strictEqual(_.repeat('abc'), '');
+ strictEqual(_.repeat('abc', '2'), 'abcabc');
+ strictEqual(_.repeat('*', { 'valueOf': _.constant(3) }), '***');
+ });
+
+ test('should coerce `string` to a string', 2, function() {
+ strictEqual(_.repeat(Object('abc'), 2), 'abcabc');
+ strictEqual(_.repeat({ 'toString': _.constant('*') }, 3), '***');
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
QUnit.module('lodash.result');
(function() {
- test('should resolve property values', 4, function() {
- var object = {
- 'a': 1,
- 'b': 2,
- 'c': function(){ return this.b; }
- };
+ var object = {
+ 'a': 1,
+ 'b': null,
+ 'c': function() { return this.a; }
+ };
+ test('should resolve property values', 4, function() {
strictEqual(_.result(object, 'a'), 1);
- strictEqual(_.result(object, 'b'), 2);
- strictEqual(_.result(object, 'c'), 2);
+ strictEqual(_.result(object, 'b'), null);
+ strictEqual(_.result(object, 'c'), 1);
strictEqual(_.result(object, 'd'), undefined);
});
- test('should return `undefined` when provided a falsey `object` argument', 1, function() {
- var actual = [],
- expected = _.map(falsey, function() { return undefined; });
+ test('should return `undefined` when `object` is nullish', 2, function() {
+ strictEqual(_.result(null, 'a'), undefined);
+ strictEqual(_.result(undefined, 'a'), undefined);
+ });
- _.forEach(falsey, function(value, index) {
- try {
- actual.push(index ? _.result(value) : _.result());
- } catch(e) { }
+ test('should return the specified default value for undefined properties', 1, function() {
+ var values = empties.concat(true, new Date, 1, /x/, 'a');
+
+ var expected = _.transform(values, function(result, value) {
+ result.push(value, value);
+ });
+
+ var actual = _.transform(values, function(result, value) {
+ result.push(
+ _.result(object, 'd', value),
+ _.result(null, 'd', value)
+ );
});
deepEqual(actual, expected);
});
+
+ test('should execute default function values', 1, function() {
+ var actual = _.result(object, 'd', object.c);
+ strictEqual(actual, 1);
+ });
}());
/*--------------------------------------------------------------------------*/
@@ -6367,19 +11234,13 @@
(function() {
var array = [1, 2, 3];
- var objects = [
- { 'a': 2, 'b': 2 },
- { 'a': 1, 'b': 1 },
- { 'a': 0, 'b': 0 }
- ];
-
test('should accept a falsey `array` argument', 1, function() {
- var expected = _.map(falsey, function() { return []; });
+ var expected = _.map(falsey, _.constant([]));
var actual = _.map(falsey, function(value, index) {
try {
return index ? _.rest(value) : _.rest();
- } catch(e) { }
+ } catch(e) {}
});
deepEqual(actual, expected);
@@ -6389,69 +11250,29 @@
deepEqual(_.rest(array), [2, 3]);
});
- test('should exclude the first two elements', 1, function() {
- deepEqual(_.rest(array, 2), [3]);
- });
-
- test('should return all elements when `n` < `1`', 3, function() {
- _.forEach([0, -1, -2], function(n) {
- deepEqual(_.rest(array, n), [1, 2, 3]);
- });
- });
-
- test('should return an empty array when `n` >= `array.length`', 2, function() {
- _.forEach([3, 4], function(n) {
- deepEqual(_.rest(array, n), []);
- });
- });
-
test('should return an empty when querying empty arrays', 1, function() {
deepEqual(_.rest([]), []);
});
- test('should work when used as `callback` for `_.map`', 1, function() {
+ test('should work as an iteratee for `_.map`', 1, function() {
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
actual = _.map(array, _.rest);
deepEqual(actual, [[2, 3], [5, 6], [8, 9]]);
});
- test('should work with a `callback`', 1, function() {
- var actual = _.rest(array, function(num) {
- return num < 3;
- });
-
- deepEqual(actual, [3]);
- });
-
- test('should pass the correct `callback` arguments', 1, function() {
- var args;
-
- _.rest(array, function() {
- args || (args = slice.call(arguments));
- });
-
- deepEqual(args, [1, 0, array]);
- });
-
- test('supports the `thisArg` argument', 1, function() {
- var actual = _.rest(array, function(num, index) {
- return this[index] < 3;
- }, array);
-
- deepEqual(actual, [3]);
- });
-
- test('should work with an object for `callback`', 1, function() {
- deepEqual(_.rest(objects, { 'b': 2 }), objects.slice(-2));
- });
-
- test('should work with a string for `callback`', 1, function() {
- deepEqual(_.rest(objects, 'b'), objects.slice(-1));
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(array).rest();
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [2, 3]);
+ }
+ else {
+ skipTest(2);
+ }
});
- test('should be aliased', 2, function() {
- strictEqual(_.drop, _.rest);
+ test('should be aliased', 1, function() {
strictEqual(_.tail, _.rest);
});
}());
@@ -6477,6 +11298,22 @@
skipTest();
}
});
+
+ test('should use a zeroed `_.uniqueId` counter', 3, function() {
+ if (!isModularize) {
+ var oldId = (_.uniqueId(), _.uniqueId()),
+ lodash = _.runInContext();
+
+ ok(_.uniqueId() > oldId);
+
+ var id = lodash.uniqueId();
+ strictEqual(id, '1');
+ ok(id < oldId);
+ }
+ else {
+ skipTest(3);
+ }
+ });
}());
/*--------------------------------------------------------------------------*/
@@ -6488,12 +11325,12 @@
test('should return a random element', 1, function() {
var actual = _.sample(array);
- ok(_.contains(array, actual));
+ ok(_.includes(array, actual));
});
test('should return two random elements', 1, function() {
var actual = _.sample(array, 2);
- ok(actual[0] !== actual[1] && _.contains(array, actual[0]) && _.contains(array, actual[1]));
+ ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1]));
});
test('should contain elements of the collection', 1, function() {
@@ -6501,14 +11338,26 @@
deepEqual(actual.sort(), array);
});
- test('should return an empty array when `n` < `1`', 3, function() {
- _.forEach([0, -1, -2], function(n) {
+ test('should treat falsey `n` values, except nullish, as `0`', 1, function() {
+ var expected = _.map(falsey, function(value) {
+ return value == null ? 1 : [];
+ });
+
+ var actual = _.map(falsey, function(n) {
+ return _.sample([1], n);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return an empty array when `n` < `1` or `NaN`', 3, function() {
+ _.each([0, -1, -Infinity], function(n) {
deepEqual(_.sample(array, n), []);
});
});
- test('should return all elements when `n` >= `array.length`', 2, function() {
- _.forEach([3, 4], function(n) {
+ test('should return all elements when `n` >= `array.length`', 4, function() {
+ _.each([3, 4, Math.pow(2, 32), Infinity], function(n) {
deepEqual(_.sample(array, n).sort(), array);
});
});
@@ -6517,17 +11366,16 @@
strictEqual(_.sample([]), undefined);
});
- test('should return an empty array for empty or falsey collections', 1, function() {
- var actual = [];
-
+ test('should return an empty array for empty collections', 1, function() {
var expected = _.transform(empties, function(result) {
- result.push([], []);
+ result.push(undefined, []);
});
- _.forEach(empties, function(value) {
+ var actual = [];
+ _.each(empties, function(value) {
try {
- actual.push(_.shuffle(value), _.shuffle(value, 1));
- } catch(e) { }
+ actual.push(_.sample(value), _.sample(value, 1));
+ } catch(e) {}
});
deepEqual(actual, expected);
@@ -6537,52 +11385,72 @@
var object = { 'a': 1, 'b': 2, 'c': 3 },
actual = _.sample(object);
- ok(_.contains(array, actual));
+ ok(_.includes(array, actual));
actual = _.sample(object, 2);
- ok(actual[0] !== actual[1] && _.contains(array, actual[0]) && _.contains(array, actual[1]));
+ ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1]));
});
- test('should work when used as `callback` for `_.map`', 1, function() {
- var a = [1, 2, 3],
- b = [4, 5, 6],
- c = [7, 8, 9],
- actual = _.map([a, b, c], _.sample);
+ test('should work as an iteratee for `_.map`', 2, function() {
+ _.each([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], ['abc', 'def', 'ghi']], function(values) {
+ var a = values[0],
+ b = values[1],
+ c = values[2],
+ actual = _.map(values, _.sample);
- ok(_.contains(a, actual[0]) && _.contains(b, actual[1]) && _.contains(c, actual[2]));
+ ok(_.includes(a, actual[0]) && _.includes(b, actual[1]) && _.includes(c, actual[2]));
+ });
});
- test('should chain when passing `n`', 1, function() {
+ test('should return a wrapped value when chaining and `n` is provided', 2, function() {
if (!isNpm) {
- var actual = _(array).sample(2);
- ok(actual instanceof _);
+ var wrapped = _(array).sample(2);
+ ok(wrapped instanceof _);
+
+ var actual = wrapped.value();
+ ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1]));
}
else {
- skipTest();
+ skipTest(2);
}
});
- test('should not chain when arguments are not provided', 1, function() {
+ test('should return an unwrapped value when chaining and `n` is not provided', 1, function() {
if (!isNpm) {
var actual = _(array).sample();
- ok(_.contains(array, actual));
+ ok(_.includes(array, actual));
}
else {
skipTest();
}
});
- _.forEach({
+ test('should use a stored reference to `_.sample` when chaining', 2, function() {
+ if (!isNpm) {
+ var sample = _.sample;
+ _.sample = _.noop;
+
+ var wrapped = _(array);
+ notStrictEqual(wrapped.sample(), undefined);
+ notStrictEqual(wrapped.sample(2).value(), undefined);
+ _.sample = sample;
+ }
+ else {
+ skipTest(2);
+ }
+ });
+
+ _.each({
'literal': 'abc',
'object': Object('abc')
},
function(collection, key) {
test('should work with a string ' + key + ' for `collection`', 2, function() {
var actual = _.sample(collection);
- ok(_.contains(collection, actual));
+ ok(_.includes(collection, actual));
actual = _.sample(collection, 2);
- ok(actual[0] !== actual[1] && _.contains(collection, actual[0]) && _.contains(collection, actual[1]));
+ ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(collection, actual[0]) && _.includes(collection, actual[1]));
});
});
}());
@@ -6604,12 +11472,19 @@
deepEqual(_.shuffle(object).sort(), array);
});
- test('should shuffle an object', 1, function() {
- var actual = _.shuffle(object);
- deepEqual(actual.sort(), array);
+ test('should shuffle small collections', 1, function() {
+ var actual = _.times(1000, function() {
+ return _.shuffle([1, 2]);
+ });
+
+ deepEqual(_.sortBy(_.uniq(actual, String), '0'), [[1, 2], [2, 1]]);
});
- _.forEach({
+ test('should treat number values for `collection` as empty', 1, function() {
+ deepEqual(_.shuffle(1), []);
+ });
+
+ _.each({
'literal': 'abc',
'object': Object('abc')
},
@@ -6630,45 +11505,53 @@
array = [1, 2, 3];
test('should return the number of own enumerable properties of an object', 1, function() {
- equal(_.size({ 'one': 1, 'two': 2, 'three': 3 }), 3);
+ strictEqual(_.size({ 'one': 1, 'two': 2, 'three': 3 }), 3);
});
test('should return the length of an array', 1, function() {
- equal(_.size(array), 3);
+ strictEqual(_.size(array), 3);
});
test('should accept a falsey `object` argument', 1, function() {
- var expected = _.map(falsey, function() { return 0; });
+ var expected = _.map(falsey, _.constant(0));
var actual = _.map(falsey, function(value, index) {
try {
return index ? _.size(value) : _.size();
- } catch(e) { }
+ } catch(e) {}
});
deepEqual(actual, expected);
});
+ test('should work with `arguments` objects (test in IE < 9)', 1, function() {
+ strictEqual(_.size(args), 3);
+ });
+
test('should work with jQuery/MooTools DOM query collections', 1, function() {
function Foo(elements) { push.apply(this, elements); }
- Foo.prototype = { 'length': 0, 'splice': Array.prototype.splice };
+ Foo.prototype = { 'length': 0, 'splice': arrayProto.splice };
- equal(_.size(new Foo(array)), 3);
+ strictEqual(_.size(new Foo(array)), 3);
});
- test('should work with `arguments` objects (test in IE < 9)', 1, function() {
- if (!isPhantomPage) {
- equal(_.size(args), 3);
- } else {
- skipTest();
- }
+ test('should not treat objects with negative lengths as array-like', 1, function() {
+ strictEqual(_.size({ 'length': -1 }), 1);
+ });
+
+ test('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', 1, function() {
+ strictEqual(_.size({ 'length': MAX_SAFE_INTEGER + 1 }), 1);
+ });
+
+ test('should not treat objects with non-number lengths as array-like', 1, function() {
+ strictEqual(_.size({ 'length': '0' }), 1);
});
- test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', 1, function() {
- equal(_.size(shadowedObject), 7);
+ test('fixes the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() {
+ strictEqual(_.size(shadowObject), 7);
});
- _.forEach({
+ _.each({
'literal': 'abc',
'object': Object('abc')
},
@@ -6681,38 +11564,179 @@
/*--------------------------------------------------------------------------*/
+ QUnit.module('lodash.slice');
+
+ (function() {
+ var array = [1, 2, 3];
+
+ test('should work with a positive `start`', 1, function() {
+ deepEqual(_.slice(array, 1), [2, 3]);
+ });
+
+ test('should work with a `start` >= `array.length`', 4, function() {
+ _.each([3, 4, Math.pow(2, 32), Infinity], function(start) {
+ deepEqual(_.slice(array, start), []);
+ });
+ });
+
+ test('should treat falsey `start` values as `0`', 1, function() {
+ var expected = _.map(falsey, _.constant(array));
+
+ var actual = _.map(falsey, function(start) {
+ return _.slice(array, start);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should work with a negative `start`', 1, function() {
+ deepEqual(_.slice(array, -1), [3]);
+ });
+
+ test('should work with a negative `start` <= negative `array.length`', 3, function() {
+ _.each([-3, -4, -Infinity], function(start) {
+ deepEqual(_.slice(array, start), array);
+ });
+ });
+
+ test('should work with `start` >= `end`', 2, function() {
+ _.each([2, 3], function(start) {
+ deepEqual(_.slice(array, start, 2), []);
+ });
+ });
+
+ test('should work with a positive `end`', 1, function() {
+ deepEqual(_.slice(array, 0, 1), [1]);
+ });
+
+ test('should work with a `end` >= `array.length`', 4, function() {
+ _.each([3, 4, Math.pow(2, 32), Infinity], function(end) {
+ deepEqual(_.slice(array, 0, end), array);
+ });
+ });
+
+ test('should treat falsey `end` values, except `undefined`, as `0`', 1, function() {
+ var expected = _.map(falsey, function(value) {
+ return value === undefined ? array : [];
+ });
+
+ var actual = _.map(falsey, function(end) {
+ return _.slice(array, 0, end);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should work with a negative `end`', 1, function() {
+ deepEqual(_.slice(array, 0, -1), [1, 2]);
+ });
+
+ test('should work with a negative `end` <= negative `array.length`', 3, function() {
+ _.each([-3, -4, -Infinity], function(end) {
+ deepEqual(_.slice(array, 0, end), []);
+ });
+ });
+
+ test('should coerce `start` and `end` to finite numbers', 1, function() {
+ var actual = [_.slice(array, '0', 1), _.slice(array, 0, '1'), _.slice(array, '1'), _.slice(array, NaN, 1), _.slice(array, 1, NaN)];
+ deepEqual(actual, [[1], [1], [2, 3], [1], []]);
+ });
+
+ test('should work as an iteratee for `_.map`', 2, function() {
+ var array = [[1], [2, 3]],
+ actual = _.map(array, _.slice);
+
+ deepEqual(actual, array);
+ notStrictEqual(actual, array)
+ });
+
+ test('should work in a lazy chain sequence', 12, function() {
+ if (!isNpm) {
+ var wrapped = _(array);
+
+ deepEqual(wrapped.slice(0, -1).value(), [1, 2]);
+ deepEqual(wrapped.slice(1).value(), [2, 3]);
+ deepEqual(wrapped.slice(-1).value(), [3]);
+
+ deepEqual(wrapped.slice(4).value(), []);
+ deepEqual(wrapped.slice(3, 2).value(), []);
+ deepEqual(wrapped.slice(0, -4).value(), []);
+ deepEqual(wrapped.slice(0, null).value(), []);
+
+ deepEqual(wrapped.slice(0, 4).value(), array);
+ deepEqual(wrapped.slice(-4).value(), array);
+ deepEqual(wrapped.slice(null).value(), array);
+
+ deepEqual(wrapped.slice(0, 1).value(), [1]);
+ deepEqual(wrapped.slice(NaN, '1').value(), [1]);
+ }
+ else {
+ skipTest(12);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
QUnit.module('lodash.some');
(function() {
- test('should return `false` for empty or falsey collections', 1, function() {
- var expected = _.map(empties, function() { return false; });
+ test('should return `false` for empty collections', 1, function() {
+ var expected = _.map(empties, _.constant(false));
var actual = _.map(empties, function(value) {
try {
return _.some(value, _.identity);
- } catch(e) { }
+ } catch(e) {}
});
deepEqual(actual, expected);
});
- test('should return `true` if the callback returns truey for any element in the collection', 2, function() {
+ test('should return `true` if `predicate` returns truthy for any element in the collection', 2, function() {
strictEqual(_.some([false, 1, ''], _.identity), true);
strictEqual(_.some([null, 'x', 0], _.identity), true);
});
- test('should return `false` if the callback returns falsey for all elements in the collection', 2, function() {
+ test('should return `false` if `predicate` returns falsey for all elements in the collection', 2, function() {
strictEqual(_.some([false, false, false], _.identity), false);
strictEqual(_.some([null, 0, ''], _.identity), false);
});
- test('should return `true` as soon as the `callback` result is truey', 1, function() {
+ test('should return `true` as soon as `predicate` returns truthy', 1, function() {
strictEqual(_.some([null, true, null], _.identity), true);
});
- test('should use `_.identity` when no callback is provided', 2, function() {
- strictEqual(_.some([0, 1]), true);
- strictEqual(_.some([0, 0]), false);
+ test('should work with a "_.pluck" style `predicate`', 2, function() {
+ var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }];
+ strictEqual(_.some(objects, 'a'), false);
+ strictEqual(_.some(objects, 'b'), true);
+ });
+
+ test('should work with a "_where" style `predicate`', 2, function() {
+ var objects = [{ 'a': 0, 'b': 0 }, { 'a': 1, 'b': 1}];
+ strictEqual(_.some(objects, { 'a': 0 }), true);
+ strictEqual(_.some(objects, { 'b': 2 }), false);
+ });
+
+ test('should use `_.identity` when `predicate` is nullish', 2, function() {
+ var values = [, null, undefined],
+ expected = _.map(values, _.constant(false));
+
+ var actual = _.map(values, function(value, index) {
+ var array = [0, 0];
+ return index ? _.some(array, value) : _.some(array);
+ });
+
+ deepEqual(actual, expected);
+
+ expected = _.map(values, _.constant(true));
+ actual = _.map(values, function(value, index) {
+ var array = [0, 1];
+ return index ? _.some(array, value) : _.some(array);
+ });
+
+ deepEqual(actual, expected);
});
test('should be aliased', 1, function() {
@@ -6725,6 +11749,12 @@
QUnit.module('lodash.sortBy');
(function() {
+ function Pair(a, b, c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+
var objects = [
{ 'a': 'x', 'b': 3 },
{ 'a': 'y', 'b': 4 },
@@ -6732,6 +11762,19 @@
{ 'a': 'y', 'b': 2 }
];
+ var stableOrder = [
+ new Pair(1, 1, 1), new Pair(1, 2, 1),
+ new Pair(1, 1, 1), new Pair(1, 2, 1),
+ new Pair(1, 3, 1), new Pair(1, 4, 1),
+ new Pair(1, 5, 1), new Pair(1, 6, 1),
+ new Pair(2, 1, 2), new Pair(2, 2, 2),
+ new Pair(2, 3, 2), new Pair(2, 4, 2),
+ new Pair(2, 5, 2), new Pair(2, 6, 2),
+ new Pair(undefined, 1, 1), new Pair(undefined, 2, 1),
+ new Pair(undefined, 3, 1), new Pair(undefined, 4, 1),
+ new Pair(undefined, 5, 1), new Pair(undefined, 6, 1)
+ ];
+
test('should sort in ascending order', 1, function() {
var actual = _.pluck(_.sortBy(objects, function(object) {
return object.b;
@@ -6741,41 +11784,31 @@
});
test('should perform a stable sort (test in IE > 8, Opera, and V8)', 1, function() {
- function Pair(x, y) {
- this.x = x;
- this.y = y;
- }
-
- var collection = [
- new Pair(1, 1), new Pair(1, 2),
- new Pair(1, 3), new Pair(1, 4),
- new Pair(1, 5), new Pair(1, 6),
- new Pair(2, 1), new Pair(2, 2),
- new Pair(2, 3), new Pair(2, 4),
- new Pair(2, 5), new Pair(2, 6),
- new Pair(undefined, 1), new Pair(undefined, 2),
- new Pair(undefined, 3), new Pair(undefined, 4),
- new Pair(undefined, 5), new Pair(undefined, 6)
- ];
-
- var actual = _.sortBy(collection, function(pair) {
- return pair.x;
+ var actual = _.sortBy(stableOrder, function(pair) {
+ return pair.a;
});
- deepEqual(actual, collection);
+ deepEqual(actual, stableOrder);
});
- test('should work with `undefined` values', 1, function() {
- var array = [undefined, 4, 1, undefined, 3, 2];
- deepEqual(_.sortBy(array, _.identity), [1, 2, 3, 4, undefined, undefined]);
+ test('should use `_.identity` when `iteratee` is nullish', 1, function() {
+ var array = [3, 2, 1],
+ values = [, null, undefined],
+ expected = _.map(values, _.constant([1, 2, 3]));
+
+ var actual = _.map(values, function(value, index) {
+ return index ? _.sortBy(array, value) : _.sortBy(array);
+ });
+
+ deepEqual(actual, expected);
});
- test('should use `_.identity` when no `callback` is provided', 1, function() {
- var actual = _.sortBy([3, 2, 1]);
- deepEqual(actual, [1, 2, 3]);
+ test('should move `undefined` and `NaN` values to the end', 1, function() {
+ var array = [NaN, undefined, 4, 1, undefined, 3, NaN, 2];
+ deepEqual(_.sortBy(array), [1, 2, 3, 4, undefined, undefined, NaN, NaN]);
});
- test('should pass the correct `callback` arguments', 1, function() {
+ test('should provide the correct `iteratee` arguments', 1, function() {
var args;
_.sortBy(objects, function() {
@@ -6793,12 +11826,24 @@
deepEqual(actual, [3, 1, 2]);
});
- test('should work with an array for `callback`', 1, function() {
- var actual = _.sortBy(objects, ['a', 'b']);
- deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]);
+ test('should work with a "_.pluck" style `iteratee`', 1, function() {
+ var actual = _.pluck(_.sortBy(objects.concat(undefined), 'b'), 'b');
+ deepEqual(actual, [1, 2, 3, 4, undefined]);
+ });
+
+ test('should work with an object for `collection`', 1, function() {
+ var actual = _.sortBy({ 'a': 1, 'b': 2, 'c': 3 }, function(num) {
+ return Math.sin(num);
+ });
+
+ deepEqual(actual, [3, 1, 2]);
+ });
+
+ test('should treat number values for `collection` as empty', 1, function() {
+ deepEqual(_.sortBy(1), []);
});
- test('should coerce arrays returned from a `callback`', 1, function() {
+ test('should coerce arrays returned from `iteratee`', 1, function() {
var actual = _.sortBy(objects, function(object) {
var result = [object.a, object.b];
result.toString = function() { return String(this[0]); };
@@ -6808,72 +11853,188 @@
deepEqual(actual, [objects[0], objects[2], objects[1], objects[3]]);
});
- test('should work with a string for `callback`', 1, function() {
- var actual = _.pluck(_.sortBy(objects, 'b'), 'b');
- deepEqual(actual, [1, 2, 3, 4]);
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var actual = _.map([[2, 1, 3], [3, 2, 1]], _.sortBy);
+ deepEqual(actual, [[1, 2, 3], [1, 2, 3]]);
});
+ }());
- test('should work with an object for `collection`', 1, function() {
- var actual = _.sortBy({ 'a': 1, 'b': 2, 'c': 3 }, function(num) {
- return Math.sin(num);
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.sortByAll');
+
+ (function() {
+ function Pair(a, b, c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+
+ var objects = [
+ { 'a': 'x', 'b': 3 },
+ { 'a': 'y', 'b': 4 },
+ { 'a': 'x', 'b': 1 },
+ { 'a': 'y', 'b': 2 }
+ ];
+
+ var stableOrder = [
+ new Pair(1, 1, 1), new Pair(1, 2, 1),
+ new Pair(1, 1, 1), new Pair(1, 2, 1),
+ new Pair(1, 3, 1), new Pair(1, 4, 1),
+ new Pair(1, 5, 1), new Pair(1, 6, 1),
+ new Pair(2, 1, 2), new Pair(2, 2, 2),
+ new Pair(2, 3, 2), new Pair(2, 4, 2),
+ new Pair(2, 5, 2), new Pair(2, 6, 2),
+ new Pair(undefined, 1, 1), new Pair(undefined, 2, 1),
+ new Pair(undefined, 3, 1), new Pair(undefined, 4, 1),
+ new Pair(undefined, 5, 1), new Pair(undefined, 6, 1)
+ ];
+
+ test('should sort mutliple properties in ascending order', 1, function() {
+ var actual = _.sortByAll(objects, ['a', 'b']);
+ deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]);
+ });
+
+ test('should perform a stable sort (test in IE > 8, Opera, and V8)', 1, function() {
+ var actual = _.sortByAll(stableOrder, ['a', 'c']);
+ deepEqual(actual, stableOrder);
+ });
+
+ test('should not error on nullish elements', 1, function() {
+ try {
+ var actual = _.sortByAll(objects.concat(undefined), ['a', 'b']);
+ } catch(e) {}
+
+ deepEqual(actual, [objects[2], objects[0], objects[3], objects[1], undefined]);
+ });
+
+ test('should work as an iteratee for `_.reduce`', 1, function() {
+ var objects = [
+ { 'a': 'x', '0': 3 },
+ { 'a': 'y', '0': 4 },
+ { 'a': 'x', '0': 1 },
+ { 'a': 'y', '0': 2 }
+ ];
+
+ var funcs = [_.sortByAll, _.partialRight(_.sortByAll, 'bogus')],
+ expected = _.map(funcs, _.constant([objects[0], objects[2], objects[1], objects[3]]));
+
+ var actual = _.map(funcs, function(func) {
+ return _.reduce([['a']], func, objects);
});
- deepEqual(actual, [3, 1, 2]);
+ deepEqual(actual, expected);
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.sortedIndex');
+ QUnit.module('sortedIndex methods');
- (function() {
- var array = [20, 30, 50],
- objects = [{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }];
+ _.each(['sortedIndex', 'sortedLastIndex'], function(methodName, index) {
+ var array = [30, 50],
+ func = _[methodName],
+ isSortedIndex = !index,
+ objects = [{ 'x': 30 }, { 'x': 50 }];
+
+ test('`_.' + methodName + '` should return the correct insert index', 1, function() {
+ var array = [30, 50],
+ values = [30, 40, 50],
+ expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2];
+
+ var actual = _.map(values, function(value) {
+ return func(array, value);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('`_.' + methodName + '` should work with an array of strings', 1, function() {
+ var array = ['a', 'c'],
+ values = ['a', 'b', 'c'],
+ expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2];
- test('should return the insert index of a given value', 2, function() {
- equal(_.sortedIndex(array, 40), 2);
- equal(_.sortedIndex(array, 30), 1);
+ var actual = _.map(values, function(value) {
+ return func(array, value);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('`_.' + methodName + '` should accept a falsey `array` argument and a `value`', 1, function() {
+ var expected = _.map(falsey, _.constant([0, 0, 0]));
+
+ var actual = _.map(falsey, function(array) {
+ return [func(array, 1), func(array, undefined), func(array, NaN)];
+ });
+
+ deepEqual(actual, expected);
});
- test('should pass the correct `callback` arguments', 1, function() {
+ test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() {
var args;
- _.sortedIndex(array, 40, function() {
+ func(array, 40, function() {
args || (args = slice.call(arguments));
});
deepEqual(args, [40]);
});
- test('should support the `thisArg` argument', 1, function() {
- var actual = _.sortedIndex(array, 40, function(num) {
+ test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() {
+ var actual = func(array, 40, function(num) {
return this[num];
- }, { '20': 20, '30': 30, '40': 40 });
+ }, { '30': 30, '40': 40, '50': 50 });
- strictEqual(actual, 2);
+ strictEqual(actual, 1);
});
- test('should work with a string for `callback`', 1, function() {
- var actual = _.sortedIndex(objects, { 'x': 40 }, 'x');
- equal(actual, 2);
+ test('`_.' + methodName + '` should work with a "_.pluck" style `iteratee`', 1, function() {
+ var actual = func(objects, { 'x': 40 }, 'x');
+ strictEqual(actual, 1);
});
- test('supports arrays with lengths larger than `Math.pow(2, 31) - 1`', 1, function() {
- var length = Math.pow(2, 32) - 1,
- index = length - 1,
- array = Array(length),
- steps = 0;
+ test('`_.' + methodName + '` should align with `_.sortBy`', 8, function() {
+ var expected = [1, '2', {}, undefined, NaN, NaN];
- if (array.length == length) {
- array[index] = index;
- _.sortedIndex(array, index, function() { steps++; });
- equal(steps, 33);
- }
- else {
- skipTest();
- }
+ _.each([
+ [NaN, 1, '2', {}, NaN, undefined],
+ ['2', 1, NaN, {}, NaN, undefined]
+ ], function(array) {
+ deepEqual(_.sortBy(array), expected);
+ strictEqual(func(expected, 3), 2);
+ strictEqual(func(expected, undefined), isSortedIndex ? 3 : 4);
+ strictEqual(func(expected, NaN), isSortedIndex ? 4 : 6);
+ });
});
- }());
+
+ test('`_.' + methodName + '` should support arrays larger than `MAX_ARRAY_LENGTH / 2`', 12, function() {
+ _.each([Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH], function(length) {
+ var array = [],
+ values = [MAX_ARRAY_LENGTH, NaN, undefined];
+
+ array.length = length;
+
+ _.each(values, function(value) {
+ var steps = 0,
+ actual = func(array, value, function(value) { steps++; return value; });
+
+ var expected = (isSortedIndex ? !_.isNaN(value) : _.isFinite(value))
+ ? 0
+ : Math.min(length, MAX_ARRAY_INDEX)
+
+ // Avoid false fails in older Firefox.
+ if (array.length == length) {
+ ok(steps == 32 || steps == 33);
+ strictEqual(actual, expected);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+ });
+ });
+ });
/*--------------------------------------------------------------------------*/
@@ -6881,29 +12042,111 @@
(function() {
test('should contain properties with boolean values', 1, function() {
- ok(_.every(_.values(_.support), _.isBoolean));
+ ok(_.every(_.values(_.support), function(value) {
+ return value === true || value === false;
+ }));
});
test('should not contain minified properties (test production builds)', 1, function() {
var props = [
- 'argsClass',
+ 'argsTag',
'argsObject',
+ 'dom',
'enumErrorProps',
'enumPrototypes',
'fastBind',
'funcDecomp',
'funcNames',
- 'nodeClass',
+ 'hostObject',
+ 'nodeTag',
'nonEnumArgs',
'nonEnumShadows',
+ 'nonEnumStrings',
'ownLast',
'spliceObjects',
'unindexedChars'
];
- ok(!_.size(_.difference(_.keys(_.support), props)));
+ ok(_.isEmpty(_.difference(_.keys(_.support), props)));
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.startsWith');
+
+ (function() {
+ var string = 'abc';
+
+ test('should return `true` if a string starts with `target`', 1, function() {
+ strictEqual(_.startsWith(string, 'a'), true);
+ });
+
+ test('should return `false` if a string does not start with `target`', 1, function() {
+ strictEqual(_.startsWith(string, 'b'), false);
+ });
+
+ test('should work with a `position` argument', 1, function() {
+ strictEqual(_.startsWith(string, 'b', 1), true);
+ });
+
+ test('should work with `position` >= `string.length`', 4, function() {
+ _.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) {
+ strictEqual(_.startsWith(string, 'a', position), false);
+ });
+ });
+
+ test('should treat falsey `position` values as `0`', 1, function() {
+ var expected = _.map(falsey, _.constant(true));
+
+ var actual = _.map(falsey, function(position) {
+ return _.startsWith(string, 'a', position);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should treat a negative `position` as `0`', 6, function() {
+ _.each([-1, -3, -Infinity], function(position) {
+ strictEqual(_.startsWith(string, 'a', position), true);
+ strictEqual(_.startsWith(string, 'b', position), false);
+ });
+ });
+
+ test('should return `true` when `target` is an empty string regardless of `position`', 1, function() {
+ ok(_.every([-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity], function(position) {
+ return _.startsWith(string, '', position, true);
+ }));
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.startsWith and lodash.endsWith');
+
+ _.each(['startsWith', 'endsWith'], function(methodName, index) {
+ var func = _[methodName],
+ isStartsWith = !index;
+
+ var string = 'abc',
+ chr = isStartsWith ? 'a' : 'c';
+
+ test('`_.' + methodName + '` should coerce `string` to a string', 2, function() {
+ strictEqual(func(Object(string), chr), true);
+ strictEqual(func({ 'toString': _.constant(string) }, chr), true);
});
- }());
+
+ test('`_.' + methodName + '` should coerce `target` to a string', 2, function() {
+ strictEqual(func(string, Object(chr)), true);
+ strictEqual(func(string, { 'toString': _.constant(chr) }), true);
+ });
+
+ test('`_.' + methodName + '` should coerce `position` to a number', 2, function() {
+ var position = isStartsWith ? 1 : 2;
+ strictEqual(func(string, 'b', Object(position)), true);
+ strictEqual(func(string, 'b', { 'toString': _.constant(String(position)) }), true);
+ });
+ });
/*--------------------------------------------------------------------------*/
@@ -6912,73 +12155,72 @@
(function() {
test('should intercept and return the given value', 2, function() {
if (!isNpm) {
- var intercepted;
+ var intercepted,
+ array = [1, 2, 3];
- var actual = _.tap('a', function(value) {
+ var actual = _.tap(array, function(value) {
intercepted = value;
});
- equal(actual, 'a');
- equal(intercepted, 'a');
+ strictEqual(actual, array);
+ strictEqual(intercepted, array);
}
else {
skipTest(2);
}
});
- test('should return intercept unwrapped values and return wrapped values when chaining', 2, function() {
+ test('should intercept unwrapped values and return wrapped values when chaining', 2, function() {
if (!isNpm) {
var intercepted,
- array = [1, 2, 3, 4];
+ array = [1, 2, 3];
- var actual = _(array).tap(function(value) {
+ var wrapped = _(array).tap(function(value) {
intercepted = value;
value.pop();
});
- ok(actual instanceof _);
+ ok(wrapped instanceof _);
+
+ wrapped.value();
strictEqual(intercepted, array);
}
else {
skipTest(2);
}
});
- }());
-
- /*--------------------------------------------------------------------------*/
- QUnit.module('lodash.template');
+ test('should support the `thisArg` argument', 1, function() {
+ if (!isNpm) {
+ var array = [1, 2];
- (function() {
- test('should use a `with` statement by default', 1, function() {
- var compiled = _.template('<%= index %><%= collection[index] %><% _.each(collection, function(value, index) { %><%= index %><% }); %>'),
- actual = compiled({ 'index': 1, 'collection': ['a', 'b', 'c'] });
+ var wrapped = _(array.slice()).tap(function(value) {
+ value.push(this[0]);
+ }, array);
- equal(actual, '1b012');
+ deepEqual(wrapped.value(), [1, 2, 1]);
+ }
+ else {
+ skipTest();
+ }
});
+ }());
- test('should interpolate data object properties', 1, function() {
- var compiled = _.template('<%= a %>BC');
- equal(compiled({ 'a': 'A' }), 'ABC');
- });
+ /*--------------------------------------------------------------------------*/
- test('should work correctly with `this` references', 2, function() {
- var compiled = _.template('a<%= this.String("b") %>c');
- equal(compiled(), 'abc');
+ QUnit.module('lodash.template');
- var object = { 'b': 'B' };
- object.compiled = _.template('A<%= this.b %>C', null, { 'variable': 'obj' });
- equal(object.compiled(), 'ABC');
- });
+ (function() {
+ test('should escape values in "escape" delimiters', 1, function() {
+ var strings = ['<p><%- value %></p>', '<p><%-value%></p>', '<p><%-\nvalue\n%></p>'],
+ expected = _.map(strings, _.constant('<p>&<>"'`\/</p>')),
+ data = { 'value': '&<>"\'`\/' };
- test('should work with backslashes', 1, function() {
- var compiled = _.template('<%= a %> \\b');
- equal(compiled({ 'a': 'A' }), 'A \\b');
- });
+ var actual = _.map(strings, function(string) {
+ return _.template(string)(data);
+ });
- test('should support escaped values in "interpolation" delimiters', 1, function() {
- var compiled = _.template('<%= a ? "a=\\"A\\"" : "" %>');
- equal(compiled({ 'a': true }), 'a="A"');
+ deepEqual(actual, expected);
});
test('should evaluate JavaScript in "evaluate" delimiters', 1, function() {
@@ -6989,116 +12231,50 @@
} %></ul>'
);
- var actual = compiled({ 'collection': { 'a': 'A', 'b': 'B' } });
- equal(actual, '<ul><li>A</li><li>B</li></ul>');
- });
-
- test('should work with escaped characters in string literals', 2, function() {
- var compiled = _.template('<% print("\'\\n\\r\\t\\u2028\\u2029\\\\") %>');
- equal(compiled(), "'\n\r\t\u2028\u2029\\");
-
- compiled = _.template('\'\n\r\t<%= a %>\u2028\u2029\\"');
- equal(compiled({ 'a': 'A' }), '\'\n\r\tA\u2028\u2029\\"');
- });
-
- test('should work with no delimiters', 1, function() {
- var expected = 'abc';
- equal(_.template(expected, {}), expected);
- });
-
- test('should work with statements containing quotes', 1, function() {
- var compiled = _.template("<%\
- if (a == 'A' || a == \"a\") {\
- %>'a',\"A\"<%\
- } %>"
- );
-
- equal(compiled({ 'a': 'A' }), "'a',\"A\"");
- });
-
- test('should escape values in "escape" delimiters', 1, function() {
- var escaped = '<p>&<>"'\/</p>',
- unescaped = '&<>"\'\/';
-
- var compiled = _.template('<p><%- value %></p>');
- equal(compiled({ 'value': unescaped }), escaped);
- });
-
- test('should work with templates containing newlines and comments', 1, function() {
- var compiled = _.template('<%\n\
- // comment\n\
- if (value) { value += 3; }\n\
- %><p><%= value %></p>'
- );
-
- equal(compiled({ 'value': 3 }), '<p>6</p>');
- });
-
- test('should work with custom `_.templateSettings` delimiters', 1, function() {
- var settings = _.clone(_.templateSettings);
-
- _.assign(_.templateSettings, {
- 'escape': /\{\{-([\s\S]+?)\}\}/g,
- 'evaluate': /\{\{([\s\S]+?)\}\}/g,
- 'interpolate': /\{\{=([\s\S]+?)\}\}/g
- });
-
- var compiled = _.template('<ul>{{ _.each(collection, function(value, index) { }}<li>{{= index }}: {{- value }}</li>{{ }); }}</ul>'),
- expected = '<ul><li>0: a & A</li><li>1: b & B</li></ul>';
+ var data = { 'collection': { 'a': 'A', 'b': 'B' } },
+ actual = compiled(data);
- equal(compiled({ 'collection': ['a & A', 'b & B'] }), expected);
- _.assign(_.templateSettings, settings);
+ strictEqual(actual, '<ul><li>A</li><li>B</li></ul>');
});
- test('should work with `_.templateSettings` delimiters containing special characters', 1, function() {
- var settings = _.clone(_.templateSettings);
+ test('should interpolate data object properties', 1, function() {
+ var strings = ['<%= a %>BC', '<%=a%>BC', '<%=\na\n%>BC'],
+ expected = _.map(strings, _.constant('ABC')),
+ data = { 'a': 'A' };
- _.assign(_.templateSettings, {
- 'escape': /<\?-([\s\S]+?)\?>/g,
- 'evaluate': /<\?([\s\S]+?)\?>/g,
- 'interpolate': /<\?=([\s\S]+?)\?>/g
+ var actual = _.map(strings, function(string) {
+ return _.template(string)(data);
});
- var compiled = _.template('<ul><? _.each(collection, function(value, index) { ?><li><?= index ?>: <?- value ?></li><? }); ?></ul>'),
- expected = '<ul><li>0: a & A</li><li>1: b & B</li></ul>';
-
- equal(compiled({ 'collection': ['a & A', 'b & B'] }), expected);
- _.assign(_.templateSettings, settings);
+ deepEqual(actual, expected);
});
- test('supports recursive calls', 1, function() {
- var compiled = _.template('<%= a %><% a = _.template(c, obj) %><%= a %>'),
- data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' };
+ test('should support escaped values in "interpolation" delimiters', 1, function() {
+ var compiled = _.template('<%= a ? "a=\\"A\\"" : "" %>'),
+ data = { 'a': true };
- equal(compiled(data), 'AB');
+ strictEqual(compiled(data), 'a="A"');
});
- test('should not modify `_.templateSettings` when `options` are provided', 2, function() {
- equal('a' in _.templateSettings, false);
-
- _.template('', {}, { 'a': 1 });
- equal('a' in _.templateSettings, false);
+ test('should work with "interpolate" delimiters containing ternary operators', 1, function() {
+ var compiled = _.template('<%= value ? value : "b" %>'),
+ data = { 'value': 'a' };
- delete _.templateSettings.a;
+ strictEqual(compiled(data), 'a');
});
- test('should not augment the `options` object', 1, function() {
- var options = {};
- _.template('', {}, options);
- deepEqual(options, {});
- });
+ test('should work with "interpolate" delimiters containing global values', 1, function() {
+ var compiled = _.template('<%= typeof Math.abs %>');
- test('should provide the template source when a SyntaxError occurs', 1, function() {
try {
- _.template('<% if x %>');
- } catch(e) {
- var source = e.source;
- }
- ok(/__p/.test(source));
+ var actual = compiled();
+ } catch(e) {}
+
+ strictEqual(actual, 'function');
});
test('should work with complex "interpolate" delimiters', 22, function() {
- _.forEach({
+ _.each({
'<%= a + b %>': '3',
'<%= b - a %>': '1',
'<%= a = b %>': '2',
@@ -7112,7 +12288,7 @@
'<%= a & b %>': '0',
'<%= a ^ b %>': '3',
'<%= a | b %>': '3',
- '<%= {}.toString.call(0) %>': '[object Number]',
+ '<%= {}.toString.call(0) %>': numberTag,
'<%= a.toFixed(2) %>': '1.00',
'<%= obj["a"] %>': '1',
'<%= delete a %>': 'true',
@@ -7126,10 +12302,21 @@
var compiled = _.template(key),
data = { 'a': 1, 'b': 2 };
- equal(compiled(data), value, key);
+ strictEqual(compiled(data), value, key);
});
});
+ test('should parse ES6 template delimiters', 2, function() {
+ var data = { 'value': 2 };
+ strictEqual(_.template('1${value}3')(data), '123');
+ strictEqual(_.template('${"{" + value + "\\}"}')(data), '{2}');
+ });
+
+ test('should not reference `_.escape` when "escape" delimiters are not used', 1, function() {
+ var compiled = _.template('<%= typeof __e %>');
+ strictEqual(compiled({}), 'undefined');
+ });
+
test('should allow referencing variables declared in "evaluate" delimiters from other delimiters', 1, function() {
var compiled = _.template('<% var b = a; %><%= b.value %>'),
data = { 'a': { 'value': 1 } };
@@ -7137,21 +12324,142 @@
strictEqual(compiled(data), '1');
});
- test('should work when passing `options.variable`', 1, function() {
+ test('should support single line comments in "evaluate" delimiters (test production builds)', 1, function() {
+ var compiled = _.template('<% // A code comment. %><% if (value) { %>yap<% } else { %>nope<% } %>'),
+ data = { 'value': true };
+
+ strictEqual(compiled(data), 'yap');
+ });
+
+ test('should work with custom delimiters', 2, function() {
+ _.times(2, function(index) {
+ var settingsClone = _.clone(_.templateSettings);
+
+ var settings = _.assign(index ? _.templateSettings : {}, {
+ 'escape': /\{\{-([\s\S]+?)\}\}/g,
+ 'evaluate': /\{\{([\s\S]+?)\}\}/g,
+ 'interpolate': /\{\{=([\s\S]+?)\}\}/g
+ });
+
+ var compiled = _.template('<ul>{{ _.each(collection, function(value, index) {}}<li>{{= index }}: {{- value }}</li>{{}); }}</ul>', index ? null : settings),
+ expected = '<ul><li>0: a & A</li><li>1: b & B</li></ul>',
+ data = { 'collection': ['a & A', 'b & B'] };
+
+ strictEqual(compiled(data), expected);
+ _.assign(_.templateSettings, settingsClone);
+ });
+ });
+
+ test('should work with custom delimiters containing special characters', 2, function() {
+ _.times(2, function(index) {
+ var settingsClone = _.clone(_.templateSettings);
+
+ var settings = _.assign(index ? _.templateSettings : {}, {
+ 'escape': /<\?-([\s\S]+?)\?>/g,
+ 'evaluate': /<\?([\s\S]+?)\?>/g,
+ 'interpolate': /<\?=([\s\S]+?)\?>/g
+ });
+
+ var compiled = _.template('<ul><? _.each(collection, function(value, index) { ?><li><?= index ?>: <?- value ?></li><? }); ?></ul>', index ? null : settings),
+ expected = '<ul><li>0: a & A</li><li>1: b & B</li></ul>',
+ data = { 'collection': ['a & A', 'b & B'] };
+
+ strictEqual(compiled(data), expected);
+ _.assign(_.templateSettings, settingsClone);
+ });
+ });
+
+ test('should work with strings without delimiters', 1, function() {
+ var expected = 'abc';
+ strictEqual(_.template(expected)({}), expected);
+ });
+
+ test('should support the "imports" option', 1, function() {
+ var compiled = _.template('<%= a %>', { 'imports': { 'a': 1 } });
+ strictEqual(compiled({}), '1');
+ });
+
+ test('should support the "variable" options', 1, function() {
var compiled = _.template(
- '<% _.forEach( data.a, function( value ) { %>' +
+ '<% _.each( data.a, function( value ) { %>' +
'<%= value.valueOf() %>' +
- '<% }) %>', null, { 'variable': 'data' }
+ '<% }) %>', { 'variable': 'data' }
);
+ var data = { 'a': [1, 2, 3] };
+
try {
- var data = { 'a': [1, 2, 3] };
strictEqual(compiled(data), '123');
} catch(e) {
- ok(false);
+ ok(false, e.message);
}
});
+ test('should support the legacy `options` param signature', 1, function() {
+ var compiled = _.template('<%= data.a %>', null, { 'variable': 'data' }),
+ data = { 'a': 1 };
+
+ strictEqual(compiled(data), '1');
+ });
+
+ test('should use a `with` statement by default', 1, function() {
+ var compiled = _.template('<%= index %><%= collection[index] %><% _.each(collection, function(value, index) { %><%= index %><% }); %>'),
+ actual = compiled({ 'index': 1, 'collection': ['a', 'b', 'c'] });
+
+ strictEqual(actual, '1b012');
+ });
+
+ test('should work correctly with `this` references', 2, function() {
+ var compiled = _.template('a<%= this.String("b") %>c');
+ strictEqual(compiled(), 'abc');
+
+ var object = { 'b': 'B' };
+ object.compiled = _.template('A<%= this.b %>C', { 'variable': 'obj' });
+ strictEqual(object.compiled(), 'ABC');
+ });
+
+ test('should work with backslashes', 1, function() {
+ var compiled = _.template('<%= a %> \\b'),
+ data = { 'a': 'A' };
+
+ strictEqual(compiled(data), 'A \\b');
+ });
+
+ test('should work with escaped characters in string literals', 2, function() {
+ var compiled = _.template('<% print("\'\\n\\r\\t\\u2028\\u2029\\\\") %>');
+ strictEqual(compiled(), "'\n\r\t\u2028\u2029\\");
+
+ var data = { 'a': 'A' };
+ compiled = _.template('\'\n\r\t<%= a %>\u2028\u2029\\"')
+ strictEqual(compiled(data), '\'\n\r\tA\u2028\u2029\\"');
+ });
+
+ test('should handle \\u2028 & \\u2029 characters', 1, function() {
+ var compiled = _.template('\u2028<%= "\\u2028\\u2029" %>\u2029');
+ strictEqual(compiled(), '\u2028\u2028\u2029\u2029');
+ });
+
+ test('should work with statements containing quotes', 1, function() {
+ var compiled = _.template("<%\
+ if (a == 'A' || a == \"a\") {\
+ %>'a',\"A\"<%\
+ } %>"
+ );
+
+ var data = { 'a': 'A' };
+ strictEqual(compiled(data), "'a',\"A\"");
+ });
+
+ test('should work with templates containing newlines and comments', 1, function() {
+ var compiled = _.template('<%\n\
+ // A code comment.\n\
+ if (value) { value += 3; }\n\
+ %><p><%= value %></p>'
+ );
+
+ strictEqual(compiled({ 'value': 3 }), '<p>6</p>');
+ });
+
test('should not error with IE conditional comments enabled (test with development build)', 1, function() {
var compiled = _.template(''),
pass = true;
@@ -7162,112 +12470,213 @@
} catch(e) {
pass = false;
}
- ok(pass);
+ ok(pass);
+ });
+
+ test('should tokenize delimiters', 1, function() {
+ var compiled = _.template('<span class="icon-<%= type %>2"></span>'),
+ data = { 'type': 1 };
+
+ strictEqual(compiled(data), '<span class="icon-12"></span>');
+ });
+
+ test('should evaluate delimiters once', 1, function() {
+ var actual = [],
+ compiled = _.template('<%= func("a") %><%- func("b") %><% func("c") %>'),
+ data = { 'func': function(value) { actual.push(value); } };
+
+ compiled(data);
+ deepEqual(actual, ['a', 'b', 'c']);
+ });
+
+ test('should match delimiters before escaping text', 1, function() {
+ var compiled = _.template('<<\n a \n>>', { 'evaluate': /<<(.*?)>>/g });
+ strictEqual(compiled(), '<<\n a \n>>');
+ });
+
+ test('should resolve `null` and `undefined` values to an empty string', 3, function() {
+ var compiled = _.template('<%= a %><%- a %>'),
+ data = { 'a': null };
+
+ strictEqual(compiled(data), '');
+
+ data = { 'a': undefined };
+ strictEqual(compiled(data), '');
+
+ data = { 'a': {} };
+ compiled = _.template('<%= a.b %><%- a.b %>');
+ strictEqual(compiled(data), '');
+ });
+
+ test('should parse delimiters without newlines', 1, function() {
+ var expected = '<<\nprint("<p>" + (value ? "yes" : "no") + "</p>")\n>>',
+ compiled = _.template(expected, { 'evaluate': /<<(.+?)>>/g }),
+ data = { 'value': true };
+
+ strictEqual(compiled(data), expected);
+ });
+
+ test('should support recursive calls', 1, function() {
+ var compiled = _.template('<%= a %><% a = _.template(c)(obj) %><%= a %>'),
+ data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' };
+
+ strictEqual(compiled(data), 'AB');
+ });
+
+ test('should coerce `text` argument to a string', 1, function() {
+ var object = { 'toString': function() { return '<%= a %>'; } },
+ data = { 'a': 1 };
+
+ strictEqual(_.template(object)(data), '1');
+ });
+
+ test('should not augment the `options` object', 1, function() {
+ var options = {};
+ _.template('', options);
+ deepEqual(options, {});
+ });
+
+ test('should not modify `_.templateSettings` when `options` are provided', 2, function() {
+ var data = { 'a': 1 };
+
+ ok(!('a' in _.templateSettings));
+ _.template('', {}, data);
+ ok(!('a' in _.templateSettings));
+
+ delete _.templateSettings.a;
+ });
+
+ test('should not error for non-object `data` and `options` values', 2, function() {
+ var pass = true;
+
+ try {
+ _.template('')(1);
+ } catch(e) {
+ pass = false;
+ }
+ ok(pass);
+
+ pass = true;
+
+ try {
+ _.template('', 1)(1);
+ } catch(e) {
+ pass = false;
+ }
+ ok(pass);
+ });
+
+ test('should expose the source for compiled templates', 1, function() {
+ var compiled = _.template('x'),
+ values = [String(compiled), compiled.source],
+ expected = _.map(values, _.constant(true));
+
+ var actual = _.map(values, function(value) {
+ return _.includes(value, '__p');
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should expose the source when a SyntaxError occurs', 1, function() {
+ try {
+ _.template('<% if x %>');
+ } catch(e) {
+ var source = e.source;
+ }
+ ok(_.includes(source, '__p'));
});
- test('should tokenize delimiters', 1, function() {
- var compiled = _.template('<span class="icon-<%= type %>2"></span>'),
- data = { 'type': 1 };
+ test('should not include sourceURLs in the source', 1, function() {
+ var options = { 'sourceURL': '/a/b/c' },
+ compiled = _.template('x', options),
+ values = [compiled.source, undefined];
- equal(compiled(data), '<span class="icon-12"></span>');
- });
+ try {
+ _.template('<% if x %>', options);
+ } catch(e) {
+ values[1] = e.source;
+ }
+ var expected = _.map(values, _.constant(false));
- test('should work with "interpolate" delimiters containing ternary operators', 1, function() {
- var compiled = _.template('<%= value ? value : "b" %>'),
- data = { 'value': 'a' };
+ var actual = _.map(values, function(value) {
+ return _.includes(value, 'sourceURL');
+ });
- equal(compiled(data), 'a');
+ deepEqual(actual, expected);
});
- test('should work with "interpolate" delimiters containing global values', 1, function() {
- var compiled = _.template('<%= typeof Math.abs %>');
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var array = ['<%= a %>', '<%- b %>', '<% print(c) %>'],
+ compiles = _.map(array, _.template),
+ data = { 'a': 'one', 'b': '`two`', 'c': 'three' };
- try {
- var actual = compiled();
- } catch(e) { }
+ var actual = _.map(compiles, function(compiled) {
+ return compiled(data);
+ });
- equal(actual, 'function');
+ deepEqual(actual, ['one', '`two`', 'three']);
});
+ }());
- test('should evaluate delimiters once', 1, function() {
- var actual = [],
- compiled = _.template('<%= func("a") %><%- func("b") %><% func("c") %>');
+ /*--------------------------------------------------------------------------*/
- compiled({ 'func': function(value) { actual.push(value); } });
- deepEqual(actual, ['a', 'b', 'c']);
- });
+ QUnit.module('lodash.trunc');
- test('should parse delimiters with newlines', 1, function() {
- var expected = '<<\nprint("<p>" + (value ? "yes" : "no") + "</p>")\n>>',
- compiled = _.template(expected, null, { 'evaluate': /<<(.+?)>>/g }),
- data = { 'value': true };
+ (function() {
+ var string = 'hi-diddly-ho there, neighborino';
- equal(compiled(data), expected);
+ test('should truncate to a length of `30` by default', 1, function() {
+ strictEqual(_.trunc(string), 'hi-diddly-ho there, neighbo...');
});
- test('should parse ES6 template delimiters', 2, function() {
- var data = { 'value': 2 };
- strictEqual(_.template('1${value}3', data), '123');
- equal(_.template('${"{" + value + "\\}"}', data), '{2}');
+ test('should not truncate if `string` is <= `length`', 2, function() {
+ strictEqual(_.trunc(string, string.length), string);
+ strictEqual(_.trunc(string, string.length + 2), string);
});
- test('supports the "imports" option', 1, function() {
- var options = { 'imports': { 'a': 1 } },
- compiled = _.template('<%= a %>', null, options);
-
- strictEqual(compiled({}), '1');
+ test('should truncate string the given length', 1, function() {
+ strictEqual(_.trunc(string, 24), 'hi-diddly-ho there, n...');
});
- test('should coerce `text` argument to a string', 1, function() {
- var data = { 'a': 1 },
- object = { 'toString': function() { return '<%= a %>'; } };
-
- strictEqual(_.template(object, data), '1');
+ test('should support a `omission` option', 1, function() {
+ strictEqual(_.trunc(string, { 'omission': ' [...]' }), 'hi-diddly-ho there, neig [...]');
});
- test('should handle \\u2028 & \\u2029 characters', 1, function() {
- var compiled = _.template('\u2028<%= "\\u2028\\u2029" %>\u2029');
- strictEqual(compiled(), '\u2028\u2028\u2029\u2029');
+ test('should support a `length` option', 1, function() {
+ strictEqual(_.trunc(string, { 'length': 4 }), 'h...');
});
- test('should resolve `null` and `undefined` values to empty strings', 4, function() {
- var compiled = _.template('<%= a %><%- a %>');
- strictEqual(compiled({ 'a': null }), '');
- strictEqual(compiled({ 'a': undefined }), '');
-
- compiled = _.template('<%= a.b %><%- a.b %>');
- strictEqual(compiled({ 'a': {} }), '');
- strictEqual(compiled({ 'a': {} }), '');
+ test('should support a `separator` option', 2, function() {
+ strictEqual(_.trunc(string, { 'length': 24, 'separator': ' ' }), 'hi-diddly-ho there,...');
+ strictEqual(_.trunc(string, { 'length': 24, 'separator': /,? +/ }), 'hi-diddly-ho there...');
});
- test('should support single line comments in "evaluate" delimiters (test production builds)', 1, function() {
- var compiled = _.template('<% // comment %><% if (value) { %>yap<% } else { %>nope<% } %>');
- equal(compiled({ 'value': true }), 'yap');
+ test('should treat negative `length` as `0`', 4, function() {
+ _.each([0, -2], function(length) {
+ strictEqual(_.trunc(string, length), '...');
+ strictEqual(_.trunc(string, { 'length': length }), '...');
+ });
});
- test('should match delimiters before escaping text', 1, function() {
- var compiled = _.template('<<\n a \n>>', null, { 'evaluate': /<<(.*?)>>/g });
- equal(compiled(), '<<\n a \n>>');
+ test('should coerce `length` to a number', 4, function() {
+ _.each(['', '4'], function(length, index) {
+ var actual = index ? 'h...' : '...';
+ strictEqual(_.trunc(string, length), actual);
+ strictEqual(_.trunc(string, { 'length': { 'valueOf': _.constant(length) } }), actual);
+ });
});
- test('should not error when passed non-object `data` and `options` values', 2, function() {
- var pass = true;
-
- try {
- _.template('', 1);
- } catch(e) {
- pass = false;
- }
- ok(pass);
+ test('should coerce `string` to a string', 2, function() {
+ strictEqual(_.trunc(Object(string), 4), 'h...');
+ strictEqual(_.trunc({ 'toString': _.constant(string) }, 5), 'hi...');
+ });
- pass = true;
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var actual = _.map([string, string, string], _.trunc),
+ truncated = 'hi-diddly-ho there, neighbo...';
- try {
- _.template('', 1, 1);
- } catch(e) {
- pass = false;
- }
- ok(pass);
+ deepEqual(actual, [truncated, truncated, truncated]);
});
}());
@@ -7301,20 +12710,18 @@
asyncTest('subsequent calls should return the result of the first call', 5, function() {
if (!(isRhino && isModularize)) {
- var throttled = _.throttle(function(value) { return value; }, 32),
- result = [throttled('x'), throttled('y')];
+ var throttled = _.throttle(_.identity, 32),
+ result = [throttled('a'), throttled('b')];
- deepEqual(result, ['x', 'x']);
+ deepEqual(result, ['a', 'a']);
setTimeout(function() {
- var result = [throttled('a'), throttled('b')];
-
- notEqual(result[0], 'x');
+ var result = [throttled('x'), throttled('y')];
+ notEqual(result[0], 'a');
notStrictEqual(result[0], undefined);
- notEqual(result[1], 'b');
+ notEqual(result[1], 'y');
notStrictEqual(result[1], undefined);
-
QUnit.start();
}, 64);
}
@@ -7330,12 +12737,12 @@
dateCount = 0;
var getTime = function() {
- return ++dateCount < 3 ? +new Date : Infinity;
+ return ++dateCount == 5 ? Infinity : +new Date;
};
var lodash = _.runInContext(_.assign({}, root, {
'Date': function() {
- return { 'getTime': getTime, 'valueOf': getTime };
+ return { 'getTime': getTime };
}
}));
@@ -7348,7 +12755,7 @@
throttled();
setTimeout(function() {
- equal(callCount, 2);
+ strictEqual(callCount, 2);
QUnit.start();
}, 64);
}
@@ -7358,46 +12765,16 @@
}
});
- asyncTest('supports recursive calls', 3, function() {
- if (!(isRhino && isModularize)) {
- var args,
- count = 0,
- object = {};
-
- var throttled = _.throttle(function(value) {
- count++;
- args = [this];
- push.apply(args, arguments);
- if (count < 10) {
- throttled.call(this, value);
- }
- }, 32);
-
- throttled.call(object, 'a');
- equal(count, 1);
-
- setTimeout(function() {
- ok(count < 3);
- deepEqual(args, [object, 'a']);
- QUnit.start();
- }, 32);
- }
- else {
- skipTest(3);
- QUnit.start();
- }
- });
-
asyncTest('should not trigger a trailing call when invoked once', 2, function() {
if (!(isRhino && isModularize)) {
var count = 0,
throttled = _.throttle(function() { count++; }, 32);
throttled();
- equal(count, 1);
+ strictEqual(count, 1);
setTimeout(function() {
- equal(count, 1);
+ strictEqual(count, 1);
QUnit.start();
}, 64);
}
@@ -7408,10 +12785,10 @@
});
_.times(2, function(index) {
- test('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), 1, function() {
+ asyncTest('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), 1, function() {
if (!(isRhino && isModularize)) {
var count = 0,
- limit = 500,
+ limit = (argv || isPhantom) ? 1000 : 320,
options = index ? { 'leading': false } : {};
var throttled = _.throttle(function() {
@@ -7422,10 +12799,16 @@
while ((new Date - start) < limit) {
throttled();
}
- ok(count > 1);
+ var actual = count > 1;
+
+ setTimeout(function() {
+ ok(actual);
+ QUnit.start();
+ }, 1);
}
else {
- skipTest(1);
+ skipTest();
+ QUnit.start();
}
});
});
@@ -7439,8 +12822,8 @@
return value;
}, 32, {});
- equal(throttled('x'), 'x');
- equal(throttled('y'), 'x');
+ strictEqual(throttled('a'), 'a');
+ strictEqual(throttled('b'), 'a');
setTimeout(function() {
strictEqual(count, 2);
@@ -7453,24 +12836,29 @@
}
});
- test('should work with `leading` option', 4, function() {
- if (!(isRhino && isModularize)) {
- _.forEach([true, { 'leading': true }], function(options) {
+ test('should support a `leading` option', 4, function() {
+ _.each([true, { 'leading': true }], function(options) {
+ if (!(isRhino && isModularize)) {
var withLeading = _.throttle(_.identity, 32, options);
- equal(withLeading('x'), 'x');
- });
+ strictEqual(withLeading('a'), 'a');
+ }
+ else {
+ skipTest();
+ }
+ });
- _.forEach([false, { 'leading': false }], function(options) {
+ _.each([false, { 'leading': false }], function(options) {
+ if (!(isRhino && isModularize)) {
var withoutLeading = _.throttle(_.identity, 32, options);
- strictEqual(withoutLeading('x'), undefined);
- });
- }
- else {
- skipTest(4);
- }
+ strictEqual(withoutLeading('a'), undefined);
+ }
+ else {
+ skipTest();
+ }
+ });
});
- asyncTest('should work with `trailing` option', 6, function() {
+ asyncTest('should support a `trailing` option', 6, function() {
if (!(isRhino && isModularize)) {
var withCount = 0,
withoutCount = 0;
@@ -7485,14 +12873,14 @@
return value;
}, 64, { 'trailing': false });
- equal(withTrailing('x'), 'x');
- equal(withTrailing('y'), 'x');
+ strictEqual(withTrailing('a'), 'a');
+ strictEqual(withTrailing('b'), 'a');
- equal(withoutTrailing('x'), 'x');
- equal(withoutTrailing('y'), 'x');
+ strictEqual(withoutTrailing('a'), 'a');
+ strictEqual(withoutTrailing('b'), 'a');
setTimeout(function() {
- equal(withCount, 2);
+ strictEqual(withCount, 2);
strictEqual(withoutCount, 1);
QUnit.start();
}, 256);
@@ -7525,183 +12913,393 @@
}, 192);
}
else {
- skipTest();
- QUnit.start();
+ skipTest();
+ QUnit.start();
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.debounce and lodash.throttle');
+
+ _.each(['debounce', 'throttle'], function(methodName, index) {
+ var func = _[methodName],
+ isDebounce = !index;
+
+ test('_.' + methodName + ' should not error for non-object `options` values', 1, function() {
+ var pass = true;
+
+ try {
+ func(_.noop, 32, 1);
+ } catch(e) {
+ pass = false;
+ }
+ ok(pass);
+ });
+
+ asyncTest('_.' + methodName + ' should call `func` with the correct `this` binding', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var object = {
+ 'funced': func(function() { actual.push(this); }, 32)
+ };
+
+ var actual = [],
+ expected = _.times(isDebounce ? 1 : 2, _.constant(object));
+
+ object.funced();
+ if (!isDebounce) {
+ object.funced();
+ }
+ setTimeout(function() {
+ deepEqual(actual, expected);
+ QUnit.start();
+ }, 64);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+
+ asyncTest('_.' + methodName + ' supports recursive calls', 2, function() {
+ if (!(isRhino && isModularize)) {
+ var actual = [],
+ args = _.map(['a', 'b', 'c'], function(chr) { return [{}, chr]; }),
+ length = isDebounce ? 1 : 2,
+ expected = args.slice(0, length),
+ queue = args.slice();
+
+ var funced = func(function() {
+ var current = [this];
+ push.apply(current, arguments);
+ actual.push(current);
+
+ var next = queue.shift();
+ if (next) {
+ funced.call(next[0], next[1]);
+ }
+ }, 64);
+
+ var next = queue.shift();
+ funced.call(next[0], next[1]);
+ deepEqual(actual, expected.slice(0, length - 1));
+
+ setTimeout(function() {
+ deepEqual(actual, expected);
+ QUnit.start();
+ }, 96);
+ }
+ else {
+ skipTest(2);
+ QUnit.start();
+ }
+ });
+
+ asyncTest('_.' + methodName + ' should work if the system time is set backwards', 1, function() {
+ if (!isModularize) {
+ var callCount = 0,
+ dateCount = 0;
+
+ var getTime = function() {
+ return ++dateCount === 4 ? +new Date(2012, 3, 23, 23, 27, 18) : +new Date;
+ };
+
+ var lodash = _.runInContext(_.assign({}, root, {
+ 'Date': function() {
+ return { 'getTime': getTime, 'valueOf': getTime };
+ }
+ }));
+
+ var funced = lodash[methodName](function() {
+ callCount++;
+ }, 32);
+
+ funced();
+
+ setTimeout(function() {
+ funced();
+ strictEqual(callCount, isDebounce ? 1 : 2);
+ QUnit.start();
+ }, 64);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+
+ asyncTest('_.' + methodName + ' should support cancelling delayed calls', 1, function() {
+ if (!(isRhino && isModularize)) {
+ var callCount = 0;
+
+ var funced = func(function() {
+ callCount++;
+ }, 32, { 'leading': false });
+
+ funced();
+ funced.cancel();
+
+ setTimeout(function() {
+ strictEqual(callCount, 0);
+ QUnit.start();
+ }, 64);
+ }
+ else {
+ skipTest();
+ QUnit.start();
+ }
+ });
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.times');
+
+ (function() {
+ test('should coerce non-finite `n` values to `0`', 3, function() {
+ _.each([-Infinity, NaN, Infinity], function(n) {
+ deepEqual(_.times(n), []);
+ });
+ });
+
+ test('should provide the correct `iteratee` arguments', 1, function() {
+ var args;
+
+ _.times(1, function() {
+ args || (args = slice.call(arguments));
+ });
+
+ deepEqual(args, [0]);
+ });
+
+ test('should support the `thisArg` argument', 1, function() {
+ var expect = [1, 2, 3];
+
+ var actual = _.times(3, function(num) {
+ return this[num];
+ }, expect);
+
+ deepEqual(actual, expect);
+ });
+
+ test('should use `_.identity` when `iteratee` is nullish', 1, function() {
+ var values = [, null, undefined],
+ expected = _.map(values, _.constant([0, 1, 2]));
+
+ var actual = _.map(values, function(value, index) {
+ return index ? _.times(3, value) : _.times(3);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return an array of the results of each `iteratee` execution', 1, function() {
+ deepEqual(_.times(3, function(n) { return n * 2; }), [0, 2, 4]);
+ });
+
+ test('should return an empty array for falsey and negative `n` arguments', 1, function() {
+ var values = falsey.concat(-1, -Infinity),
+ expected = _.map(values, _.constant([]));
+
+ var actual = _.map(values, function(value, index) {
+ return index ? _.times(value) : _.times();
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _(3).times();
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [0, 1, 2]);
+ }
+ else {
+ skipTest(2);
}
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.debounce and lodash.throttle');
-
- _.forEach(['debounce', 'throttle'], function(methodName) {
- var func = _[methodName];
+ QUnit.module('lodash.toArray');
- test('_.' + methodName + ' should not error when passed non-object `options` values', 1, function() {
- var pass = true;
+ (function() {
+ test('should return the values of objects', 1, function() {
+ var array = [1, 2, 3],
+ object = { 'a': 1, 'b': 2, 'c': 3 };
- try {
- func(noop, 32, 1);
- } catch(e) {
- pass = false;
- }
- ok(pass);
+ deepEqual(_.toArray(object), array);
});
- asyncTest('_.' + methodName + ' should call `func` with the correct `this` binding', 1, function() {
- if (!(isRhino && isModularize)) {
- var actual = [];
-
- var object = {
- 'func': func(function() { actual.push(this); }, 32)
- };
-
- object.func();
- if (methodName == 'throttle') {
- object.func();
- }
- setTimeout(function() {
- deepEqual(actual, methodName == 'throttle' ? [object, object] : [object]);
- QUnit.start();
- }, 64);
- }
- else {
- skipTest(1);
- QUnit.start();
- }
+ test('should work with a string for `collection` (test in Opera < 10.52)', 2, function() {
+ deepEqual(_.toArray('abc'), ['a', 'b', 'c']);
+ deepEqual(_.toArray(Object('abc')), ['a', 'b', 'c']);
});
- });
+ }());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.toArray');
+ QUnit.module('lodash.slice and lodash.toArray');
- (function() {
- var args = arguments,
- array = [1, 2, 3];
+ _.each(['slice', 'toArray'], function(methodName) {
+ var args = (function() { return arguments; }(1, 2, 3)),
+ array = [1, 2, 3],
+ func = _[methodName];
test('should return a dense array', 3, function() {
var sparse = Array(3);
sparse[1] = 2;
- var actual = _.toArray(sparse);
+ var actual = func(sparse);
- ok(0 in actual);
- ok(2 in actual);
+ ok('0' in actual);
+ ok('2' in actual);
deepEqual(actual, sparse);
});
test('should treat array-like objects like arrays', 2, function() {
var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 };
- deepEqual(_.toArray(object), ['a', 'b', 'c']);
- deepEqual(_.toArray(args), array);
+ deepEqual(func(object), ['a', 'b', 'c']);
+ deepEqual(func(args), array);
});
test('should return a shallow clone of arrays', 2, function() {
- var actual = _.toArray(array);
+ var actual = func(array);
notStrictEqual(actual, array);
- deepEqual(_.toArray(array), array);
- });
-
- test('should return the values of objects', 1, function() {
- var object = { 'a': 1, 'b': 2, 'c': 3 };
- deepEqual(_.toArray(object), array);
- });
-
- test('should work with a string for `collection` (test in Opera < 10.52)', 2, function() {
- deepEqual(_.toArray('abc'), ['a', 'b', 'c']);
- deepEqual(_.toArray(Object('abc')), ['a', 'b', 'c']);
+ deepEqual(func(array), array);
});
test('should work with a node list for `collection` (test in IE < 9)', 1, function() {
if (document) {
try {
var nodeList = document.getElementsByTagName('body'),
- actual = _.toArray(nodeList);
- } catch(e) { }
+ actual = func(nodeList);
+ } catch(e) {}
+
deepEqual(actual, [body]);
- } else {
+ }
+ else {
skipTest();
}
});
- }(1, 2, 3));
+ });
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.times');
+ QUnit.module('lodash.toPlainObject');
(function() {
- test('should pass the correct `callback` arguments', 1, function() {
- var args;
+ var args = arguments;
- _.times(1, function() {
- args || (args = slice.call(arguments));
- });
+ test('should flatten inherited properties', 1, function() {
+ function Foo() { this.b = 2; }
+ Foo.prototype.c = 3;
- deepEqual(args, [0]);
+ var actual = _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+ deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
});
- test('should support the `thisArg` argument', 1, function() {
- var expect = [1, 2, 3];
-
- var actual = _.times(3, function(num) {
- return this[num];
- }, expect);
+ test('should convert `arguments` objects to plain objects', 1, function() {
+ var actual = _.toPlainObject(args),
+ expected = { '0': 1, '1': 2, '2': 3 };
- deepEqual(actual, expect);
+ deepEqual(actual, expected);
});
- test('should use `_.identity` when no `callback` is provided', 1, function() {
- var actual = _.times(3);
- deepEqual(actual, [0, 1, 2]);
- });
+ test('should convert arrays to plain objects', 1, function() {
+ var actual = _.toPlainObject(['a', 'b', 'c']),
+ expected = { '0': 'a', '1': 'b', '2': 'c' };
- test('should return an array of the results of each `callback` execution', 1, function() {
- deepEqual(_.times(3, function(n) { return n * 2; }), [0, 2, 4]);
+ deepEqual(actual, expected);
});
+ }(1, 2, 3));
- test('should return an empty array for falsey and negative `n` arguments', 1, function() {
- var values = falsey.concat(-1, -Infinity),
- expected = _.map(values, function() { return []; });
+ /*--------------------------------------------------------------------------*/
- var actual = _.map(values, function(value, index) {
- return index ? _.times(value) : _.times();
+ QUnit.module('lodash.transform');
+
+ (function() {
+ function Foo() {
+ this.a = 1;
+ this.b = 2;
+ this.c = 3;
+ }
+
+ test('should create an object with the same `[[Prototype]]` as `object` when `accumulator` is `null` or `undefined`', 4, function() {
+ var accumulators = [, null, undefined],
+ expected = _.map(accumulators, _.constant(true)),
+ object = new Foo;
+
+ var iteratee = function(result, value, key) {
+ result[key] = value * value;
+ };
+
+ var mapper = function(accumulator, index) {
+ return index ? _.transform(object, iteratee, accumulator) : _.transform(object, iteratee);
+ };
+
+ var results = _.map(accumulators, mapper);
+
+ var actual = _.map(results, function(result) {
+ return result instanceof Foo;
});
deepEqual(actual, expected);
- });
- test('should return a wrapped value when chaining', 2, function() {
- if (!isNpm) {
- var actual = _(3).times();
- ok(actual instanceof _);
- deepEqual(actual.value(), [0, 1, 2]);
- }
- else {
- skipTest(2);
- }
+ expected = _.map(accumulators, _.constant({ 'a': 1, 'b': 4, 'c': 9 }));
+ actual = _.map(results, _.clone);
+
+ deepEqual(actual, expected);
+
+ object = { 'a': 1, 'b': 2, 'c': 3 };
+ actual = _.map(accumulators, mapper);
+
+ deepEqual(actual, expected);
+
+ object = [1, 2, 3];
+ expected = _.map(accumulators, _.constant([1, 4, 9]));
+ actual = _.map(accumulators, mapper);
+
+ deepEqual(actual, expected);
});
- }());
- /*--------------------------------------------------------------------------*/
+ test('should support an `accumulator` value', 4, function() {
+ var values = [new Foo, [1, 2, 3], { 'a': 1, 'b': 2, 'c': 3 }],
+ expected = _.map(values, _.constant([0, 1, 4, 9]));
- QUnit.module('lodash.transform');
+ var actual = _.map(values, function(value) {
+ return _.transform(value, function(result, value) {
+ result.push(value * value);
+ }, [0]);
+ });
- (function() {
- test('should produce an that is an instance of the given object\'s constructor', 2, function() {
- function Foo() {
- this.a = 1;
- this.b = 2;
- this.c = 3;
- }
+ deepEqual(actual, expected);
- var actual = _.transform(new Foo, function(result, value, key) {
- result[key] = value * value;
+ var object = { '_': 0, 'a': 1, 'b': 4, 'c': 9 };
+ expected = [object, { '_': 0, '0': 1, '1': 4, '2': 9 }, object];
+ actual = _.map(values, function(value) {
+ return _.transform(value, function(result, value, key) {
+ result[key] = value * value;
+ }, { '_': 0 });
+ });
+
+ deepEqual(actual, expected);
+
+ object = {};
+ expected = _.map(values, _.constant(object));
+ actual = _.map(values, function(value) {
+ return _.transform(value, _.noop, object);
+ });
+
+ deepEqual(actual, expected);
+
+ actual = _.map(values, function(value) {
+ return _.transform(null, null, object);
});
- ok(actual instanceof Foo);
- deepEqual(_.clone(actual), { 'a': 1, 'b': 4, 'c': 9 });
+ deepEqual(actual, expected);
});
test('should treat sparse arrays as dense', 1, function() {
@@ -7712,17 +13310,46 @@
deepEqual(actual, ['undefined']);
});
- test('should work without a `callback` argument', 1, function() {
- function Foo() {}
+ test('should work without an `iteratee` argument', 1, function() {
ok(_.transform(new Foo) instanceof Foo);
});
- _.forEach({
+ test('should check that `object` is an object before using its `[[Prototype]]`', 2, function() {
+ var Ctors = [Boolean, Boolean, Number, Number, Number, String, String],
+ values = [true, false, 0, 1, NaN, '', 'a'],
+ expected = _.map(values, _.constant({}));
+
+ var results = _.map(values, function(value) {
+ return _.transform(value);
+ });
+
+ deepEqual(results, expected);
+
+ expected = _.map(values, _.constant(false));
+
+ var actual = _.map(results, function(value, index) {
+ return value instanceof Ctors[index];
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should create an empty object when provided a falsey `object` argument', 1, function() {
+ var expected = _.map(falsey, _.constant({}));
+
+ var actual = _.map(falsey, function(value, index) {
+ return index ? _.transform(value) : _.transform();
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ _.each({
'array': [1, 2, 3],
'object': { 'a': 1, 'b': 2, 'c': 3 }
},
function(object, key) {
- test('should pass the correct `callback` arguments when transforming an ' + key, 2, function() {
+ test('should provide the correct `iteratee` arguments when transforming an ' + key, 2, function() {
var args;
_.transform(object, function() {
@@ -7731,10 +13358,10 @@
var first = args[0];
if (key == 'array') {
- ok(first != object && _.isArray(first));
+ ok(first !== object && _.isArray(first));
deepEqual(args, [first, 1, 0, object]);
} else {
- ok(first != object && _.isPlainObject(first));
+ ok(first !== object && _.isPlainObject(first));
deepEqual(args, [first, 1, 'a', object]);
}
});
@@ -7748,31 +13375,153 @@
deepEqual(actual, object);
});
});
+
+ test('should create an object from the same realm as `object`', 1, function() {
+ var objects = _.transform(_, function(result, value, key) {
+ if (_.startsWith(key, '_') && _.isObject(value) && !_.isElement(value)) {
+ result.push(value);
+ }
+ }, []);
+
+ var expected = _.times(objects.length, _.constant(true));
+
+ var actual = _.map(objects, function(object) {
+ var Ctor = object.constructor,
+ result = _.transform(object);
+
+ if (result === object) {
+ return false;
+ }
+ if (_.isTypedArray(object)) {
+ return result instanceof Array;
+ }
+ return result instanceof Ctor || !(new Ctor instanceof Ctor);
+ });
+
+ deepEqual(actual, expected);
+ });
}());
/*--------------------------------------------------------------------------*/
+ QUnit.module('trim methods');
+
+ _.each(['trim', 'trimLeft', 'trimRight'], function(methodName, index) {
+ var func = _[methodName];
+
+ var parts = [];
+ if (index != 2) {
+ parts.push('leading');
+ }
+ if (index != 1) {
+ parts.push('trailing');
+ }
+ parts = parts.join(' and ');
+
+ test('`_.' + methodName + '` should remove ' + parts + ' whitespace', 1, function() {
+ var string = whitespace + 'a b c' + whitespace,
+ expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : '');
+
+ strictEqual(func(string), expected);
+ });
+
+ test('`_.' + methodName + '` should not remove non-whitespace characters', 1, function() {
+ // Zero-width space (zws), next line character (nel), and non-character (bom) are not whitespace.
+ var problemChars = '\x85\u200b\ufffe',
+ string = problemChars + 'a b c' + problemChars;
+
+ strictEqual(func(string), string);
+ });
+
+ test('`_.' + methodName + '` should coerce `string` to a string', 1, function() {
+ var object = { 'toString': function() { return whitespace + 'a b c' + whitespace; } },
+ expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : '');
+
+ strictEqual(func(object), expected);
+ });
+
+ test('`_.' + methodName + '` should remove ' + parts + ' `chars`', 1, function() {
+ var string = '-_-a-b-c-_-',
+ expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : '');
+
+ strictEqual(func(string, '_-'), expected);
+ });
+
+ test('`_.' + methodName + '` should coerce `chars` to a string', 1, function() {
+ var object = { 'toString': function() { return '_-'; } },
+ string = '-_-a-b-c-_-',
+ expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : '');
+
+ strictEqual(func(string, object), expected);
+ });
+
+ test('`_.' + methodName + '` should return an empty string when provided `null`, `undefined`, or empty string and `chars`', 6, function() {
+ _.each([null, '_-'], function(chars) {
+ strictEqual(func(null, chars), '');
+ strictEqual(func(undefined, chars), '');
+ strictEqual(func('', chars), '');
+ });
+ });
+
+ test('`_.' + methodName + '` should work with `null`, `undefined`, or empty string for `chars`', 3, function() {
+ var string = whitespace + 'a b c' + whitespace,
+ expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : '');
+
+ strictEqual(func(string, null), expected);
+ strictEqual(func(string, undefined), expected);
+ strictEqual(func(string, ''), string);
+ });
+
+ test('`_.' + methodName + '` should work as an iteratee for `_.map`', 1, function() {
+ var string = Object(whitespace + 'a b c' + whitespace),
+ trimmed = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''),
+ actual = _.map([string, string, string], func);
+
+ deepEqual(actual, [trimmed, trimmed, trimmed]);
+ });
+
+ test('`_.' + methodName + '` should return an unwrapped value when chaining', 1, function() {
+ if (!isNpm) {
+ var string = whitespace + 'a b c' + whitespace,
+ expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : '');
+
+ strictEqual(_(string)[methodName](), expected);
+ }
+ else {
+ skipTest();
+ }
+ });
+ });
+
+ /*--------------------------------------------------------------------------*/
+
QUnit.module('lodash.unescape');
(function() {
var escaped = '&<>"'\/',
unescaped = '&<>"\'\/';
+ escaped += escaped;
+ unescaped += unescaped;
+
test('should unescape entities in the correct order', 1, function() {
- equal(_.unescape('<'), '<');
+ strictEqual(_.unescape('<'), '<');
});
test('should unescape the proper entities', 1, function() {
- equal(_.unescape(escaped), unescaped);
+ strictEqual(_.unescape(escaped), unescaped);
});
- test('should unescape the same characters escaped by `_.escape`', 1, function() {
- equal(_.unescape(_.escape(unescaped)), unescaped);
+ test('should not unescape the "/" entity', 1, function() {
+ strictEqual(_.unescape('/'), '/');
});
- test('should return an empty string when provided `null` or `undefined`', 2, function() {
- equal(_.unescape(null), '');
- equal(_.unescape(undefined), '');
+ test('should handle strings with nothing to unescape', 1, function() {
+ strictEqual(_.unescape('abc'), 'abc');
+ });
+
+ test('should unescape the same characters escaped by `_.escape`', 1, function() {
+ strictEqual(_.unescape(_.escape(unescaped)), unescaped);
});
}());
@@ -7781,28 +13530,25 @@
QUnit.module('lodash.union');
(function() {
+ var args = arguments;
+
test('should return the union of the given arrays', 1, function() {
- var actual = _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
- deepEqual(actual, [1, 2, 3, 5, 4]);
+ var actual = _.union([1, 3, 2], [5, 2, 1, 4], [2, 1]);
+ deepEqual(actual, [1, 3, 2, 5, 4]);
});
test('should not flatten nested arrays', 1, function() {
- var actual = _.union([1, 2, 3], [1, [5]], [2, [4]]);
- deepEqual(actual, [1, 2, 3, [5], [4]]);
- });
-
- test('should produce correct results when provided a falsey `array` argument', 1, function() {
- var expected = [1, 2, 3],
- actual = _.union(null, expected);
-
- deepEqual(actual, expected);
+ var actual = _.union([1, 3, 2], [1, [5]], [2, [4]]);
+ deepEqual(actual, [1, 3, 2, [5], [4]]);
});
- test('should ignore individual secondary values', 1, function() {
- var array = [1];
- deepEqual(_.union(array, 1, 2, 3), array);
+ test('should ignore values that are not arrays or `arguments` objects', 3, function() {
+ var array = [0];
+ deepEqual(_.union(array, 3, null, { '0': 1 }), array);
+ deepEqual(_.union(null, array, null, [2, 1]), [0, 2, 1]);
+ deepEqual(_.union(null, array, null, args), [0, 1, 2, 3]);
});
- }());
+ }(1, 2, 3));
/*--------------------------------------------------------------------------*/
@@ -7821,29 +13567,35 @@
deepEqual(_.uniq(array), [1, 2, 3]);
});
- test('should work with large arrays', 1, function() {
- var object = {};
+ test('should treat object instances as unique', 1, function() {
+ deepEqual(_.uniq(objects), objects);
+ });
- var largeArray = _.times(largeArraySize, function(index) {
- switch (index % 3) {
- case 0: return 0;
- case 1: return 'a';
- case 2: return object;
- }
- });
+ test('should not treat `NaN` as unique', 1, function() {
+ deepEqual(_.uniq([1, NaN, 3, NaN]), [1, NaN, 3]);
+ });
- deepEqual(_.uniq(largeArray), [0, 'a', object]);
+ test('should work with `isSorted`', 3, function() {
+ var expected = [1, 2, 3];
+ deepEqual(_.uniq([1, 2, 3], true), expected);
+ deepEqual(_.uniq([1, 1, 2, 2, 3], true), expected);
+ deepEqual(_.uniq([1, 2, 3, 3, 3, 3, 3], true), expected);
});
- test('should work with a `callback`', 1, function() {
- var actual = _.uniq(objects, false, function(object) {
- return object.a;
- });
+ test('should work with `iteratee`', 2, function() {
+ _.each([objects, _.sortBy(objects, 'a')], function(array, index) {
+ var isSorted = !!index,
+ expected = isSorted ? [objects[2], objects[0], objects[1]] : objects.slice(0, 3);
- deepEqual(actual, objects.slice(0, 3));
+ var actual = _.uniq(array, isSorted, function(object) {
+ return object.a;
+ });
+
+ deepEqual(actual, expected);
+ });
});
- test('should work with a `callback` without specifying `isSorted`', 1, function() {
+ test('should work with `iteratee` without specifying `isSorted`', 1, function() {
var actual = _.uniq(objects, function(object) {
return object.a;
});
@@ -7859,28 +13611,54 @@
deepEqual(actual, [1, 2, 3]);
});
- test('should perform an unsorted uniq operation when used as `callback` for `_.map`', 1, function() {
+ test('should work with a "_.pluck" style `iteratee`', 2, function() {
+ var actual = _.uniq(objects, 'a');
+
+ deepEqual(actual, objects.slice(0, 3));
+
+ var arrays = [[2], [3], [1], [2], [3], [1]];
+ actual = _.uniq(arrays, 0);
+
+ deepEqual(actual, arrays.slice(0, 3));
+ });
+
+ test('should perform an unsorted uniq when used as an iteratee for `_.map`', 1, function() {
var array = [[2, 1, 2], [1, 2, 1]],
actual = _.map(array, _.uniq);
- deepEqual(actual, [[2, 1], [1, 2]]);
+ deepEqual(actual, [[2, 1], [1, 2]]);
+ });
+
+ test('should work with large arrays', 1, function() {
+ var object = {};
+
+ var largeArray = _.times(LARGE_ARRAY_SIZE, function(index) {
+ switch (index % 3) {
+ case 0: return 0;
+ case 1: return 'a';
+ case 2: return object;
+ }
+ });
+
+ deepEqual(_.uniq(largeArray), [0, 'a', object]);
});
- test('should work with large arrays of boolean, `null`, and `undefined` values', 1, function() {
+ test('should work with large arrays of boolean, `NaN`, `null`, and `undefined` values', 1, function() {
var array = [],
- expected = [true, false, null, undefined],
- count = Math.ceil(largeArraySize / expected.length);
+ expected = [true, false, NaN, null, undefined],
+ count = Math.ceil(LARGE_ARRAY_SIZE / expected.length);
_.times(count, function() {
push.apply(array, expected);
});
+
deepEqual(_.uniq(array), expected);
});
test('should distinguish between numbers and numeric strings', 1, function() {
var array = [],
expected = ['2', 2, Object('2'), Object(2)],
- count = Math.ceil(largeArraySize / expected.length);
+ count = Math.ceil(LARGE_ARRAY_SIZE / expected.length);
_.times(count, function() {
push.apply(array, expected);
@@ -7889,13 +13667,13 @@
deepEqual(_.uniq(array), expected);
});
- _.forEach({
+ _.each({
'an object': ['a'],
'a number': 0,
'a string': '0'
},
function(callback, key) {
- test('should work with ' + key + ' for `callback`', 1, function() {
+ test('should work with ' + key + ' for `iteratee`', 1, function() {
var actual = _.uniq([['a'], ['b'], ['a']], callback);
deepEqual(actual, [['a'], ['b']]);
});
@@ -7912,16 +13690,15 @@
(function() {
test('should generate unique ids', 1, function() {
- var actual = [];
- _.times(1000, function() {
- actual.push(_.uniqueId());
+ var actual = _.times(1000, function() {
+ return _.uniqueId();
});
- equal(_.uniq(actual).length, actual.length);
+ strictEqual(_.uniq(actual).length, actual.length);
});
- test('should return a string value when not passing a prefix argument', 1, function() {
- equal(typeof _.uniqueId(), 'string');
+ test('should return a string value when not providing a prefix argument', 1, function() {
+ strictEqual(typeof _.uniqueId(), 'string');
});
test('should coerce the prefix argument to a string', 1, function() {
@@ -7946,67 +13723,61 @@
});
}());
+ /*--------------------------------------------------------------------------*/
+
QUnit.module('lodash.where');
(function() {
- var array = [
- { 'a': 1 },
- { 'a': 1 },
- { 'a': 1, 'b': 2 },
- { 'a': 2, 'b': 2 },
- { 'a': 3 }
- ];
-
- test('should filter by properties', 6, function() {
- deepEqual(_.where(array, { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }]);
- deepEqual(_.where(array, { 'a': 2 }), [{ 'a': 2, 'b': 2 }]);
- deepEqual(_.where(array, { 'a': 3 }), [{ 'a': 3 }]);
- deepEqual(_.where(array, { 'b': 1 }), []);
- deepEqual(_.where(array, { 'b': 2 }), [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]);
- deepEqual(_.where(array, { 'a': 1, 'b': 2 }), [{ 'a': 1, 'b': 2 }]);
- });
-
- test('should not filter by inherited properties', 1, function() {
- function Foo() {}
- Foo.prototype = { 'a': 2 };
+ test('should filter by `source` properties', 12, function() {
+ var objects = [
+ { 'a': 1 },
+ { 'a': 1 },
+ { 'a': 1, 'b': 2 },
+ { 'a': 2, 'b': 2 },
+ { 'a': 3 }
+ ];
- var properties = new Foo;
- properties.b = 2;
- deepEqual(_.where(array, properties), [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]);
- });
+ var pairs = [
+ [{ 'a': 1 }, [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }]],
+ [{ 'a': 2 }, [{ 'a': 2, 'b': 2 }]],
+ [{ 'a': 3 }, [{ 'a': 3 }]],
+ [{ 'b': 1 }, []],
+ [{ 'b': 2 }, [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]],
+ [{ 'a': 1, 'b': 2 }, [{ 'a': 1, 'b': 2 }]]
+ ];
- test('should filter by problem JScript properties (test in IE < 9)', 1, function() {
- var collection = [shadowedObject];
- deepEqual(_.where(collection, shadowedObject), [shadowedObject]);
+ _.each(pairs, function(pair) {
+ var actual = _.where(objects, pair[0]);
+ deepEqual(actual, pair[1]);
+ ok(_.isEmpty(_.difference(actual, objects)));
+ });
});
test('should work with an object for `collection`', 1, function() {
- var collection = {
+ var object = {
'x': { 'a': 1 },
'y': { 'a': 3 },
'z': { 'a': 1, 'b': 2 }
};
- deepEqual(_.where(collection, { 'a': 1 }), [{ 'a': 1 }, { 'a': 1, 'b': 2 }]);
- });
-
- test('should return an empty array when provided an empty `properties` object', 1, function() {
- deepEqual(_.where(array, {}), []);
+ var actual = _.where(object, { 'a': 1 });
+ deepEqual(actual, [object.x, object.z]);
});
- test('should deep compare `properties` values', 1, function() {
- var collection = [{ 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }],
- expected = _.cloneDeep(collection);
-
- deepEqual(_.where(collection, { 'a': { 'b': { 'c': 1 } } }), expected);
- });
-
- test('should search of arrays for values', 2, function() {
- var collection = [{ 'a': [1, 2] }],
- expected = _.cloneDeep(collection);
+ test('should work in a lazy chain sequence', 1, function() {
+ if (!isNpm) {
+ var array = [
+ { 'a': 1 },
+ { 'a': 3 },
+ { 'a': 1, 'b': 2 }
+ ];
- deepEqual(_.where(collection, { 'a': [] }), []);
- deepEqual(_.where(collection, { 'a': [2] }), expected);
+ var actual = _(array).where({ 'a': 1 }).value();
+ deepEqual(actual, [array[0], array[2]]);
+ }
+ else {
+ skipTest();
+ }
});
}());
@@ -8032,6 +13803,49 @@
/*--------------------------------------------------------------------------*/
+ QUnit.module('lodash.words');
+
+ (function() {
+ test('should treat latin-1 supplementary letters as words', 1, function() {
+ var expected = _.map(burredLetters, function(letter) {
+ return [letter];
+ });
+
+ var actual = _.map(burredLetters, function(letter) {
+ return _.words(letter);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should not treat mathematical operators as words', 1, function() {
+ var operators = ['\xd7', '\xf7'],
+ expected = _.map(operators, _.constant([])),
+ actual = _.map(operators, _.words);
+
+ deepEqual(actual, expected);
+ });
+
+ test('should work as an iteratee for `_.map`', 1, function() {
+ var strings = _.map(['a', 'b', 'c'], Object),
+ actual = _.map(strings, _.words);
+
+ deepEqual(actual, [['a'], ['b'], ['c']]);
+ });
+
+ test('should work with compound words', 6, function() {
+ deepEqual(_.words('LETTERSAeiouAreVowels'), ['LETTERS', 'Aeiou', 'Are', 'Vowels']);
+ deepEqual(_.words('aeiouAreVowels'), ['aeiou', 'Are', 'Vowels']);
+ deepEqual(_.words('aeiou2Consonants'), ['aeiou', '2', 'Consonants']);
+
+ deepEqual(_.words('LETTERSÆiouAreVowels'), ['LETTERS', 'Æiou', 'Are', 'Vowels']);
+ deepEqual(_.words('æiouAreVowels'), ['æiou', 'Are', 'Vowels']);
+ deepEqual(_.words('æiou2Consonants'), ['æiou', '2', 'Consonants']);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
QUnit.module('lodash.wrap');
(function() {
@@ -8040,180 +13854,468 @@
return '<p>' + func(text) + '</p>';
});
- equal(p('Fred, Wilma, & Pebbles'), '<p>Fred, Wilma, & Pebbles</p>');
+ strictEqual(p('fred, barney, & pebbles'), '<p>fred, barney, & pebbles</p>');
+ });
+
+ test('should provide the correct `wrapper` arguments', 1, function() {
+ var args;
+
+ var wrapped = _.wrap(_.noop, function() {
+ args || (args = slice.call(arguments));
+ });
+
+ wrapped(1, 2, 3);
+ deepEqual(args, [_.noop, 1, 2, 3]);
+ });
+
+ test('should not set a `this` binding', 1, function() {
+ var p = _.wrap(_.escape, function(func) {
+ return '<p>' + func(this.text) + '</p>';
+ });
+
+ var object = { 'p': p, 'text': 'fred, barney, & pebbles' };
+ strictEqual(object.p(), '<p>fred, barney, & pebbles</p>');
+ });
+
+ test('should use `_.identity` when `wrapper` is nullish', 1, function() {
+ var values = [, null, undefined],
+ expected = _.map(values, _.constant('a'));
+
+ var actual = _.map(values, function(value, index) {
+ var wrapped = index ? _.wrap('a', value) : _.wrap('a');
+ return wrapped('b', 'c');
+ });
+
+ deepEqual(actual, expected);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.xor');
+
+ (function() {
+ var args = arguments;
+
+ test('should return the symmetric difference of the given arrays', 1, function() {
+ var actual = _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+ deepEqual(actual, [1, 4, 5]);
+ });
+
+ test('should return an array of unique values', 2, function() {
+ var actual = _.xor([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]);
+ deepEqual(actual, [1, 4, 5]);
+
+ actual = _.xor([1, 1]);
+ deepEqual(actual, [1]);
+ });
+
+ test('should return a new array when a single array is provided', 1, function() {
+ var array = [1];
+ notStrictEqual(_.xor(array), array);
+ });
+
+ test('should ignore individual secondary arguments', 1, function() {
+ var array = [0];
+ deepEqual(_.xor(array, 3, null, { '0': 1 }), array);
+ });
+
+ test('should ignore values that are not arrays or `arguments` objects', 3, function() {
+ var array = [1, 2];
+ deepEqual(_.xor(array, 3, null, { '0': 1 }), array);
+ deepEqual(_.xor(null, array, null, [2, 3]), [1, 3]);
+ deepEqual(_.xor(null, array, null, args), [3]);
+ });
+
+ test('should return a wrapped value when chaining', 2, function() {
+ if (!isNpm) {
+ var wrapped = _([1, 2, 3]).xor([5, 2, 1, 4]);
+ ok(wrapped instanceof _);
+ deepEqual(wrapped.value(), [3, 5, 4]);
+ }
+ else {
+ skipTest(2);
+ }
+ });
+
+ test('should work when in a lazy chain sequence before `first` or `last`', 1, function() {
+ if (!isNpm) {
+ var wrapped = _([1, 2]).slice().xor([2, 3]);
+
+ var actual = _.map(['first', 'last'], function(methodName) {
+ return wrapped[methodName]();
+ });
+
+ deepEqual(actual, [1, 3]);
+ }
+ else {
+ skipTest();
+ }
+ });
+ }(1, 2, 3));
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.unzip and lodash.zip');
+
+ _.each(['unzip', 'zip'], function(methodName, index) {
+ var func = _[methodName];
+ func = _.bind(index ? func.apply : func.call, func, null);
+
+ var object = {
+ 'an empty array': [
+ [],
+ []
+ ],
+ '0-tuples': [
+ [[], []],
+ []
+ ],
+ '2-tuples': [
+ [['barney', 'fred'], [36, 40]],
+ [['barney', 36], ['fred', 40]]
+ ],
+ '3-tuples': [
+ [['barney', 'fred'], [36, 40], [true, false]],
+ [['barney', 36, true], ['fred', 40, false]]
+ ]
+ };
+
+ _.forOwn(object, function(pair, key) {
+ test('`_.' + methodName + '` should work with ' + key, 2, function() {
+ var actual = func(pair[0]);
+ deepEqual(actual, pair[1]);
+ deepEqual(func(actual), actual.length ? pair[0] : []);
+ });
+ });
+
+ test('`_.' + methodName + '` should work with tuples of different lengths', 4, function() {
+ var pair = [
+ [['barney', 36], ['fred', 40, false]],
+ [['barney', 'fred'], [36, 40], [undefined, false]]
+ ];
+
+ var actual = func(pair[0]);
+ ok('0' in actual[2]);
+ deepEqual(actual, pair[1]);
+
+ actual = func(actual);
+ ok('2' in actual[0]);
+ deepEqual(actual, [['barney', 36, undefined], ['fred', 40, false]]);
+ });
+
+ test('`_.' + methodName + '` should treat falsey values as empty arrays', 1, function() {
+ var expected = _.map(falsey, _.constant([]));
+
+ var actual = _.map(falsey, function(value) {
+ return func([value, value, value]);
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('`_.' + methodName + '` should support consuming its return value', 1, function() {
+ var expected = [['barney', 'fred'], [36, 40]];
+ deepEqual(func(func(func(func(expected)))), expected);
+ });
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash.zipObject');
+
+ (function() {
+ var object = { 'barney': 36, 'fred': 40 },
+ array = [['barney', 36], ['fred', 40]];
+
+ test('should skip falsey elements in a given two dimensional array', 1, function() {
+ var actual = _.zipObject(array.concat(falsey));
+ deepEqual(actual, object);
+ });
+
+ test('should zip together key/value arrays into an object', 1, function() {
+ var actual = _.zipObject(['barney', 'fred'], [36, 40]);
+ deepEqual(actual, object);
+ });
+
+ test('should ignore extra `values`', 1, function() {
+ deepEqual(_.zipObject(['a'], [1, 2]), { 'a': 1 });
+ });
+
+ test('should accept a two dimensional array', 1, function() {
+ var actual = _.zipObject(array);
+ deepEqual(actual, object);
+ });
+
+ test('should not assume `keys` is two dimensional if `values` is not provided', 1, function() {
+ var actual = _.zipObject(['barney', 'fred']);
+ deepEqual(actual, { 'barney': undefined, 'fred': undefined });
+ });
+
+ test('should accept a falsey `array` argument', 1, function() {
+ var expected = _.map(falsey, _.constant({}));
+
+ var actual = _.map(falsey, function(value, index) {
+ try {
+ return index ? _.zipObject(value) : _.zipObject();
+ } catch(e) {}
+ });
+
+ deepEqual(actual, expected);
+ });
+
+ test('should support consuming the return value of `_.pairs`', 1, function() {
+ deepEqual(_.zipObject(_.pairs(object)), object);
+ });
+
+ test('should work in a lazy chain sequence', 1, function() {
+ if (!isNpm) {
+ var array = [['a', 1], ['b', 2]],
+ predicate = function(value) { return value > 1; },
+ actual = _(array).zipObject().map(String).filter(predicate).take().value();
+
+ deepEqual(actual, ['2']);
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ test('should be aliased', 1, function() {
+ strictEqual(_.object, _.zipObject);
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash(...).concat');
+
+ (function() {
+ test('should return a new wrapped array', 3, function() {
+ if (!isNpm) {
+ var array = [1],
+ wrapped = _(array).concat([2, 3]),
+ actual = wrapped.value();
+
+ notStrictEqual(actual, array);
+ deepEqual(actual, [1, 2, 3]);
+ deepEqual(array, [1]);
+ }
+ else {
+ skipTest(3);
+ }
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ QUnit.module('lodash(...).join');
+
+ (function() {
+ test('should return join all array elements into a string', 2, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3],
+ wrapped = _(array),
+ actual = wrapped.join('.');
+
+ strictEqual(actual, '1.2.3');
+ strictEqual(wrapped.value(), array);
+ }
+ else {
+ skipTest(2);
+ }
});
+ }());
- test('should pass the correct `wrapper` arguments', 1, function() {
- var args;
+ /*--------------------------------------------------------------------------*/
- var wrapped = _.wrap(noop, function() {
- args || (args = slice.call(arguments));
- });
+ QUnit.module('lodash(...).pop');
- wrapped(1, 2, 3);
- deepEqual(args, [noop, 1, 2, 3]);
- });
+ (function() {
+ test('should remove elements from the end of `array`', 5, function() {
+ if (!isNpm) {
+ var array = [1, 2],
+ wrapped = _(array);
- test('should not set a `this` binding', 1, function() {
- var p = _.wrap(_.escape, function(func) {
- return '<p>' + func(this.text) + '</p>';
- });
+ strictEqual(wrapped.pop(), 2);
+ deepEqual(wrapped.value(), [1]);
+ strictEqual(wrapped.pop(), 1);
- var object = { 'p': p, 'text': 'Fred, Wilma, & Pebbles' };
- equal(object.p(), '<p>Fred, Wilma, & Pebbles</p>');
+ var actual = wrapped.value();
+ strictEqual(actual, array);
+ deepEqual(actual, []);
+ }
+ else {
+ skipTest(5);
+ }
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.xor');
+ QUnit.module('lodash(...).push');
(function() {
- test('should return the symmetric difference of the given arrays', 1, function() {
- var actual = _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
- deepEqual(actual, [1, 4, 5]);
- });
-
- test('should return an array of unique values', 1, function() {
- var actual = _.xor([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]);
- deepEqual(actual, [1, 4, 5]);
- });
-
- test('should return a wrapped value when chaining', 2, function() {
+ test('should append elements to `array`', 2, function() {
if (!isNpm) {
- var actual = _([1, 2, 3]).xor([5, 2, 1, 4]);
- ok(actual instanceof _);
- deepEqual(actual.value(), [3, 5, 4]);
+ var array = [1],
+ wrapped = _(array).push(2, 3),
+ actual = wrapped.value();
+
+ strictEqual(actual, array);
+ deepEqual(actual, [1, 2, 3]);
}
else {
skipTest(2);
}
});
-
- test('should ignore individual secondary values', 1, function() {
- var array = [1, null, 3];
- deepEqual(_.xor(array, 3, null), array);
- });
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.zip');
+ QUnit.module('lodash(...).reverse');
(function() {
- var object = {
- 'an empty array': [
- [],
- []
- ],
- '0-tuples': [
- [[], []],
- []
- ],
- '2-tuples': [
- [['barney', 'fred'], [36, 40]],
- [['barney', 36], ['fred', 40]]
- ],
- '3-tuples': [
- [['barney', 'fred'], [36, 40], [true, false]],
- [['barney', 36, true], ['fred', 40, false]]
- ]
- };
+ test('should return the wrapped reversed `array`', 3, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3],
+ wrapped = _(array).reverse(),
+ actual = wrapped.value();
- _.forOwn(object, function(pair, key) {
- test('should work with ' + key, 2, function() {
- var actual = _.zip.apply(_, pair[0]);
- deepEqual(actual, pair[1]);
- deepEqual(_.zip.apply(_, actual), actual.length ? pair[0] : []);
- });
+ ok(wrapped instanceof _);
+ strictEqual(actual, array);
+ deepEqual(actual, [3, 2, 1]);
+ }
+ else {
+ skipTest(3);
+ }
});
- test('should work with tuples of different lengths', 4, function() {
- var pair = [
- [['barney', 36], ['fred', 40, false]],
- [['barney', 'fred'], [36, 40], [undefined, false]]
- ];
+ test('should be lazy when in a lazy chain sequence', 2, function() {
+ if (!isNpm) {
+ var spy = {
+ 'toString': function() {
+ throw new Error('Spy was revealed');
+ }
+ };
- var actual = _.zip(pair[0]);
- ok(0 in actual[2]);
- deepEqual(actual, pair[1]);
+ try {
+ var wrapped = _(['a', spy]).map(String).reverse(),
+ actual = wrapped.last();
+ } catch(e) {}
- actual = _.zip.apply(_, actual);
- ok(2 in actual[0]);
- deepEqual(actual, [['barney', 36, undefined], ['fred', 40, false]]);
+ ok(wrapped instanceof _);
+ strictEqual(actual, 'a');
+ }
+ else {
+ skipTest(2);
+ }
});
+ }());
- test('should support consuming it\'s return value', 1, function() {
- var expected = [['barney', 'fred'], [36, 40]];
- deepEqual(_.zip(_.zip(_.zip(_.zip(expected)))), expected);
- });
+ /*--------------------------------------------------------------------------*/
- test('should be aliased', 1, function() {
- strictEqual(_.unzip, _.zip);
+ QUnit.module('lodash(...).shift');
+
+ (function() {
+ test('should remove elements from the front of `array`', 5, function() {
+ if (!isNpm) {
+ var array = [1, 2],
+ wrapped = _(array);
+
+ strictEqual(wrapped.shift(), 1);
+ deepEqual(wrapped.value(), [2]);
+ strictEqual(wrapped.shift(), 2);
+
+ var actual = wrapped.value();
+ strictEqual(actual, array);
+ deepEqual(actual, []);
+ }
+ else {
+ skipTest(5);
+ }
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash.zipObject');
+ QUnit.module('lodash(...).slice');
(function() {
- var object = { 'barney': 36, 'fred': 40 },
- array = [['barney', 36], ['fred', 40]];
+ test('should return a slice of `array`', 3, function() {
+ if (!isNpm) {
+ var array = [1, 2, 3],
+ wrapped = _(array).slice(0, 2),
+ actual = wrapped.value();
- test('should skip falsey elements in a given two dimensional array', 1, function() {
- var actual = _.zipObject(array.concat(falsey));
- deepEqual(actual, object);
+ notStrictEqual(actual, array);
+ deepEqual(actual, [1, 2]);
+ deepEqual(array, [1, 2, 3]);
+ }
+ else {
+ skipTest(3);
+ }
});
+ }());
- test('should zip together key/value arrays into an object', 1, function() {
- var actual = _.zipObject(['barney', 'fred'], [36, 40]);
- deepEqual(actual, object);
- });
+ /*--------------------------------------------------------------------------*/
- test('should accept a two dimensional array', 1, function() {
- var actual = _.zipObject(array);
- deepEqual(actual, object);
- });
+ QUnit.module('lodash(...).sort');
- test('should not assume `keys` is two dimensional if `values` is not provided', 1, function() {
- var actual = _.zipObject(['barney', 'fred']);
- deepEqual(actual, { 'barney': undefined, 'fred': undefined });
+ (function() {
+ test('should return the wrapped sorted `array`', 2, function() {
+ if (!isNpm) {
+ var array = [3, 1, 2],
+ wrapped = _(array).sort(),
+ actual = wrapped.value();
+
+ strictEqual(actual, array);
+ deepEqual(actual, [1, 2, 3]);
+ }
+ else {
+ skipTest(2);
+ }
});
+ }());
- test('should accept a falsey `array` argument', 1, function() {
- var expected = _.map(falsey, function() { return {}; });
+ /*--------------------------------------------------------------------------*/
- var actual = _.map(falsey, function(value, index) {
- try {
- return index ? _.zipObject(value) : _.zipObject();
- } catch(e) { }
- });
+ QUnit.module('lodash(...).splice');
- deepEqual(actual, expected);
- });
+ (function() {
+ test('should support removing and inserting elements', 5, function() {
+ if (!isNpm) {
+ var array = [1, 2],
+ wrapped = _(array);
- test('should support consuming the return value of `_.pairs`', 1, function() {
- deepEqual(_.zipObject(_.pairs(object)), object);
- });
+ deepEqual(wrapped.splice(1, 1, 3).value(), [2]);
+ deepEqual(wrapped.value(), [1, 3]);
- test('should be aliased', 1, function() {
- strictEqual(_.object, _.zipObject);
+ deepEqual(wrapped.splice(0, 2).value(), [1, 3]);
+
+ var actual = wrapped.value();
+ strictEqual(actual, array);
+ deepEqual(actual, []);
+ }
+ else {
+ skipTest(5);
+ }
});
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash(...).shift');
+ QUnit.module('lodash(...).unshift');
(function() {
- test('should remove the value at index `0` when length is `0` (test in IE 8 compatibility mode)', 2, function() {
+ test('should prepend elements to `array`', 2, function() {
if (!isNpm) {
- var wrapped = _({ '0': 1, 'length': 1 });
- wrapped.shift();
+ var array = [3],
+ wrapped = _(array).unshift(1, 2),
+ actual = wrapped.value();
- deepEqual(wrapped.keys().value(), ['length']);
- equal(wrapped.first(), undefined);
+ strictEqual(actual, array);
+ deepEqual(actual, [1, 2, 3]);
}
else {
skipTest(2);
@@ -8223,22 +14325,25 @@
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash(...).splice');
+ QUnit.module('splice objects');
- (function() {
- test('should remove the value at index `0` when length is `0` (test in IE < 9, and in compatibility mode for IE9)', 2, function() {
+ _.each(['pop', 'shift', 'splice'], function(methodName) {
+ test('`_(...).' + methodName + '` should remove the value at index `0` when length is `0` (test in IE 8 compatibility mode)', 2, function() {
if (!isNpm) {
var wrapped = _({ '0': 1, 'length': 1 });
- wrapped.splice(0, 1);
-
+ if (methodName == 'splice') {
+ wrapped.splice(0, 1).value();
+ } else {
+ wrapped[methodName]();
+ }
deepEqual(wrapped.keys().value(), ['length']);
- equal(wrapped.first(), undefined);
+ strictEqual(wrapped.first(), undefined);
}
else {
skipTest(2);
}
});
- }());
+ });
/*--------------------------------------------------------------------------*/
@@ -8248,7 +14353,7 @@
test('should return the `toString` result of the wrapped value', 1, function() {
if (!isNpm) {
var wrapped = _([1, 2, 3]);
- equal(String(wrapped), '1,2,3');
+ strictEqual(String(wrapped), '1,2,3');
}
else {
skipTest();
@@ -8264,22 +14369,40 @@
test('should return the `valueOf` result of the wrapped value', 1, function() {
if (!isNpm) {
var wrapped = _(123);
- equal(Number(wrapped), 123);
+ strictEqual(Number(wrapped), 123);
+ }
+ else {
+ skipTest();
+ }
+ });
+
+ test('should stringify the wrapped value when used by `JSON.stringify`', 1, function() {
+ if (!isNpm && JSON) {
+ var wrapped = _([1, 2, 3]);
+ strictEqual(JSON.stringify(wrapped), '[1,2,3]');
}
else {
skipTest();
}
});
+
+ test('should be aliased', 2, function() {
+ if (!isNpm) {
+ var expected = _.prototype.valueOf;
+ strictEqual(_.prototype.toJSON, expected);
+ strictEqual(_.prototype.value, expected);
+ }
+ else {
+ skipTest(2);
+ }
+ });
}());
/*--------------------------------------------------------------------------*/
- QUnit.module('lodash(...) methods that return existing wrapped values');
+ QUnit.module('lodash(...) methods that return the wrapped modified array');
(function() {
- var array = [1, 2, 3],
- wrapped = _(array);
-
var funcs = [
'push',
'reverse',
@@ -8287,13 +14410,18 @@
'unshift'
];
- _.forEach(funcs, function(methodName) {
- test('`_(...).' + methodName + '` should return the existing wrapped value', 1, function() {
+ _.each(funcs, function(methodName) {
+ test('`_(...).' + methodName + '` should return a new wrapper', 2, function() {
if (!isNpm) {
- strictEqual(wrapped[methodName](), wrapped);
+ var array = [1, 2, 3],
+ wrapped = _(array),
+ actual = wrapped[methodName]();
+
+ ok(actual instanceof _);
+ notStrictEqual(actual, wrapped);
}
else {
- skipTest();
+ skipTest(2);
}
});
});
@@ -8304,22 +14432,24 @@
QUnit.module('lodash(...) methods that return new wrapped values');
(function() {
- var array = [1, 2, 3],
- wrapped = _(array);
-
var funcs = [
'concat',
'slice',
'splice'
];
- _.forEach(funcs, function(methodName) {
- test('`_(...).' + methodName + '` should return a new wrapped value', 1, function() {
+ _.each(funcs, function(methodName) {
+ test('`_(...).' + methodName + '` should return a new wrapped value', 2, function() {
if (!isNpm) {
- ok(wrapped[methodName]() instanceof _);
+ var array = [1, 2, 3],
+ wrapped = _(array),
+ actual = wrapped[methodName]();
+
+ ok(actual instanceof _);
+ notStrictEqual(actual, wrapped);
}
else {
- skipTest();
+ skipTest(2);
}
});
});
@@ -8330,9 +14460,6 @@
QUnit.module('lodash(...) methods that return unwrapped values');
(function() {
- var array = [1, 2, 3],
- wrapped = _(array);
-
var funcs = [
'clone',
'contains',
@@ -8347,6 +14474,7 @@
'isElement',
'isEmpty',
'isEqual',
+ 'isError',
'isFinite',
'isFunction',
'isNaN',
@@ -8359,93 +14487,36 @@
'isUndefined',
'join',
'last',
+ 'max',
+ 'min',
+ 'parseInt',
'pop',
'shift',
+ 'random',
'reduce',
'reduceRight',
'some'
];
- _.forEach(funcs, function(methodName) {
- test('`_(...).' + methodName + '` should return an unwrapped value', 1, function() {
- if (!isNpm) {
- var actual = methodName == 'reduceRight'
- ? wrapped[methodName](_.identity)
- : wrapped[methodName]();
-
- equal(actual instanceof _, false);
- }
- else {
- skipTest();
- }
- });
- });
- }());
-
- /*--------------------------------------------------------------------------*/
-
- QUnit.module('lodash(...) methods capable of returning wrapped and unwrapped values');
-
- (function() {
- var array = [1, 2, 3],
- wrapped = _(array);
-
- var funcs = [
- 'first',
- 'last',
- 'sample'
- ];
-
- _.forEach(funcs, function(methodName) {
- test('`_(...).' + methodName + '` called without an `n` argument should return an unwrapped value', 1, function() {
- if (!isNpm) {
- equal(typeof wrapped[methodName](), 'number');
- }
- else {
- skipTest();
- }
- });
-
- test('`_(...).' + methodName + '` called with an `n` argument should return a wrapped value', 1, function() {
- if (!isNpm) {
- ok(wrapped[methodName](1) instanceof _);
- }
- else {
- skipTest();
- }
- });
-
- test('`_.' + methodName + '` should return `undefined` when querying falsey arguments without an `n` argument', 1, function() {
+ _.each(funcs, function(methodName) {
+ test('`_(...).' + methodName + '` should return an unwrapped value when intuitively chaining', 1, function() {
if (!isNpm) {
- var actual = [],
- expected = _.map(falsey, function() { return undefined; }),
- func = _[methodName];
-
- _.forEach(falsey, function(value, index) {
- try {
- actual.push(index ? func(value) : func());
- } catch(e) { }
- });
+ var array = [1, 2, 3],
+ actual = _(array)[methodName]();
- deepEqual(actual, expected);
+ ok(!(actual instanceof _));
}
else {
skipTest();
}
});
- test('`_.' + methodName + '` should return an empty array when querying falsey arguments with an `n` argument', 1, function() {
+ test('`_(...).' + methodName + '` should return a wrapped value when explicitly chaining', 1, function() {
if (!isNpm) {
- var expected = _.map(falsey, function() { return []; }),
- func = _[methodName];
-
- var actual = _.map(falsey, function(value, index) {
- try {
- return func(value, 2);
- } catch(e) { }
- });
+ var array = [1, 2, 3],
+ actual = _(array).chain()[methodName]();
- deepEqual(actual, expected);
+ ok(actual instanceof _);
}
else {
skipTest();
@@ -8462,14 +14533,11 @@
var args = arguments,
array = [1, 2, 3, 4, 5, 6];
- test('should work with `arguments` objects', 23, function() {
+ test('should work with `arguments` objects', 29, function() {
function message(methodName) {
return '`_.' + methodName + '` should work with `arguments` objects';
}
- deepEqual(_.at(args, 0, 4), [1, 5], message('at'));
- deepEqual(_.at(array, args), [2, undefined, 4, undefined, 6], '_.at should work with `arguments` objects as secondary arguments');
-
deepEqual(_.difference(args, [null]), [1, [3], 5], message('difference'));
deepEqual(_.difference(array, args), [2, 3, 4, 6], '_.difference should work with `arguments` objects as secondary arguments');
@@ -8477,41 +14545,50 @@
deepEqual(_.union(array, args), array.concat([null, [3]]), '_.union should work with `arguments` objects as secondary arguments');
deepEqual(_.compact(args), [1, [3], 5], message('compact'));
+ deepEqual(_.drop(args, 3), [null, 5], message('drop'));
+ deepEqual(_.dropRight(args, 3), [1, null], message('dropRight'));
+ deepEqual(_.dropRightWhile(args,_.identity), [1, null, [3], null], message('dropRightWhile'));
+ deepEqual(_.dropWhile(args,_.identity), [ null, [3], null, 5], message('dropWhile'));
deepEqual(_.findIndex(args, _.identity), 0, message('findIndex'));
deepEqual(_.findLastIndex(args, _.identity), 4, message('findLastIndex'));
deepEqual(_.first(args), 1, message('first'));
deepEqual(_.flatten(args), [1, null, 3, null, 5], message('flatten'));
deepEqual(_.indexOf(args, 5), 4, message('indexOf'));
- deepEqual(_.initial(args, 4), [1], message('initial'));
+ deepEqual(_.initial(args), [1, null, [3], null], message('initial'));
deepEqual(_.intersection(args, [1]), [1], message('intersection'));
deepEqual(_.last(args), 5, message('last'));
deepEqual(_.lastIndexOf(args, 1), 0, message('lastIndexOf'));
- deepEqual(_.rest(args, 4), [5], message('rest'));
+ deepEqual(_.rest(args, 4), [null, [3], null, 5], message('rest'));
deepEqual(_.sortedIndex(args, 6), 5, message('sortedIndex'));
+ deepEqual(_.take(args, 2), [1, null], message('take'));
+ deepEqual(_.takeRight(args, 1), [5], message('takeRight'));
+ deepEqual(_.takeRightWhile(args, _.identity), [5], message('takeRightWhile'));
+ deepEqual(_.takeWhile(args, _.identity), [1], message('takeWhile'));
deepEqual(_.uniq(args), [1, null, [3], 5], message('uniq'));
deepEqual(_.without(args, null), [1, [3], 5], message('without'));
deepEqual(_.zip(args, args), [[1, 1], [null, null], [[3], [3]], [null, null], [5, 5]], message('zip'));
- if (_.support.argsClass && _.support.argsObject && !_.support.nonEnumArgs) {
+ if (_.support.argsTag && _.support.argsObject && !_.support.nonEnumArgs) {
_.pull(args, null);
deepEqual([args[0], args[1], args[2]], [1, [3], 5], message('pull'));
_.remove(args, function(value) { return typeof value == 'number'; });
- ok(args.length == 1 && _.isEqual(args[0], [3]), message('remove'));
+ ok(args.length === 1 && _.isEqual(args[0], [3]), message('remove'));
}
else {
- skipTest(2)
+ skipTest(2);
}
});
- test('should accept falsey primary arguments', 3, function() {
+ test('should accept falsey primary arguments', 4, function() {
function message(methodName) {
return '`_.' + methodName + '` should accept falsey primary arguments';
}
- deepEqual(_.difference(null, array), [], message('difference'));
- deepEqual(_.intersection(null, array), [], message('intersection'));
+ deepEqual(_.difference(null, array), array, message('difference'));
+ deepEqual(_.intersection(null, array), array, message('intersection'));
deepEqual(_.union(null, array), array, message('union'));
+ deepEqual(_.xor(null, array), array, message('xor'));
});
test('should accept falsey secondary arguments', 3, function() {
@@ -8520,24 +14597,60 @@
}
deepEqual(_.difference(array, null), array, message('difference'));
- deepEqual(_.intersection(array, null), [], message('intersection'));
+ deepEqual(_.intersection(array, null), array, message('intersection'));
deepEqual(_.union(array, null), array, message('union'));
});
}(1, null, [3], null, 5));
/*--------------------------------------------------------------------------*/
+ QUnit.module('"Strings" category methods');
+
+ (function() {
+ var stringMethods = [
+ 'camelCase',
+ 'capitalize',
+ 'escape',
+ 'escapeRegExp',
+ 'kebabCase',
+ 'pad',
+ 'padLeft',
+ 'padRight',
+ 'repeat',
+ 'snakeCase',
+ 'trim',
+ 'trimLeft',
+ 'trimRight',
+ 'trunc',
+ 'unescape'
+ ];
+
+ _.each(stringMethods, function(methodName) {
+ var func = _[methodName];
+
+ test('`_.' + methodName + '` should return an empty string when provided `null`, `undefined`, or empty string', 3, function() {
+ strictEqual(func(null), '');
+ strictEqual(func(undefined), '');
+ strictEqual(func(''), '');
+ });
+ });
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
QUnit.module('lodash methods');
(function() {
- var allMethods = _.reject(_.functions(_), function(methodName) {
- return /^_/.test(methodName);
+ var allMethods = _.reject(_.functions(_).sort(), function(methodName) {
+ return _.startsWith(methodName, '_');
});
var returnArrays = [
'at',
+ 'chunk',
'compact',
'difference',
+ 'drop',
'filter',
'flatten',
'functions',
@@ -8548,11 +14661,17 @@
'map',
'pairs',
'pluck',
+ 'pull',
+ 'pullAt',
'range',
'reject',
+ 'remove',
'rest',
+ 'sample',
'shuffle',
'sortBy',
+ 'sortByAll',
+ 'take',
'times',
'toArray',
'union',
@@ -8566,30 +14685,38 @@
var rejectFalsey = [
'after',
+ 'ary',
+ 'backflow',
+ 'before',
'bind',
'compose',
'curry',
+ 'curryRight',
'debounce',
'defer',
'delay',
+ 'flow',
+ 'flowRight',
'memoize',
+ 'negate',
'once',
'partial',
'partialRight',
+ 'rearg',
'tap',
'throttle',
- 'wrap'
+ 'thru'
];
var acceptFalsey = _.difference(allMethods, rejectFalsey);
- test('should accept falsey arguments', 155, function() {
- var isExported = '_' in root,
+ test('should accept falsey arguments', 205, function() {
+ var emptyArrays = _.map(falsey, _.constant([])),
+ isExposed = '_' in root,
oldDash = root._;
-
- _.forEach(acceptFalsey, function(methodName) {
- var expected = _.map(falsey, function() { return []; }),
+ _.each(acceptFalsey, function(methodName) {
+ var expected = emptyArrays,
func = _[methodName],
pass = true;
@@ -8602,33 +14729,61 @@
});
if (methodName == 'noConflict') {
- if (isExported) {
+ if (isExposed) {
root._ = oldDash;
} else {
delete root._;
}
}
- if (_.indexOf(returnArrays, methodName) > -1) {
+ else if (methodName == 'pull') {
+ expected = falsey;
+ }
+ if (_.includes(returnArrays, methodName) && methodName != 'sample') {
deepEqual(actual, expected, '_.' + methodName + ' returns an array');
}
ok(pass, '`_.' + methodName + '` accepts falsey arguments');
});
- // skip tests for missing methods of modularized builds
- _.forEach(['noConflict', 'runInContext', 'tap'], function(methodName) {
+ // Skip tests for missing methods of modularized builds.
+ _.each(['chain', 'noConflict', 'runInContext'], function(methodName) {
if (!_[methodName]) {
skipTest();
}
});
});
- test('should reject falsey arguments', 14, function() {
- _.forEach(rejectFalsey, function(methodName) {
- var expected = _.map(falsey, function() { return true; }),
+ test('should return an array', 70, function() {
+ var array = [1, 2, 3];
+
+ _.each(returnArrays, function(methodName) {
+ var actual,
+ func = _[methodName];
+
+ switch (methodName) {
+ case 'invoke':
+ actual = func(array, 'toFixed');
+ break;
+ case 'sample':
+ actual = func(array, 1);
+ break;
+ default:
+ actual = func(array);
+ }
+ ok(_.isArray(actual), '_.' + methodName + ' returns an array');
+
+ var isPull = methodName == 'pull';
+ strictEqual(actual === array, isPull, '_.' + methodName + ' should ' + (isPull ? '' : 'not ') + 'return the provided array');
+ });
+ });
+
+ test('should throw an error for falsey arguments', 22, function() {
+ _.each(rejectFalsey, function(methodName) {
+ var expected = _.map(falsey, _.constant(true)),
func = _[methodName];
var actual = _.map(falsey, function(value, index) {
- var pass = !index && methodName == 'compose';
+ var pass = !index && /^(?:backflow|compose|flow(Right)?)$/.test(methodName);
+
try {
index ? func(value) : func();
} catch(e) {
@@ -8641,13 +14796,16 @@
});
});
- test('should handle `null` `thisArg` arguments', 30, function() {
- var thisArg,
- callback = function() { thisArg = this; },
- expected = (function() { return this; }).call(null);
+ test('should handle `null` `thisArg` arguments', 44, function() {
+ var expected = (function() { return this; }).call(null);
var funcs = [
+ 'assign',
+ 'clone',
+ 'cloneDeep',
'countBy',
+ 'dropWhile',
+ 'dropRightWhile',
'every',
'filter',
'find',
@@ -8663,10 +14821,14 @@
'forOwn',
'forOwnRight',
'groupBy',
+ 'isEqual',
'map',
+ 'mapValues',
'max',
+ 'merge',
'min',
'omit',
+ 'partition',
'pick',
'reduce',
'reduceRight',
@@ -8675,38 +14837,45 @@
'some',
'sortBy',
'sortedIndex',
+ 'takeWhile',
+ 'takeRightWhile',
+ 'tap',
'times',
+ 'transform',
+ 'thru',
'uniq'
];
- _.forEach(funcs, function(methodName) {
- var array = ['a'],
+ _.each(funcs, function(methodName) {
+ var actual,
+ array = ['a'],
+ callback = function() { actual = this; },
func = _[methodName],
message = '`_.' + methodName + '` handles `null` `thisArg` arguments';
- thisArg = undefined;
-
- if (/^reduce/.test(methodName)) {
- func(array, callback, 0, null);
- } else if (methodName == 'sortedIndex') {
- func(array, 'a', callback, null);
- } else if (methodName == 'times') {
- func(1, callback, null);
- } else {
- func(array, callback, null);
+ if (func) {
+ if (_.startsWith(methodName, 'reduce') || methodName == 'transform') {
+ func(array, callback, 0, null);
+ } else if (_.includes(['assign', 'merge'], methodName)) {
+ func(array, array, callback, null);
+ } else if (_.includes(['isEqual', 'sortedIndex'], methodName)) {
+ func(array, 'a', callback, null);
+ } else if (methodName == 'times') {
+ func(1, callback, null);
+ } else {
+ func(array, callback, null);
+ }
+ strictEqual(actual, expected, message);
}
-
- if (expected === null) {
- strictEqual(thisArg, null, message);
- } else {
- equal(thisArg, expected, message);
+ else {
+ skipTest();
}
});
});
test('should not contain minified method names (test production builds)', 1, function() {
ok(_.every(_.functions(_), function(methodName) {
- return methodName.length > 2 || methodName == 'at';
+ return methodName.length > 2 || methodName === 'at';
}));
});
}());
@@ -8715,8 +14884,15 @@
QUnit.config.asyncRetries = 10;
- if (!document) {
+ if (document) {
+ QUnit.begin(function() {
+ QUnit.config.hidepassed = true;
+ document.getElementById('qunit-tests').className += ' hidepass';
+ document.getElementById('qunit-urlconfig-hidepassed').checked = true;
+ });
+ } else {
+ QUnit.config.hidepassed = true;
QUnit.config.noglobals = true;
- QUnit.start();
+ QUnit.load();
}
-}(typeof global == 'object' && global || this));
+}.call(this));
diff --git a/test/underscore.html b/test/underscore.html
index 8ae1606..c483ec6 100644
--- a/test/underscore.html
+++ b/test/underscore.html
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>Underscore Test Suite</title>
- <link rel="stylesheet" href="../vendor/qunit/qunit/qunit.css">
+ <link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
<style>
iframe {
display: none;
@@ -19,20 +19,72 @@
</div>
<img id="chart_image" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==">
</div>
- <script src="../vendor/qunit/qunit/qunit.js"></script>
- <script src="../vendor/qunit-extras/qunit-extras.js"></script>
- <script src="../vendor/jquery/jquery.js"></script>
- <script src="../vendor/platform.js/platform.js"></script>
+ <script>
+ // avoid reporting tests to Sauce Labs when script errors occur
+ if (location.port == '9001') {
+ window.onerror = function(message) {
+ if (window.QUnit) {
+ QUnit.config.done.length = 0;
+ }
+ global_test_results = { 'message': message };
+ };
+ }
+ </script>
+ <script src="../node_modules/qunitjs/qunit/qunit.js"></script>
+ <script src="../node_modules/qunit-extras/qunit-extras.js"></script>
+ <script src="../node_modules/jquery/dist/jquery.js"></script>
+ <script src="../node_modules/platform/platform.js"></script>
<script src="./asset/test-ui.js"></script>
<script>
QUnit.config.asyncRetries = 10;
- QUnit.config.hidepassed = true;
+
+ QUnit.begin(function() {
+ QUnit.config.hidepassed = true;
+ $('#qunit-tests').addClass('hidepass');
+ $('#qunit-urlconfig-hidepassed').prop('checked', true);
+ });
// excuse tests we intentionally fail or those with problems
QUnit.config.excused = {
'Arrays': {
- 'union': [
- '[null,1,2,3]'
+ 'drop': [
+ 'alias for rest'
+ ],
+ 'first': [
+ 'can pass an index to first',
+ '[1,2]',
+ '0'
+ ],
+ 'flatten': [
+ 'can flatten nested arrays',
+ 'can shallowly flatten nested arrays',
+ 'works on an arguments object',
+ 'can shallowly flatten arrays containing only other arrays'
+ ],
+ 'initial': [
+ 'initial can take an index',
+ 'initial can take a large index',
+ 'initial works on arguments object'
+ ],
+ 'intersection': [
+ 'can perform an OO-style intersection',
+ 'returns an empty array when passed null as first argument',
+ 'returns an empty array when passed null as argument beyond the first'
+ ],
+ 'last': [
+ 'can pass an index to last',
+ '0'
+ ],
+ 'lastIndexOf': [
+ '[0,-1,-1]'
+ ],
+ 'rest': [
+ 'working rest(0)',
+ 'rest can take an index',
+ 'works on arguments object'
+ ],
+ 'take': [
+ 'alias for first'
]
},
'Chaining': {
@@ -43,10 +95,16 @@
'Died on test #1'
],
'reverse/concat/unshift/pop/map': [
- '"34, 10, 8, 6, 4, 2, 10, 10"'
+ 'can chain together array functions.'
]
},
'Collections': {
+ 'filter': [
+ 'OO-filter'
+ ],
+ 'map': [
+ 'OO-style doubled numbers'
+ ],
'reduce': [
'handles a null (without initial value) properly',
'throws an error for empty arrays with no initial value'
@@ -54,9 +112,6 @@
'reduceRight': [
'handles a null (without initial value) properly',
'throws an error for empty arrays with no initial value'
- ],
- 'where': [
- 'Only get the first object matched.'
]
},
'Functions': {
@@ -67,6 +122,10 @@
'bindAll': [
'throws an error for bindAll with no functions named'
],
+ 'memoize': [
+ '{"bar":"BAR","foo":"FOO"}',
+ 'Died on test #8'
+ ],
'throttle repeatedly with results': true,
'more throttle does not trigger leading call when leading is set to false': true,
'throttle does not trigger trailing call when trailing is set to false': true,
@@ -77,23 +136,29 @@
'Died on test #60',
'Died on test #63'
],
+ 'isFinite': [
+ 'Numeric strings are numbers',
+ 'Number instances can be finite'
+ ],
'keys': [
- 'throws an error for `null` values',
- 'throws an error for `undefined` values',
- 'throws an error for number primitives',
- 'throws an error for string primitives',
- 'throws an error for boolean primitives'
+ 'is not fooled by sparse arrays; see issue #95',
+ '[]'
+ ],
+ 'matches': [
+ 'inherited and own properties are checked on the test object',
+ 'doesnt fasley match constructor on undefined/null'
]
},
'Utility': {
- '_.escape': [
- '"<a href="http://moe.com">Curly & Moe's</a>"'
+ 'now': [
+ 'Produces the correct time in milliseconds'
],
- '_.unescape': [
- '"<a href=\\"http://moe.com\\">Curly & Moe's</a>"'
+ '_.templateSettings.variable': [
+ '"x"'
],
'times': [
- 'Died on test #1'
+ 'Died on test #1',
+ 'works as a wrapper'
],
'uniqueId': [
'Died on test #1'
@@ -102,7 +167,8 @@
};
// only excuse in Sauce Labs (buggy Safari and timers)
- if (location.port != '9001') {
+ if (!ui.isSauceLabs) {
+ QUnit.config.excused.Utility.times.shift();
delete QUnit.config.excused.Chaining['select/reject/sortBy'];
delete QUnit.config.excused.Chaining['select/reject/sortBy in functional style'];
delete QUnit.config.excused.Functions['throttle repeatedly with results'];
@@ -110,24 +176,9 @@
delete QUnit.config.excused.Functions['throttle does not trigger trailing call when trailing is set to false'];
delete QUnit.config.excused.Functions['debounce asap'];
delete QUnit.config.excused.Objects.isEqual;
- delete QUnit.config.excused.Utility.times;
delete QUnit.config.excused.Utility.uniqueId;
}
- // only excuse in non-Underscore builds
- if (/\bunderscore\b/i.test(ui.buildPath)) {
- delete QUnit.config.excused.Chaining;
- delete QUnit.config.excused.Collections.where;
- delete QUnit.config.excused.Utility['_.escape'];
- delete QUnit.config.excused.Utility['_.unescape'];
- }
-
- // assign results to `global_test_results` for Sauce Labs
- var global_test_results;
- QUnit.done(function(results) {
- global_test_results = results;
- });
-
- // load Lo-Dash and test scripts
+ // load test scripts
document.write(ui.urlParams.loader != 'none'
? '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>'
: ([
@@ -150,24 +201,20 @@
return;
}
var reBasename = /[\w.-]+$/,
- basePath = ('//' + location.host + location.pathname).replace(/\btest\/$/, ''),
+ basePath = ('//' + location.host + location.pathname.replace(reBasename, '')).replace(/\btest\/$/, ''),
modulePath = ui.buildPath.replace(/\.js$/, ''),
- locationPath = modulePath.replace(reBasename, ''),
- moduleMain = modulePath.match(reBasename)[0];
+ locationPath = modulePath.replace(reBasename, '').replace(/^\/|\/$/g, ''),
+ moduleId = /\bunderscore\b/i.test(ui.buildPath) ? 'underscore' : 'lodash',
+ moduleMain = modulePath.match(reBasename)[0],
+ uid = +new Date;
- QUnit.config.autostart = false;
-
- // load Lo-Dash as a module
- require({
- 'baseUrl': './',
- 'urlArgs': 't=' + (+new Date),
- 'packages': [
- {
- 'name': 'lodash',
- 'location': locationPath,
- 'main': moduleMain
- },
- {
+ function getConfig() {
+ var result = {
+ 'baseUrl': './',
+ 'urlArgs': 't=' + uid++,
+ 'waitSeconds': 0,
+ 'paths': {},
+ 'packages': [{
'name': 'test',
'location': '../vendor/underscore/test',
'config': {
@@ -175,14 +222,28 @@
'exports': 'QUnit',
'loader': 'curl/loader/legacy'
}
- }
- ]
- },
- ['lodash'], function(lodash) {
+ }]
+ };
+
+ if (ui.isModularize) {
+ result.packages.push({
+ 'name': moduleId,
+ 'location': locationPath,
+ 'main': moduleMain
+ });
+ } else {
+ result.paths[moduleId] = modulePath;
+ }
+ return result;
+ }
+
+ QUnit.config.autostart = false;
+
+ require(getConfig(), [moduleId], function(lodash) {
if (ui.isModularize) {
window._ = lodash;
}
- require([
+ require(getConfig(), [
'test/collections',
'test/arrays',
'test/functions',
diff --git a/vendor/backbone/LICENSE b/vendor/backbone/LICENSE
index dda0a58..3ffd97d 100644
--- a/vendor/backbone/LICENSE
+++ b/vendor/backbone/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2010-2013 Jeremy Ashkenas, DocumentCloud
+Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
diff --git a/vendor/backbone/backbone.js b/vendor/backbone/backbone.js
index f7783c2..24a550a 100644
--- a/vendor/backbone/backbone.js
+++ b/vendor/backbone/backbone.js
@@ -1,20 +1,35 @@
-// Backbone.js 1.1.0
+// Backbone.js 1.1.2
-// (c) 2010-2011 Jeremy Ashkenas, DocumentCloud Inc.
-// (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Backbone may be freely distributed under the MIT license.
// For all details and documentation:
// http://backbonejs.org
-(function(){
+(function(root, factory) {
+
+ // Set up Backbone appropriately for the environment. Start with AMD.
+ if (typeof define === 'function' && define.amd) {
+ define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
+ // Export global even in AMD case in case this script is loaded with
+ // others that may still expect a global Backbone.
+ root.Backbone = factory(root, exports, _, $);
+ });
+
+ // Next for Node.js or CommonJS. jQuery may not be needed as a module.
+ } else if (typeof exports !== 'undefined') {
+ var _ = require('underscore');
+ factory(root, exports, _);
+
+ // Finally, as a browser global.
+ } else {
+ root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
+ }
+
+}(this, function(root, Backbone, _, $) {
// Initial Setup
// -------------
- // Save a reference to the global object (`window` in the browser, `exports`
- // on the server).
- var root = this;
-
// Save the previous value of the `Backbone` variable, so that it can be
// restored later on, if `noConflict` is used.
var previousBackbone = root.Backbone;
@@ -25,25 +40,12 @@
var slice = array.slice;
var splice = array.splice;
- // The top-level namespace. All public Backbone classes and modules will
- // be attached to this. Exported for both the browser and the server.
- var Backbone;
- if (typeof exports !== 'undefined') {
- Backbone = exports;
- } else {
- Backbone = root.Backbone = {};
- }
-
// Current version of the library. Keep in sync with `package.json`.
- Backbone.VERSION = '1.1.0';
-
- // Require Underscore, if we're on the server, and it's not already present.
- var _ = root._;
- if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
+ Backbone.VERSION = '1.1.2';
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
// the `$` variable.
- Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
+ Backbone.$ = $;
// Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
// to its previous owner. Returns a reference to this Backbone object.
@@ -109,7 +111,7 @@
var retain, ev, events, names, i, l, j, k;
if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
if (!name && !callback && !context) {
- this._events = {};
+ this._events = void 0;
return this;
}
names = name ? [name] : _.keys(this._events);
@@ -205,7 +207,7 @@
case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
- default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
+ default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
}
};
@@ -350,7 +352,7 @@
// Trigger all relevant attribute changes.
if (!silent) {
- if (changes.length) this._pending = true;
+ if (changes.length) this._pending = options;
for (var i = 0, l = changes.length; i < l; i++) {
this.trigger('change:' + changes[i], this, current[changes[i]], options);
}
@@ -361,6 +363,7 @@
if (changing) return this;
if (!silent) {
while (this._pending) {
+ options = this._pending;
this._pending = false;
this.trigger('change', this, options);
}
@@ -528,9 +531,12 @@
// using Backbone's restful methods, override this to change the endpoint
// that will be called.
url: function() {
- var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
+ var base =
+ _.result(this, 'urlRoot') ||
+ _.result(this.collection, 'url') ||
+ urlError();
if (this.isNew()) return base;
- return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
+ return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
},
// **parse** converts a response into the hash of attributes to be `set` on
@@ -546,7 +552,7 @@
// A model is new if it has never been saved to the server, and lacks an id.
isNew: function() {
- return this.id == null;
+ return !this.has(this.idAttribute);
},
// Check if the model is currently in a valid state.
@@ -650,7 +656,7 @@
options.index = index;
model.trigger('remove', model, this, options);
}
- this._removeReference(model);
+ this._removeReference(model, options);
}
return singular ? models[0] : models;
},
@@ -676,11 +682,11 @@
// Turn bare objects into model references, and prevent invalid models
// from being added.
for (i = 0, l = models.length; i < l; i++) {
- attrs = models[i];
+ attrs = models[i] || {};
if (attrs instanceof Model) {
id = model = attrs;
} else {
- id = attrs[targetModel.prototype.idAttribute];
+ id = attrs[targetModel.prototype.idAttribute || 'id'];
}
// If a duplicate is found, prevent it from being added and
@@ -700,14 +706,13 @@
model = models[i] = this._prepareModel(attrs, options);
if (!model) continue;
toAdd.push(model);
-
- // Listen to added models' events, and index models for lookup by
- // `id` and by `cid`.
- model.on('all', this._onModelEvent, this);
- this._byId[model.cid] = model;
- if (model.id != null) this._byId[model.id] = model;
+ this._addReference(model, options);
}
- if (order) order.push(existing || model);
+
+ // Do not add multiple models with the same `id`.
+ model = existing || model;
+ if (order && (model.isNew() || !modelMap[model.id])) order.push(model);
+ modelMap[model.id] = true;
}
// Remove nonexistent models if appropriate.
@@ -745,7 +750,7 @@
}
if (sort || (order && order.length)) this.trigger('sort', this, options);
}
-
+
// Return the added (or merged) model (or models).
return singular ? models[0] : models;
},
@@ -757,7 +762,7 @@
reset: function(models, options) {
options || (options = {});
for (var i = 0, l = this.models.length; i < l; i++) {
- this._removeReference(this.models[i]);
+ this._removeReference(this.models[i], options);
}
options.previousModels = this.models;
this._reset();
@@ -798,7 +803,7 @@
// Get a model from the set by id.
get: function(obj) {
if (obj == null) return void 0;
- return this._byId[obj.id] || this._byId[obj.cid] || this._byId[obj];
+ return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];
},
// Get the model at the given index.
@@ -874,7 +879,7 @@
if (!options.wait) this.add(model, options);
var collection = this;
var success = options.success;
- options.success = function(model, resp, options) {
+ options.success = function(model, resp) {
if (options.wait) collection.add(model, options);
if (success) success(model, resp, options);
};
@@ -904,10 +909,7 @@
// Prepare a hash of attributes (or other model) to be added to this
// collection.
_prepareModel: function(attrs, options) {
- if (attrs instanceof Model) {
- if (!attrs.collection) attrs.collection = this;
- return attrs;
- }
+ if (attrs instanceof Model) return attrs;
options = options ? _.clone(options) : {};
options.collection = this;
var model = new this.model(attrs, options);
@@ -916,8 +918,16 @@
return false;
},
+ // Internal method to create a model's ties to a collection.
+ _addReference: function(model, options) {
+ this._byId[model.cid] = model;
+ if (model.id != null) this._byId[model.id] = model;
+ if (!model.collection) model.collection = this;
+ model.on('all', this._onModelEvent, this);
+ },
+
// Internal method to sever a model's ties to a collection.
- _removeReference: function(model) {
+ _removeReference: function(model, options) {
if (this === model.collection) delete model.collection;
model.off('all', this._onModelEvent, this);
},
@@ -946,7 +956,7 @@
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
- 'lastIndexOf', 'isEmpty', 'chain'];
+ 'lastIndexOf', 'isEmpty', 'chain', 'sample'];
// Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function(method) {
@@ -958,7 +968,7 @@
});
// Underscore methods that take a property name as an argument.
- var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
+ var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
// Use attributes instead of properties.
_.each(attributeMethods, function(method) {
@@ -1180,7 +1190,9 @@
return xhr;
};
- var noXhrPatch = typeof window !== 'undefined' && !!window.ActiveXObject && !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
+ var noXhrPatch =
+ typeof window !== 'undefined' && !!window.ActiveXObject &&
+ !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
var methodMap = {
@@ -1239,7 +1251,7 @@
var router = this;
Backbone.history.route(route, function(fragment) {
var args = router._extractParameters(route, fragment);
- callback && callback.apply(router, args);
+ router.execute(callback, args);
router.trigger.apply(router, ['route:' + name].concat(args));
router.trigger('route', name, args);
Backbone.history.trigger('route', router, name, args);
@@ -1247,6 +1259,12 @@
return this;
},
+ // Execute a route handler with the provided parameters. This is an
+ // excellent place to do pre-route setup or post-route cleanup.
+ execute: function(callback, args) {
+ if (callback) callback.apply(this, args);
+ },
+
// Simple proxy to `Backbone.history` to save a fragment into the history.
navigate: function(fragment, options) {
Backbone.history.navigate(fragment, options);
@@ -1271,10 +1289,10 @@
route = route.replace(escapeRegExp, '\\$&')
.replace(optionalParam, '(?:$1)?')
.replace(namedParam, function(match, optional) {
- return optional ? match : '([^\/]+)';
+ return optional ? match : '([^/?]+)';
})
- .replace(splatParam, '(.*?)');
- return new RegExp('^' + route + '$');
+ .replace(splatParam, '([^?]*?)');
+ return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
},
// Given a route, and a URL fragment that it matches, return the array of
@@ -1282,7 +1300,9 @@
// treated as `null` to normalize cross-browser behavior.
_extractParameters: function(route, fragment) {
var params = route.exec(fragment).slice(1);
- return _.map(params, function(param) {
+ return _.map(params, function(param, i) {
+ // Don't decode the search params.
+ if (i === params.length - 1) return param || null;
return param ? decodeURIComponent(param) : null;
});
}
@@ -1320,8 +1340,8 @@
// Cached regex for removing a trailing slash.
var trailingSlash = /\/$/;
- // Cached regex for stripping urls of hash and query.
- var pathStripper = /[?#].*$/;
+ // Cached regex for stripping urls of hash.
+ var pathStripper = /#.*$/;
// Has the history handling already been started?
History.started = false;
@@ -1333,6 +1353,11 @@
// twenty times a second.
interval: 50,
+ // Are we at the app root?
+ atRoot: function() {
+ return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root;
+ },
+
// Gets the true hash value. Cannot use location.hash directly due to bug
// in Firefox where location.hash will always be decoded.
getHash: function(window) {
@@ -1345,7 +1370,7 @@
getFragment: function(fragment, forcePushState) {
if (fragment == null) {
if (this._hasPushState || !this._wantsHashChange || forcePushState) {
- fragment = this.location.pathname;
+ fragment = decodeURI(this.location.pathname + this.location.search);
var root = this.root.replace(trailingSlash, '');
if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
} else {
@@ -1376,7 +1401,8 @@
this.root = ('/' + this.root + '/').replace(rootStripper, '/');
if (oldIE && this._wantsHashChange) {
- this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
+ var frame = Backbone.$('<iframe src="javascript:0" tabindex="-1">');
+ this.iframe = frame.hide().appendTo('body')[0].contentWindow;
this.navigate(fragment);
}
@@ -1394,7 +1420,6 @@
// opened by a non-pushState browser.
this.fragment = fragment;
var loc = this.location;
- var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
// Transition from hashChange to pushState or vice versa if both are
// requested.
@@ -1402,17 +1427,17 @@
// If we've started off with a route from a `pushState`-enabled
// browser, but we're currently in a browser that doesn't support it...
- if (!this._hasPushState && !atRoot) {
+ if (!this._hasPushState && !this.atRoot()) {
this.fragment = this.getFragment(null, true);
- this.location.replace(this.root + this.location.search + '#' + this.fragment);
+ this.location.replace(this.root + '#' + this.fragment);
// Return immediately as browser will do redirect to new url
return true;
// Or if we've started out with a hash-based route, but we're currently
// in a browser where it could be `pushState`-based instead...
- } else if (this._hasPushState && atRoot && loc.hash) {
+ } else if (this._hasPushState && this.atRoot() && loc.hash) {
this.fragment = this.getHash().replace(routeStripper, '');
- this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
+ this.history.replaceState({}, document.title, this.root + this.fragment);
}
}
@@ -1424,7 +1449,7 @@
// but possibly useful for unit testing Routers.
stop: function() {
Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
- clearInterval(this._checkUrlInterval);
+ if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
History.started = false;
},
@@ -1472,7 +1497,7 @@
var url = this.root + (fragment = this.getFragment(fragment || ''));
- // Strip the fragment of the query and hash for matching.
+ // Strip the hash for matching.
fragment = fragment.replace(pathStripper, '');
if (this.fragment === fragment) return;
@@ -1578,4 +1603,6 @@
};
};
-}).call(this);
+ return Backbone;
+
+}));
diff --git a/vendor/backbone/test/collection.js b/vendor/backbone/test/collection.js
index 748d7bb..37be417 100644
--- a/vendor/backbone/test/collection.js
+++ b/vendor/backbone/test/collection.js
@@ -85,6 +85,11 @@
equal(col2.get(model.clone()), col2.first());
});
+ test('get with "undefined" id', function() {
+ var collection = new Backbone.Collection([{id: 1}, {id: 'undefined'}]);
+ equal(collection.get(1).id, 1);
+ }),
+
test("update index when id changes", 4, function() {
var col = new Backbone.Collection();
col.add([
@@ -107,7 +112,7 @@
equal(col.pluck('label').join(' '), 'a b c d');
});
- test("add", 10, function() {
+ test("add", 14, function() {
var added, opts, secondAdded;
added = opts = secondAdded = null;
e = new Backbone.Model({id: 10, label : 'e'});
@@ -136,6 +141,18 @@
equal(atCol.length, 4);
equal(atCol.at(1), e);
equal(atCol.last(), h);
+
+ var coll = new Backbone.Collection(new Array(2));
+ var addCount = 0;
+ coll.on('add', function(){
+ addCount += 1;
+ });
+ coll.add([undefined, f, g]);
+ equal(coll.length, 5);
+ equal(addCount, 3);
+ coll.add(new Array(4));
+ equal(coll.length, 9);
+ equal(addCount, 7);
});
test("add multiple models", 6, function() {
@@ -535,7 +552,7 @@
equal(coll.findWhere({a: 4}), void 0);
});
- test("Underscore methods", 14, function() {
+ test("Underscore methods", 16, function() {
equal(col.map(function(model){ return model.get('label'); }).join(' '), 'a b c d');
equal(col.any(function(model){ return model.id === 100; }), false);
equal(col.any(function(model){ return model.id === 0; }), true);
@@ -554,9 +571,12 @@
.value(),
[4, 0]);
deepEqual(col.difference([c, d]), [a, b]);
+ ok(col.include(col.sample()));
+ var first = col.first();
+ ok(col.indexBy('id')[first.id] === first);
});
- test("reset", 12, function() {
+ test("reset", 16, function() {
var resetCount = 0;
var models = col.models;
col.on('reset', function() { resetCount += 1; });
@@ -576,6 +596,15 @@
col.reset();
equal(col.length, 0);
equal(resetCount, 4);
+
+ var f = new Backbone.Model({id: 20, label : 'f'});
+ col.reset([undefined, f]);
+ equal(col.length, 2);
+ equal(resetCount, 5);
+
+ col.reset(new Array(4));
+ equal(col.length, 4);
+ equal(resetCount, 6);
});
test ("reset with different values", function(){
@@ -942,20 +971,6 @@
strictEqual(c.length, 0);
});
- test("set with many models does not overflow the stack", function() {
- var n = 150000;
- var collection = new Backbone.Collection();
- var models = [];
- for (var i = 0; i < n; i++) {
- models.push({id: i});
- }
- collection.set(models);
- equal(collection.length, n);
- collection.reset();
- collection.set(models, {at: 0});
- equal(collection.length, n);
- });
-
test("set with only cids", 3, function() {
var m1 = new Backbone.Model;
var m2 = new Backbone.Model;
@@ -1274,4 +1289,50 @@
equal(job.items.get(2).subItems.get(3).get('subName'), 'NewThree');
});
+ test('_addReference binds all collection events & adds to the lookup hashes', 9, function() {
+
+ var calls = {add: 0, remove: 0};
+
+ var Collection = Backbone.Collection.extend({
+
+ _addReference: function(model) {
+ Backbone.Collection.prototype._addReference.apply(this, arguments);
+ calls.add++;
+ equal(model, this._byId[model.id]);
+ equal(model, this._byId[model.cid]);
+ equal(model._events.all.length, 1);
+ },
+
+ _removeReference: function(model) {
+ Backbone.Collection.prototype._removeReference.apply(this, arguments);
+ calls.remove++;
+ equal(this._byId[model.id], void 0);
+ equal(this._byId[model.cid], void 0);
+ equal(model.collection, void 0);
+ equal(model._events.all, void 0);
+ }
+
+ });
+
+ var collection = new Collection();
+ var model = collection.add({id: 1});
+ collection.remove(model);
+
+ equal(calls.add, 1);
+ equal(calls.remove, 1);
+
+ });
+
+ test('Do not allow duplicate models to be `add`ed or `set`', function() {
+ var c = new Backbone.Collection();
+
+ c.add([{id: 1}, {id: 1}]);
+ equal(c.length, 1);
+ equal(c.models.length, 1);
+
+ c.set([{id: 1}, {id: 1}]);
+ equal(c.length, 1);
+ equal(c.models.length, 1);
+ });
+
})();
diff --git a/vendor/backbone/test/environment.js b/vendor/backbone/test/environment.js
index 996884b..309f23c 100644
--- a/vendor/backbone/test/environment.js
+++ b/vendor/backbone/test/environment.js
@@ -4,9 +4,15 @@
var ajax = Backbone.ajax;
var emulateHTTP = Backbone.emulateHTTP;
var emulateJSON = Backbone.emulateJSON;
+ var history = window.history;
+ var pushState = history.pushState;
+ var replaceState = history.replaceState;
QUnit.testStart(function() {
- var env = this.config.current.testEnvironment;
+ var env = QUnit.config.current.testEnvironment;
+
+ // We never want to actually call these during tests.
+ history.pushState = history.replaceState = function(){};
// Capture ajax settings for comparison.
Backbone.ajax = function(settings) {
@@ -30,6 +36,8 @@
Backbone.ajax = ajax;
Backbone.emulateHTTP = emulateHTTP;
Backbone.emulateJSON = emulateJSON;
+ history.pushState = pushState;
+ history.replaceState = replaceState;
});
})();
diff --git a/vendor/backbone/test/events.js b/vendor/backbone/test/events.js
index 9f6878e..92b800a 100644
--- a/vendor/backbone/test/events.js
+++ b/vendor/backbone/test/events.js
@@ -305,7 +305,7 @@
test("if callback is truthy but not a function, `on` should throw an error just like jQuery", 1, function() {
var view = _.extend({}, Backbone.Events).on('test', 'noop');
- throws(function() {
+ raises(function() {
view.trigger('test');
});
});
diff --git a/vendor/backbone/test/model.js b/vendor/backbone/test/model.js
index ec1ba54..89f01cf 100644
--- a/vendor/backbone/test/model.js
+++ b/vendor/backbone/test/model.js
@@ -262,6 +262,26 @@
model.set({result: void 0});
});
+ test("nested set triggers with the correct options", function() {
+ var model = new Backbone.Model();
+ var o1 = {};
+ var o2 = {};
+ var o3 = {};
+ model.on('change', function(__, options) {
+ switch (model.get('a')) {
+ case 1:
+ equal(options, o1);
+ return model.set('a', 2, o2);
+ case 2:
+ equal(options, o2);
+ return model.set('a', 3, o3);
+ case 3:
+ equal(options, o3);
+ }
+ });
+ model.set('a', 1, o1);
+ });
+
test("multiple unsets", 1, function() {
var i = 0;
var counter = function(){ i++; };
diff --git a/vendor/backbone/test/router.js b/vendor/backbone/test/router.js
index 296546e..57e138d 100644
--- a/vendor/backbone/test/router.js
+++ b/vendor/backbone/test/router.js
@@ -5,10 +5,10 @@
var lastRoute = null;
var lastArgs = [];
- function onRoute(router, route, args) {
+ var onRoute = function(router, route, args) {
lastRoute = route;
lastArgs = args;
- }
+ };
var Location = function(href) {
this.replace(href);
@@ -16,8 +16,11 @@
_.extend(Location.prototype, {
+ parser: document.createElement('a'),
+
replace: function(href) {
- _.extend(this, _.pick($('<a></a>', {href: href})[0],
+ this.parser.href = href;
+ _.extend(this, _.pick(this.parser,
'href',
'hash',
'host',
@@ -64,7 +67,7 @@
this.value = value;
}
};
- _.bindAll(ExternalObject);
+ _.bindAll(ExternalObject, 'routingFunction');
var Router = Backbone.Router.extend({
@@ -87,7 +90,7 @@
":repo/compare/*from...*to": "github",
"decode/:named/*splat": "decode",
"*first/complex-*part/*rest": "complex",
- ":entity?*args": "query",
+ "query/:entity": "query",
"function/:value": ExternalObject.routingFunction,
"*anything": "anything"
},
@@ -208,6 +211,11 @@
equal(router.page, '20');
});
+ test("routes via navigate with params", 1, function() {
+ Backbone.history.navigate('query/test?a=b', {trigger: true});
+ equal(router.queryArgs, 'a=b');
+ });
+
test("routes via navigate for backwards-compatibility", 2, function() {
Backbone.history.navigate('search/manhattan/p20', true);
equal(router.query, 'manhattan');
@@ -285,7 +293,7 @@
});
test("routes (query)", 5, function() {
- location.replace('http://example.com#mandel?a=b&c=d');
+ location.replace('http://example.com#query/mandel?a=b&c=d');
Backbone.history.checkUrl();
equal(router.entity, 'mandel');
equal(router.queryArgs, 'a=b&c=d');
@@ -535,7 +543,7 @@
Backbone.history.stop();
location.replace('http://example.com/root/x/y?a=b');
location.replace = function(url) {
- strictEqual(url, '/root/?a=b#x/y');
+ strictEqual(url, '/root/#x/y?a=b');
};
Backbone.history = _.extend(new Backbone.History, {
location: location,
@@ -552,7 +560,7 @@
test("#1695 - hashChange to pushState with search.", 1, function() {
Backbone.history.stop();
- location.replace('http://example.com/root?a=b#x/y');
+ location.replace('http://example.com/root#x/y?a=b');
Backbone.history = _.extend(new Backbone.History, {
location: location,
history: {
@@ -601,7 +609,7 @@
test("#2062 - Trigger 'route' event on router instance.", 2, function() {
router.on('route', function(name, args) {
strictEqual(name, 'routeEvent');
- deepEqual(args, ['x']);
+ deepEqual(args, ['x', null]);
});
location.replace('http://example.com#route-event/x');
Backbone.history.checkUrl();
@@ -684,7 +692,7 @@
}
});
location.replace('http://example.com/root/path');
- Backbone.history.start({pushState: true, root: 'root'});
+ Backbone.history.start({pushState: true, hashChange: false, root: 'root'});
Backbone.history.navigate('');
});
@@ -699,7 +707,7 @@
}
});
location.replace('http://example.com/path');
- Backbone.history.start({pushState: true});
+ Backbone.history.start({pushState: true, hashChange: false});
Backbone.history.navigate('');
});
@@ -722,8 +730,81 @@
var router = new Router;
location.replace('http://example.com/');
- Backbone.history.start({pushState: true});
+ Backbone.history.start({pushState: true, hashChange: false});
Backbone.history.navigate('path?query#hash', true);
});
+ test('Do not decode the search params.', function() {
+ var Router = Backbone.Router.extend({
+ routes: {
+ path: function(params){
+ strictEqual(params, 'x=y%20z');
+ }
+ }
+ });
+ var router = new Router;
+ Backbone.history.navigate('path?x=y%20z', true);
+ });
+
+ test('Navigate to a hash url.', function() {
+ Backbone.history.stop();
+ Backbone.history = _.extend(new Backbone.History, {location: location});
+ Backbone.history.start({pushState: true});
+ var Router = Backbone.Router.extend({
+ routes: {
+ path: function(params) {
+ strictEqual(params, 'x=y');
+ }
+ }
+ });
+ var router = new Router;
+ location.replace('http://example.com/path?x=y#hash');
+ Backbone.history.checkUrl();
+ });
+
+ test('#navigate to a hash url.', function() {
+ Backbone.history.stop();
+ Backbone.history = _.extend(new Backbone.History, {location: location});
+ Backbone.history.start({pushState: true});
+ var Router = Backbone.Router.extend({
+ routes: {
+ path: function(params) {
+ strictEqual(params, 'x=y');
+ }
+ }
+ });
+ var router = new Router;
+ Backbone.history.navigate('path?x=y#hash', true);
+ });
+
+ test('unicode pathname', 1, function() {
+ location.replace('http://example.com/myyjä');
+ Backbone.history.stop();
+ Backbone.history = _.extend(new Backbone.History, {location: location});
+ var Router = Backbone.Router.extend({
+ routes: {
+ myyjä: function() {
+ ok(true);
+ }
+ }
+ });
+ new Router;
+ Backbone.history.start({pushState: true});
+ });
+
+ test('newline in route', 1, function() {
+ location.replace('http://example.com/stuff%0Anonsense?param=foo%0Abar');
+ Backbone.history.stop();
+ Backbone.history = _.extend(new Backbone.History, {location: location});
+ var Router = Backbone.Router.extend({
+ routes: {
+ 'stuff\nnonsense': function() {
+ ok(true);
+ }
+ }
+ });
+ new Router;
+ Backbone.history.start({pushState: true});
+ });
+
})();
diff --git a/vendor/backbone/test/view.js b/vendor/backbone/test/view.js
index 65eee25..76f0f1d 100644
--- a/vendor/backbone/test/view.js
+++ b/vendor/backbone/test/view.js
@@ -39,23 +39,23 @@
test("delegateEvents", 6, function() {
var counter1 = 0, counter2 = 0;
- var view = new Backbone.View({el: '<p><a id="test"></a></p>'});
+ var view = new Backbone.View({el: '#testElement'});
view.increment = function(){ counter1++; };
view.$el.on('click', function(){ counter2++; });
- var events = {'click #test': 'increment'};
+ var events = {'click h1': 'increment'};
view.delegateEvents(events);
- view.$('#test').trigger('click');
+ view.$('h1').trigger('click');
equal(counter1, 1);
equal(counter2, 1);
- view.$('#test').trigger('click');
+ view.$('h1').trigger('click');
equal(counter1, 2);
equal(counter2, 2);
view.delegateEvents(events);
- view.$('#test').trigger('click');
+ view.$('h1').trigger('click');
equal(counter1, 3);
equal(counter2, 3);
});
@@ -92,24 +92,24 @@
test("undelegateEvents", 6, function() {
var counter1 = 0, counter2 = 0;
- var view = new Backbone.View({el: '<p><a id="test"></a></p>'});
+ var view = new Backbone.View({el: '#testElement'});
view.increment = function(){ counter1++; };
view.$el.on('click', function(){ counter2++; });
- var events = {'click #test': 'increment'};
+ var events = {'click h1': 'increment'};
view.delegateEvents(events);
- view.$('#test').trigger('click');
+ view.$('h1').trigger('click');
equal(counter1, 1);
equal(counter2, 1);
view.undelegateEvents();
- view.$('#test').trigger('click');
+ view.$('h1').trigger('click');
equal(counter1, 1);
equal(counter2, 2);
view.delegateEvents(events);
- view.$('#test').trigger('click');
+ view.$('h1').trigger('click');
equal(counter1, 2);
equal(counter2, 3);
});
@@ -218,7 +218,7 @@
$('body').trigger('fake$event').trigger('fake$event');
equal(count, 2);
- $('body').unbind('.namespaced');
+ $('body').off('.namespaced');
$('body').trigger('fake$event');
equal(count, 2);
});
@@ -304,28 +304,24 @@
ok(view.$el.has('a'));
});
- test("events passed in options", 2, function() {
+ test("events passed in options", 1, function() {
var counter = 0;
var View = Backbone.View.extend({
- el: '<p><a id="test"></a></p>',
+ el: '#testElement',
increment: function() {
counter++;
}
});
- var view = new View({events:{'click #test':'increment'}});
- var view2 = new View({events:function(){
- return {'click #test':'increment'};
- }});
+ var view = new View({
+ events: {
+ 'click h1': 'increment'
+ }
+ });
- view.$('#test').trigger('click');
- view2.$('#test').trigger('click');
+ view.$('h1').trigger('click').trigger('click');
equal(counter, 2);
-
- view.$('#test').trigger('click');
- view2.$('#test').trigger('click');
- equal(counter, 4);
});
})();
diff --git a/vendor/benchmark.js/LICENSE.txt b/vendor/benchmark.js/LICENSE.txt
index ae29aba..feed4c8 100644
--- a/vendor/benchmark.js/LICENSE.txt
+++ b/vendor/benchmark.js/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright 2010-2013 Mathias Bynens <http://mathiasbynens.be/>
+Copyright 2010-2015 Mathias Bynens <http://mathiasbynens.be/>
Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/>
Modified by John-David Dalton <http://allyoucanleet.com/>
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/benchmark.js/benchmark.js b/vendor/benchmark.js/benchmark.js
index c76cf66..a5bf8d3 100644
--- a/vendor/benchmark.js/benchmark.js
+++ b/vendor/benchmark.js/benchmark.js
@@ -1,46 +1,60 @@
/*!
- * Benchmark.js v1.0.0 <http://benchmarkjs.com/>
- * Copyright 2010-2013 Mathias Bynens <http://mths.be/>
+ * Benchmark.js v2.0.0-pre <http://benchmarkjs.com/>
+ * Copyright 2010-2015 Mathias Bynens <http://mths.be/>
* Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/>
* Modified by John-David Dalton <http://allyoucanleet.com/>
* Available under MIT license <http://mths.be/mit>
*/
-;(function(root, undefined) {
+;(function() {
'use strict';
+ /** Used as a safe reference for `undefined` in pre ES5 environments */
+ var undefined;
+
+ /** Used to determine if values are of the language type Object */
+ var objectTypes = {
+ 'function': true,
+ 'object': true
+ };
+
+ /** Used as a reference to the global object */
+ var root = (objectTypes[typeof window] && window) || this;
+
/** Detect free variable `define` */
- var freeDefine = typeof define == 'function' &&
- typeof define.amd == 'object' && define.amd && define;
+ var freeDefine = typeof define == 'function' && typeof define.amd == 'object' && define.amd && define;
/** Detect free variable `exports` */
- var freeExports = typeof exports == 'object' && exports;
+ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
/** Detect free variable `module` */
- var freeModule = typeof module == 'object' && module && module.exports == freeExports && module;
+ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
- /** Detect free variable `require` */
- var freeRequire = typeof require == 'function' && require;
-
- /** Detect free variable `global`, from Node.js or Browserified code, and use it as `root` */
- var freeGlobal = typeof global == 'object' && global;
- if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+ /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
+ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
root = freeGlobal;
}
+ /** Detect free variable `require` */
+ var freeRequire = typeof require == 'function' && require;
+
/** Used to assign each benchmark an incrimented id */
var counter = 0;
- /** Used to make every compiled test unique */
- var uidCounter = 0;
+ /** Detect the popular CommonJS extension `module.exports` */
+ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
/** Used to detect primitive types */
var rePrimitive = /^(?:boolean|number|string|undefined)$/;
+ /** Used to make every compiled test unique */
+ var uidCounter = 0;
+
/** Used to assign default `context` object properties */
var contextProps = [
'Array', 'Date', 'Function', 'Math', 'Object', 'RegExp', 'String', '_',
'clearTimeout', 'chrome', 'chromium', 'document', 'java', 'navigator',
- 'performance', 'platform', 'process', 'runtime', 'setTimeout'
+ 'phantom', 'platform', 'process', 'runtime', 'setTimeout'
];
/** Used to avoid hz of Infinity */
@@ -106,10 +120,10 @@
* @static
* @memberOf Benchmark
* @param {Object} [context=root] The context object.
- * @returns {Function} Returns the `Benchmark` function.
+ * @returns {Function} Returns a new `Benchmark` function.
*/
function runInContext(context) {
- // exit early if unable to acquire lodash
+ // exit early if unable to acquire Lo-Dash
var _ = context && context._ || req('lodash') || root._;
if (!_) {
Benchmark.runInContext = runInContext;
@@ -147,31 +161,23 @@
shift = arrayRef.shift,
slice = arrayRef.slice,
sqrt = Math.sqrt,
- toString = objectProto.toString;
+ toString = objectProto.toString,
+ unshift = arrayRef.unshift;
/** Detect DOM document object */
var doc = isHostType(context, 'document') && context.document;
- /** Used to access Wade Simmons' Node microtime module */
+ /** Used to access Wade Simmons' Node.js `microtime` module */
var microtimeObject = req('microtime');
- /** Used to access the browser's high resolution timer */
- var perfObject = isHostType(context, 'performance') && context.performance;
-
- /** Used to call the browser's high resolution timer */
- var perfName = perfObject && (
- perfObject.now && 'now' ||
- perfObject.webkitNow && 'webkitNow'
- );
-
- /** Used to access Node's high resolution timer */
+ /** Used to access Node.js's high resolution timer */
var processObject = isHostType(context, 'process') && context.process;
/** Used to prevent a `removeChild` memory leak in IE < 9 */
var trash = doc && doc.createElement('div');
/** Used to integrity check compiled tests */
- var uid = 'uid' + (+new Date);
+ var uid = 'uid' + _.now();
/** Used to avoid infinite recursion when methods call each other */
var calledBy = {};
@@ -188,39 +194,39 @@
(function() {
/**
- * Detect Adobe AIR.
+ * Detect if running in a browser environment.
*
* @memberOf Benchmark.support
* @type boolean
*/
- support.air = isClassOf(context.runtime, 'ScriptBridgingProxyObject');
+ support.browser = doc && isHostType(context, 'navigator') && !isHostType(context, 'phantom');
/**
- * Detect if in a browser environment.
+ * Detect if Java is enabled/exposed.
*
* @memberOf Benchmark.support
* @type boolean
*/
- support.browser = doc && isHostType(context, 'navigator') && !isHostType(context, 'phantom');
+ support.java = isClassOf(context.java, 'JavaPackage');
/**
- * Detect if Java is enabled/exposed.
+ * Detect if the Timers API exists.
*
* @memberOf Benchmark.support
* @type boolean
*/
- support.java = isClassOf(context.java, 'JavaPackage');
+ support.timeout = isHostType(context, 'setTimeout') && isHostType(context, 'clearTimeout');
/**
- * Detect if the Timers API exists.
+ * Detect if `Array#unshift` returns the new length of the array (all but IE < 8).
*
* @memberOf Benchmark.support
* @type boolean
*/
- support.timeout = isHostType(context, 'setTimeout') && isHostType(context, 'clearTimeout');
+ support.unshiftResult = !![].unshift(1);
/**
- * Detect if functions support decompilation.
+ * Detect if function decompilation is support.
*
* @name decompilation
* @memberOf Benchmark.support
@@ -228,13 +234,15 @@
*/
try {
// Safari 2.x removes commas in object literals
- // from Function#toString results
+ // from `Function#toString` results
// http://webk.it/11609
// Firefox 3.6 and Opera 9.25 strip grouping
- // parentheses from Function#toString results
+ // parentheses from `Function#toString` results
// http://bugzil.la/559438
support.decompilation = Function(
- 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')'
+ ('return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')')
+ // avoid issues with code added by Istanbul
+ .replace(/__cov__[^;]+;/g, '')
)()(0).x === '1';
} catch(e) {
support.decompilation = false;
@@ -282,6 +290,14 @@
/**
* The Benchmark constructor.
*
+ * Note: The Benchmark constructor exposes a handful of Lo-Dash methods to
+ * make working with arrays, collections, and objects easier. The Lo-Dash
+ * methods are:
+ * [`each/forEach`](https://lodash.com/docs#forEach), [`forOwn`](https://lodash.com/docs#forOwn),
+ * [`has`](https://lodash.com/docs#has), [`indexOf`](https://lodash.com/docs#indexOf),
+ * [`map`](https://lodash.com/docs#map), [`pluck`](https://lodash.com/docs#pluck),
+ * and [`reduce`](https://lodash.com/docs#reduce)
+ *
* @constructor
* @param {string} name A name to identify the benchmark.
* @param {Function|string} fn The test to benchmark.
@@ -297,7 +313,7 @@
* // or with options
* var bench = new Benchmark('foo', fn, {
*
- * // displayed by Benchmark#toString if `name` is not available
+ * // displayed by `Benchmark#toString` if `name` is not available
* 'id': 'xyz',
*
* // called when the benchmark starts running
@@ -333,7 +349,7 @@
*
* // benchmark test function
* 'fn': function(deferred) {
- * // call resolve() when the deferred test is finished
+ * // call `Deferred#resolve` when the deferred test is finished
* deferred.resolve();
* }
* });
@@ -350,7 +366,7 @@
*
* // a test's `this` binding is set to the benchmark instance
* var bench = new Benchmark('foo', function() {
- * 'My name is '.concat(this.name); // My name is foo
+ * 'My name is '.concat(this.name); // "My name is foo"
* });
*/
function Benchmark(name, fn, options) {
@@ -414,17 +430,23 @@
*/
function Event(type) {
var event = this;
+ if (type instanceof Event) {
+ return type;
+ }
return (event == null || event.constructor != Event)
? new Event(type)
- : (type instanceof Event
- ? type
- : _.extend(event, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type)
- );
+ : _.assign(event, { 'timeStamp': _.now() }, typeof type == 'string' ? { 'type': type } : type);
}
/**
* The Suite constructor.
*
+ * Note: Each Suite instance has a handful of wrapped Lo-Dash methods to
+ * make working with Suites easier. The wrapped Lo-Dash methods are:
+ * [`each/forEach`](https://lodash.com/docs#forEach), [`indexOf`](https://lodash.com/docs#indexOf),
+ * [`map`](https://lodash.com/docs#map), [`pluck`](https://lodash.com/docs#pluck),
+ * and [`reduce`](https://lodash.com/docs#reduce)
+ *
* @constructor
* @memberOf Benchmark
* @param {string} name A name to identify the suite.
@@ -467,7 +489,7 @@
return new Suite(name, options);
}
// juggle arguments
- if (isClassOf(name, 'Object')) {
+ if (_.isPlainObject(name)) {
// 1 argument (options)
options = name;
} else {
@@ -486,9 +508,9 @@
* @param {*} value The value to clone.
* @returns {*} The cloned value.
*/
- var cloneDeep = _.partialRight(_.cloneDeep, function(value) {
- // do not clone non-Object objects
- return (typeof value == 'object' && !_.isArray(value) && !_.isPlainObject(value))
+ var cloneDeep = _.partial(_.cloneDeep, _, function(value) {
+ // only clone primitives, arrays, and plain objects
+ return (_.isObject(value) && !_.isArray(value) && !_.isPlainObject(value))
? value
: undefined;
});
@@ -515,7 +537,7 @@
};
// fix JaegerMonkey bug
// http://bugzil.la/639720
- createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function;
+ createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || _.noop)() == uid ? createFunction : Function;
return createFunction.apply(null, arguments);
}
@@ -571,22 +593,21 @@
*
* @private
* @param {Function} fn The function.
- * @param {string} altSource A string used when a function's source code is unretrievable.
* @returns {string} The function's source code.
*/
- function getSource(fn, altSource) {
- var result = altSource;
+ function getSource(fn) {
+ var result = '';
if (isStringable(fn)) {
result = String(fn);
} else if (support.decompilation) {
// escape the `{` for Firefox 1
- result = (/^[^{]+\{([\s\S]*)\}\s*$/.exec(fn) || 0)[1];
+ result = _.result(/^[^{]+\{([\s\S]*)\}\s*$/.exec(fn), 1);
}
// trim string
result = (result || '').replace(/^\s+|\s+$/g, '');
// detect strings containing only the "use strict" directive
- return /^(?:\/\*+[\w|\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result)
+ return /^(?:\/\*+[\w\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result)
? ''
: result;
}
@@ -629,20 +650,11 @@
* @returns {boolean} Returns `true` if the value can be coerced, else `false`.
*/
function isStringable(value) {
- return _.has(value, 'toString') || isClassOf(value, 'String');
+ return _.isString(value) || (_.has(value, 'toString') && _.isFunction(value.toString));
}
/**
- * A no-operation function.
- *
- * @private
- */
- function noop() {
- // no operation performed
- }
-
- /**
- * A wrapper around require() to suppress `module missing` errors.
+ * A wrapper around `require()` to suppress `module missing` errors.
*
* @private
* @param {string} id The module id.
@@ -651,7 +663,7 @@
function req(id) {
try {
var result = freeExports && freeRequire(id);
- } catch(e) { }
+ } catch(e) {}
return result || null;
}
@@ -694,8 +706,9 @@
* @param {Object} [options={}] Options object.
*/
function setOptions(object, options) {
- options = _.extend({}, object.constructor.options, options);
- object.options = _.forOwn(options, function(value, key) {
+ options = object.options = _.assign({}, cloneDeep(object.constructor.options), cloneDeep(options));
+
+ _.forOwn(options, function(value, key) {
if (value != null) {
// add event listeners
if (/^on[A-Z]/.test(key)) {
@@ -806,7 +819,7 @@
* @memberOf Benchmark
* @param {Array} benches Array of benchmarks to iterate over.
* @param {Object|string} name The name of the method to invoke OR options object.
- * @param {...*} [arg] Arguments to invoke the method with.
+ * @param {...*} [args] Arguments to invoke the method with.
* @returns {Array} A new array of values returned from each method invoked.
* @example
*
@@ -844,7 +857,7 @@
queued,
index = -1,
eventProps = { 'currentTarget': benches },
- options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop },
+ options = { 'onStart': _.noop, 'onCycle': _.noop, 'onComplete': _.noop },
result = _.toArray(benches);
/**
@@ -862,7 +875,7 @@
}
// execute method
result[index] = _.isFunction(bench && bench[name]) ? bench[name].apply(bench, args) : undefined;
- // if synchronous return true until finished
+ // if synchronous return `true` until finished
return !async && getNext();
}
@@ -892,7 +905,7 @@
}
else if (async) {
// resume execution if previously asynchronous but now synchronous
- while (execute()) { }
+ while (execute()) {}
}
else {
// continue synchronous execution
@@ -945,7 +958,7 @@
args = slice.call(arguments, 2);
} else {
// 2 arguments (array, options)
- options = _.extend(options, name);
+ options = _.assign(options, name);
name = options.name;
args = _.isArray(args = 'args' in options ? options.args : []) ? args : [args];
queued = options.queued;
@@ -973,7 +986,7 @@
if (isAsync(bench)) {
delay(bench, execute);
} else {
- while (execute()) { }
+ while (execute()) {}
}
}
}
@@ -1092,7 +1105,7 @@
*/
function cloneSuite(options) {
var suite = this,
- result = new suite.constructor(_.extend({}, suite.options, options));
+ result = new suite.constructor(_.assign({}, suite.options, options));
// copy own properties
_.forOwn(suite, function(value, key) {
@@ -1115,7 +1128,7 @@
*/
function filterSuite(callback) {
var suite = this,
- result = new suite.constructor;
+ result = new suite.constructor(suite.options);
result.push.apply(result, filter(suite, callback));
return result;
@@ -1202,6 +1215,7 @@
*
* @memberOf Benchmark, Benchmark.Suite
* @param {Object|string} type The event type or object.
+ * @param {...*} [args] Arguments to invoke the listener with.
* @returns {*} Returns the return value of the last listener executed.
*/
function emit(type) {
@@ -1371,11 +1385,10 @@
*/
function clone(options) {
var bench = this,
- sample = bench.stats.sample,
- result = new bench.constructor(_.extend({}, bench, options));
+ result = new bench.constructor(_.assign({}, bench, options));
// correct the `options` object
- result.options = _.extend({}, bench.options, options);
+ result.options = _.assign({}, cloneDeep(bench.options), cloneDeep(options));
// copy own custom properties
_.forOwn(bench, function(value, key) {
@@ -1395,9 +1408,14 @@
* @returns {number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate.
*/
function compare(other) {
+ var bench = this;
+
+ // exit early if comparing the same benchmark
+ if (bench == other) {
+ return 0;
+ }
var critical,
zStat,
- bench = this,
sample1 = bench.stats.sample,
sample2 = other.stats.sample,
size1 = sample1.length,
@@ -1423,11 +1441,6 @@
function getZ(u) {
return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12);
}
-
- // exit early if comparing the same benchmark
- if (bench == other) {
- return 0;
- }
// reject the null hyphothesis the two samples come from the
// same population (i.e. have the same median) if...
if (size1 + size2 > 30) {
@@ -1448,70 +1461,72 @@
* @returns {Object} The benchmark instance.
*/
function reset() {
- var data,
- event,
- bench = this,
- index = 0,
- changes = { 'length': 0 },
- queue = { 'length': 0 };
-
+ var bench = this;
if (bench.running && !calledBy.abort) {
// no worries, `reset()` is called within `abort()`
calledBy.reset = true;
bench.abort();
delete calledBy.reset;
+ return bench;
}
- else {
- // a non-recursive solution to check if properties have changed
- // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4
- data = { 'destination': bench, 'source': _.extend({}, bench.constructor.prototype, bench.options) };
- do {
- _.forOwn(data.source, function(value, key) {
- var changed,
- destination = data.destination,
- currValue = destination[key];
-
- // skip pseudo private properties like `_timerId` which could be a
- // Java object in environments like RingoJS
- if (key.charAt(0) == '_') {
- return;
- }
- if (value && typeof value == 'object') {
- if (_.isArray(value)) {
- // check if an array value has changed to a non-array value
- if (!_.isArray(currValue)) {
- changed = currValue = [];
- }
- // or has changed its length
- if (currValue.length != value.length) {
- changed = currValue = currValue.slice(0, value.length);
- currValue.length = value.length;
- }
- }
- // check if an object has changed to a non-object value
- else if (!currValue || typeof currValue != 'object') {
- changed = currValue = {};
+ var event,
+ index = 0,
+ changes = [],
+ queue = [];
+
+ // a non-recursive solution to check if properties have changed
+ // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4
+ var data = {
+ 'destination': bench,
+ 'source': _.assign({}, cloneDeep(bench.constructor.prototype), cloneDeep(bench.options))
+ };
+
+ do {
+ _.forOwn(data.source, function(value, key) {
+ var changed,
+ destination = data.destination,
+ currValue = destination[key];
+
+ // skip pseudo private properties like `_timerId` which could be a
+ // Java object in environments like RingoJS
+ if (key.charAt(0) == '_') {
+ return;
+ }
+ if (value && typeof value == 'object') {
+ if (_.isArray(value)) {
+ // check if an array value has changed to a non-array value
+ if (!_.isArray(currValue)) {
+ changed = currValue = [];
}
- // register a changed object
- if (changed) {
- changes[changes.length++] = { 'destination': destination, 'key': key, 'value': currValue };
+ // or has changed its length
+ if (currValue.length != value.length) {
+ changed = currValue = currValue.slice(0, value.length);
+ currValue.length = value.length;
}
- queue[queue.length++] = { 'destination': currValue, 'source': value };
}
- // register a changed primitive
- else if (value !== currValue && !(value == null || _.isFunction(value))) {
- changes[changes.length++] = { 'destination': destination, 'key': key, 'value': value };
+ // check if an object has changed to a non-object value
+ else if (!currValue || typeof currValue != 'object') {
+ changed = currValue = {};
}
- });
- }
- while ((data = queue[index++]));
+ // register a changed object
+ if (changed) {
+ changes.push({ 'destination': destination, 'key': key, 'value': currValue });
+ }
+ queue.push({ 'destination': currValue, 'source': value });
+ }
+ // register a changed primitive
+ else if (value !== currValue && !(value == null || _.isFunction(value))) {
+ changes.push({ 'destination': destination, 'key': key, 'value': value });
+ }
+ });
+ }
+ while ((data = queue[index++]));
- // if changed emit the `reset` event and if it isn't cancelled reset the benchmark
- if (changes.length && (bench.emit(event = Event('reset')), !event.cancelled)) {
- _.each(changes, function(data) {
- data.destination[data.key] = data.value;
- });
- }
+ // if changed emit the `reset` event and if it isn't cancelled reset the benchmark
+ if (changes.length && (bench.emit(event = Event('reset')), !event.cancelled)) {
+ _.each(changes, function(data) {
+ data.destination[data.key] = data.value;
+ });
}
return bench;
}
@@ -1568,7 +1583,7 @@
var bench = clone._original,
stringable = isStringable(bench.fn),
count = bench.count = clone.count,
- decompilable = support.decompilation || stringable,
+ decompilable = stringable || (support.decompilation && (clone.setup !== _.noop || clone.teardown !== _.noop)),
id = bench.id,
name = bench.name || (typeof id == 'number' ? '<Test #' + id + '>' : id),
result = 0;
@@ -1586,7 +1601,6 @@
timer.ns = new applet.Packages.nano;
}
}
-
// Compile in setup/teardown functions and the test loop.
// Create a new compiled test, instead of using the cached `bench.compiled`,
// to avoid potential engine optimizations enabled over the life of the test.
@@ -1608,20 +1622,20 @@
: 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count,n#=t#.ns;${setup}\n${begin};' +
'while(i#--){${fn}\n}${end};${teardown}\nreturn{elapsed:r#,uid:"${uid}"}';
- var compiled = bench.compiled = clone.compiled = createCompiled(bench, deferred, funcBody),
+ var compiled = bench.compiled = clone.compiled = createCompiled(bench, decompilable, deferred, funcBody),
isEmpty = !(templateData.fn || stringable);
try {
if (isEmpty) {
- // Firefox may remove dead code from Function#toString results
+ // Firefox may remove dead code from `Function#toString` results
// http://bugzil.la/536085
throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.');
}
else if (!deferred) {
- // pretest to determine if compiled code is exits early, usually by a
+ // pretest to determine if compiled code exits early, usually by a
// rogue `return` statement, by checking for a return object with the uid
bench.count = 1;
- compiled = (compiled.call(bench, context, timer) || {}).uid == templateData.uid && compiled;
+ compiled = decompilable && (compiled.call(bench, context, timer) || {}).uid == templateData.uid && compiled;
bench.count = count;
}
} catch(e) {
@@ -1630,16 +1644,16 @@
bench.count = count;
}
// fallback when a test exits early or errors during pretest
- if (decompilable && !compiled && !deferred && !isEmpty) {
+ if (!compiled && !deferred && !isEmpty) {
funcBody = (
- clone.error && !stringable
- ? 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count'
- : 'function f#(){${fn}\n}var r#,s#,m#=this,i#=m#.count'
+ stringable || (decompilable && !clone.error)
+ ? 'function f#(){${fn}\n}var r#,s#,m#=this,i#=m#.count'
+ : 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count'
) +
',n#=t#.ns;${setup}\n${begin};m#.f#=f#;while(i#--){m#.f#()}${end};' +
'delete m#.f#;${teardown}\nreturn{elapsed:r#}';
- compiled = createCompiled(bench, deferred, funcBody);
+ compiled = createCompiled(bench, decompilable, deferred, funcBody);
try {
// pretest one more time to check for errors
@@ -1657,7 +1671,7 @@
}
// if no errors run the full test loop
if (!clone.error) {
- compiled = bench.compiled = clone.compiled = createCompiled(bench, deferred, funcBody);
+ compiled = bench.compiled = clone.compiled = createCompiled(bench, decompilable, deferred, funcBody);
result = compiled.call(deferred || bench, context, timer).elapsed;
}
return result;
@@ -1668,28 +1682,28 @@
/**
* Creates a compiled function from the given function `body`.
*/
- function createCompiled(bench, deferred, body) {
+ function createCompiled(bench, decompilable, deferred, body) {
var fn = bench.fn,
fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '';
templateData.uid = uid + uidCounter++;
- _.extend(templateData, {
- 'setup': getSource(bench.setup, interpolate('m#.setup()')),
- 'fn': getSource(fn, interpolate('m#.fn(' + fnArg + ')')),
+ _.assign(templateData, {
+ 'setup': decompilable ? getSource(bench.setup) : interpolate('m#.setup()'),
+ 'fn': decompilable ? getSource(fn) : interpolate('m#.fn(' + fnArg + ')'),
'fnArg': fnArg,
- 'teardown': getSource(bench.teardown, interpolate('m#.teardown()'))
+ 'teardown': decompilable ? getSource(bench.teardown) : interpolate('m#.teardown()')
});
// use API of chosen timer
if (timer.unit == 'ns') {
if (timer.ns.nanoTime) {
- _.extend(templateData, {
+ _.assign(templateData, {
'begin': interpolate('s#=n#.nanoTime()'),
'end': interpolate('r#=(n#.nanoTime()-s#)/1e9')
});
} else {
- _.extend(templateData, {
+ _.assign(templateData, {
'begin': interpolate('s#=n#()'),
'end': interpolate('r#=n#(s#);r#=r#[0]+(r#[1]/1e9)')
});
@@ -1697,26 +1711,27 @@
}
else if (timer.unit == 'us') {
if (timer.ns.stop) {
- _.extend(templateData, {
+ _.assign(templateData, {
'begin': interpolate('s#=n#.start()'),
'end': interpolate('r#=n#.microseconds()/1e6')
});
- } else if (perfName) {
- _.extend(templateData, {
- 'begin': interpolate('s#=n#.' + perfName + '()'),
- 'end': interpolate('r#=(n#.' + perfName + '()-s#)/1e3')
- });
} else {
- _.extend(templateData, {
+ _.assign(templateData, {
'begin': interpolate('s#=n#()'),
'end': interpolate('r#=(n#()-s#)/1e6')
});
}
}
+ else if (timer.ns.now) {
+ _.assign(templateData, {
+ 'begin': interpolate('s#=n#.now()'),
+ 'end': interpolate('r#=(n#.now()-s#)/1e3')
+ });
+ }
else {
- _.extend(templateData, {
- 'begin': interpolate('s#=new n#'),
- 'end': interpolate('r#=(new n#-s#)/1e3')
+ _.assign(templateData, {
+ 'begin': interpolate('s#=new n#().getTime()'),
+ 'end': interpolate('r#=(new n#().getTime()-s#)/1e3')
});
}
// define `timer` methods
@@ -1755,31 +1770,32 @@
divisor = 1e6;
if (ns.stop) {
ns.start();
- while (!(measured = ns.microseconds())) { }
- } else if (ns[perfName]) {
- divisor = 1e3;
- measured = Function('n', 'var r,s=n.' + perfName + '();while(!(r=n.' + perfName + '()-s)){};return r')(ns);
+ while (!(measured = ns.microseconds())) {}
} else {
begin = ns();
- while (!(measured = ns() - begin)) { }
+ while (!(measured = ns() - begin)) {}
}
}
else if (unit == 'ns') {
divisor = 1e9;
if (ns.nanoTime) {
begin = ns.nanoTime();
- while (!(measured = ns.nanoTime() - begin)) { }
+ while (!(measured = ns.nanoTime() - begin)) {}
} else {
begin = (begin = ns())[0] + (begin[1] / divisor);
- while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) { }
+ while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) {}
divisor = 1;
}
}
+ else if (ns.now) {
+ begin = ns.now();
+ while (!(measured = ns.now() - begin)) {}
+ }
else {
- begin = new ns;
- while (!(measured = new ns - begin)) { }
+ begin = new ns().getTime();
+ while (!(measured = new ns().getTime() - begin)) {}
}
- // check for broken timers (nanoTime may have issues)
+ // check for broken timers (`nanoTime` may have issues)
// http://alivebutsleepy.srnet.cz/unreliable-system-nanotime/
if (measured > 0) {
sample.push(measured);
@@ -1797,7 +1813,7 @@
*/
function interpolate(string) {
// replaces all occurrences of `#` with a unique number and template tokens with content
- return _.template(string.replace(/\#/g, /\d+/.exec(templateData.uid)), templateData);
+ return _.template(string.replace(/\#/g, /\d+/.exec(templateData.uid)))(templateData);
}
/*----------------------------------------------------------------------*/
@@ -1812,7 +1828,7 @@
if (typeof timer.ns.nanoTime() == 'number') {
timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' });
}
- } catch(e) { }
+ } catch(e) {}
// detect Chrome's microsecond timer:
// enable benchmarking via the --enable-benchmarking command
@@ -1821,27 +1837,18 @@
if ((timer.ns = new (context.chrome || context.chromium).Interval)) {
timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
}
- } catch(e) { }
-
- // detect `performance.now` microsecond resolution timer
- if ((timer.ns = perfName && perfObject)) {
- timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
- }
+ } catch(e) {}
- // detect Node's nanosecond resolution timer available in Node >= 0.8
+ // detect Node.js's nanosecond resolution timer available in Node.js >= 0.8
if (processObject && typeof (timer.ns = processObject.hrtime) == 'function') {
timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' });
}
-
- // detect Wade Simmons' Node microtime module
+ // detect Wade Simmons' Node.js `microtime` module
if (microtimeObject && typeof (timer.ns = microtimeObject.now) == 'function') {
timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
}
-
// pick timer with highest resolution
- timer = _.reduce(timers, function(timer, other) {
- return other.res < timer.res ? other : timer;
- });
+ timer = _.min(timers, 'res');
// remove unused applet
if (timer.unit != 'ns' && applet) {
@@ -1936,7 +1943,7 @@
variance,
clone = event.target,
done = bench.aborted,
- now = +new Date,
+ now = _.now(),
size = sample.push(clone.times.period),
maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime,
times = bench.times,
@@ -1965,7 +1972,7 @@
// relative margin of error
rme = (moe / mean) * 100 || 0;
- _.extend(bench.stats, {
+ _.assign(bench.stats, {
'deviation': sd,
'mean': mean,
'moe': moe,
@@ -1996,7 +2003,7 @@
if (queue.length < 2 && !maxedOut) {
enqueue();
}
- // abort the invoke cycle when done
+ // abort the `invoke` cycle when done
event.aborted = done;
}
@@ -2141,7 +2148,7 @@
bench.running = true;
bench.count = bench.initCount;
- bench.times.timeStamp = +new Date;
+ bench.times.timeStamp = _.now();
bench.emit(event);
if (!event.cancelled) {
@@ -2170,8 +2177,8 @@
// The bugginess continues as the `Benchmark` constructor has an argument
// named `options` and Firefox 1 will not assign a value to `Benchmark.options`,
// making it non-writable in the process, unless it is the first property
- // assigned by for-in loop of `_.extend()`.
- _.extend(Benchmark, {
+ // assigned by for-in loop of `_.assign()`.
+ _.assign(Benchmark, {
/**
* The default options copied by benchmark instances.
@@ -2207,7 +2214,7 @@
'delay': 0.005,
/**
- * Displayed by Benchmark#toString when a `name` is not available
+ * Displayed by `Benchmark#toString` when a `name` is not available
* (auto-generated if absent).
*
* @memberOf Benchmark.options
@@ -2308,7 +2315,7 @@
/**
* Platform object with properties describing things like browser name,
- * version, and operating system.
+ * version, and operating system. See [`platform.js`](http://mths.be/platform).
*
* @static
* @memberOf Benchmark
@@ -2335,10 +2342,10 @@
* @memberOf Benchmark
* @type string
*/
- 'version': '1.0.0'
+ 'version': '2.0.0-pre'
});
- _.extend(Benchmark, {
+ _.assign(Benchmark, {
'filter': filter,
'formatNumber': formatNumber,
'invoke': invoke,
@@ -2354,7 +2361,7 @@
/*------------------------------------------------------------------------*/
- _.extend(Benchmark.prototype, {
+ _.assign(Benchmark.prototype, {
/**
* The number of times a test was executed.
@@ -2481,7 +2488,7 @@
* }())
* }())
*/
- 'setup': noop,
+ 'setup': _.noop,
/**
* Compiled into the test and executed immediately **after** the test loop.
@@ -2489,7 +2496,7 @@
* @memberOf Benchmark
* @type {Function|string}
*/
- 'teardown': noop,
+ 'teardown': _.noop,
/**
* An object of stats including mean, margin or error, and standard deviation.
@@ -2598,7 +2605,7 @@
}
});
- _.extend(Benchmark.prototype, {
+ _.assign(Benchmark.prototype, {
'abort': abort,
'clone': clone,
'compare': compare,
@@ -2613,7 +2620,7 @@
/*------------------------------------------------------------------------*/
- _.extend(Deferred.prototype, {
+ _.assign(Deferred.prototype, {
/**
* The deferred benchmark instance.
@@ -2648,13 +2655,13 @@
'timeStamp': 0
});
- _.extend(Deferred.prototype, {
+ _.assign(Deferred.prototype, {
'resolve': resolve
});
/*------------------------------------------------------------------------*/
- _.extend(Event.prototype, {
+ _.assign(Event.prototype, {
/**
* A flag to indicate if the emitters listener iteration is aborted.
@@ -2735,7 +2742,7 @@
/*------------------------------------------------------------------------*/
- _.extend(Suite.prototype, {
+ _.assign(Suite.prototype, {
/**
* The number of benchmarks in the suite.
@@ -2762,7 +2769,7 @@
'running': false
});
- _.extend(Suite.prototype, {
+ _.assign(Suite.prototype, {
'abort': abortSuite,
'add': add,
'clone': cloneSuite,
@@ -2778,16 +2785,16 @@
'run': runSuite,
'reverse': arrayRef.reverse,
'shift': shift,
- 'slice': arrayRef.slice,
+ 'slice': slice,
'sort': arrayRef.sort,
'splice': arrayRef.splice,
- 'unshift': arrayRef.unshift
+ 'unshift': unshift
});
/*------------------------------------------------------------------------*/
// expose Deferred, Event, and Suite
- _.extend(Benchmark, {
+ _.assign(Benchmark, {
'Deferred': Deferred,
'Event': Event,
'Suite': Suite
@@ -2822,16 +2829,21 @@
};
});
}
- // trigger clock's lazy define early to avoid a security error
- if (support.air) {
- clock({ '_original': { 'fn': noop, 'count': 1, 'options': {} } });
+ // avoid buggy `Array#unshift` in IE < 8 which doesn't return the new
+ // length of the array
+ if (!support.unshiftResult) {
+ Suite.prototype.unshift = function() {
+ var value = this;
+ unshift.apply(value, arguments);
+ return value.length;
+ };
}
return Benchmark;
}
/*--------------------------------------------------------------------------*/
- // expose Benchmark
+ // export Benchmark
// some AMD build optimizers, like r.js, check for condition patterns like the following:
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
// define as an anonymous module so, through path mapping, it can be aliased
@@ -2846,19 +2858,19 @@
var Benchmark = runInContext();
// check for `exports` after `define` in case a build optimizer adds an `exports` object
- if (freeExports && !freeExports.nodeType) {
- // in Node.js or RingoJS v0.8.0+
- if (freeModule) {
+ if (freeExports && freeModule) {
+ // in Node.js or RingoJS
+ if (moduleExports) {
(freeModule.exports = Benchmark).Benchmark = Benchmark;
}
- // in Narwhal or RingoJS v0.7.0-
+ // in Narwhal or Rhino -require
else {
freeExports.Benchmark = Benchmark;
}
}
- // in a browser or Rhino
else {
+ // in a browser or Rhino
root.Benchmark = Benchmark;
}
}
-}(this));
+}.call(this));
diff --git a/vendor/curl/LICENSE.txt b/vendor/curl/LICENSE.txt
deleted file mode 100644
index 1755b7a..0000000
--- a/vendor/curl/LICENSE.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Open Source Initiative OSI - The MIT License
-
-http://www.opensource.org/licenses/mit-license.php
-
-Copyright (c) 2010-2013 Brian Cavalier and John Hann
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/docdown/LICENSE.txt b/vendor/docdown/LICENSE.txt
deleted file mode 100644
index a7501f9..0000000
--- a/vendor/docdown/LICENSE.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright 2011-2013 John-David Dalton <http://allyoucanleet.com/>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/vendor/docdown/docdown.php b/vendor/docdown/docdown.php
deleted file mode 100644
index b25ea91..0000000
--- a/vendor/docdown/docdown.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-/*!
- * Docdown v1.0.0-pre
- * Copyright 2011-2013 John-David Dalton <http://allyoucanleet.com/>
- * Available under MIT license <http://mths.be/mit>
- */
-require(dirname(__FILE__) . '/src/DocDown/MarkdownGenerator.php');
-
-/**
- * Generates Markdown from JSDoc entries in a given file.
- *
- * @param {Array} [$options=array()] The options array.
- * @returns {string} The generated Markdown.
- * @example
- *
- * // specify a file path
- * $markdown = docdown(array(
- * // path to js file
- * 'path' => $filepath,
- * // url used to reference line numbers in code
- * 'url' => 'https://github.com/username/project/blob/master/my.js'
- * ));
- *
- * // or pass raw js
- * $markdown = docdown(array(
- * // raw JavaScript source
- * 'source' => $rawJS,
- * // documentation title
- * 'title' => 'My API Documentation',
- * // url used to reference line numbers in code
- * 'url' => 'https://github.com/username/project/blob/master/my.js'
- * ));
- */
-function docdown( $options = array() ) {
- $gen = new MarkdownGenerator($options);
- return $gen->generate();
-}
-?>
\ No newline at end of file
diff --git a/vendor/docdown/src/DocDown/Alias.php b/vendor/docdown/src/DocDown/Alias.php
deleted file mode 100644
index c04e55c..0000000
--- a/vendor/docdown/src/DocDown/Alias.php
+++ /dev/null
@@ -1,226 +0,0 @@
-<?php
-
-/**
- * A class to represent a JSDoc entry alias.
- */
-class Alias {
-
- /**
- * The alias owner.
- *
- * @memberOf Alias
- * @type Object
- */
- public $owner;
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * The Alias constructor.
- *
- * @constructor
- * @param {string} $name The alias name.
- * @param {Object} $owner The alias owner.
- */
- public function __construct( $name, $owner ) {
- $this->owner = $owner;
- $this->_name = $name;
- $this->_call = $owner->getCall();
- $this->_category = $owner->getCategory();
- $this->_desc = $owner->getDesc();
- $this->_example = $owner->getExample();
- $this->_isCtor = $owner->isCtor();
- $this->_isLicense = $owner->isLicense();
- $this->_isPlugin = $owner->isPlugin();
- $this->_isPrivate = $owner->isPrivate();
- $this->_isStatic = $owner->isStatic();
- $this->_lineNumber = $owner->getLineNumber();
- $this->_members = $owner->getMembers();
- $this->_params = $owner->getParams();
- $this->_returns = $owner->getReturns();
- $this->_type = $owner->getType();
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Extracts the entry's `alias` objects.
- *
- * @memberOf Alias
- * @param {number} $index The index of the array value to return.
- * @returns {Array|string} The entry's `alias` objects.
- */
- public function getAliases( $index = null ) {
- $result = array();
- return $index !== null
- ? @$result[$index]
- : $result;
- }
-
- /**
- * Extracts the function call from the owner entry.
- *
- * @memberOf Alias
- * @returns {string} The function call.
- */
- public function getCall() {
- return $this->_call;
- }
-
- /**
- * Extracts the owner entry's `category` data.
- *
- * @memberOf Alias
- * @returns {string} The owner entry's `category` data.
- */
- public function getCategory() {
- return $this->_category;
- }
-
- /**
- * Extracts the owner entry's description.
- *
- * @memberOf Alias
- * @returns {string} The owner entry's description.
- */
- public function getDesc() {
- return $this->_desc;
- }
-
- /**
- * Extracts the owner entry's `example` data.
- *
- * @memberOf Alias
- * @returns {string} The owner entry's `example` data.
- */
- public function getExample() {
- return $this->_example;
- }
-
- /**
- * Checks if the entry is an alias.
- *
- * @memberOf Alias
- * @returns {boolean} Returns `true`.
- */
- public function isAlias() {
- return true;
- }
-
- /**
- * Checks if the owner entry is a constructor.
- *
- * @memberOf Alias
- * @returns {boolean} Returns `true` if a constructor, else `false`.
- */
- public function isCtor() {
- return $this->_isCtor;
- }
-
- /**
- * Checks if the owner entry is a license.
- *
- * @memberOf Alias
- * @returns {boolean} Returns `true` if a license, else `false`.
- */
- public function isLicense() {
- return $this->_isLicense;
- }
-
- /**
- * Checks if the owner entry *is* assigned to a prototype.
- *
- * @memberOf Alias
- * @returns {boolean} Returns `true` if assigned to a prototype, else `false`.
- */
- public function isPlugin() {
- return $this->_isPlugin;
- }
-
- /**
- * Checks if the owner entry is private.
- *
- * @memberOf Alias
- * @returns {boolean} Returns `true` if private, else `false`.
- */
- public function isPrivate() {
- return $this->_isPrivate;
- }
-
- /**
- * Checks if the owner entry is *not* assigned to a prototype.
- *
- * @memberOf Alias
- * @returns {boolean} Returns `true` if not assigned to a prototype, else `false`.
- */
- public function isStatic() {
- return $this->_isStatic;
- }
-
- /**
- * Resolves the owner entry's line number.
- *
- * @memberOf Alias
- * @returns {number} The owner entry's line number.
- */
- public function getLineNumber() {
- return $this->_lineNumber;
- }
-
- /**
- * Extracts the owner entry's `member` data.
- *
- * @memberOf Alias
- * @param {number} $index The index of the array value to return.
- * @returns {Array|string} The owner entry's `member` data.
- */
- public function getMembers( $index = null ) {
- return $index !== null
- ? @$this->_members[$index]
- : $this->_members;
- }
-
- /**
- * Extracts the owner entry's `name` data.
- *
- * @memberOf Alias
- * @returns {string} The owner entry's `name` data.
- */
- public function getName() {
- return $this->_name;
- }
-
- /**
- * Extracts the owner entry's `param` data.
- *
- * @memberOf Alias
- * @param {number} $index The index of the array value to return.
- * @returns {Array} The owner entry's `param` data.
- */
- public function getParams( $index = null ) {
- return $index !== null
- ? @$this->_params[$index]
- : $this->_params;
- }
-
- /**
- * Extracts the owner entry's `returns` data.
- *
- * @memberOf Alias
- * @returns {string} The owner entry's `returns` data.
- */
- public function getReturns() {
- return $this->_returns;
- }
-
- /**
- * Extracts the owner entry's `type` data.
- *
- * @memberOf Alias
- * @returns {string} The owner entry's `type` data.
- */
- public function getType() {
- return $this->_type;
- }
-}
-?>
\ No newline at end of file
diff --git a/vendor/docdown/src/DocDown/Entry.php b/vendor/docdown/src/DocDown/Entry.php
deleted file mode 100644
index 51facb6..0000000
--- a/vendor/docdown/src/DocDown/Entry.php
+++ /dev/null
@@ -1,452 +0,0 @@
-<?php
-
-require(dirname(__FILE__) . "/Alias.php");
-
-/**
- * A class to simplify parsing a single JSDoc entry.
- */
-class Entry {
-
- /**
- * The documentation entry.
- *
- * @memberOf Entry
- * @type string
- */
- public $entry = '';
-
- /**
- * The language highlighter used for code examples.
- *
- * @memberOf Entry
- * @type string
- */
- public $lang = '';
-
- /**
- * The source code.
- *
- * @memberOf Entry
- * @type string
- */
- public $source = '';
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * The Entry constructor.
- *
- * @constructor
- * @param {string} $entry The documentation entry to analyse.
- * @param {string} $source The source code.
- * @param {string} [$lang ='js'] The language highlighter used for code examples.
- */
- public function __construct( $entry, $source, $lang = 'js' ) {
- $this->entry = $entry;
- $this->lang = $lang;
- $this->source = str_replace(PHP_EOL, "\n", $source);
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Extracts the documentation entries from source code.
- *
- * @static
- * @memberOf Entry
- * @param {string} $source The source code.
- * @returns {Array} The array of entries.
- */
- public static function getEntries( $source ) {
- preg_match_all('#/\*\*(?![-!])[\s\S]*?\*/\s*.+#', $source, $result);
- return array_pop($result);
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Checks if the entry is a function reference.
- *
- * @private
- * @memberOf Entry
- * @returns {boolean} Returns `true` if the entry is a function reference, else `false`.
- */
- private function isFunction() {
- if (!isset($this->_isFunction)) {
- $this->_isFunction = !!(
- $this->isCtor() ||
- count($this->getParams()) ||
- count($this->getReturns()) ||
- preg_match('/\*[\t ]*@function\b/', $this->entry) ||
- preg_match('#\*/\s*function #', $this->entry)
- );
- }
- return $this->_isFunction;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Extracts the entry's `alias` objects.
- *
- * @memberOf Entry
- * @param {number} $index The index of the array value to return.
- * @returns {Array|string} The entry's `alias` objects.
- */
- public function getAliases( $index = null ) {
- if (!isset($this->_aliases)) {
- preg_match('#\*[\t ]*@alias\s+(.+)#', $this->entry, $result);
-
- if (count($result)) {
- $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]));
- $result = preg_split('/,\s*/', $result);
- natsort($result);
-
- foreach ($result as $resultIndex => $value) {
- $result[$resultIndex] = new Alias($value, $this);
- }
- }
- $this->_aliases = $result;
- }
- return $index !== null
- ? @$this->_aliases[$index]
- : $this->_aliases;
- }
-
- /**
- * Extracts the function call from the entry.
- *
- * @memberOf Entry
- * @returns {string} The function call.
- */
- public function getCall() {
- if (isset($this->_call)) {
- return $this->_call;
- }
-
- preg_match('#\*/\s*(?:function ([^(]*)|(.*?)(?=[:=,]|return\b))#', $this->entry, $result);
- if ($result = array_pop($result)) {
- $result = array_pop(explode('var ', trim(trim(array_pop(explode('.', $result))), "'")));
- }
- // resolve name
- // avoid $this->getName() because it calls $this->getCall()
- preg_match('#\*[\t ]*@name\s+(.+)#', $this->entry, $name);
- if (count($name)) {
- $name = trim($name[1]);
- } else {
- $name = $result;
- }
- // compile function call syntax
- if ($this->isFunction()) {
- // compose parts
- $result = array($result);
- $params = $this->getParams();
-
- foreach ($params as $param) {
- // skip params that are properties of other params (e.g. `options.leading`)
- if (!preg_match('/\w+\.[\w.]+\s*=/', $param[1])) {
- $result[] = $param[1];
- }
- }
- // format
- $result = $name .'('. implode(array_slice($result, 1), ', ') .')';
- }
-
- $this->_call = $result ? $result : $name;
- return $this->_call;
- }
-
- /**
- * Extracts the entry's `category` data.
- *
- * @memberOf Entry
- * @returns {string} The entry's `category` data.
- */
- public function getCategory() {
- if (isset($this->_category)) {
- return $this->_category;
- }
-
- preg_match('#\*[\t ]*@category\s+(.+)#', $this->entry, $result);
- if (count($result)) {
- $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]));
- } else {
- $result = $this->getType() == 'Function' ? 'Methods' : 'Properties';
- }
- $this->_category = $result;
- return $result;
- }
-
- /**
- * Extracts the entry's description.
- *
- * @memberOf Entry
- * @returns {string} The entry's description.
- */
- public function getDesc() {
- if (isset($this->_desc)) {
- return $this->_desc;
- }
-
- preg_match('#/\*\*(?:\s*\*)?([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
- if (count($result)) {
- $type = $this->getType();
- $result = preg_replace('/:\n[\t ]*\*[\t ]*/', ":<br>\n", $result[1]);
- $result = preg_replace('/(?:^|\n)[\t ]*\*\n[\t ]*\*[\t ]*/', "\n\n", $result);
- $result = preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result);
- $result = trim($result);
- $result = ($type == 'Function' ? '' : '(' . str_replace('|', ', ', trim($type, '{}')) . '): ') . $result;
- }
- $this->_desc = $result;
- return $result;
- }
-
- /**
- * Extracts the entry's `example` data.
- *
- * @memberOf Entry
- * @returns {string} The entry's `example` data.
- */
- public function getExample() {
- if (isset($this->_example)) {
- return $this->_example;
- }
-
- preg_match('#\*[\t ]*@example\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
- if (count($result)) {
- $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', "\n", $result[1]));
- $result = '```' . $this->lang . "\n" . $result . "\n```";
- }
- $this->_example = $result;
- return $result;
- }
-
- /**
- * Checks if the entry is an alias.
- *
- * @memberOf Entry
- * @returns {boolean} Returns `false`.
- */
- public function isAlias() {
- return false;
- }
-
- /**
- * Checks if the entry is a constructor.
- *
- * @memberOf Entry
- * @returns {boolean} Returns `true` if a constructor, else `false`.
- */
- public function isCtor() {
- if (!isset($this->_isCtor)) {
- $this->_isCtor = !!preg_match('/\*[\t ]*@constructor\b/', $this->entry);
- }
- return $this->_isCtor;
- }
-
- /**
- * Checks if the entry is a license.
- *
- * @memberOf Entry
- * @returns {boolean} Returns `true` if a license, else `false`.
- */
- public function isLicense() {
- if (!isset($this->_isLicense)) {
- $this->_isLicense = !!preg_match('/\*[\t ]*@license\b/', $this->entry);
- }
- return $this->_isLicense;
- }
-
- /**
- * Checks if the entry *is* assigned to a prototype.
- *
- * @memberOf Entry
- * @returns {boolean} Returns `true` if assigned to a prototype, else `false`.
- */
- public function isPlugin() {
- if (!isset($this->_isPlugin)) {
- $this->_isPlugin = !$this->isCtor() && !$this->isPrivate() && !$this->isStatic();
- }
- return $this->_isPlugin;
- }
-
- /**
- * Checks if the entry is private.
- *
- * @memberOf Entry
- * @returns {boolean} Returns `true` if private, else `false`.
- */
- public function isPrivate() {
- if (!isset($this->_isPrivate)) {
- $this->_isPrivate = $this->isLicense() || !!preg_match('/\*[\t ]*@private\b/', $this->entry) || !preg_match('/\*[\t ]*@[a-z]+\b/', $this->entry);
- }
- return $this->_isPrivate;
- }
-
- /**
- * Checks if the entry is *not* assigned to a prototype.
- *
- * @memberOf Entry
- * @returns {boolean} Returns `true` if not assigned to a prototype, else `false`.
- */
- public function isStatic() {
- if (isset($this->_isStatic)) {
- return $this->_isStatic;
- }
-
- $public = !$this->isPrivate();
- $result = $public && !!preg_match('/\*[\t ]*@static\b/', $this->entry);
-
- // set in cases where it isn't explicitly stated
- if ($public && !$result) {
- if ($parent = array_pop(preg_split('/[#.]/', $this->getMembers(0)))) {
- foreach (Entry::getEntries($this->source) as $entry) {
- $entry = new Entry($entry, $this->source);
- if ($entry->getName() == $parent) {
- $result = !$entry->isCtor();
- break;
- }
- }
- } else {
- $result = true;
- }
- }
- $this->_isStatic = $result;
- return $result;
- }
-
- /**
- * Resolves the entry's line number.
- *
- * @memberOf Entry
- * @returns {number} The entry's line number.
- */
- public function getLineNumber() {
- if (!isset($this->_lineNumber)) {
- preg_match_all('/\n/', substr($this->source, 0, strrpos($this->source, $this->entry) + strlen($this->entry)), $lines);
- $this->_lineNumber = count(array_pop($lines)) + 1;
- }
- return $this->_lineNumber;
- }
-
- /**
- * Extracts the entry's `member` data.
- *
- * @memberOf Entry
- * @param {number} $index The index of the array value to return.
- * @returns {Array|string} The entry's `member` data.
- */
- public function getMembers( $index = null ) {
- if (!isset($this->_members)) {
- preg_match('#\*[\t ]*@member(?:Of)?\s+(.+)#', $this->entry, $result);
- if (count($result)) {
- $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]));
- $result = preg_split('/,\s*/', $result);
- natsort($result);
- }
- $this->_members = $result;
- }
- return $index !== null
- ? @$this->_members[$index]
- : $this->_members;
- }
-
- /**
- * Extracts the entry's `name` data.
- *
- * @memberOf Entry
- * @returns {string} The entry's `name` data.
- */
- public function getName() {
- if (isset($this->_name)) {
- return $this->_name;
- }
-
- preg_match('#\*[\t ]*@name\s+(.+)#', $this->entry, $result);
- if (count($result)) {
- $result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]));
- } else {
- $result = array_shift(explode('(', $this->getCall()));
- }
- $this->_name = $result;
- return $result;
- }
-
- /**
- * Extracts the entry's `param` data.
- *
- * @memberOf Entry
- * @param {number} $index The index of the array value to return.
- * @returns {Array} The entry's `param` data.
- */
- public function getParams( $index = null ) {
- if (!isset($this->_params)) {
- preg_match_all('#\*[\t ]*@param\s+\{\(?([^})]+)\)?\}\s+(\[.+\]|[$\w|]+(?:\[.+\])?)\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#i', $this->entry, $matchTuples);
- $matchTuples = array_filter(array_slice($matchTuples, 1));
- $result = array();
-
- if (count($matchTuples)) {
- foreach ($matchTuples as $tupleKey => $tuple) {
- foreach ($tuple as $key => $value) {
- if (!isset($result[$key])) {
- $result[$key] = array();
- }
- $result[$key][] = $tupleKey
- ? trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]*/', ' ', $value))
- : trim($value);
- }
- }
- }
- $this->_params = $result;
- }
- return $index !== null
- ? @$this->_params[$index]
- : $this->_params;
- }
-
- /**
- * Extracts the entry's `returns` data.
- *
- * @memberOf Entry
- * @returns {string} The entry's `returns` data.
- */
- public function getReturns() {
- if (isset($this->_returns)) {
- return $this->_returns;
- }
-
- preg_match('#\*[\t ]*@returns\s+\{([^}]+)\}\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
- if (count($result)) {
- $result = array_map('trim', array_slice($result, 1));
- $result[0] = str_replace('|', ', ', $result[0]);
- $result[1] = preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]);
- }
- $this->_returns = $result;
- return $result;
- }
-
- /**
- * Extracts the entry's `type` data.
- *
- * @memberOf Entry
- * @returns {string} The entry's `type` data.
- */
- public function getType() {
- if (isset($this->_type)) {
- return $this->_type;
- }
-
- preg_match('#\*[\t ]*@type\s(?:\{\(?)?([^)}\n]+)#', $this->entry, $result);
- if (count($result)) {
- $result = trim($result[1]);
- if (preg_match('/^(?:array|function|object|regexp)$/', $result)) {
- $result = ucfirst($result);
- }
- } else {
- $result = $this->isFunction() ? 'Function' : 'unknown';
- }
- $this->_type = $result;
- return $result;
- }
-}
-?>
\ No newline at end of file
diff --git a/vendor/docdown/src/DocDown/MarkdownGenerator.php b/vendor/docdown/src/DocDown/MarkdownGenerator.php
deleted file mode 100644
index fd7fc15..0000000
--- a/vendor/docdown/src/DocDown/MarkdownGenerator.php
+++ /dev/null
@@ -1,648 +0,0 @@
-<?php
-
-require(dirname(__FILE__) . "/Entry.php");
-
-/**
- * Generates Markdown from JSDoc entries.
- */
-class MarkdownGenerator {
-
- /**
- * The HTML for the close tag.
- *
- * @static
- * @memberOf MarkdownGenerator
- * @type string
- */
- public $closeTag = "\n<!-- /div -->\n";
-
- /**
- * An array of JSDoc entries.
- *
- * @memberOf MarkdownGenerator
- * @type Array
- */
- public $entries = array();
-
- /**
- * The HTML for the open tag.
- *
- * @memberOf MarkdownGenerator
- * @type string
- */
- public $openTag = "\n<!-- div -->\n";
-
- /**
- * An options array used to configure the generator.
- *
- * @memberOf MarkdownGenerator
- * @type Array
- */
- public $options = array();
-
- /**
- * The file's source code.
- *
- * @memberOf MarkdownGenerator
- * @type string
- */
- public $source = '';
-
- /**
- * The array of code snippets that are tokenized by `escape`.
- *
- * @private
- * @memberOf MarkdownGenerator
- * @type Array
- */
- private $snippets = array();
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * The MarkdownGenerator constructor.
- *
- * @constructor
- * @param {string} $source The source code to parse.
- * @param {Array} $options The options array.
- */
- public function __construct( $source, $options = array() ) {
- // juggle arguments
- if (is_array($source)) {
- $options = $source;
- } else {
- $options['source'] = $source;
- }
- if (isset($options['source']) && realpath($options['source'])) {
- $options['path'] = $options['source'];
- }
- if (isset($options['path'])) {
- preg_match('/(?<=\.)[a-z]+$/', $options['path'], $ext);
- $options['source'] = file_get_contents($options['path']);
- $ext = array_pop($ext);
-
- if (!isset($options['lang']) && $ext) {
- $options['lang'] = $ext;
- }
- if (!isset($options['title'])) {
- $options['title'] = ucfirst(basename($options['path'])) . ' API documentation';
- }
- }
- if (!isset($options['lang'])) {
- $options['lang'] = 'js';
- }
- if (!isset($options['toc'])) {
- $options['toc'] = 'properties';
- }
-
- $this->options = $options;
- $this->source = str_replace(PHP_EOL, "\n", $options['source']);
- $this->entries = Entry::getEntries($this->source);
-
- foreach ($this->entries as $index => $value) {
- $this->entries[$index] = new Entry($value, $this->source, $options['lang']);
- }
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Performs common string formatting operations.
- *
- * @private
- * @static
- * @memberOf MarkdownGenerator
- * @param {string} $string The string to format.
- * @returns {string} The formatted string.
- */
- private static function format( $string ) {
- $counter = 0;
-
- // tokenize inline code snippets
- preg_match_all('/`[^`]+`/', $string, $tokenized);
- $tokenized = $tokenized[0];
- foreach ($tokenized as $snippet) {
- $string = str_replace($snippet, '__token' . ($counter++) .'__', $string);
- }
-
- // italicize parentheses
- $string = preg_replace('/(^|\s)(\([^)]+\))/', '$1*$2*', $string);
-
- // mark numbers as inline code
- $string = preg_replace('/[\t ](-?\d+(?:.\d+)?)(?!\.[^\n])/', ' `$1`', $string);
-
- // detokenize inline code snippets
- $counter = 0;
- foreach ($tokenized as $snippet) {
- $string = str_replace('__token' . ($counter++) . '__', $snippet, $string);
- }
-
- return trim($string);
- }
-
- /**
- * Modify a string by replacing named tokens with matching assoc. array values.
- *
- * @private
- * @static
- * @memberOf MarkdownGenerator
- * @param {string} $string The string to modify.
- * @param {Array|Object} $object The template object.
- * @returns {string} The modified string.
- */
- private static function interpolate( $string, $object ) {
- preg_match_all('/#\{([^}]+)\}/', $string, $tokens);
- $tokens = array_unique(array_pop($tokens));
-
- foreach ($tokens as $token) {
- $pattern = '/#\{' . preg_replace('/([.*+?^${}()|[\]\\\])/', '\\\$1', $token) . '\}/';
- $replacement = '';
-
- if (is_object($object)) {
- preg_match('/\(([^)]+?)\)$/', $token, $args);
- $args = preg_split('/,\s*/', array_pop($args));
- $method = 'get' . ucfirst(preg_replace('/\([^)]+?\)$/', '', $token));
-
- if (method_exists($object, $method)) {
- $replacement = (string) call_user_func_array(array($object, $method), $args);
- } else if (isset($object->{$token})) {
- $replacement = (string) $object->{$token};
- }
- } else if (isset($object[$token])) {
- $replacement = (string) $object[$token];
- }
- $string = preg_replace($pattern, trim($replacement), $string);
- }
- return MarkdownGenerator::format($string);
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Adds the given `$entries` to the `$result` array.
- *
- * @private
- * @memberOf MarkdownGenerator
- * @param {Array} $result The result array to modify.
- * @param {Array} $entries The entries to add to the `$result`.
- */
- private function addEntries( &$result, $entries ) {
- foreach ($entries as $entry) {
- // skip aliases
- if ($entry->isAlias()) {
- continue;
- }
- // name and description
- array_push(
- $result,
- $this->openTag,
- MarkdownGenerator::interpolate("### <a id=\"#{hash}\"></a>`#{member}#{separator}#{call}`\n<a href=\"##{hash}\">#</a> [Ⓢ](#{href} \"View in source\") [Ⓣ][1]\n\n#{desc}", array(
- 'call' => $entry->getCall(),
- 'desc' => $this->escape($entry->getDesc()),
- 'hash' => $entry->hash,
- 'href' => $entry->href,
- 'member' => $entry->member,
- 'separator' => $entry->separator
- ))
- );
-
- // @alias
- if (count($aliases = $entry->getAliases())) {
- array_push($result, '', '#### Aliases');
- foreach ($aliases as $index => $alias) {
- $aliases[$index] = MarkdownGenerator::interpolate('#{member}#{separator}#{name}', $alias);
- }
- $result[] = '*' . implode(', ', $aliases) . '*';
- }
- // @param
- if (count($params = $entry->getParams())) {
- array_push($result, '', '#### Arguments');
- foreach ($params as $index => $param) {
- $result[] = MarkdownGenerator::interpolate('#{num}. `#{name}` (#{type}): #{desc}', array(
- 'desc' => $this->escape($param[2]),
- 'name' => $param[1],
- 'num' => $index + 1,
- 'type' => $this->escape($param[0])
- ));
- }
- }
- // @returns
- if (count($returns = $entry->getReturns())) {
- array_push(
- $result, '',
- '#### Returns',
- MarkdownGenerator::interpolate('(#{type}): #{desc}', array(
- 'desc' => $this->escape($returns[1]),
- 'type' => $this->escape($returns[0])
- ))
- );
- }
- // @example
- if ($example = $entry->getExample()) {
- array_push($result, '', '#### Example', $example);
- }
- array_push($result, "\n* * *", $this->closeTag);
- }
- }
-
- /**
- * Escapes special Markdown characters.
- *
- * @private
- * @memberOf Entry
- * @param {string} $string The string to escape.
- * @returns {string} Returns the escaped string.
- */
- private function escape( $string ) {
- $string = preg_replace_callback('/`.*?\`/', array($this, 'swapSnippetsToTokens'), $string);
- $string = preg_replace('/(?<!\\\)\*/', '*', $string);
- $string = preg_replace('/(?<!\\\)\[/', '[', $string);
- $string = preg_replace('/(?<!\\\)\]/', ']', $string);
- $string = preg_replace_callback('/@@token@@/', array($this, 'swapTokensToSnippets'), $string);
- return $string;
- }
-
- /**
- * Resolves the entry's hash used to navigate the documentation.
- *
- * @private
- * @memberOf MarkdownGenerator
- * @param {number|Object} $entry The entry object.
- * @param {string} $member The name of the member.
- * @returns {string} The url hash.
- */
- private function getHash( $entry, $member = '' ) {
- $entry = is_numeric($entry) ? $this->entries[$entry] : $entry;
- $member = !$member ? $entry->getMembers(0) : $member;
-
- $result = ($member ? $member . ($entry->isPlugin() ? 'prototype' : '') : '') . $entry->getCall();
- $result = preg_replace('/\(\[|\[\]/', '', $result);
- $result = preg_replace('/[\t =|\'"{}.()\]]/', '', $result);
- $result = preg_replace('/[\[#,]+/', '-', $result);
- return strtolower($result);
- }
-
- /**
- * Resolves the entry's url for the specific line number.
- *
- * @private
- * @memberOf MarkdownGenerator
- * @param {number|Object} $entry The entry object.
- * @returns {string} The url.
- */
- private function getLineUrl( $entry ) {
- $entry = is_numeric($entry) ? $this->entries($entry) : $entry;
- return $this->options['url'] . '#L' . $entry->getLineNumber();
- }
-
- /**
- * Extracts the character used to separate the entry's name from its member.
- *
- * @private
- * @memberOf MarkdownGenerator
- * @param {number|Object} $entry The entry object.
- * @returns {string} The separator.
- */
- private function getSeparator( $entry ) {
- $entry = is_numeric($entry) ? $this->entries($entry) : $entry;
- return $entry->isPlugin() ? '.prototype.' : '.';
- }
-
- /**
- * Swaps code snippets with tokens as a `preg_replace_callback` callback
- * used by `escape`.
- *
- * @private
- * @memberOf Entry
- * @param {Array} $matches The array of regexp matches.
- * @returns {string} Returns the token.
- */
- private function swapSnippetsToTokens( $matches ) {
- $this->snippets[] = $matches[0];
- return '@@token@@';
- }
-
- /**
- * Swaps tokens with code snippets as a `preg_replace_callback` callback
- * used by `escape`.
- *
- * @private
- * @memberOf Entry
- * @returns {string} Returns the code snippet.
- */
- private function swapTokensToSnippets() {
- return array_shift($this->snippets);
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Generates Markdown from JSDoc entries.
- *
- * @memberOf MarkdownGenerator
- * @returns {string} The rendered Markdown.
- */
- public function generate() {
- $api = array();
- $byCategory = $this->options['toc'] == 'categories';
- $categories = array();
- $closeTag = $this->closeTag;
- $compiling = false;
- $openTag = $this->openTag;
- $result = array('# ' . $this->options['title']);
- $toc = 'toc';
-
- // initialize $api array
- foreach ($this->entries as $entry) {
- // skip invalid or private entries
- $name = $entry->getName();
- if (!$name || $entry->isPrivate()) {
- continue;
- }
-
- $members = $entry->getMembers();
- $members = count($members) ? $members : array('');
-
- foreach ($members as $member) {
- // create api category arrays
- if ($member && !isset($api[$member])) {
- // create temporary entry to be replaced later
- $api[$member] = new stdClass;
- $api[$member]->static = array();
- $api[$member]->plugin = array();
- }
-
- // append entry to api member
- if (!$member || $entry->isCtor() || ($entry->getType() == 'Object' &&
- !preg_match('/[=:]\s*(?:null|undefined)\s*[,;]?$/', $entry->entry))) {
-
- // assign the real entry, replacing the temporary entry if it exist
- $member = ($member ? $member . ($entry->isPlugin() ? '#' : '.') : '') . $name;
- $entry->static = @$api[$member] ? $api[$member]->static : array();
- $entry->plugin = @$api[$member] ? $api[$member]->plugin : array();
-
- $api[$member] = $entry;
- foreach ($entry->getAliases() as $alias) {
- $api[$member]->static[] = $alias;
- }
- }
- else if ($entry->isStatic()) {
- $api[$member]->static[] = $entry;
- foreach ($entry->getAliases() as $alias) {
- $api[$member]->static[] = $alias;
- }
- }
- else if (!$entry->isCtor()) {
- $api[$member]->plugin[] = $entry;
- foreach ($entry->getAliases() as $alias) {
- $api[$member]->plugin[] = $alias;
- }
- }
- }
- }
-
- // add properties to each entry
- foreach ($api as $entry) {
- $entry->hash = $this->getHash($entry);
- $entry->href = $this->getLineUrl($entry);
- $entry->separator = '';
-
- $member = $entry->getMembers(0);
- $member = ($member ? $member . $this->getSeparator($entry) : '') . $entry->getName();
- $entry->member = preg_replace('/' . $entry->getName() . '$/', '', $member);
-
- // add properties to static and plugin sub-entries
- foreach (array('static', 'plugin') as $kind) {
- foreach ($entry->{$kind} as $subentry) {
- $subentry->hash = $this->getHash($subentry);
- $subentry->href = $this->getLineUrl($subentry);
- $subentry->member = $member;
- $subentry->separator = $this->getSeparator($subentry);
- }
- }
- }
-
- /*------------------------------------------------------------------------*/
-
- // custom sort for root level entries
- // TODO: see how well it handles deeper namespace traversal
- function sortCompare($a, $b) {
- $score = array( 'a' => 0, 'b' => 0);
- foreach (array( 'a' => $a, 'b' => $b) as $key => $value) {
- // capitalized properties are last
- if (preg_match('/[#.][A-Z]/', $value)) {
- $score[$key] = 0;
- }
- // lowercase prototype properties are next to last
- else if (preg_match('/#[a-z]/', $value)) {
- $score[$key] = 1;
- }
- // lowercase static properties next to first
- else if (preg_match('/\.[a-z]/', $value)) {
- $score[$key] = 2;
- }
- // root properties are first
- else if (preg_match('/^[^#.]+$/', $value)) {
- $score[$key] = 3;
- }
- }
- $score = $score['b'] - $score['a'];
- return $score ? $score : strcasecmp($a, $b);
- }
-
- uksort($api, 'sortCompare');
-
- // sort static and plugin sub-entries
- foreach ($api as $entry) {
- foreach (array('static', 'plugin') as $kind) {
- $sortBy = array( 'a' => array(), 'b' => array(), 'c' => array() );
- foreach ($entry->{$kind} as $subentry) {
- $name = $subentry->getName();
- // functions w/o ALL-CAPs names are last
- $sortBy['a'][] = $subentry->getType() == 'Function' && !preg_match('/^[A-Z_]+$/', $name);
- // ALL-CAPs properties first
- $sortBy['b'][] = preg_match('/^[A-Z_]+$/', $name);
- // lowercase alphanumeric sort
- $sortBy['c'][] = strtolower($name);
- }
- array_multisort($sortBy['a'], SORT_ASC, $sortBy['b'], SORT_DESC, $sortBy['c'], SORT_ASC, $entry->{$kind});
- }
- }
-
- /*------------------------------------------------------------------------*/
-
- // add categories
- foreach ($api as $entry) {
- $categories[$entry->getCategory()][] = $entry;
- foreach (array('static', 'plugin') as $kind) {
- foreach ($entry->{$kind} as $subentry) {
- $categories[$subentry->getCategory()][] = $subentry;
- }
- }
- }
-
- // sort categories
- ksort($categories);
-
- foreach(array('Methods', 'Properties') as $category) {
- if (isset($categories[$category])) {
- $entries = $categories[$category];
- unset($categories[$category]);
- $categories[$category] = $entries;
- }
- }
-
- /*------------------------------------------------------------------------*/
-
- // compile TOC
- $result[] = $openTag;
-
- // compile TOC by categories
- if ($byCategory) {
- foreach ($categories as $category => $entries) {
- if ($compiling) {
- $result[] = $closeTag;
- } else {
- $compiling = true;
- }
- // assign TOC hash
- if (count($result) == 2) {
- $toc = strtolower($category);
- }
- // add category
- array_push(
- $result,
- $openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $category . '`'
- );
- // add entries
- foreach ($entries as $entry) {
- if ($entry->isAlias()) {
- $result[] = MarkdownGenerator::interpolate('* <a href="##{hash}" class="alias">`#{member}#{separator}#{name}` -> `#{realName}`</a>', array(
- 'hash' => $entry->hash,
- 'member' => $entry->member,
- 'name' => $entry->getName(),
- 'realName' => $entry->owner->getName(),
- 'separator' => $entry->separator
- ));
- }
- else {
- $result[] = MarkdownGenerator::interpolate('* <a href="##{hash}">`#{member}#{separator}#{name}`</a>', $entry);
- }
- }
- }
- }
- // compile TOC by namespace
- else {
- foreach ($api as $entry) {
- if ($compiling) {
- $result[] = $closeTag;
- } else {
- $compiling = true;
- }
- $member = $entry->member . $entry->getName();
-
- // assign TOC hash
- if (count($result) == 2) {
- $toc = $member;
- }
- // add root entry
- array_push(
- $result,
- $openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $member . '`',
- MarkdownGenerator::interpolate('* [`' . $member . '`](##{hash})', $entry)
- );
-
- // add static and plugin sub-entries
- foreach (array('static', 'plugin') as $kind) {
- if ($kind == 'plugin' && count($entry->plugin)) {
- array_push(
- $result,
- $closeTag,
- $openTag,
- '## `' . $member . ($entry->isCtor() ? '.prototype`' : '`')
- );
- }
- foreach ($entry->{$kind} as $subentry) {
- $subentry->member = $member;
- if ($subentry->isAlias()) {
- $result[] = MarkdownGenerator::interpolate('* <a href="##{hash}" class="alias">`#{member}#{separator}#{name}` -> `#{realName}`</a>', array(
- 'hash' => $subentry->hash,
- 'member' => $subentry->member,
- 'name' => $subentry->getName(),
- 'realName' => $subentry->owner->getName(),
- 'separator' => $subentry->separator
- ));
- }
- else {
- $result[] = MarkdownGenerator::interpolate('* <a href="##{hash}">`#{member}#{separator}#{name}`</a>', $subentry);
- }
- }
- }
- }
- }
-
- array_push($result, $closeTag, $closeTag);
-
- /*------------------------------------------------------------------------*/
-
- // compile content
- $compiling = false;
- $result[] = $openTag;
-
- if ($byCategory) {
- foreach ($categories as $category => $entries) {
- if ($compiling) {
- $result[] = $closeTag;
- } else {
- $compiling = true;
- }
- if ($category != 'Methods' && $category != 'Properties') {
- $category = '“' . $category . '” Methods';
- }
- array_push($result, $openTag, '## `' . $category . '`');
- $this->addEntries($result, $entries);
- }
- }
- else {
- foreach ($api as $entry) {
- // skip aliases
- if ($entry->isAlias()) {
- continue;
- }
- if ($compiling) {
- $result[] = $closeTag;
- } else {
- $compiling = true;
- }
- // add root entry name
- $member = $entry->member . $entry->getName();
- array_push($result, $openTag, '## `' . $member . '`');
-
- foreach (array($entry, 'static', 'plugin') as $kind) {
- $subentries = is_string($kind) ? $entry->{$kind} : array($kind);
-
- // add sub-entry name
- if ($kind != 'static' && $entry->getType() != 'Object' &&
- count($subentries) && $subentries[0] != $kind) {
- if ($kind == 'plugin') {
- $result[] = $closeTag;
- }
- array_push(
- $result,
- $openTag,
- '## `' . $member . ($kind == 'plugin' ? '.prototype`' : '`')
- );
- }
- $this->addEntries($result, $subentries);
- }
- }
- }
-
- // close tags add TOC link reference
- array_push($result, $closeTag, $closeTag, '', ' [1]: #' . $toc . ' "Jump back to the TOC."');
-
- // cleanup whitespace
- return trim(preg_replace('/[\t ]+\n/', "\n", join($result, "\n")));
- }
-}
-?>
\ No newline at end of file
diff --git a/vendor/dojo/LICENSE b/vendor/dojo/LICENSE
deleted file mode 100644
index b1ddd34..0000000
--- a/vendor/dojo/LICENSE
+++ /dev/null
@@ -1,195 +0,0 @@
-Dojo is available under *either* the terms of the modified BSD license *or* the
-Academic Free License version 2.1. As a recipient of Dojo, you may choose which
-license to receive this code under (except as noted in per-module LICENSE
-files). Some modules may not be the copyright of the Dojo Foundation. These
-modules contain explicit declarations of copyright in both the LICENSE files in
-the directories in which they reside and in the code itself. No external
-contributions are allowed under licenses which are fundamentally incompatible
-with the AFL or BSD licenses that Dojo is distributed under.
-
-The text of the AFL and BSD licenses is reproduced below.
-
--------------------------------------------------------------------------------
-The "New" BSD License:
-**********************
-
-Copyright (c) 2005-2013, The Dojo Foundation
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the Dojo Foundation nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------------------
-The Academic Free License, v. 2.1:
-**********************************
-
-This Academic Free License (the "License") applies to any original work of
-authorship (the "Original Work") whose owner (the "Licensor") has placed the
-following notice immediately following the copyright notice for the Original
-Work:
-
-Licensed under the Academic Free License version 2.1
-
-1) Grant of Copyright License. Licensor hereby grants You a world-wide,
-royalty-free, non-exclusive, perpetual, sublicenseable license to do the
-following:
-
-a) to reproduce the Original Work in copies;
-
-b) to prepare derivative works ("Derivative Works") based upon the Original
-Work;
-
-c) to distribute copies of the Original Work and Derivative Works to the
-public;
-
-d) to perform the Original Work publicly; and
-
-e) to display the Original Work publicly.
-
-2) Grant of Patent License. Licensor hereby grants You a world-wide,
-royalty-free, non-exclusive, perpetual, sublicenseable license, under patent
-claims owned or controlled by the Licensor that are embodied in the Original
-Work as furnished by the Licensor, to make, use, sell and offer for sale the
-Original Work and Derivative Works.
-
-3) Grant of Source Code License. The term "Source Code" means the preferred
-form of the Original Work for making modifications to it and all available
-documentation describing how to modify the Original Work. Licensor hereby
-agrees to provide a machine-readable copy of the Source Code of the Original
-Work along with each copy of the Original Work that Licensor distributes.
-Licensor reserves the right to satisfy this obligation by placing a
-machine-readable copy of the Source Code in an information repository
-reasonably calculated to permit inexpensive and convenient access by You for as
-long as Licensor continues to distribute the Original Work, and by publishing
-the address of that information repository in a notice immediately following
-the copyright notice that applies to the Original Work.
-
-4) Exclusions From License Grant. Neither the names of Licensor, nor the names
-of any contributors to the Original Work, nor any of their trademarks or
-service marks, may be used to endorse or promote products derived from this
-Original Work without express prior written permission of the Licensor. Nothing
-in this License shall be deemed to grant any rights to trademarks, copyrights,
-patents, trade secrets or any other intellectual property of Licensor except as
-expressly stated herein. No patent license is granted to make, use, sell or
-offer to sell embodiments of any patent claims other than the licensed claims
-defined in Section 2. No right is granted to the trademarks of Licensor even if
-such marks are included in the Original Work. Nothing in this License shall be
-interpreted to prohibit Licensor from licensing under different terms from this
-License any Original Work that Licensor otherwise would have a right to
-license.
-
-5) This section intentionally omitted.
-
-6) Attribution Rights. You must retain, in the Source Code of any Derivative
-Works that You create, all copyright, patent or trademark notices from the
-Source Code of the Original Work, as well as any notices of licensing and any
-descriptive text identified therein as an "Attribution Notice." You must cause
-the Source Code for any Derivative Works that You create to carry a prominent
-Attribution Notice reasonably calculated to inform recipients that You have
-modified the Original Work.
-
-7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
-the copyright in and to the Original Work and the patent rights granted herein
-by Licensor are owned by the Licensor or are sublicensed to You under the terms
-of this License with the permission of the contributor(s) of those copyrights
-and patent rights. Except as expressly stated in the immediately proceeding
-sentence, the Original Work is provided under this License on an "AS IS" BASIS
-and WITHOUT WARRANTY, either express or implied, including, without limitation,
-the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU.
-This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No
-license to Original Work is granted hereunder except under this disclaimer.
-
-8) Limitation of Liability. Under no circumstances and under no legal theory,
-whether in tort (including negligence), contract, or otherwise, shall the
-Licensor be liable to any person for any direct, indirect, special, incidental,
-or consequential damages of any character arising as a result of this License
-or the use of the Original Work including, without limitation, damages for loss
-of goodwill, work stoppage, computer failure or malfunction, or any and all
-other commercial damages or losses. This limitation of liability shall not
-apply to liability for death or personal injury resulting from Licensor's
-negligence to the extent applicable law prohibits such limitation. Some
-jurisdictions do not allow the exclusion or limitation of incidental or
-consequential damages, so this exclusion and limitation may not apply to You.
-
-9) Acceptance and Termination. If You distribute copies of the Original Work or
-a Derivative Work, You must make a reasonable effort under the circumstances to
-obtain the express assent of recipients to the terms of this License. Nothing
-else but this License (or another written agreement between Licensor and You)
-grants You permission to create Derivative Works based upon the Original Work
-or to exercise any of the rights granted in Section 1 herein, and any attempt
-to do so except under the terms of this License (or another written agreement
-between Licensor and You) is expressly prohibited by U.S. copyright law, the
-equivalent laws of other countries, and by international treaty. Therefore, by
-exercising any of the rights granted to You in Section 1 herein, You indicate
-Your acceptance of this License and all of its terms and conditions.
-
-10) Termination for Patent Action. This License shall terminate automatically
-and You may no longer exercise any of the rights granted to You by this License
-as of the date You commence an action, including a cross-claim or counterclaim,
-against Licensor or any licensee alleging that the Original Work infringes a
-patent. This termination provision shall not apply for an action alleging
-patent infringement by combinations of the Original Work with other software or
-hardware.
-
-11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
-License may be brought only in the courts of a jurisdiction wherein the
-Licensor resides or in which Licensor conducts its primary business, and under
-the laws of that jurisdiction excluding its conflict-of-law provisions. The
-application of the United Nations Convention on Contracts for the International
-Sale of Goods is expressly excluded. Any use of the Original Work outside the
-scope of this License or after its termination shall be subject to the
-requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et
-seq., the equivalent laws of other countries, and international treaty. This
-section shall survive the termination of this License.
-
-12) Attorneys Fees. In any action to enforce the terms of this License or
-seeking damages relating thereto, the prevailing party shall be entitled to
-recover its costs and expenses, including, without limitation, reasonable
-attorneys' fees and costs incurred in connection with such action, including
-any appeal of such action. This section shall survive the termination of this
-License.
-
-13) Miscellaneous. This License represents the complete agreement concerning
-the subject matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent necessary to
-make it enforceable.
-
-14) Definition of "You" in This License. "You" throughout this License, whether
-in upper or lower case, means an individual or a legal entity exercising rights
-under, and complying with all of the terms of, this License. For legal
-entities, "You" includes any entity that controls, is controlled by, or is
-under common control with you. For purposes of this definition, "control" means
-(i) the power, direct or indirect, to cause the direction or management of such
-entity, whether by contract or otherwise, or (ii) ownership of fifty percent
-(50%) or more of the outstanding shares, or (iii) beneficial ownership of such
-entity.
-
-15) Right to Use. You may use the Original Work in all ways not otherwise
-restricted or conditioned by this License or by law, and Licensor promises not
-to interfere with or be responsible for such uses by You.
-
-This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved.
-Permission is hereby granted to copy and distribute this license without
-modification. This license may not be modified without the express written
-permission of its copyright owner.
diff --git a/vendor/dojo/dojo.js b/vendor/dojo/dojo.js
deleted file mode 100644
index 54d4b8e..0000000
--- a/vendor/dojo/dojo.js
+++ /dev/null
@@ -1,1997 +0,0 @@
-(function(
- userConfig,
- defaultConfig
-){
- // summary:
- // This is the "source loader" and is the entry point for Dojo during development. You may also load Dojo with
- // any AMD-compliant loader via the package main module dojo/main.
- // description:
- // This is the "source loader" for Dojo. It provides an AMD-compliant loader that can be configured
- // to operate in either synchronous or asynchronous modes. After the loader is defined, dojo is loaded
- // IAW the package main module dojo/main. In the event you wish to use a foreign loader, you may load dojo as a package
- // via the package main module dojo/main and this loader is not required; see dojo/package.json for details.
- //
- // In order to keep compatibility with the v1.x line, this loader includes additional machinery that enables
- // the dojo.provide, dojo.require et al API. This machinery is loaded by default, but may be dynamically removed
- // via the has.js API and statically removed via the build system.
- //
- // This loader includes sniffing machinery to determine the environment; the following environments are supported:
- //
- // - browser
- // - node.js
- // - rhino
- //
- // This is the so-called "source loader". As such, it includes many optional features that may be discarded by
- // building a customized version with the build system.
-
- // Design and Implementation Notes
- //
- // This is a dojo-specific adaption of bdLoad, donated to the dojo foundation by Altoviso LLC.
- //
- // This function defines an AMD-compliant (http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition)
- // loader that can be configured to operate in either synchronous or asynchronous modes.
- //
- // Since this machinery implements a loader, it does not have the luxury of using a load system and/or
- // leveraging a utility library. This results in an unpleasantly long file; here is a road map of the contents:
- //
- // 1. Small library for use implementing the loader.
- // 2. Define the has.js API; this is used throughout the loader to bracket features.
- // 3. Define the node.js and rhino sniffs and sniff.
- // 4. Define the loader's data.
- // 5. Define the configuration machinery.
- // 6. Define the script element sniffing machinery and sniff for configuration data.
- // 7. Configure the loader IAW the provided user, default, and sniffing data.
- // 8. Define the global require function.
- // 9. Define the module resolution machinery.
- // 10. Define the module and plugin module definition machinery
- // 11. Define the script injection machinery.
- // 12. Define the window load detection.
- // 13. Define the logging API.
- // 14. Define the tracing API.
- // 16. Define the AMD define function.
- // 17. Define the dojo v1.x provide/require machinery--so called "legacy" modes.
- // 18. Publish global variables.
- //
- // Language and Acronyms and Idioms
- //
- // moduleId: a CJS module identifier, (used for public APIs)
- // mid: moduleId (used internally)
- // packageId: a package identifier (used for public APIs)
- // pid: packageId (used internally); the implied system or default package has pid===""
- // pack: package is used internally to reference a package object (since javascript has reserved words including "package")
- // prid: plugin resource identifier
- // The integer constant 1 is used in place of true and 0 in place of false.
-
- // define a minimal library to help build the loader
- var noop = function(){
- },
-
- isEmpty = function(it){
- for(var p in it){
- return 0;
- }
- return 1;
- },
-
- toString = {}.toString,
-
- isFunction = function(it){
- return toString.call(it) == "[object Function]";
- },
-
- isString = function(it){
- return toString.call(it) == "[object String]";
- },
-
- isArray = function(it){
- return toString.call(it) == "[object Array]";
- },
-
- forEach = function(vector, callback){
- if(vector){
- for(var i = 0; vector[i];){
- callback(vector[i++]);
- }
- }
- },
-
- mix = function(dest, src){
- for(var p in src){
- dest[p] = src[p];
- }
- return dest;
- },
-
- makeError = function(error, info){
- return mix(new Error(error), {src:"dojoLoader", info:info});
- },
-
- uidSeed = 1,
-
- uid = function(){
- // Returns a unique identifier (within the lifetime of the document) of the form /_d+/.
- return "_" + uidSeed++;
- },
-
- // FIXME: how to doc window.require() api
-
- // this will be the global require function; define it immediately so we can start hanging things off of it
- req = function(
- config, //(object, optional) hash of configuration properties
- dependencies, //(array of commonjs.moduleId, optional) list of modules to be loaded before applying callback
- callback //(function, optional) lambda expression to apply to module values implied by dependencies
- ){
- return contextRequire(config, dependencies, callback, 0, req);
- },
-
- // the loader uses the has.js API to control feature inclusion/exclusion; define then use throughout
- global = this,
-
- doc = global.document,
-
- element = doc && doc.createElement("DiV"),
-
- has = req.has = function(name){
- return isFunction(hasCache[name]) ? (hasCache[name] = hasCache[name](global, doc, element)) : hasCache[name];
- },
-
- hasCache = has.cache = defaultConfig.hasCache;
-
- has.add = function(name, test, now, force){
- (hasCache[name]===undefined || force) && (hasCache[name] = test);
- return now && has(name);
- };
-
- has.add("host-node", userConfig.has && "host-node" in userConfig.has ?
- userConfig.has["host-node"] :
- (typeof process == "object" && process.versions && process.versions.node && process.versions.v8));
- if(has("host-node")){
- // fixup the default config for node.js environment
- require("./_base/configNode.js").config(defaultConfig);
- // remember node's require (with respect to baseUrl==dojo's root)
- defaultConfig.loaderPatch.nodeRequire = require;
- }
-
- has.add("host-rhino", userConfig.has && "host-rhino" in userConfig.has ?
- userConfig.has["host-rhino"] :
- (typeof load == "function" && (typeof Packages == "function" || typeof Packages == "object")));
- if(has("host-rhino")){
- // owing to rhino's lame feature that hides the source of the script, give the user a way to specify the baseUrl...
- for(var baseUrl = userConfig.baseUrl || ".", arg, rhinoArgs = this.arguments, i = 0; i < rhinoArgs.length;){
- arg = (rhinoArgs[i++] + "").split("=");
- if(arg[0] == "baseUrl"){
- baseUrl = arg[1];
- break;
- }
- }
- load(baseUrl + "/_base/configRhino.js");
- rhinoDojoConfig(defaultConfig, baseUrl, rhinoArgs);
- }
-
- // userConfig has tests override defaultConfig has tests; do this after the environment detection because
- // the environment detection usually sets some has feature values in the hasCache.
- for(var p in userConfig.has){
- has.add(p, userConfig.has[p], 0, 1);
- }
-
- //
- // define the loader data
- //
-
- // the loader will use these like symbols if the loader has the traceApi; otherwise
- // define magic numbers so that modules can be provided as part of defaultConfig
- var requested = 1,
- arrived = 2,
- nonmodule = 3,
- executing = 4,
- executed = 5;
-
- if(has("dojo-trace-api")){
- // these make debugging nice; but using strings for symbols is a gross rookie error; don't do it for production code
- requested = "requested";
- arrived = "arrived";
- nonmodule = "not-a-module";
- executing = "executing";
- executed = "executed";
- }
-
- var legacyMode = 0,
- sync = "sync",
- xd = "xd",
- syncExecStack = [],
- dojoRequirePlugin = 0,
- checkDojoRequirePlugin = noop,
- transformToAmd = noop,
- getXhr;
- if(has("dojo-sync-loader")){
- req.isXdUrl = noop;
-
- req.initSyncLoader = function(dojoRequirePlugin_, checkDojoRequirePlugin_, transformToAmd_){
- // the first dojo/_base/loader loaded gets to define these variables; they are designed to work
- // in the presence of zero to many mapped dojo/_base/loaders
- if(!dojoRequirePlugin){
- dojoRequirePlugin = dojoRequirePlugin_;
- checkDojoRequirePlugin = checkDojoRequirePlugin_;
- transformToAmd = transformToAmd_;
- }
-
- return {
- sync:sync,
- requested:requested,
- arrived:arrived,
- nonmodule:nonmodule,
- executing:executing,
- executed:executed,
- syncExecStack:syncExecStack,
- modules:modules,
- execQ:execQ,
- getModule:getModule,
- injectModule:injectModule,
- setArrived:setArrived,
- signal:signal,
- finishExec:finishExec,
- execModule:execModule,
- dojoRequirePlugin:dojoRequirePlugin,
- getLegacyMode:function(){return legacyMode;},
- guardCheckComplete:guardCheckComplete
- };
- };
-
- if(has("dom")){
- // in legacy sync mode, the loader needs a minimal XHR library
-
- var locationProtocol = location.protocol,
- locationHost = location.host;
- req.isXdUrl = function(url){
- if(/^\./.test(url)){
- // begins with a dot is always relative to page URL; therefore not xdomain
- return false;
- }
- if(/^\/\//.test(url)){
- // for v1.6- backcompat, url starting with // indicates xdomain
- return true;
- }
- // get protocol and host
- // \/+ takes care of the typical file protocol that looks like file:///drive/path/to/file
- // locationHost is falsy if file protocol => if locationProtocol matches and is "file:", || will return false
- var match = url.match(/^([^\/\:]+\:)\/+([^\/]+)/);
- return match && (match[1] != locationProtocol || (locationHost && match[2] != locationHost));
- };
-
-
- // note: to get the file:// protocol to work in FF, you must set security.fileuri.strict_origin_policy to false in about:config
- has.add("dojo-xhr-factory", 1);
- has.add("dojo-force-activex-xhr", has("host-browser") && !doc.addEventListener && window.location.protocol == "file:");
- has.add("native-xhr", typeof XMLHttpRequest != "undefined");
- if(has("native-xhr") && !has("dojo-force-activex-xhr")){
- getXhr = function(){
- return new XMLHttpRequest();
- };
- }else{
- // if in the browser an old IE; find an xhr
- for(var XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], progid, i = 0; i < 3;){
- try{
- progid = XMLHTTP_PROGIDS[i++];
- if(new ActiveXObject(progid)){
- // this progid works; therefore, use it from now on
- break;
- }
- }catch(e){
- // squelch; we're just trying to find a good ActiveX progid
- // if they all fail, then progid ends up as the last attempt and that will signal the error
- // the first time the client actually tries to exec an xhr
- }
- }
- getXhr = function(){
- return new ActiveXObject(progid);
- };
- }
- req.getXhr = getXhr;
-
- has.add("dojo-gettext-api", 1);
- req.getText = function(url, async, onLoad){
- var xhr = getXhr();
- xhr.open('GET', fixupUrl(url), false);
- xhr.send(null);
- if(xhr.status == 200 || (!location.host && !xhr.status)){
- if(onLoad){
- onLoad(xhr.responseText, async);
- }
- }else{
- throw makeError("xhrFailed", xhr.status);
- }
- return xhr.responseText;
- };
- }
- }else{
- req.async = 1;
- }
-
- //
- // loader eval
- //
- var eval_ =
- // use the function constructor so our eval is scoped close to (but not in) in the global space with minimal pollution
- new Function('return eval(arguments[0]);');
-
- req.eval =
- function(text, hint){
- return eval_(text + "\r\n////@ sourceURL=" + hint);
- };
-
- //
- // loader micro events API
- //
- var listenerQueues = {},
- error = "error",
- signal = req.signal = function(type, args){
- var queue = listenerQueues[type];
- // notice we run a copy of the queue; this allows listeners to add/remove
- // other listeners without affecting this particular signal
- forEach(queue && queue.slice(0), function(listener){
- listener.apply(null, isArray(args) ? args : [args]);
- });
- },
- on = req.on = function(type, listener){
- // notice a queue is not created until a client actually connects
- var queue = listenerQueues[type] || (listenerQueues[type] = []);
- queue.push(listener);
- return {
- remove:function(){
- for(var i = 0; i<queue.length; i++){
- if(queue[i]===listener){
- queue.splice(i, 1);
- return;
- }
- }
- }
- };
- };
-
- // configuration machinery; with an optimized/built defaultConfig, all configuration machinery can be discarded
- // lexical variables hold key loader data structures to help with minification; these may be completely,
- // one-time initialized by defaultConfig for optimized/built versions
- var
- aliases
- // a vector of pairs of [regexs or string, replacement] => (alias, actual)
- = [],
-
- paths
- // CommonJS paths
- = {},
-
- pathsMapProg
- // list of (from-path, to-path, regex, length) derived from paths;
- // a "program" to apply paths; see computeMapProg
- = [],
-
- packs
- // a map from packageId to package configuration object; see fixupPackageInfo
- = {},
-
- map = req.map
- // AMD map config variable; dojo/_base/kernel needs req.map to figure out the scope map
- = {},
-
- mapProgs
- // vector of quads as described by computeMapProg; map-key is AMD map key, map-value is AMD map value
- = [],
-
- modules
- // A hash:(mid) --> (module-object) the module namespace
- //
- // pid: the package identifier to which the module belongs (e.g., "dojo"); "" indicates the system or default package
- // mid: the fully-resolved (i.e., mappings have been applied) module identifier without the package identifier (e.g., "dojo/io/script")
- // url: the URL from which the module was retrieved
- // pack: the package object of the package to which the module belongs
- // executed: 0 => not executed; executing => in the process of traversing deps and running factory; executed => factory has been executed
- // deps: the dependency vector for this module (vector of modules objects)
- // def: the factory for this module
- // result: the result of the running the factory for this module
- // injected: (0 | requested | arrived) the status of the module; nonmodule means the resource did not call define
- // load: plugin load function; applicable only for plugins
- //
- // Modules go through several phases in creation:
- //
- // 1. Requested: some other module's definition or a require application contained the requested module in
- // its dependency vector or executing code explicitly demands a module via req.require.
- //
- // 2. Injected: a script element has been appended to the insert-point element demanding the resource implied by the URL
- //
- // 3. Loaded: the resource injected in [2] has been evaluated.
- //
- // 4. Defined: the resource contained a define statement that advised the loader about the module. Notice that some
- // resources may just contain a bundle of code and never formally define a module via define
- //
- // 5. Evaluated: the module was defined via define and the loader has evaluated the factory and computed a result.
- = {},
-
- cacheBust
- // query string to append to module URLs to bust browser cache
- = "",
-
- cache
- // hash:(mid | url)-->(function | string)
- //
- // A cache of resources. The resources arrive via a config.cache object, which is a hash from either mid --> function or
- // url --> string. The url key is distinguished from the mid key by always containing the prefix "url:". url keys as provided
- // by config.cache always have a string value that represents the contents of the resource at the given url. mid keys as provided
- // by configl.cache always have a function value that causes the same code to execute as if the module was script injected.
- //
- // Both kinds of key-value pairs are entered into cache via the function consumePendingCache, which may relocate keys as given
- // by any mappings *iff* the config.cache was received as part of a module resource request.
- //
- // Further, for mid keys, the implied url is computed and the value is entered into that key as well. This allows mapped modules
- // to retrieve cached items that may have arrived consequent to another namespace.
- //
- = {},
-
- urlKeyPrefix
- // the prefix to prepend to a URL key in the cache.
- = "url:",
-
- pendingCacheInsert
- // hash:(mid)-->(function)
- //
- // Gives a set of cache modules pending entry into cache. When cached modules are published to the loader, they are
- // entered into pendingCacheInsert; modules are then pressed into cache upon (1) AMD define or (2) upon receiving another
- // independent set of cached modules. (1) is the usual case, and this case allows normalizing mids given in the pending
- // cache for the local configuration, possibly relocating modules.
- = {},
-
- dojoSniffConfig
- // map of configuration variables
- // give the data-dojo-config as sniffed from the document (if any)
- = {},
-
- insertPointSibling
- // the nodes used to locate where scripts are injected into the document
- = 0;
-
- if(has("dojo-config-api")){
- var consumePendingCacheInsert = function(referenceModule){
- var p, item, match, now, m;
- for(p in pendingCacheInsert){
- item = pendingCacheInsert[p];
- match = p.match(/^url\:(.+)/);
- if(match){
- cache[urlKeyPrefix + toUrl(match[1], referenceModule)] = item;
- }else if(p=="*now"){
- now = item;
- }else if(p!="*noref"){
- m = getModuleInfo(p, referenceModule);
- cache[m.mid] = cache[urlKeyPrefix + m.url] = item;
- }
- }
- if(now){
- now(createRequire(referenceModule));
- }
- pendingCacheInsert = {};
- },
-
- escapeString = function(s){
- return s.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function(c){ return "\\" + c; });
- },
-
- computeMapProg = function(map, dest){
- // This routine takes a map as represented by a JavaScript object and initializes dest, a vector of
- // quads of (map-key, map-value, refex-for-map-key, length-of-map-key), sorted decreasing by length-
- // of-map-key. The regex looks for the map-key followed by either "/" or end-of-string at the beginning
- // of a the search source. Notice the map-value is irrelevant to the algorithm
- dest.splice(0, dest.length);
- for(var p in map){
- dest.push([
- p,
- map[p],
- new RegExp("^" + escapeString(p) + "(\/|$)"),
- p.length]);
- }
- dest.sort(function(lhs, rhs){ return rhs[3] - lhs[3]; });
- return dest;
- },
-
- computeAliases = function(config, dest){
- forEach(config, function(pair){
- // take a fixed-up copy...
- dest.push([isString(pair[0]) ? new RegExp("^" + escapeString(pair[0]) + "$") : pair[0], pair[1]]);
- });
- },
-
-
- fixupPackageInfo = function(packageInfo){
- // calculate the precise (name, location, main, mappings) for a package
- var name = packageInfo.name;
- if(!name){
- // packageInfo must be a string that gives the name
- name = packageInfo;
- packageInfo = {name:name};
- }
- packageInfo = mix({main:"main"}, packageInfo);
- packageInfo.location = packageInfo.location ? packageInfo.location : name;
-
- // packageMap is deprecated in favor of AMD map
- if(packageInfo.packageMap){
- map[name] = packageInfo.packageMap;
- }
-
- if(!packageInfo.main.indexOf("./")){
- packageInfo.main = packageInfo.main.substring(2);
- }
-
- // now that we've got a fully-resolved package object, push it into the configuration
- packs[name] = packageInfo;
- },
-
- delayedModuleConfig
- // module config cannot be consumed until the loader is completely initialized; therefore, all
- // module config detected during booting is memorized and applied at the end of loader initialization
- // TODO: this is a bit of a kludge; all config should be moved to end of loader initialization, but
- // we'll delay this chore and do it with a final loader 1.x cleanup after the 2.x loader prototyping is complete
- = [],
-
-
- config = function(config, booting, referenceModule){
- for(var p in config){
- if(p=="waitSeconds"){
- req.waitms = (config[p] || 0) * 1000;
- }
- if(p=="cacheBust"){
- cacheBust = config[p] ? (isString(config[p]) ? config[p] : (new Date()).getTime() + "") : "";
- }
- if(p=="baseUrl" || p=="combo"){
- req[p] = config[p];
- }
- if(has("dojo-sync-loader") && p=="async"){
- // falsy or "sync" => legacy sync loader
- // "xd" => sync but loading xdomain tree and therefore loading asynchronously (not configurable, set automatically by the loader)
- // "legacyAsync" => permanently in "xd" by choice
- // "debugAtAllCosts" => trying to load everything via script injection (not implemented)
- // otherwise, must be truthy => AMD
- // legacyMode: sync | legacyAsync | xd | false
- var mode = config[p];
- req.legacyMode = legacyMode = (isString(mode) && /sync|legacyAsync/.test(mode) ? mode : (!mode ? sync : false));
- req.async = !legacyMode;
- }
- if(config[p]!==hasCache){
- // accumulate raw config info for client apps which can use this to pass their own config
- req.rawConfig[p] = config[p];
- p!="has" && has.add("config-"+p, config[p], 0, booting);
- }
- }
-
- // make sure baseUrl exists
- if(!req.baseUrl){
- req.baseUrl = "./";
- }
- // make sure baseUrl ends with a slash
- if(!/\/$/.test(req.baseUrl)){
- req.baseUrl += "/";
- }
-
- // now do the special work for has, packages, packagePaths, paths, aliases, and cache
-
- for(p in config.has){
- has.add(p, config.has[p], 0, booting);
- }
-
- // for each package found in any packages config item, augment the packs map owned by the loader
- forEach(config.packages, fixupPackageInfo);
-
- // for each packagePath found in any packagePaths config item, augment the packageConfig
- // packagePaths is deprecated; remove in 2.0
- for(baseUrl in config.packagePaths){
- forEach(config.packagePaths[baseUrl], function(packageInfo){
- var location = baseUrl + "/" + packageInfo;
- if(isString(packageInfo)){
- packageInfo = {name:packageInfo};
- }
- packageInfo.location = location;
- fixupPackageInfo(packageInfo);
- });
- }
-
- // notice that computeMapProg treats the dest as a reference; therefore, if/when that variable
- // is published (see dojo-publish-privates), the published variable will always hold a valid value.
-
- // this must come after all package processing since package processing may mutate map
- computeMapProg(mix(map, config.map), mapProgs);
- forEach(mapProgs, function(item){
- item[1] = computeMapProg(item[1], []);
- if(item[0]=="*"){
- mapProgs.star = item;
- }
- });
-
- // push in any paths and recompute the internal pathmap
- computeMapProg(mix(paths, config.paths), pathsMapProg);
-
- // aliases
- computeAliases(config.aliases, aliases);
-
- if(booting){
- delayedModuleConfig.push({config:config.config});
- }else{
- for(p in config.config){
- var module = getModule(p, referenceModule);
- module.config = mix(module.config || {}, config.config[p]);
- }
- }
-
- // push in any new cache values
- if(config.cache){
- consumePendingCacheInsert();
- pendingCacheInsert = config.cache;
- if(config.cache["*noref"]){
- consumePendingCacheInsert();
- }
- }
-
- signal("config", [config, req.rawConfig]);
- };
-
- //
- // execute the various sniffs; userConfig can override and value
- //
-
- if(has("dojo-cdn") || has("dojo-sniff")){
- // the sniff regex looks for a src attribute ending in dojo.js, optionally preceded with a path.
- // match[3] returns the path to dojo.js (if any) without the trailing slash. This is used for the
- // dojo location on CDN deployments and baseUrl when either/both of these are not provided
- // explicitly in the config data; this is the 1.6- behavior.
-
- var scripts = doc.getElementsByTagName("script"),
- i = 0,
- script, dojoDir, src, match;
- while(i < scripts.length){
- script = scripts[i++];
- if((src = script.getAttribute("src")) && (match = src.match(/(((.*)\/)|^)dojo\.js(\W|$)/i))){
- // sniff dojoDir and baseUrl
- dojoDir = match[3] || "";
- defaultConfig.baseUrl = defaultConfig.baseUrl || dojoDir;
-
- // remember an insertPointSibling
- insertPointSibling = script;
- }
-
- // sniff configuration on attribute in script element
- if((src = (script.getAttribute("data-dojo-config") || script.getAttribute("djConfig")))){
- dojoSniffConfig = req.eval("({ " + src + " })", "data-dojo-config");
-
- // remember an insertPointSibling
- insertPointSibling = script;
- }
-
- // sniff requirejs attribute
- if(has("dojo-requirejs-api")){
- if((src = script.getAttribute("data-main"))){
- dojoSniffConfig.deps = dojoSniffConfig.deps || [src];
- }
- }
- }
- }
-
- if(has("dojo-test-sniff")){
- // pass down doh.testConfig from parent as if it were a data-dojo-config
- try{
- if(window.parent != window && window.parent.require){
- var doh = window.parent.require("doh");
- doh && mix(dojoSniffConfig, doh.testConfig);
- }
- }catch(e){}
- }
-
- // configure the loader; let the user override defaults
- req.rawConfig = {};
- config(defaultConfig, 1);
-
- // do this before setting userConfig/sniffConfig to allow userConfig/sniff overrides
- if(has("dojo-cdn")){
- packs.dojo.location = dojoDir;
- if(dojoDir){
- dojoDir += "/";
- }
- packs.dijit.location = dojoDir + "../dijit/";
- packs.dojox.location = dojoDir + "../dojox/";
- }
-
- config(userConfig, 1);
- config(dojoSniffConfig, 1);
-
- }else{
- // no config API, assume defaultConfig has everything the loader needs...for the entire lifetime of the application
- paths = defaultConfig.paths;
- pathsMapProg = defaultConfig.pathsMapProg;
- packs = defaultConfig.packs;
- aliases = defaultConfig.aliases;
- mapProgs = defaultConfig.mapProgs;
- modules = defaultConfig.modules;
- cache = defaultConfig.cache;
- cacheBust = defaultConfig.cacheBust;
-
- // remember the default config for other processes (e.g., dojo/config)
- req.rawConfig = defaultConfig;
- }
-
-
- if(has("dojo-combo-api")){
- req.combo = req.combo || {add:noop};
- var comboPending = 0,
- combosPending = [],
- comboPendingTimer = null;
- }
-
-
- // build the loader machinery iaw configuration, including has feature tests
- var injectDependencies = function(module){
- // checkComplete!=0 holds the idle signal; we're not idle if we're injecting dependencies
- guardCheckComplete(function(){
- forEach(module.deps, injectModule);
- if(has("dojo-combo-api") && comboPending && !comboPendingTimer){
- comboPendingTimer = setTimeout(function() {
- comboPending = 0;
- comboPendingTimer = null;
- req.combo.done(function(mids, url) {
- var onLoadCallback= function(){
- // defQ is a vector of module definitions 1-to-1, onto mids
- runDefQ(0, mids);
- checkComplete();
- };
- combosPending.push(mids);
- injectingModule = mids;
- req.injectUrl(url, onLoadCallback, mids);
- injectingModule = 0;
- }, req);
- }, 0);
- }
- });
- },
-
- contextRequire = function(a1, a2, a3, referenceModule, contextRequire){
- var module, syntheticMid;
- if(isString(a1)){
- // signature is (moduleId)
- module = getModule(a1, referenceModule, true);
- if(module && module.executed){
- return module.result;
- }
- throw makeError("undefinedModule", a1);
- }
- if(!isArray(a1)){
- // a1 is a configuration
- config(a1, 0, referenceModule);
-
- // juggle args; (a2, a3) may be (dependencies, callback)
- a1 = a2;
- a2 = a3;
- }
- if(isArray(a1)){
- // signature is (requestList [,callback])
- if(!a1.length){
- a2 && a2();
- }else{
- syntheticMid = "require*" + uid();
-
- // resolve the request list with respect to the reference module
- for(var mid, deps = [], i = 0; i < a1.length;){
- mid = a1[i++];
- deps.push(getModule(mid, referenceModule));
- }
-
- // construct a synthetic module to control execution of the requestList, and, optionally, callback
- module = mix(makeModuleInfo("", syntheticMid, 0, ""), {
- injected: arrived,
- deps: deps,
- def: a2 || noop,
- require: referenceModule ? referenceModule.require : req,
- gc: 1 //garbage collect
- });
- modules[module.mid] = module;
-
- // checkComplete!=0 holds the idle signal; we're not idle if we're injecting dependencies
- injectDependencies(module);
-
- // try to immediately execute
- // if already traversing a factory tree, then strict causes circular dependency to abort the execution; maybe
- // it's possible to execute this require later after the current traversal completes and avoid the circular dependency.
- // ...but *always* insist on immediate in synch mode
- var strict = checkCompleteGuard && legacyMode!=sync;
- guardCheckComplete(function(){
- execModule(module, strict);
- });
- if(!module.executed){
- // some deps weren't on board or circular dependency detected and strict; therefore, push into the execQ
- execQ.push(module);
- }
- checkComplete();
- }
- }
- return contextRequire;
- },
-
- createRequire = function(module){
- if(!module){
- return req;
- }
- var result = module.require;
- if(!result){
- result = function(a1, a2, a3){
- return contextRequire(a1, a2, a3, module, result);
- };
- module.require = mix(result, req);
- result.module = module;
- result.toUrl = function(name){
- return toUrl(name, module);
- };
- result.toAbsMid = function(mid){
- return toAbsMid(mid, module);
- };
- if(has("dojo-undef-api")){
- result.undef = function(mid){
- req.undef(mid, module);
- };
- }
- if(has("dojo-sync-loader")){
- result.syncLoadNls = function(mid){
- var nlsModuleInfo = getModuleInfo(mid, module),
- nlsModule = modules[nlsModuleInfo.mid];
- if(!nlsModule || !nlsModule.executed){
- cached = cache[nlsModuleInfo.mid] || cache[urlKeyPrefix + nlsModuleInfo.url];
- if(cached){
- evalModuleText(cached);
- nlsModule = modules[nlsModuleInfo.mid];
- }
- }
- return nlsModule && nlsModule.executed && nlsModule.result;
- };
- }
-
- }
- return result;
- },
-
- execQ =
- // The list of modules that need to be evaluated.
- [],
-
- defQ =
- // The queue of define arguments sent to loader.
- [],
-
- waiting =
- // The set of modules upon which the loader is waiting for definition to arrive
- {},
-
- setRequested = function(module){
- module.injected = requested;
- waiting[module.mid] = 1;
- if(module.url){
- waiting[module.url] = module.pack || 1;
- }
- startTimer();
- },
-
- setArrived = function(module){
- module.injected = arrived;
- delete waiting[module.mid];
- if(module.url){
- delete waiting[module.url];
- }
- if(isEmpty(waiting)){
- clearTimer();
- has("dojo-sync-loader") && legacyMode==xd && (legacyMode = sync);
- }
- },
-
- execComplete = req.idle =
- // says the loader has completed (or not) its work
- function(){
- return !defQ.length && isEmpty(waiting) && !execQ.length && !checkCompleteGuard;
- },
-
- runMapProg = function(targetMid, map){
- // search for targetMid in map; return the map item if found; falsy otherwise
- if(map){
- for(var i = 0; i < map.length; i++){
- if(map[i][2].test(targetMid)){
- return map[i];
- }
- }
- }
- return 0;
- },
-
- compactPath = function(path){
- var result = [],
- segment, lastSegment;
- path = path.replace(/\\/g, '/').split('/');
- while(path.length){
- segment = path.shift();
- if(segment==".." && result.length && lastSegment!=".."){
- result.pop();
- lastSegment = result[result.length - 1];
- }else if(segment!="."){
- result.push(lastSegment= segment);
- } // else ignore "."
- }
- return result.join("/");
- },
-
- makeModuleInfo = function(pid, mid, pack, url){
- if(has("dojo-sync-loader")){
- var xd= req.isXdUrl(url);
- return {pid:pid, mid:mid, pack:pack, url:url, executed:0, def:0, isXd:xd, isAmd:!!(xd || (packs[pid] && packs[pid].isAmd))};
- }else{
- return {pid:pid, mid:mid, pack:pack, url:url, executed:0, def:0};
- }
- },
-
- getModuleInfo_ = function(mid, referenceModule, packs, modules, baseUrl, mapProgs, pathsMapProg, aliases, alwaysCreate){
- // arguments are passed instead of using lexical variables so that this function my be used independent of the loader (e.g., the builder)
- // alwaysCreate is useful in this case so that getModuleInfo never returns references to real modules owned by the loader
- var pid, pack, midInPackage, mapItem, url, result, isRelative, requestedMid;
- requestedMid = mid;
- isRelative = /^\./.test(mid);
- if(/(^\/)|(\:)|(\.js$)/.test(mid) || (isRelative && !referenceModule)){
- // absolute path or protocol of .js filetype, or relative path but no reference module and therefore relative to page
- // whatever it is, it's not a module but just a URL of some sort
- // note: pid===0 indicates the routine is returning an unmodified mid
-
- return makeModuleInfo(0, mid, 0, mid);
- }else{
- // relative module ids are relative to the referenceModule; get rid of any dots
- mid = compactPath(isRelative ? (referenceModule.mid + "/../" + mid) : mid);
- if(/^\./.test(mid)){
- throw makeError("irrationalPath", mid);
- }
- // at this point, mid is an absolute mid
-
- // map the mid
- if(referenceModule){
- mapItem = runMapProg(referenceModule.mid, mapProgs);
- }
- mapItem = mapItem || mapProgs.star;
- mapItem = mapItem && runMapProg(mid, mapItem[1]);
-
- if(mapItem){
- mid = mapItem[1] + mid.substring(mapItem[3]);
- }
-
- match = mid.match(/^([^\/]+)(\/(.+))?$/);
- pid = match ? match[1] : "";
- if((pack = packs[pid])){
- mid = pid + "/" + (midInPackage = (match[3] || pack.main));
- }else{
- pid = "";
- }
-
- // search aliases
- var candidateLength = 0,
- candidate = 0;
- forEach(aliases, function(pair){
- var match = mid.match(pair[0]);
- if(match && match.length>candidateLength){
- candidate = isFunction(pair[1]) ? mid.replace(pair[0], pair[1]) : pair[1];
- }
- });
- if(candidate){
- return getModuleInfo_(candidate, 0, packs, modules, baseUrl, mapProgs, pathsMapProg, aliases, alwaysCreate);
- }
-
- result = modules[mid];
- if(result){
- return alwaysCreate ? makeModuleInfo(result.pid, result.mid, result.pack, result.url) : modules[mid];
- }
- }
- // get here iff the sought-after module does not yet exist; therefore, we need to compute the URL given the
- // fully resolved (i.e., all relative indicators and package mapping resolved) module id
-
- // note: pid!==0 indicates the routine is returning a url that has .js appended unmodified mid
- mapItem = runMapProg(mid, pathsMapProg);
- if(mapItem){
- url = mapItem[1] + mid.substring(mapItem[3]);
- }else if(pid){
- url = pack.location + "/" + midInPackage;
- }else if(has("config-tlmSiblingOfDojo")){
- url = "../" + mid;
- }else{
- url = mid;
- }
- // if result is not absolute, add baseUrl
- if(!(/(^\/)|(\:)/.test(url))){
- url = baseUrl + url;
- }
- url += ".js";
- return makeModuleInfo(pid, mid, pack, compactPath(url));
- },
-
- getModuleInfo = function(mid, referenceModule){
- return getModuleInfo_(mid, referenceModule, packs, modules, req.baseUrl, mapProgs, pathsMapProg, aliases);
- },
-
- resolvePluginResourceId = function(plugin, prid, referenceModule){
- return plugin.normalize ? plugin.normalize(prid, function(mid){return toAbsMid(mid, referenceModule);}) : toAbsMid(prid, referenceModule);
- },
-
- dynamicPluginUidGenerator = 0,
-
- getModule = function(mid, referenceModule, immediate){
- // compute and optionally construct (if necessary) the module implied by the mid with respect to referenceModule
- var match, plugin, prid, result;
- match = mid.match(/^(.+?)\!(.*)$/);
- if(match){
- // name was <plugin-module>!<plugin-resource-id>
- plugin = getModule(match[1], referenceModule, immediate);
-
- if(has("dojo-sync-loader") && legacyMode == sync && !plugin.executed){
- injectModule(plugin);
- if(plugin.injected===arrived && !plugin.executed){
- guardCheckComplete(function(){
- execModule(plugin);
- });
- }
- if(plugin.executed){
- promoteModuleToPlugin(plugin);
- }else{
- // we are in xdomain mode for some reason
- execQ.unshift(plugin);
- }
- }
-
-
-
- if(plugin.executed === executed && !plugin.load){
- // executed the module not knowing it was a plugin
- promoteModuleToPlugin(plugin);
- }
-
- // if the plugin has not been loaded, then can't resolve the prid and must assume this plugin is dynamic until we find out otherwise
- if(plugin.load){
- prid = resolvePluginResourceId(plugin, match[2], referenceModule);
- mid = (plugin.mid + "!" + (plugin.dynamic ? ++dynamicPluginUidGenerator + "!" : "") + prid);
- }else{
- prid = match[2];
- mid = plugin.mid + "!" + (++dynamicPluginUidGenerator) + "!waitingForPlugin";
- }
- result = {plugin:plugin, mid:mid, req:createRequire(referenceModule), prid:prid};
- }else{
- result = getModuleInfo(mid, referenceModule);
- }
- return modules[result.mid] || (!immediate && (modules[result.mid] = result));
- },
-
- toAbsMid = req.toAbsMid = function(mid, referenceModule){
- return getModuleInfo(mid, referenceModule).mid;
- },
-
- toUrl = req.toUrl = function(name, referenceModule){
- var moduleInfo = getModuleInfo(name+"/x", referenceModule),
- url= moduleInfo.url;
- return fixupUrl(moduleInfo.pid===0 ?
- // if pid===0, then name had a protocol or absolute path; either way, toUrl is the identify function in such cases
- name :
- // "/x.js" since getModuleInfo automatically appends ".js" and we appended "/x" to make name look like a module id
- url.substring(0, url.length-5)
- );
- },
-
- nonModuleProps = {
- injected: arrived,
- executed: executed,
- def: nonmodule,
- result: nonmodule
- },
-
- makeCjs = function(mid){
- return modules[mid] = mix({mid:mid}, nonModuleProps);
- },
-
- cjsRequireModule = makeCjs("require"),
- cjsExportsModule = makeCjs("exports"),
- cjsModuleModule = makeCjs("module"),
-
- runFactory = function(module, args){
- req.trace("loader-run-factory", [module.mid]);
- var factory = module.def,
- result;
- has("dojo-sync-loader") && syncExecStack.unshift(module);
- if(has("config-dojo-loader-catches")){
- try{
- result= isFunction(factory) ? factory.apply(null, args) : factory;
- }catch(e){
- signal(error, module.result = makeError("factoryThrew", [module, e]));
- }
- }else{
- result= isFunction(factory) ? factory.apply(null, args) : factory;
- }
- module.result = result===undefined && module.cjs ? module.cjs.exports : result;
- has("dojo-sync-loader") && syncExecStack.shift(module);
- },
-
- abortExec = {},
-
- defOrder = 0,
-
- promoteModuleToPlugin = function(pluginModule){
- var plugin = pluginModule.result;
- pluginModule.dynamic = plugin.dynamic;
- pluginModule.normalize = plugin.normalize;
- pluginModule.load = plugin.load;
- return pluginModule;
- },
-
- resolvePluginLoadQ = function(plugin){
- // plugins is a newly executed module that has a loadQ waiting to run
-
- // step 1: traverse the loadQ and fixup the mid and prid; remember the map from original mid to new mid
- // recall the original mid was created before the plugin was on board and therefore it was impossible to
- // compute the final mid; accordingly, prid may or may not change, but the mid will definitely change
- var map = {};
- forEach(plugin.loadQ, function(pseudoPluginResource){
- // manufacture and insert the real module in modules
- var prid = resolvePluginResourceId(plugin, pseudoPluginResource.prid, pseudoPluginResource.req.module),
- mid = plugin.dynamic ? pseudoPluginResource.mid.replace(/waitingForPlugin$/, prid) : (plugin.mid + "!" + prid),
- pluginResource = mix(mix({}, pseudoPluginResource), {mid:mid, prid:prid, injected:0});
- if(!modules[mid]){
- // create a new (the real) plugin resource and inject it normally now that the plugin is on board
- injectPlugin(modules[mid] = pluginResource);
- } // else this was a duplicate request for the same (plugin, rid) for a nondynamic plugin
-
- // pluginResource is really just a placeholder with the wrong mid (because we couldn't calculate it until the plugin was on board)
- // mark is as arrived and delete it from modules; the real module was requested above
- map[pseudoPluginResource.mid] = modules[mid];
- setArrived(pseudoPluginResource);
- delete modules[pseudoPluginResource.mid];
- });
- plugin.loadQ = 0;
-
- // step2: replace all references to any placeholder modules with real modules
- var substituteModules = function(module){
- for(var replacement, deps = module.deps || [], i = 0; i<deps.length; i++){
- replacement = map[deps[i].mid];
- if(replacement){
- deps[i] = replacement;
- }
- }
- };
- for(var p in modules){
- substituteModules(modules[p]);
- }
- forEach(execQ, substituteModules);
- },
-
- finishExec = function(module){
- req.trace("loader-finish-exec", [module.mid]);
- module.executed = executed;
- module.defOrder = defOrder++;
- has("dojo-sync-loader") && forEach(module.provides, function(cb){ cb(); });
- if(module.loadQ){
- // the module was a plugin
- promoteModuleToPlugin(module);
- resolvePluginLoadQ(module);
- }
- // remove all occurrences of this module from the execQ
- for(i = 0; i < execQ.length;){
- if(execQ[i] === module){
- execQ.splice(i, 1);
- }else{
- i++;
- }
- }
- // delete references to synthetic modules
- if (/^require\*/.test(module.mid)) {
- delete modules[module.mid];
- }
- },
-
- circleTrace = [],
-
- execModule = function(module, strict){
- // run the dependency vector, then run the factory for module
- if(module.executed === executing){
- req.trace("loader-circular-dependency", [circleTrace.concat(module.mid).join("->")]);
- return (!module.def || strict) ? abortExec : (module.cjs && module.cjs.exports);
- }
- // at this point the module is either not executed or fully executed
-
-
- if(!module.executed){
- if(!module.def){
- return abortExec;
- }
- var mid = module.mid,
- deps = module.deps || [],
- arg, argResult,
- args = [],
- i = 0;
-
- if(has("dojo-trace-api")){
- circleTrace.push(mid);
- req.trace("loader-exec-module", ["exec", circleTrace.length, mid]);
- }
-
- // for circular dependencies, assume the first module encountered was executed OK
- // modules that circularly depend on a module that has not run its factory will get
- // the pre-made cjs.exports===module.result. They can take a reference to this object and/or
- // add properties to it. When the module finally runs its factory, the factory can
- // read/write/replace this object. Notice that so long as the object isn't replaced, any
- // reference taken earlier while walking the deps list is still valid.
- module.executed = executing;
- while((arg = deps[i++])){
- argResult = ((arg === cjsRequireModule) ? createRequire(module) :
- ((arg === cjsExportsModule) ? module.cjs.exports :
- ((arg === cjsModuleModule) ? module.cjs :
- execModule(arg, strict))));
- if(argResult === abortExec){
- module.executed = 0;
- req.trace("loader-exec-module", ["abort", mid]);
- has("dojo-trace-api") && circleTrace.pop();
- return abortExec;
- }
- args.push(argResult);
- }
- runFactory(module, args);
- finishExec(module);
- has("dojo-trace-api") && circleTrace.pop();
- }
- // at this point the module is guaranteed fully executed
-
- return module.result;
- },
-
-
- checkCompleteGuard = 0,
-
- guardCheckComplete = function(proc){
- try{
- checkCompleteGuard++;
- proc();
- }finally{
- checkCompleteGuard--;
- }
- if(execComplete()){
- signal("idle", []);
- }
- },
-
- checkComplete = function(){
- // keep going through the execQ as long as at least one factory is executed
- // plugins, recursion, cached modules all make for many execution path possibilities
- if(checkCompleteGuard){
- return;
- }
- guardCheckComplete(function(){
- checkDojoRequirePlugin();
- for(var currentDefOrder, module, i = 0; i < execQ.length;){
- currentDefOrder = defOrder;
- module = execQ[i];
- execModule(module);
- if(currentDefOrder!=defOrder){
- // defOrder was bumped one or more times indicating something was executed (note, this indicates
- // the execQ was modified, maybe a lot (for example a later module causes an earlier module to execute)
- checkDojoRequirePlugin();
- i = 0;
- }else{
- // nothing happened; check the next module in the exec queue
- i++;
- }
- }
- });
- };
-
-
- if(has("dojo-undef-api")){
- req.undef = function(moduleId, referenceModule){
- // In order to reload a module, it must be undefined (this routine) and then re-requested.
- // This is useful for testing frameworks (at least).
- var module = getModule(moduleId, referenceModule);
- setArrived(module);
- mix(module, {def:0, executed:0, injected:0, node:0});
- };
- }
-
- if(has("dojo-inject-api")){
- if(has("dojo-loader-eval-hint-url")===undefined){
- has.add("dojo-loader-eval-hint-url", 1);
- }
-
- var fixupUrl= function(url){
- url += ""; // make sure url is a Javascript string (some paths may be a Java string)
- return url + (cacheBust ? ((/\?/.test(url) ? "&" : "?") + cacheBust) : "");
- },
-
- injectPlugin = function(
- module
- ){
- // injects the plugin module given by module; may have to inject the plugin itself
- var plugin = module.plugin;
-
- if(plugin.executed === executed && !plugin.load){
- // executed the module not knowing it was a plugin
- promoteModuleToPlugin(plugin);
- }
-
- var onLoad = function(def){
- module.result = def;
- setArrived(module);
- finishExec(module);
- checkComplete();
- };
-
- if(plugin.load){
- plugin.load(module.prid, module.req, onLoad);
- }else if(plugin.loadQ){
- plugin.loadQ.push(module);
- }else{
- // the unshift instead of push is important: we don't want plugins to execute as
- // dependencies of some other module because this may cause circles when the plugin
- // loadQ is run; also, generally, we want plugins to run early since they may load
- // several other modules and therefore can potentially unblock many modules
- plugin.loadQ = [module];
- execQ.unshift(plugin);
- injectModule(plugin);
- }
- },
-
- // for IE, injecting a module may result in a recursive execution if the module is in the cache
-
- cached = 0,
-
- injectingModule = 0,
-
- injectingCachedModule = 0,
-
- evalModuleText = function(text, module){
- // see def() for the injectingCachedModule bracket; it simply causes a short, safe circuit
- if(has("config-stripStrict")){
- text = text.replace(/"use strict"/g, '');
- }
- injectingCachedModule = 1;
- if(has("config-dojo-loader-catches")){
- try{
- if(text===cached){
- cached.call(null);
- }else{
- req.eval(text, has("dojo-loader-eval-hint-url") ? module.url : module.mid);
- }
- }catch(e){
- signal(error, makeError("evalModuleThrew", module));
- }
- }else{
- if(text===cached){
- cached.call(null);
- }else{
- req.eval(text, has("dojo-loader-eval-hint-url") ? module.url : module.mid);
- }
- }
- injectingCachedModule = 0;
- },
-
- injectModule = function(module){
- // Inject the module. In the browser environment, this means appending a script element into
- // the document; in other environments, it means loading a file.
- //
- // If in synchronous mode, then get the module synchronously if it's not xdomainLoading.
-
- var mid = module.mid,
- url = module.url;
- if(module.executed || module.injected || waiting[mid] || (module.url && ((module.pack && waiting[module.url]===module.pack) || waiting[module.url]==1))){
- return;
- }
- setRequested(module);
-
- if(has("dojo-combo-api")){
- var viaCombo = 0;
- if(module.plugin && module.plugin.isCombo){
- // a combo plugin; therefore, must be handled by combo service
- // the prid should have already been converted to a URL (if required by the plugin) during
- // the normalize process; in any event, there is no way for the loader to know how to
- // to the conversion; therefore the third argument is zero
- req.combo.add(module.plugin.mid, module.prid, 0, req);
- viaCombo = 1;
- }else if(!module.plugin){
- viaCombo = req.combo.add(0, module.mid, module.url, req);
- }
- if(viaCombo){
- comboPending= 1;
- return;
- }
- }
-
- if(module.plugin){
- injectPlugin(module);
- return;
- } // else a normal module (not a plugin)
-
-
- var onLoadCallback = function(){
- runDefQ(module);
- if(module.injected !== arrived){
- // the script that contained the module arrived and has been executed yet
- // nothing was added to the defQ (so it wasn't an AMD module) and the module
- // wasn't marked as arrived by dojo.provide (so it wasn't a v1.6- module);
- // therefore, it must not have been a module; adjust state accordingly
- if(has("dojo-enforceDefine")){
- signal(error, makeError("noDefine", module));
- return;
- }
- setArrived(module);
- mix(module, nonModuleProps);
- req.trace("loader-define-nonmodule", [module.url]);
- }
-
- if(has("dojo-sync-loader") && legacyMode){
- // must call checkComplete even in for sync loader because we may be in xdomainLoading mode;
- // but, if xd loading, then don't call checkComplete until out of the current sync traversal
- // in order to preserve order of execution of the dojo.required modules
- !syncExecStack.length && checkComplete();
- }else{
- checkComplete();
- }
- };
- cached = cache[mid] || cache[urlKeyPrefix + module.url];
- if(cached){
- req.trace("loader-inject", ["cache", module.mid, url]);
- evalModuleText(cached, module);
- onLoadCallback();
- return;
- }
- if(has("dojo-sync-loader") && legacyMode){
- if(module.isXd){
- // switch to async mode temporarily; if current legacyMode!=sync, then is must be one of {legacyAsync, xd, false}
- legacyMode==sync && (legacyMode = xd);
- // fall through and load via script injection
- }else if(module.isAmd && legacyMode!=sync){
- // fall through and load via script injection
- }else{
- // mode may be sync, xd/legacyAsync, or async; module may be AMD or legacy; but module is always located on the same domain
- var xhrCallback = function(text){
- if(legacyMode==sync){
- // the top of syncExecStack gives the current synchronously executing module; the loader needs
- // to know this if it has to switch to async loading in the middle of evaluating a legacy module
- // this happens when a modules dojo.require's a module that must be loaded async because it's xdomain
- // (using unshift/shift because there is no back() methods for Javascript arrays)
- syncExecStack.unshift(module);
- evalModuleText(text, module);
- syncExecStack.shift();
-
- // maybe the module was an AMD module
- runDefQ(module);
-
- // legacy modules never get to defineModule() => cjs and injected never set; also evaluation implies executing
- if(!module.cjs){
- setArrived(module);
- finishExec(module);
- }
-
- if(module.finish){
- // while synchronously evaluating this module, dojo.require was applied referencing a module
- // that had to be loaded async; therefore, the loader stopped answering all dojo.require
- // requests so they could be answered completely in the correct sequence; module.finish gives
- // the list of dojo.requires that must be re-applied once all target modules are available;
- // make a synthetic module to execute the dojo.require's in the correct order
-
- // compute a guaranteed-unique mid for the synthetic finish module; remember the finish vector; remove it from the reference module
- // TODO: can we just leave the module.finish...what's it hurting?
- var finishMid = mid + "*finish",
- finish = module.finish;
- delete module.finish;
-
- def(finishMid, ["dojo", ("dojo/require!" + finish.join(",")).replace(/\./g, "/")], function(dojo){
- forEach(finish, function(mid){ dojo.require(mid); });
- });
- // unshift, not push, which causes the current traversal to be reattempted from the top
- execQ.unshift(getModule(finishMid));
- }
- onLoadCallback();
- }else{
- text = transformToAmd(module, text);
- if(text){
- evalModuleText(text, module);
- onLoadCallback();
- }else{
- // if transformToAmd returned falsy, then the module was already AMD and it can be script-injected
- // do so to improve debugability(even though it means another download...which probably won't happen with a good browser cache)
- injectingModule = module;
- req.injectUrl(fixupUrl(url), onLoadCallback, module);
- injectingModule = 0;
- }
- }
- };
-
- req.trace("loader-inject", ["xhr", module.mid, url, legacyMode!=sync]);
- if(has("config-dojo-loader-catches")){
- try{
- req.getText(url, legacyMode!=sync, xhrCallback);
- }catch(e){
- signal(error, makeError("xhrInjectFailed", [module, e]));
- }
- }else{
- req.getText(url, legacyMode!=sync, xhrCallback);
- }
- return;
- }
- } // else async mode or fell through in xdomain loading mode; either way, load by script injection
- req.trace("loader-inject", ["script", module.mid, url]);
- injectingModule = module;
- req.injectUrl(fixupUrl(url), onLoadCallback, module);
- injectingModule = 0;
- },
-
- defineModule = function(module, deps, def){
- req.trace("loader-define-module", [module.mid, deps]);
-
- if(has("dojo-combo-api") && module.plugin && module.plugin.isCombo){
- // the module is a plugin resource loaded by the combo service
- // note: check for module.plugin should be enough since normal plugin resources should
- // not follow this path; module.plugin.isCombo is future-proofing belt and suspenders
- module.result = isFunction(def) ? def() : def;
- setArrived(module);
- finishExec(module);
- return module;
- }
-
- var mid = module.mid;
- if(module.injected === arrived){
- signal(error, makeError("multipleDefine", module));
- return module;
- }
- mix(module, {
- deps: deps,
- def: def,
- cjs: {
- id: module.mid,
- uri: module.url,
- exports: (module.result = {}),
- setExports: function(exports){
- module.cjs.exports = exports;
- },
- config:function(){
- return module.config;
- }
- }
- });
-
- // resolve deps with respect to this module
- for(var i = 0; deps[i]; i++){
- deps[i] = getModule(deps[i], module);
- }
-
- if(has("dojo-sync-loader") && legacyMode && !waiting[mid]){
- // the module showed up without being asked for; it was probably in a <script> element
- injectDependencies(module);
- execQ.push(module);
- checkComplete();
- }
- setArrived(module);
-
- if(!isFunction(def) && !deps.length){
- module.result = def;
- finishExec(module);
- }
-
- return module;
- },
-
- runDefQ = function(referenceModule, mids){
- // defQ is an array of [id, dependencies, factory]
- // mids (if any) is a vector of mids given by a combo service
- var definedModules = [],
- module, args;
- while(defQ.length){
- args = defQ.shift();
- mids && (args[0]= mids.shift());
- // explicit define indicates possible multiple modules in a single file; delay injecting dependencies until defQ fully
- // processed since modules earlier in the queue depend on already-arrived modules that are later in the queue
- // TODO: what if no args[0] and no referenceModule
- module = (args[0] && getModule(args[0])) || referenceModule;
- definedModules.push([module, args[1], args[2]]);
- }
- consumePendingCacheInsert(referenceModule);
- forEach(definedModules, function(args){
- injectDependencies(defineModule.apply(null, args));
- });
- };
- }
-
- var timerId = 0,
- clearTimer = noop,
- startTimer = noop;
- if(has("dojo-timeout-api")){
- // Timer machinery that monitors how long the loader is waiting and signals an error when the timer runs out.
- clearTimer = function(){
- timerId && clearTimeout(timerId);
- timerId = 0;
- };
-
- startTimer = function(){
- clearTimer();
- if(req.waitms){
- timerId = window.setTimeout(function(){
- clearTimer();
- signal(error, makeError("timeout", waiting));
- }, req.waitms);
- }
- };
- }
-
- if (has("dom")) {
- // Test for IE's different way of signaling when scripts finish loading. Note that according to
- // http://bugs.dojotoolkit.org/ticket/15096#comment:14, IE9 also needs to follow the
- // IE specific code path even though it has an addEventListener() method.
- // Unknown if special path needed on IE10+, which also has a document.attachEvent() method.
- // Should evaluate to false for Opera and Windows 8 apps, even though they document.attachEvent()
- // is defined in both those environments.
- has.add("ie-event-behavior", doc.attachEvent && typeof Windows === "undefined" &&
- (typeof opera === "undefined" || opera.toString() != "[object Opera]"));
- }
-
- if(has("dom") && (has("dojo-inject-api") || has("dojo-dom-ready-api"))){
- var domOn = function(node, eventName, ieEventName, handler){
- // Add an event listener to a DOM node using the API appropriate for the current browser;
- // return a function that will disconnect the listener.
- if(!has("ie-event-behavior")){
- node.addEventListener(eventName, handler, false);
- return function(){
- node.removeEventListener(eventName, handler, false);
- };
- }else{
- node.attachEvent(ieEventName, handler);
- return function(){
- node.detachEvent(ieEventName, handler);
- };
- }
- },
- windowOnLoadListener = domOn(window, "load", "onload", function(){
- req.pageLoaded = 1;
- doc.readyState!="complete" && (doc.readyState = "complete");
- windowOnLoadListener();
- });
-
- if(has("dojo-inject-api")){
- // if the loader is on the page, there must be at least one script element
- // getting its parent and then doing insertBefore solves the "Operation Aborted"
- // error in IE from appending to a node that isn't properly closed; see
- // dojo/tests/_base/loader/requirejs/simple-badbase.html for an example
- // don't use scripts with type dojo/... since these may be removed; see #15809
- // prefer to use the insertPoint computed during the config sniff in case a script is removed; see #16958
- var scripts = doc.getElementsByTagName("script"),
- i = 0,
- script;
- while(!insertPointSibling){
- if(!/^dojo/.test((script = scripts[i++]) && script.type)){
- insertPointSibling= script;
- }
- }
-
- req.injectUrl = function(url, callback, owner){
- // insert a script element to the insert-point element with src=url;
- // apply callback upon detecting the script has loaded.
-
- var node = owner.node = doc.createElement("script"),
- onLoad = function(e){
- e = e || window.event;
- var node = e.target || e.srcElement;
- if(e.type === "load" || /complete|loaded/.test(node.readyState)){
- loadDisconnector();
- errorDisconnector();
- callback && callback();
- }
- },
- loadDisconnector = domOn(node, "load", "onreadystatechange", onLoad),
- errorDisconnector = domOn(node, "error", "onerror", function(e){
- loadDisconnector();
- errorDisconnector();
- signal(error, makeError("scriptError", [url, e]));
- });
-
- node.type = "text/javascript";
- node.charset = "utf-8";
- node.src = url;
- insertPointSibling.parentNode.insertBefore(node, insertPointSibling);
- return node;
- };
- }
- }
-
- if(has("dojo-log-api")){
- req.log = function(){
- try{
- for(var i = 0; i < arguments.length; i++){
- console.log(arguments[i]);
- }
- }catch(e){}
- };
- }else{
- req.log = noop;
- }
-
- if(has("dojo-trace-api")){
- var trace = req.trace = function(
- group, // the trace group to which this application belongs
- args // the contents of the trace
- ){
- ///
- // Tracing interface by group.
- //
- // Sends the contents of args to the console iff (req.trace.on && req.trace[group])
-
- if(trace.on && trace.group[group]){
- signal("trace", [group, args]);
- for(var arg, dump = [], text= "trace:" + group + (args.length ? (":" + args[0]) : ""), i= 1; i<args.length;){
- arg = args[i++];
- if(isString(arg)){
- text += ", " + arg;
- }else{
- dump.push(arg);
- }
- }
- req.log(text);
- dump.length && dump.push(".");
- req.log.apply(req, dump);
- }
- };
- mix(trace, {
- on:1,
- group:{},
- set:function(group, value){
- if(isString(group)){
- trace.group[group]= value;
- }else{
- mix(trace.group, group);
- }
- }
- });
- trace.set(mix(mix(mix({}, defaultConfig.trace), userConfig.trace), dojoSniffConfig.trace));
- on("config", function(config){
- config.trace && trace.set(config.trace);
- });
- }else{
- req.trace = noop;
- }
-
- var def = function(
- mid, //(commonjs.moduleId, optional)
- dependencies, //(array of commonjs.moduleId, optional) list of modules to be loaded before running factory
- factory //(any)
- ){
- ///
- // Advises the loader of a module factory. //Implements http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition.
- ///
- //note
- // CommonJS factory scan courtesy of http://requirejs.org
-
- var arity = arguments.length,
- defaultDeps = ["require", "exports", "module"],
- // the predominate signature...
- args = [0, mid, dependencies];
- if(arity==1){
- args = [0, (isFunction(mid) ? defaultDeps : []), mid];
- }else if(arity==2 && isString(mid)){
- args = [mid, (isFunction(dependencies) ? defaultDeps : []), dependencies];
- }else if(arity==3){
- args = [mid, dependencies, factory];
- }
-
- if(has("dojo-amd-factory-scan") && args[1]===defaultDeps){
- args[2].toString()
- .replace(/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg, "")
- .replace(/require\(["']([\w\!\-_\.\/]+)["']\)/g, function(match, dep){
- args[1].push(dep);
- });
- }
-
- req.trace("loader-define", args.slice(0, 2));
- var targetModule = args[0] && getModule(args[0]),
- module;
- if(targetModule && !waiting[targetModule.mid]){
- // given a mid that hasn't been requested; therefore, defined through means other than injecting
- // consequent to a require() or define() application; examples include defining modules on-the-fly
- // due to some code path or including a module in a script element. In any case,
- // there is no callback waiting to finish processing and nothing to trigger the defQ and the
- // dependencies are never requested; therefore, do it here.
- injectDependencies(defineModule(targetModule, args[1], args[2]));
- }else if(!has("ie-event-behavior") || !has("host-browser") || injectingCachedModule){
- // not IE path: anonymous module and therefore must have been injected; therefore, onLoad will fire immediately
- // after script finishes being evaluated and the defQ can be run from that callback to detect the module id
- defQ.push(args);
- }else{
- // IE path: possibly anonymous module and therefore injected; therefore, cannot depend on 1-to-1,
- // in-order exec of onLoad with script eval (since it's IE) and must manually detect here
- targetModule = targetModule || injectingModule;
- if(!targetModule){
- for(mid in waiting){
- module = modules[mid];
- if(module && module.node && module.node.readyState === 'interactive'){
- targetModule = module;
- break;
- }
- }
- if(has("dojo-combo-api") && !targetModule){
- for(var i = 0; i<combosPending.length; i++){
- targetModule = combosPending[i];
- if(targetModule.node && targetModule.node.readyState === 'interactive'){
- break;
- }
- targetModule= 0;
- }
- }
- }
- if(has("dojo-combo-api") && isArray(targetModule)){
- injectDependencies(defineModule(getModule(targetModule.shift()), args[1], args[2]));
- if(!targetModule.length){
- combosPending.splice(i, 1);
- }
- }else if(targetModule){
- consumePendingCacheInsert(targetModule);
- injectDependencies(defineModule(targetModule, args[1], args[2]));
- }else{
- signal(error, makeError("ieDefineFailed", args[0]));
- }
- checkComplete();
- }
- };
- def.amd = {
- vendor:"dojotoolkit.org"
- };
-
- if(has("dojo-requirejs-api")){
- req.def = def;
- }
-
- // allow config to override default implementation of named functions; this is useful for
- // non-browser environments, e.g., overriding injectUrl, getText, log, etc. in node.js, Rhino, etc.
- // also useful for testing and monkey patching loader
- mix(mix(req, defaultConfig.loaderPatch), userConfig.loaderPatch);
-
- // now that req is fully initialized and won't change, we can hook it up to the error signal
- on(error, function(arg){
- try{
- console.error(arg);
- if(arg instanceof Error){
- for(var p in arg){
- console.log(p + ":", arg[p]);
- }
- console.log(".");
- }
- }catch(e){}
- });
-
- // always publish these
- mix(req, {
- uid:uid,
- cache:cache,
- packs:packs
- });
-
-
- if(has("dojo-publish-privates")){
- mix(req, {
- // these may be interesting to look at when debugging
- paths:paths,
- aliases:aliases,
- modules:modules,
- legacyMode:legacyMode,
- execQ:execQ,
- defQ:defQ,
- waiting:waiting,
-
- // these are used for testing
- // TODO: move testing infrastructure to a different has feature
- packs:packs,
- mapProgs:mapProgs,
- pathsMapProg:pathsMapProg,
- listenerQueues:listenerQueues,
-
- // these are used by the builder (at least)
- computeMapProg:computeMapProg,
- computeAliases:computeAliases,
- runMapProg:runMapProg,
- compactPath:compactPath,
- getModuleInfo:getModuleInfo_
- });
- }
-
- // the loader can be defined exactly once; look for global define which is the symbol AMD loaders are
- // *required* to define (as opposed to require, which is optional)
- if(global.define){
- if(has("dojo-log-api")){
- signal(error, makeError("defineAlreadyDefined", 0));
- }
- return;
- }else{
- global.define = def;
- global.require = req;
- if(has("host-node")){
- require = req;
- }
- }
-
- if(has("dojo-combo-api") && req.combo && req.combo.plugins){
- var plugins = req.combo.plugins,
- pluginName;
- for(pluginName in plugins){
- mix(mix(getModule(pluginName), plugins[pluginName]), {isCombo:1, executed:"executed", load:1});
- }
- }
-
- if(has("dojo-config-api")){
- forEach(delayedModuleConfig, function(c){ config(c); });
- var bootDeps = dojoSniffConfig.deps || userConfig.deps || defaultConfig.deps,
- bootCallback = dojoSniffConfig.callback || userConfig.callback || defaultConfig.callback;
- req.boot = (bootDeps || bootCallback) ? [bootDeps || [], bootCallback] : 0;
- }
- if(!has("dojo-built")){
- !req.async && req(["dojo"]);
- req.boot && req.apply(null, req.boot);
- }
-})
-//>>excludeStart("replaceLoaderConfig", kwArgs.replaceLoaderConfig);
-(
- // userConfig
- (function(){
- // make sure we're looking at global dojoConfig etc.
- return this.dojoConfig || this.djConfig || this.require || {};
- })(),
-
- // defaultConfig
- {
- // the default configuration for a browser; this will be modified by other environments
- hasCache:{
- "host-browser":1,
- "dom":1,
- "dojo-amd-factory-scan":1,
- "dojo-loader":1,
- "dojo-has-api":1,
- "dojo-inject-api":1,
- "dojo-timeout-api":1,
- "dojo-trace-api":1,
- "dojo-log-api":1,
- "dojo-dom-ready-api":1,
- "dojo-publish-privates":1,
- "dojo-config-api":1,
- "dojo-sniff":1,
- "dojo-sync-loader":1,
- "dojo-test-sniff":1,
- "config-deferredInstrumentation":1,
- "config-useDeferredInstrumentation":"report-unhandled-rejections",
- "config-tlmSiblingOfDojo":1
- },
- packages:[{
- // note: like v1.6-, this bootstrap computes baseUrl to be the dojo directory
- name:'dojo',
- location:'.'
- },{
- name:'tests',
- location:'./tests'
- },{
- name:'dijit',
- location:'../dijit'
- },{
- name:'build',
- location:'../util/build'
- },{
- name:'doh',
- location:'../util/doh'
- },{
- name:'dojox',
- location:'../dojox'
- },{
- name:'demos',
- location:'../demos'
- }],
- trace:{
- // these are listed so it's simple to turn them on/off while debugging loading
- "loader-inject":0,
- "loader-define":0,
- "loader-exec-module":0,
- "loader-run-factory":0,
- "loader-finish-exec":0,
- "loader-define-module":0,
- "loader-circular-dependency":0,
- "loader-define-nonmodule":0
- },
- async:0,
- waitSeconds:15
- }
-);
-//>>excludeEnd("replaceLoaderConfig")
diff --git a/vendor/firebug-lite/skin/xp/textEditorBorders.gif b/vendor/firebug-lite/skin/xp/textEditorBorders.gif
deleted file mode 100755
index 0ee5497..0000000
Binary files a/vendor/firebug-lite/skin/xp/textEditorBorders.gif and /dev/null differ
diff --git a/vendor/firebug-lite/skin/xp/textEditorCorners.gif b/vendor/firebug-lite/skin/xp/textEditorCorners.gif
deleted file mode 100755
index 04f8421..0000000
Binary files a/vendor/firebug-lite/skin/xp/textEditorCorners.gif and /dev/null differ
diff --git a/vendor/jquery/MIT-LICENSE.txt b/vendor/jquery/MIT-LICENSE.txt
deleted file mode 100644
index 7b154c1..0000000
--- a/vendor/jquery/MIT-LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Copyright 2012 jQuery Foundation and other contributors
-http://jquery.com/
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/jquery/jquery.js b/vendor/jquery/jquery.js
deleted file mode 100644
index 12c7797..0000000
--- a/vendor/jquery/jquery.js
+++ /dev/null
@@ -1,9440 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.8.2
- * http://jquery.com/
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: Thu Sep 20 2012 21:13:05 GMT-0400 (Eastern Daylight Time)
- */
-(function( window, undefined ) {
-var
- // A central reference to the root jQuery(document)
- rootjQuery,
-
- // The deferred used on DOM ready
- readyList,
-
- // Use the correct document accordingly with window argument (sandbox)
- document = window.document,
- location = window.location,
- navigator = window.navigator,
-
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
-
- // Map over the $ in case of overwrite
- _$ = window.$,
-
- // Save a reference to some core methods
- core_push = Array.prototype.push,
- core_slice = Array.prototype.slice,
- core_indexOf = Array.prototype.indexOf,
- core_toString = Object.prototype.toString,
- core_hasOwn = Object.prototype.hasOwnProperty,
- core_trim = String.prototype.trim,
-
- // Define a local copy of jQuery
- jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init( selector, context, rootjQuery );
- },
-
- // Used for matching numbers
- core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,
-
- // Used for detecting and trimming whitespace
- core_rnotwhite = /\S/,
- core_rspace = /\s+/,
-
- // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
- rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
-
- // A simple way to check for HTML strings
- // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
- rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
-
- // Match a standalone tag
- rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
-
- // JSON RegExp
- rvalidchars = /^[\],:{}\s]*$/,
- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
- rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
- rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,
-
- // Matches dashed string for camelizing
- rmsPrefix = /^-ms-/,
- rdashAlpha = /-([\da-z])/gi,
-
- // Used by jQuery.camelCase as callback to replace()
- fcamelCase = function( all, letter ) {
- return ( letter + "" ).toUpperCase();
- },
-
- // The ready event handler and self cleanup method
- DOMContentLoaded = function() {
- if ( document.addEventListener ) {
- document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
- jQuery.ready();
- } else if ( document.readyState === "complete" ) {
- // we're here because readyState === "complete" in oldIE
- // which is good enough for us to call the dom ready!
- document.detachEvent( "onreadystatechange", DOMContentLoaded );
- jQuery.ready();
- }
- },
-
- // [[Class]] -> type pairs
- class2type = {};
-
-jQuery.fn = jQuery.prototype = {
- constructor: jQuery,
- init: function( selector, context, rootjQuery ) {
- var match, elem, ret, doc;
-
- // Handle $(""), $(null), $(undefined), $(false)
- if ( !selector ) {
- return this;
- }
-
- // Handle $(DOMElement)
- if ( selector.nodeType ) {
- this.context = this[0] = selector;
- this.length = 1;
- return this;
- }
-
- // Handle HTML strings
- if ( typeof selector === "string" ) {
- if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
- // Assume that strings that start and end with <> are HTML and skip the regex check
- match = [ null, selector, null ];
-
- } else {
- match = rquickExpr.exec( selector );
- }
-
- // Match html or make sure no context is specified for #id
- if ( match && (match[1] || !context) ) {
-
- // HANDLE: $(html) -> $(array)
- if ( match[1] ) {
- context = context instanceof jQuery ? context[0] : context;
- doc = ( context && context.nodeType ? context.ownerDocument || context : document );
-
- // scripts is true for back-compat
- selector = jQuery.parseHTML( match[1], doc, true );
- if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
- this.attr.call( selector, context, true );
- }
-
- return jQuery.merge( this, selector );
-
- // HANDLE: $(#id)
- } else {
- elem = document.getElementById( match[2] );
-
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id !== match[2] ) {
- return rootjQuery.find( selector );
- }
-
- // Otherwise, we inject the element directly into the jQuery object
- this.length = 1;
- this[0] = elem;
- }
-
- this.context = document;
- this.selector = selector;
- return this;
- }
-
- // HANDLE: $(expr, $(...))
- } else if ( !context || context.jquery ) {
- return ( context || rootjQuery ).find( selector );
-
- // HANDLE: $(expr, context)
- // (which is just equivalent to: $(context).find(expr)
- } else {
- return this.constructor( context ).find( selector );
- }
-
- // HANDLE: $(function)
- // Shortcut for document ready
- } else if ( jQuery.isFunction( selector ) ) {
- return rootjQuery.ready( selector );
- }
-
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
-
- return jQuery.makeArray( selector, this );
- },
-
- // Start with an empty selector
- selector: "",
-
- // The current version of jQuery being used
- jquery: "1.8.2",
-
- // The default length of a jQuery object is 0
- length: 0,
-
- // The number of elements contained in the matched element set
- size: function() {
- return this.length;
- },
-
- toArray: function() {
- return core_slice.call( this );
- },
-
- // Get the Nth element in the matched element set OR
- // Get the whole matched element set as a clean array
- get: function( num ) {
- return num == null ?
-
- // Return a 'clean' array
- this.toArray() :
-
- // Return just the object
- ( num < 0 ? this[ this.length + num ] : this[ num ] );
- },
-
- // Take an array of elements and push it onto the stack
- // (returning the new matched element set)
- pushStack: function( elems, name, selector ) {
-
- // Build a new jQuery matched element set
- var ret = jQuery.merge( this.constructor(), elems );
-
- // Add the old object onto the stack (as a reference)
- ret.prevObject = this;
-
- ret.context = this.context;
-
- if ( name === "find" ) {
- ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
- } else if ( name ) {
- ret.selector = this.selector + "." + name + "(" + selector + ")";
- }
-
- // Return the newly-formed element set
- return ret;
- },
-
- // Execute a callback for every element in the matched set.
- // (You can seed the arguments with an array of args, but this is
- // only used internally.)
- each: function( callback, args ) {
- return jQuery.each( this, callback, args );
- },
-
- ready: function( fn ) {
- // Add the callback
- jQuery.ready.promise().done( fn );
-
- return this;
- },
-
- eq: function( i ) {
- i = +i;
- return i === -1 ?
- this.slice( i ) :
- this.slice( i, i + 1 );
- },
-
- first: function() {
- return this.eq( 0 );
- },
-
- last: function() {
- return this.eq( -1 );
- },
-
- slice: function() {
- return this.pushStack( core_slice.apply( this, arguments ),
- "slice", core_slice.call(arguments).join(",") );
- },
-
- map: function( callback ) {
- return this.pushStack( jQuery.map(this, function( elem, i ) {
- return callback.call( elem, i, elem );
- }));
- },
-
- end: function() {
- return this.prevObject || this.constructor(null);
- },
-
- // For internal use only.
- // Behaves like an Array's method, not like a jQuery method.
- push: core_push,
- sort: [].sort,
- splice: [].splice
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-jQuery.extend = jQuery.fn.extend = function() {
- var options, name, src, copy, copyIsArray, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false;
-
- // Handle a deep copy situation
- if ( typeof target === "boolean" ) {
- deep = target;
- target = arguments[1] || {};
- // skip the boolean and the target
- i = 2;
- }
-
- // Handle case when target is a string or something (possible in deep copy)
- if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
- target = {};
- }
-
- // extend jQuery itself if only one argument is passed
- if ( length === i ) {
- target = this;
- --i;
- }
-
- for ( ; i < length; i++ ) {
- // Only deal with non-null/undefined values
- if ( (options = arguments[ i ]) != null ) {
- // Extend the base object
- for ( name in options ) {
- src = target[ name ];
- copy = options[ name ];
-
- // Prevent never-ending loop
- if ( target === copy ) {
- continue;
- }
-
- // Recurse if we're merging plain objects or arrays
- if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
- if ( copyIsArray ) {
- copyIsArray = false;
- clone = src && jQuery.isArray(src) ? src : [];
-
- } else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
- }
-
- // Never move original objects, clone them
- target[ name ] = jQuery.extend( deep, clone, copy );
-
- // Don't bring in undefined values
- } else if ( copy !== undefined ) {
- target[ name ] = copy;
- }
- }
- }
- }
-
- // Return the modified object
- return target;
-};
-
-jQuery.extend({
- noConflict: function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
-
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
-
- return jQuery;
- },
-
- // Is the DOM ready to be used? Set to true once it occurs.
- isReady: false,
-
- // A counter to track how many items to wait for before
- // the ready event fires. See #6781
- readyWait: 1,
-
- // Hold (or release) the ready event
- holdReady: function( hold ) {
- if ( hold ) {
- jQuery.readyWait++;
- } else {
- jQuery.ready( true );
- }
- },
-
- // Handle when the DOM is ready
- ready: function( wait ) {
-
- // Abort if there are pending holds or we're already ready
- if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
- return;
- }
-
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( !document.body ) {
- return setTimeout( jQuery.ready, 1 );
- }
-
- // Remember that the DOM is ready
- jQuery.isReady = true;
-
- // If a normal DOM Ready event fired, decrement, and wait if need be
- if ( wait !== true && --jQuery.readyWait > 0 ) {
- return;
- }
-
- // If there are functions bound, to execute
- readyList.resolveWith( document, [ jQuery ] );
-
- // Trigger any bound ready events
- if ( jQuery.fn.trigger ) {
- jQuery( document ).trigger("ready").off("ready");
- }
- },
-
- // See test/unit/core.js for details concerning isFunction.
- // Since version 1.3, DOM methods and functions like alert
- // aren't supported. They return false on IE (#2968).
- isFunction: function( obj ) {
- return jQuery.type(obj) === "function";
- },
-
- isArray: Array.isArray || function( obj ) {
- return jQuery.type(obj) === "array";
- },
-
- isWindow: function( obj ) {
- return obj != null && obj == obj.window;
- },
-
- isNumeric: function( obj ) {
- return !isNaN( parseFloat(obj) ) && isFinite( obj );
- },
-
- type: function( obj ) {
- return obj == null ?
- String( obj ) :
- class2type[ core_toString.call(obj) ] || "object";
- },
-
- isPlainObject: function( obj ) {
- // Must be an Object.
- // Because of IE, we also have to check the presence of the constructor property.
- // Make sure that DOM nodes and window objects don't pass through, as well
- if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
- return false;
- }
-
- try {
- // Not own constructor property must be Object
- if ( obj.constructor &&
- !core_hasOwn.call(obj, "constructor") &&
- !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
- } catch ( e ) {
- // IE8,9 Will throw exceptions on certain host objects #9897
- return false;
- }
-
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
-
- var key;
- for ( key in obj ) {}
-
- return key === undefined || core_hasOwn.call( obj, key );
- },
-
- isEmptyObject: function( obj ) {
- var name;
- for ( name in obj ) {
- return false;
- }
- return true;
- },
-
- error: function( msg ) {
- throw new Error( msg );
- },
-
- // data: string of html
- // context (optional): If specified, the fragment will be created in this context, defaults to document
- // scripts (optional): If true, will include scripts passed in the html string
- parseHTML: function( data, context, scripts ) {
- var parsed;
- if ( !data || typeof data !== "string" ) {
- return null;
- }
- if ( typeof context === "boolean" ) {
- scripts = context;
- context = 0;
- }
- context = context || document;
-
- // Single tag
- if ( (parsed = rsingleTag.exec( data )) ) {
- return [ context.createElement( parsed[1] ) ];
- }
-
- parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
- return jQuery.merge( [],
- (parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
- },
-
- parseJSON: function( data ) {
- if ( !data || typeof data !== "string") {
- return null;
- }
-
- // Make sure leading/trailing whitespace is removed (IE can't handle it)
- data = jQuery.trim( data );
-
- // Attempt to parse using the native JSON parser first
- if ( window.JSON && window.JSON.parse ) {
- return window.JSON.parse( data );
- }
-
- // Make sure the incoming data is actual JSON
- // Logic borrowed from http://json.org/json2.js
- if ( rvalidchars.test( data.replace( rvalidescape, "@" )
- .replace( rvalidtokens, "]" )
- .replace( rvalidbraces, "")) ) {
-
- return ( new Function( "return " + data ) )();
-
- }
- jQuery.error( "Invalid JSON: " + data );
- },
-
- // Cross-browser xml parsing
- parseXML: function( data ) {
- var xml, tmp;
- if ( !data || typeof data !== "string" ) {
- return null;
- }
- try {
- if ( window.DOMParser ) { // Standard
- tmp = new DOMParser();
- xml = tmp.parseFromString( data , "text/xml" );
- } else { // IE
- xml = new ActiveXObject( "Microsoft.XMLDOM" );
- xml.async = "false";
- xml.loadXML( data );
- }
- } catch( e ) {
- xml = undefined;
- }
- if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
- jQuery.error( "Invalid XML: " + data );
- }
- return xml;
- },
-
- noop: function() {},
-
- // Evaluates a script in a global context
- // Workarounds based on findings by Jim Driscoll
- // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
- globalEval: function( data ) {
- if ( data && core_rnotwhite.test( data ) ) {
- // We use execScript on Internet Explorer
- // We use an anonymous function so that context is window
- // rather than jQuery in Firefox
- ( window.execScript || function( data ) {
- window[ "eval" ].call( window, data );
- } )( data );
- }
- },
-
- // Convert dashed to camelCase; used by the css and data modules
- // Microsoft forgot to hump their vendor prefix (#9572)
- camelCase: function( string ) {
- return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
- },
-
- nodeName: function( elem, name ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
- },
-
- // args is for internal usage only
- each: function( obj, callback, args ) {
- var name,
- i = 0,
- length = obj.length,
- isObj = length === undefined || jQuery.isFunction( obj );
-
- if ( args ) {
- if ( isObj ) {
- for ( name in obj ) {
- if ( callback.apply( obj[ name ], args ) === false ) {
- break;
- }
- }
- } else {
- for ( ; i < length; ) {
- if ( callback.apply( obj[ i++ ], args ) === false ) {
- break;
- }
- }
- }
-
- // A special, fast, case for the most common use of each
- } else {
- if ( isObj ) {
- for ( name in obj ) {
- if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
- break;
- }
- }
- } else {
- for ( ; i < length; ) {
- if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
- break;
- }
- }
- }
- }
-
- return obj;
- },
-
- // Use native String.trim function wherever possible
- trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
- function( text ) {
- return text == null ?
- "" :
- core_trim.call( text );
- } :
-
- // Otherwise use our own trimming functionality
- function( text ) {
- return text == null ?
- "" :
- ( text + "" ).replace( rtrim, "" );
- },
-
- // results is for internal usage only
- makeArray: function( arr, results ) {
- var type,
- ret = results || [];
-
- if ( arr != null ) {
- // The window, strings (and functions) also have 'length'
- // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
- type = jQuery.type( arr );
-
- if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) {
- core_push.call( ret, arr );
- } else {
- jQuery.merge( ret, arr );
- }
- }
-
- return ret;
- },
-
- inArray: function( elem, arr, i ) {
- var len;
-
- if ( arr ) {
- if ( core_indexOf ) {
- return core_indexOf.call( arr, elem, i );
- }
-
- len = arr.length;
- i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
-
- for ( ; i < len; i++ ) {
- // Skip accessing in sparse arrays
- if ( i in arr && arr[ i ] === elem ) {
- return i;
- }
- }
- }
-
- return -1;
- },
-
- merge: function( first, second ) {
- var l = second.length,
- i = first.length,
- j = 0;
-
- if ( typeof l === "number" ) {
- for ( ; j < l; j++ ) {
- first[ i++ ] = second[ j ];
- }
-
- } else {
- while ( second[j] !== undefined ) {
- first[ i++ ] = second[ j++ ];
- }
- }
-
- first.length = i;
-
- return first;
- },
-
- grep: function( elems, callback, inv ) {
- var retVal,
- ret = [],
- i = 0,
- length = elems.length;
- inv = !!inv;
-
- // Go through the array, only saving the items
- // that pass the validator function
- for ( ; i < length; i++ ) {
- retVal = !!callback( elems[ i ], i );
- if ( inv !== retVal ) {
- ret.push( elems[ i ] );
- }
- }
-
- return ret;
- },
-
- // arg is for internal usage only
- map: function( elems, callback, arg ) {
- var value, key,
- ret = [],
- i = 0,
- length = elems.length,
- // jquery objects are treated as arrays
- isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
-
- // Go through the array, translating each of the items to their
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
-
- // Go through every key on the object,
- } else {
- for ( key in elems ) {
- value = callback( elems[ key ], key, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
- }
-
- // Flatten any nested arrays
- return ret.concat.apply( [], ret );
- },
-
- // A global GUID counter for objects
- guid: 1,
-
- // Bind a function to a context, optionally partially applying any
- // arguments.
- proxy: function( fn, context ) {
- var tmp, args, proxy;
-
- if ( typeof context === "string" ) {
- tmp = fn[ context ];
- context = fn;
- fn = tmp;
- }
-
- // Quick check to determine if target is callable, in the spec
- // this throws a TypeError, but we will just return undefined.
- if ( !jQuery.isFunction( fn ) ) {
- return undefined;
- }
-
- // Simulated bind
- args = core_slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context, args.concat( core_slice.call( arguments ) ) );
- };
-
- // Set the guid of unique handler to the same of original handler, so it can be removed
- proxy.guid = fn.guid = fn.guid || jQuery.guid++;
-
- return proxy;
- },
-
- // Multifunctional method to get and set values of a collection
- // The value/s can optionally be executed if it's a function
- access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
- var exec,
- bulk = key == null,
- i = 0,
- length = elems.length;
-
- // Sets many values
- if ( key && typeof key === "object" ) {
- for ( i in key ) {
- jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
- }
- chainable = 1;
-
- // Sets one value
- } else if ( value !== undefined ) {
- // Optionally, function values get executed if exec is true
- exec = pass === undefined && jQuery.isFunction( value );
-
- if ( bulk ) {
- // Bulk operations only iterate when executing function values
- if ( exec ) {
- exec = fn;
- fn = function( elem, key, value ) {
- return exec.call( jQuery( elem ), value );
- };
-
- // Otherwise they run against the entire set
- } else {
- fn.call( elems, value );
- fn = null;
- }
- }
-
- if ( fn ) {
- for (; i < length; i++ ) {
- fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
- }
- }
-
- chainable = 1;
- }
-
- return chainable ?
- elems :
-
- // Gets
- bulk ?
- fn.call( elems ) :
- length ? fn( elems[0], key ) : emptyGet;
- },
-
- now: function() {
- return ( new Date() ).getTime();
- }
-});
-
-jQuery.ready.promise = function( obj ) {
- if ( !readyList ) {
-
- readyList = jQuery.Deferred();
-
- // Catch cases where $(document).ready() is called after the browser event has already occurred.
- // we once tried to use readyState "interactive" here, but it caused issues like the one
- // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
- if ( document.readyState === "complete" ) {
- // Handle it asynchronously to allow scripts the opportunity to delay ready
- setTimeout( jQuery.ready, 1 );
-
- // Standards-based browsers support DOMContentLoaded
- } else if ( document.addEventListener ) {
- // Use the handy event callback
- document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-
- // A fallback to window.onload, that will always work
- window.addEventListener( "load", jQuery.ready, false );
-
- // If IE event model is used
- } else {
- // Ensure firing before onload, maybe late but safe also for iframes
- document.attachEvent( "onreadystatechange", DOMContentLoaded );
-
- // A fallback to window.onload, that will always work
- window.attachEvent( "onload", jQuery.ready );
-
- // If IE and not a frame
- // continually check to see if the document is ready
- var top = false;
-
- try {
- top = window.frameElement == null && document.documentElement;
- } catch(e) {}
-
- if ( top && top.doScroll ) {
- (function doScrollCheck() {
- if ( !jQuery.isReady ) {
-
- try {
- // Use the trick by Diego Perini
- // http://javascript.nwbox.com/IEContentLoaded/
- top.doScroll("left");
- } catch(e) {
- return setTimeout( doScrollCheck, 50 );
- }
-
- // and execute any waiting functions
- jQuery.ready();
- }
- })();
- }
- }
- }
- return readyList.promise( obj );
-};
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
- class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-// String to Object options format cache
-var optionsCache = {};
-
-// Convert String-formatted options into Object-formatted ones and store in cache
-function createOptions( options ) {
- var object = optionsCache[ options ] = {};
- jQuery.each( options.split( core_rspace ), function( _, flag ) {
- object[ flag ] = true;
- });
- return object;
-}
-
-/*
- * Create a callback list using the following parameters:
- *
- * options: an optional list of space-separated options that will change how
- * the callback list behaves or a more traditional option object
- *
- * By default a callback list will act like an event callback list and can be
- * "fired" multiple times.
- *
- * Possible options:
- *
- * once: will ensure the callback list can only be fired once (like a Deferred)
- *
- * memory: will keep track of previous values and will call any callback added
- * after the list has been fired right away with the latest "memorized"
- * values (like a Deferred)
- *
- * unique: will ensure a callback can only be added once (no duplicate in the list)
- *
- * stopOnFalse: interrupt callings when a callback returns false
- *
- */
-jQuery.Callbacks = function( options ) {
-
- // Convert options from String-formatted to Object-formatted if needed
- // (we check in cache first)
- options = typeof options === "string" ?
- ( optionsCache[ options ] || createOptions( options ) ) :
- jQuery.extend( {}, options );
-
- var // Last fire value (for non-forgettable lists)
- memory,
- // Flag to know if list was already fired
- fired,
- // Flag to know if list is currently firing
- firing,
- // First callback to fire (used internally by add and fireWith)
- firingStart,
- // End of the loop when firing
- firingLength,
- // Index of currently firing callback (modified by remove if needed)
- firingIndex,
- // Actual callback list
- list = [],
- // Stack of fire calls for repeatable lists
- stack = !options.once && [],
- // Fire callbacks
- fire = function( data ) {
- memory = options.memory && data;
- fired = true;
- firingIndex = firingStart || 0;
- firingStart = 0;
- firingLength = list.length;
- firing = true;
- for ( ; list && firingIndex < firingLength; firingIndex++ ) {
- if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
- memory = false; // To prevent further calls using add
- break;
- }
- }
- firing = false;
- if ( list ) {
- if ( stack ) {
- if ( stack.length ) {
- fire( stack.shift() );
- }
- } else if ( memory ) {
- list = [];
- } else {
- self.disable();
- }
- }
- },
- // Actual Callbacks object
- self = {
- // Add a callback or a collection of callbacks to the list
- add: function() {
- if ( list ) {
- // First, we save the current length
- var start = list.length;
- (function add( args ) {
- jQuery.each( args, function( _, arg ) {
- var type = jQuery.type( arg );
- if ( type === "function" && ( !options.unique || !self.has( arg ) ) ) {
- list.push( arg );
- } else if ( arg && arg.length && type !== "string" ) {
- // Inspect recursively
- add( arg );
- }
- });
- })( arguments );
- // Do we need to add the callbacks to the
- // current firing batch?
- if ( firing ) {
- firingLength = list.length;
- // With memory, if we're not firing then
- // we should call right away
- } else if ( memory ) {
- firingStart = start;
- fire( memory );
- }
- }
- return this;
- },
- // Remove a callback from the list
- remove: function() {
- if ( list ) {
- jQuery.each( arguments, function( _, arg ) {
- var index;
- while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
- list.splice( index, 1 );
- // Handle firing indexes
- if ( firing ) {
- if ( index <= firingLength ) {
- firingLength--;
- }
- if ( index <= firingIndex ) {
- firingIndex--;
- }
- }
- }
- });
- }
- return this;
- },
- // Control if a given callback is in the list
- has: function( fn ) {
- return jQuery.inArray( fn, list ) > -1;
- },
- // Remove all callbacks from the list
- empty: function() {
- list = [];
- return this;
- },
- // Have the list do nothing anymore
- disable: function() {
- list = stack = memory = undefined;
- return this;
- },
- // Is it disabled?
- disabled: function() {
- return !list;
- },
- // Lock the list in its current state
- lock: function() {
- stack = undefined;
- if ( !memory ) {
- self.disable();
- }
- return this;
- },
- // Is it locked?
- locked: function() {
- return !stack;
- },
- // Call all callbacks with the given context and arguments
- fireWith: function( context, args ) {
- args = args || [];
- args = [ context, args.slice ? args.slice() : args ];
- if ( list && ( !fired || stack ) ) {
- if ( firing ) {
- stack.push( args );
- } else {
- fire( args );
- }
- }
- return this;
- },
- // Call all the callbacks with the given arguments
- fire: function() {
- self.fireWith( this, arguments );
- return this;
- },
- // To know if the callbacks have already been called at least once
- fired: function() {
- return !!fired;
- }
- };
-
- return self;
-};
-jQuery.extend({
-
- Deferred: function( func ) {
- var tuples = [
- // action, add listener, listener list, final state
- [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
- [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
- [ "notify", "progress", jQuery.Callbacks("memory") ]
- ],
- state = "pending",
- promise = {
- state: function() {
- return state;
- },
- always: function() {
- deferred.done( arguments ).fail( arguments );
- return this;
- },
- then: function( /* fnDone, fnFail, fnProgress */ ) {
- var fns = arguments;
- return jQuery.Deferred(function( newDefer ) {
- jQuery.each( tuples, function( i, tuple ) {
- var action = tuple[ 0 ],
- fn = fns[ i ];
- // deferred[ done | fail | progress ] for forwarding actions to newDefer
- deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
- function() {
- var returned = fn.apply( this, arguments );
- if ( returned && jQuery.isFunction( returned.promise ) ) {
- returned.promise()
- .done( newDefer.resolve )
- .fail( newDefer.reject )
- .progress( newDefer.notify );
- } else {
- newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
- }
- } :
- newDefer[ action ]
- );
- });
- fns = null;
- }).promise();
- },
- // Get a promise for this deferred
- // If obj is provided, the promise aspect is added to the object
- promise: function( obj ) {
- return obj != null ? jQuery.extend( obj, promise ) : promise;
- }
- },
- deferred = {};
-
- // Keep pipe for back-compat
- promise.pipe = promise.then;
-
- // Add list-specific methods
- jQuery.each( tuples, function( i, tuple ) {
- var list = tuple[ 2 ],
- stateString = tuple[ 3 ];
-
- // promise[ done | fail | progress ] = list.add
- promise[ tuple[1] ] = list.add;
-
- // Handle state
- if ( stateString ) {
- list.add(function() {
- // state = [ resolved | rejected ]
- state = stateString;
-
- // [ reject_list | resolve_list ].disable; progress_list.lock
- }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
- }
-
- // deferred[ resolve | reject | notify ] = list.fire
- deferred[ tuple[0] ] = list.fire;
- deferred[ tuple[0] + "With" ] = list.fireWith;
- });
-
- // Make the deferred a promise
- promise.promise( deferred );
-
- // Call given func if any
- if ( func ) {
- func.call( deferred, deferred );
- }
-
- // All done!
- return deferred;
- },
-
- // Deferred helper
- when: function( subordinate /* , ..., subordinateN */ ) {
- var i = 0,
- resolveValues = core_slice.call( arguments ),
- length = resolveValues.length,
-
- // the count of uncompleted subordinates
- remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
-
- // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
- deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
-
- // Update function for both resolve and progress values
- updateFunc = function( i, contexts, values ) {
- return function( value ) {
- contexts[ i ] = this;
- values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
- if( values === progressValues ) {
- deferred.notifyWith( contexts, values );
- } else if ( !( --remaining ) ) {
- deferred.resolveWith( contexts, values );
- }
- };
- },
-
- progressValues, progressContexts, resolveContexts;
-
- // add listeners to Deferred subordinates; treat others as resolved
- if ( length > 1 ) {
- progressValues = new Array( length );
- progressContexts = new Array( length );
- resolveContexts = new Array( length );
- for ( ; i < length; i++ ) {
- if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
- resolveValues[ i ].promise()
- .done( updateFunc( i, resolveContexts, resolveValues ) )
- .fail( deferred.reject )
- .progress( updateFunc( i, progressContexts, progressValues ) );
- } else {
- --remaining;
- }
- }
- }
-
- // if we're not waiting on anything, resolve the master
- if ( !remaining ) {
- deferred.resolveWith( resolveContexts, resolveValues );
- }
-
- return deferred.promise();
- }
-});
-jQuery.support = (function() {
-
- var support,
- all,
- a,
- select,
- opt,
- input,
- fragment,
- eventName,
- i,
- isSupported,
- clickFn,
- div = document.createElement("div");
-
- // Preliminary tests
- div.setAttribute( "className", "t" );
- div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
-
- all = div.getElementsByTagName("*");
- a = div.getElementsByTagName("a")[ 0 ];
- a.style.cssText = "top:1px;float:left;opacity:.5";
-
- // Can't get basic test support
- if ( !all || !all.length ) {
- return {};
- }
-
- // First batch of supports tests
- select = document.createElement("select");
- opt = select.appendChild( document.createElement("option") );
- input = div.getElementsByTagName("input")[ 0 ];
-
- support = {
- // IE strips leading whitespace when .innerHTML is used
- leadingWhitespace: ( div.firstChild.nodeType === 3 ),
-
- // Make sure that tbody elements aren't automatically inserted
- // IE will insert them into empty tables
- tbody: !div.getElementsByTagName("tbody").length,
-
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- htmlSerialize: !!div.getElementsByTagName("link").length,
-
- // Get the style information from getAttribute
- // (IE uses .cssText instead)
- style: /top/.test( a.getAttribute("style") ),
-
- // Make sure that URLs aren't manipulated
- // (IE normalizes it by default)
- hrefNormalized: ( a.getAttribute("href") === "/a" ),
-
- // Make sure that element opacity exists
- // (IE uses filter instead)
- // Use a regex to work around a WebKit issue. See #5145
- opacity: /^0.5/.test( a.style.opacity ),
-
- // Verify style float existence
- // (IE uses styleFloat instead of cssFloat)
- cssFloat: !!a.style.cssFloat,
-
- // Make sure that if no value is specified for a checkbox
- // that it defaults to "on".
- // (WebKit defaults to "" instead)
- checkOn: ( input.value === "on" ),
-
- // Make sure that a selected-by-default option has a working selected property.
- // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
- optSelected: opt.selected,
-
- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
- getSetAttribute: div.className !== "t",
-
- // Tests for enctype support on a form(#6743)
- enctype: !!document.createElement("form").enctype,
-
- // Makes sure cloning an html5 element does not cause problems
- // Where outerHTML is undefined, this still works
- html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
-
- // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
- boxModel: ( document.compatMode === "CSS1Compat" ),
-
- // Will be defined later
- submitBubbles: true,
- changeBubbles: true,
- focusinBubbles: false,
- deleteExpando: true,
- noCloneEvent: true,
- inlineBlockNeedsLayout: false,
- shrinkWrapBlocks: false,
- reliableMarginRight: true,
- boxSizingReliable: true,
- pixelPosition: false
- };
-
- // Make sure checked status is properly cloned
- input.checked = true;
- support.noCloneChecked = input.cloneNode( true ).checked;
-
- // Make sure that the options inside disabled selects aren't marked as disabled
- // (WebKit marks them as disabled)
- select.disabled = true;
- support.optDisabled = !opt.disabled;
-
- // Test to see if it's possible to delete an expando from an element
- // Fails in Internet Explorer
- try {
- delete div.test;
- } catch( e ) {
- support.deleteExpando = false;
- }
-
- if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
- div.attachEvent( "onclick", clickFn = function() {
- // Cloning a node shouldn't copy over any
- // bound event handlers (IE does this)
- support.noCloneEvent = false;
- });
- div.cloneNode( true ).fireEvent("onclick");
- div.detachEvent( "onclick", clickFn );
- }
-
- // Check if a radio maintains its value
- // after being appended to the DOM
- input = document.createElement("input");
- input.value = "t";
- input.setAttribute( "type", "radio" );
- support.radioValue = input.value === "t";
-
- input.setAttribute( "checked", "checked" );
-
- // #11217 - WebKit loses check when the name is after the checked attribute
- input.setAttribute( "name", "t" );
-
- div.appendChild( input );
- fragment = document.createDocumentFragment();
- fragment.appendChild( div.lastChild );
-
- // WebKit doesn't clone checked state correctly in fragments
- support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
- // Check if a disconnected checkbox will retain its checked
- // value of true after appended to the DOM (IE6/7)
- support.appendChecked = input.checked;
-
- fragment.removeChild( input );
- fragment.appendChild( div );
-
- // Technique from Juriy Zaytsev
- // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
- // We only care about the case where non-standard event systems
- // are used, namely in IE. Short-circuiting here helps us to
- // avoid an eval call (in setAttribute) which can cause CSP
- // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
- if ( div.attachEvent ) {
- for ( i in {
- submit: true,
- change: true,
- focusin: true
- }) {
- eventName = "on" + i;
- isSupported = ( eventName in div );
- if ( !isSupported ) {
- div.setAttribute( eventName, "return;" );
- isSupported = ( typeof div[ eventName ] === "function" );
- }
- support[ i + "Bubbles" ] = isSupported;
- }
- }
-
- // Run tests that need a body at doc ready
- jQuery(function() {
- var container, div, tds, marginDiv,
- divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;",
- body = document.getElementsByTagName("body")[0];
-
- if ( !body ) {
- // Return for frameset docs that don't have a body
- return;
- }
-
- container = document.createElement("div");
- container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";
- body.insertBefore( container, body.firstChild );
-
- // Construct the test element
- div = document.createElement("div");
- container.appendChild( div );
-
- // Check if table cells still have offsetWidth/Height when they are set
- // to display:none and there are still other visible table cells in a
- // table row; if so, offsetWidth/Height are not reliable for use when
- // determining if an element has been hidden directly using
- // display:none (it is still safe to use offsets if a parent element is
- // hidden; don safety goggles and see bug #4512 for more information).
- // (only IE 8 fails this test)
- div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
- tds = div.getElementsByTagName("td");
- tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
- isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
- tds[ 0 ].style.display = "";
- tds[ 1 ].style.display = "none";
-
- // Check if empty table cells still have offsetWidth/Height
- // (IE <= 8 fail this test)
- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
- // Check box-sizing and margin behavior
- div.innerHTML = "";
- div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
- support.boxSizing = ( div.offsetWidth === 4 );
- support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
-
- // NOTE: To any future maintainer, we've window.getComputedStyle
- // because jsdom on node.js will break without it.
- if ( window.getComputedStyle ) {
- support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
- support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
-
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. For more
- // info see bug #3333
- // Fails in WebKit before Feb 2011 nightlies
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- marginDiv = document.createElement("div");
- marginDiv.style.cssText = div.style.cssText = divReset;
- marginDiv.style.marginRight = marginDiv.style.width = "0";
- div.style.width = "1px";
- div.appendChild( marginDiv );
- support.reliableMarginRight =
- !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
- }
-
- if ( typeof div.style.zoom !== "undefined" ) {
- // Check if natively block-level elements act like inline-block
- // elements when setting their display to 'inline' and giving
- // them layout
- // (IE < 8 does this)
- div.innerHTML = "";
- div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
-
- // Check if elements with layout shrink-wrap their children
- // (IE 6 does this)
- div.style.display = "block";
- div.style.overflow = "visible";
- div.innerHTML = "<div></div>";
- div.firstChild.style.width = "5px";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
-
- container.style.zoom = 1;
- }
-
- // Null elements to avoid leaks in IE
- body.removeChild( container );
- container = div = tds = marginDiv = null;
- });
-
- // Null elements to avoid leaks in IE
- fragment.removeChild( div );
- all = a = select = opt = input = fragment = div = null;
-
- return support;
-})();
-var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
- rmultiDash = /([A-Z])/g;
-
-jQuery.extend({
- cache: {},
-
- deletedIds: [],
-
- // Remove at next major release (1.9/2.0)
- uuid: 0,
-
- // Unique for each copy of jQuery on the page
- // Non-digits removed to match rinlinejQuery
- expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
-
- // The following elements throw uncatchable exceptions if you
- // attempt to add expando properties to them.
- noData: {
- "embed": true,
- // Ban all objects except for Flash (which handle expandos)
- "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
- "applet": true
- },
-
- hasData: function( elem ) {
- elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
- return !!elem && !isEmptyDataObject( elem );
- },
-
- data: function( elem, name, data, pvt /* Internal Use Only */ ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, ret,
- internalKey = jQuery.expando,
- getByName = typeof name === "string",
-
- // We have to handle DOM nodes and JS objects differently because IE6-7
- // can't GC object references properly across the DOM-JS boundary
- isNode = elem.nodeType,
-
- // Only DOM nodes need the global jQuery cache; JS object data is
- // attached directly to the object so GC can occur automatically
- cache = isNode ? jQuery.cache : elem,
-
- // Only defining an ID for JS objects if its cache already exists allows
- // the code to shortcut on the same path as a DOM node with no cache
- id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
-
- // Avoid doing any more work than we need to when trying to get data on an
- // object that has no data at all
- if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
- return;
- }
-
- if ( !id ) {
- // Only DOM nodes need a new unique ID for each element since their data
- // ends up in the global cache
- if ( isNode ) {
- elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
- } else {
- id = internalKey;
- }
- }
-
- if ( !cache[ id ] ) {
- cache[ id ] = {};
-
- // Avoids exposing jQuery metadata on plain JS objects when the object
- // is serialized using JSON.stringify
- if ( !isNode ) {
- cache[ id ].toJSON = jQuery.noop;
- }
- }
-
- // An object can be passed to jQuery.data instead of a key/value pair; this gets
- // shallow copied over onto the existing cache
- if ( typeof name === "object" || typeof name === "function" ) {
- if ( pvt ) {
- cache[ id ] = jQuery.extend( cache[ id ], name );
- } else {
- cache[ id ].data = jQuery.extend( cache[ id ].data, name );
- }
- }
-
- thisCache = cache[ id ];
-
- // jQuery data() is stored in a separate object inside the object's internal data
- // cache in order to avoid key collisions between internal data and user-defined
- // data.
- if ( !pvt ) {
- if ( !thisCache.data ) {
- thisCache.data = {};
- }
-
- thisCache = thisCache.data;
- }
-
- if ( data !== undefined ) {
- thisCache[ jQuery.camelCase( name ) ] = data;
- }
-
- // Check for both converted-to-camel and non-converted data property names
- // If a data property was specified
- if ( getByName ) {
-
- // First Try to find as-is property data
- ret = thisCache[ name ];
-
- // Test for null|undefined property data
- if ( ret == null ) {
-
- // Try to find the camelCased property
- ret = thisCache[ jQuery.camelCase( name ) ];
- }
- } else {
- ret = thisCache;
- }
-
- return ret;
- },
-
- removeData: function( elem, name, pvt /* Internal Use Only */ ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, i, l,
-
- isNode = elem.nodeType,
-
- // See jQuery.data for more information
- cache = isNode ? jQuery.cache : elem,
- id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
-
- // If there is already no cache entry for this object, there is no
- // purpose in continuing
- if ( !cache[ id ] ) {
- return;
- }
-
- if ( name ) {
-
- thisCache = pvt ? cache[ id ] : cache[ id ].data;
-
- if ( thisCache ) {
-
- // Support array or space separated string names for data keys
- if ( !jQuery.isArray( name ) ) {
-
- // try the string as a key before any manipulation
- if ( name in thisCache ) {
- name = [ name ];
- } else {
-
- // split the camel cased version by spaces unless a key with the spaces exists
- name = jQuery.camelCase( name );
- if ( name in thisCache ) {
- name = [ name ];
- } else {
- name = name.split(" ");
- }
- }
- }
-
- for ( i = 0, l = name.length; i < l; i++ ) {
- delete thisCache[ name[i] ];
- }
-
- // If there is no data left in the cache, we want to continue
- // and let the cache object itself get destroyed
- if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
- return;
- }
- }
- }
-
- // See jQuery.data for more information
- if ( !pvt ) {
- delete cache[ id ].data;
-
- // Don't destroy the parent cache unless the internal data object
- // had been the only thing left in it
- if ( !isEmptyDataObject( cache[ id ] ) ) {
- return;
- }
- }
-
- // Destroy the cache
- if ( isNode ) {
- jQuery.cleanData( [ elem ], true );
-
- // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
- } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
- delete cache[ id ];
-
- // When all else fails, null
- } else {
- cache[ id ] = null;
- }
- },
-
- // For internal use only.
- _data: function( elem, name, data ) {
- return jQuery.data( elem, name, data, true );
- },
-
- // A method for determining if a DOM node can handle the data expando
- acceptData: function( elem ) {
- var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
-
- // nodes accept data unless otherwise specified; rejection can be conditional
- return !noData || noData !== true && elem.getAttribute("classid") === noData;
- }
-});
-
-jQuery.fn.extend({
- data: function( key, value ) {
- var parts, part, attr, name, l,
- elem = this[0],
- i = 0,
- data = null;
-
- // Gets all values
- if ( key === undefined ) {
- if ( this.length ) {
- data = jQuery.data( elem );
-
- if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
- attr = elem.attributes;
- for ( l = attr.length; i < l; i++ ) {
- name = attr[i].name;
-
- if ( !name.indexOf( "data-" ) ) {
- name = jQuery.camelCase( name.substring(5) );
-
- dataAttr( elem, name, data[ name ] );
- }
- }
- jQuery._data( elem, "parsedAttrs", true );
- }
- }
-
- return data;
- }
-
- // Sets multiple values
- if ( typeof key === "object" ) {
- return this.each(function() {
- jQuery.data( this, key );
- });
- }
-
- parts = key.split( ".", 2 );
- parts[1] = parts[1] ? "." + parts[1] : "";
- part = parts[1] + "!";
-
- return jQuery.access( this, function( value ) {
-
- if ( value === undefined ) {
- data = this.triggerHandler( "getData" + part, [ parts[0] ] );
-
- // Try to fetch any internally stored data first
- if ( data === undefined && elem ) {
- data = jQuery.data( elem, key );
- data = dataAttr( elem, key, data );
- }
-
- return data === undefined && parts[1] ?
- this.data( parts[0] ) :
- data;
- }
-
- parts[1] = value;
- this.each(function() {
- var self = jQuery( this );
-
- self.triggerHandler( "setData" + part, parts );
- jQuery.data( this, key, value );
- self.triggerHandler( "changeData" + part, parts );
- });
- }, null, value, arguments.length > 1, null, false );
- },
-
- removeData: function( key ) {
- return this.each(function() {
- jQuery.removeData( this, key );
- });
- }
-});
-
-function dataAttr( elem, key, data ) {
- // If nothing was found internally, try to fetch any
- // data from the HTML5 data-* attribute
- if ( data === undefined && elem.nodeType === 1 ) {
-
- var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
-
- data = elem.getAttribute( name );
-
- if ( typeof data === "string" ) {
- try {
- data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null :
- // Only convert to a number if it doesn't change the string
- +data + "" === data ? +data :
- rbrace.test( data ) ? jQuery.parseJSON( data ) :
- data;
- } catch( e ) {}
-
- // Make sure we set the data so it isn't changed later
- jQuery.data( elem, key, data );
-
- } else {
- data = undefined;
- }
- }
-
- return data;
-}
-
-// checks a cache object for emptiness
-function isEmptyDataObject( obj ) {
- var name;
- for ( name in obj ) {
-
- // if the public data object is empty, the private is still empty
- if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
- continue;
- }
- if ( name !== "toJSON" ) {
- return false;
- }
- }
-
- return true;
-}
-jQuery.extend({
- queue: function( elem, type, data ) {
- var queue;
-
- if ( elem ) {
- type = ( type || "fx" ) + "queue";
- queue = jQuery._data( elem, type );
-
- // Speed up dequeue by getting out quickly if this is just a lookup
- if ( data ) {
- if ( !queue || jQuery.isArray(data) ) {
- queue = jQuery._data( elem, type, jQuery.makeArray(data) );
- } else {
- queue.push( data );
- }
- }
- return queue || [];
- }
- },
-
- dequeue: function( elem, type ) {
- type = type || "fx";
-
- var queue = jQuery.queue( elem, type ),
- startLength = queue.length,
- fn = queue.shift(),
- hooks = jQuery._queueHooks( elem, type ),
- next = function() {
- jQuery.dequeue( elem, type );
- };
-
- // If the fx queue is dequeued, always remove the progress sentinel
- if ( fn === "inprogress" ) {
- fn = queue.shift();
- startLength--;
- }
-
- if ( fn ) {
-
- // Add a progress sentinel to prevent the fx queue from being
- // automatically dequeued
- if ( type === "fx" ) {
- queue.unshift( "inprogress" );
- }
-
- // clear up the last queue stop function
- delete hooks.stop;
- fn.call( elem, next, hooks );
- }
-
- if ( !startLength && hooks ) {
- hooks.empty.fire();
- }
- },
-
- // not intended for public consumption - generates a queueHooks object, or returns the current one
- _queueHooks: function( elem, type ) {
- var key = type + "queueHooks";
- return jQuery._data( elem, key ) || jQuery._data( elem, key, {
- empty: jQuery.Callbacks("once memory").add(function() {
- jQuery.removeData( elem, type + "queue", true );
- jQuery.removeData( elem, key, true );
- })
- });
- }
-});
-
-jQuery.fn.extend({
- queue: function( type, data ) {
- var setter = 2;
-
- if ( typeof type !== "string" ) {
- data = type;
- type = "fx";
- setter--;
- }
-
- if ( arguments.length < setter ) {
- return jQuery.queue( this[0], type );
- }
-
- return data === undefined ?
- this :
- this.each(function() {
- var queue = jQuery.queue( this, type, data );
-
- // ensure a hooks for this queue
- jQuery._queueHooks( this, type );
-
- if ( type === "fx" && queue[0] !== "inprogress" ) {
- jQuery.dequeue( this, type );
- }
- });
- },
- dequeue: function( type ) {
- return this.each(function() {
- jQuery.dequeue( this, type );
- });
- },
- // Based off of the plugin by Clint Helfers, with permission.
- // http://blindsignals.com/index.php/2009/07/jquery-delay/
- delay: function( time, type ) {
- time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
- type = type || "fx";
-
- return this.queue( type, function( next, hooks ) {
- var timeout = setTimeout( next, time );
- hooks.stop = function() {
- clearTimeout( timeout );
- };
- });
- },
- clearQueue: function( type ) {
- return this.queue( type || "fx", [] );
- },
- // Get a promise resolved when queues of a certain type
- // are emptied (fx is the type by default)
- promise: function( type, obj ) {
- var tmp,
- count = 1,
- defer = jQuery.Deferred(),
- elements = this,
- i = this.length,
- resolve = function() {
- if ( !( --count ) ) {
- defer.resolveWith( elements, [ elements ] );
- }
- };
-
- if ( typeof type !== "string" ) {
- obj = type;
- type = undefined;
- }
- type = type || "fx";
-
- while( i-- ) {
- tmp = jQuery._data( elements[ i ], type + "queueHooks" );
- if ( tmp && tmp.empty ) {
- count++;
- tmp.empty.add( resolve );
- }
- }
- resolve();
- return defer.promise( obj );
- }
-});
-var nodeHook, boolHook, fixSpecified,
- rclass = /[\t\r\n]/g,
- rreturn = /\r/g,
- rtype = /^(?:button|input)$/i,
- rfocusable = /^(?:button|input|object|select|textarea)$/i,
- rclickable = /^a(?:rea|)$/i,
- rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
- getSetAttribute = jQuery.support.getSetAttribute;
-
-jQuery.fn.extend({
- attr: function( name, value ) {
- return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
- },
-
- removeAttr: function( name ) {
- return this.each(function() {
- jQuery.removeAttr( this, name );
- });
- },
-
- prop: function( name, value ) {
- return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
- },
-
- removeProp: function( name ) {
- name = jQuery.propFix[ name ] || name;
- return this.each(function() {
- // try/catch handles cases where IE balks (such as removing a property on window)
- try {
- this[ name ] = undefined;
- delete this[ name ];
- } catch( e ) {}
- });
- },
-
- addClass: function( value ) {
- var classNames, i, l, elem,
- setClass, c, cl;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).addClass( value.call(this, j, this.className) );
- });
- }
-
- if ( value && typeof value === "string" ) {
- classNames = value.split( core_rspace );
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- elem = this[ i ];
-
- if ( elem.nodeType === 1 ) {
- if ( !elem.className && classNames.length === 1 ) {
- elem.className = value;
-
- } else {
- setClass = " " + elem.className + " ";
-
- for ( c = 0, cl = classNames.length; c < cl; c++ ) {
- if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) {
- setClass += classNames[ c ] + " ";
- }
- }
- elem.className = jQuery.trim( setClass );
- }
- }
- }
- }
-
- return this;
- },
-
- removeClass: function( value ) {
- var removes, className, elem, c, cl, i, l;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).removeClass( value.call(this, j, this.className) );
- });
- }
- if ( (value && typeof value === "string") || value === undefined ) {
- removes = ( value || "" ).split( core_rspace );
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- elem = this[ i ];
- if ( elem.nodeType === 1 && elem.className ) {
-
- className = (" " + elem.className + " ").replace( rclass, " " );
-
- // loop over each item in the removal list
- for ( c = 0, cl = removes.length; c < cl; c++ ) {
- // Remove until there is nothing to remove,
- while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) {
- className = className.replace( " " + removes[ c ] + " " , " " );
- }
- }
- elem.className = value ? jQuery.trim( className ) : "";
- }
- }
- }
-
- return this;
- },
-
- toggleClass: function( value, stateVal ) {
- var type = typeof value,
- isBool = typeof stateVal === "boolean";
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( i ) {
- jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
- });
- }
-
- return this.each(function() {
- if ( type === "string" ) {
- // toggle individual class names
- var className,
- i = 0,
- self = jQuery( this ),
- state = stateVal,
- classNames = value.split( core_rspace );
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space separated list
- state = isBool ? state : !self.hasClass( className );
- self[ state ? "addClass" : "removeClass" ]( className );
- }
-
- } else if ( type === "undefined" || type === "boolean" ) {
- if ( this.className ) {
- // store className if set
- jQuery._data( this, "__className__", this.className );
- }
-
- // toggle whole className
- this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
- }
- });
- },
-
- hasClass: function( selector ) {
- var className = " " + selector + " ",
- i = 0,
- l = this.length;
- for ( ; i < l; i++ ) {
- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
- return true;
- }
- }
-
- return false;
- },
-
- val: function( value ) {
- var hooks, ret, isFunction,
- elem = this[0];
-
- if ( !arguments.length ) {
- if ( elem ) {
- hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
-
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
- return ret;
- }
-
- ret = elem.value;
-
- return typeof ret === "string" ?
- // handle most common string cases
- ret.replace(rreturn, "") :
- // handle cases where value is null/undef or number
- ret == null ? "" : ret;
- }
-
- return;
- }
-
- isFunction = jQuery.isFunction( value );
-
- return this.each(function( i ) {
- var val,
- self = jQuery(this);
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, self.val() );
- } else {
- val = value;
- }
-
- // Treat null/undefined as ""; convert numbers to string
- if ( val == null ) {
- val = "";
- } else if ( typeof val === "number" ) {
- val += "";
- } else if ( jQuery.isArray( val ) ) {
- val = jQuery.map(val, function ( value ) {
- return value == null ? "" : value + "";
- });
- }
-
- hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
-
- // If set returns undefined, fall back to normal setting
- if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
- this.value = val;
- }
- });
- }
-});
-
-jQuery.extend({
- valHooks: {
- option: {
- get: function( elem ) {
- // attributes.value is undefined in Blackberry 4.7 but
- // uses .value. See #6932
- var val = elem.attributes.value;
- return !val || val.specified ? elem.value : elem.text;
- }
- },
- select: {
- get: function( elem ) {
- var value, i, max, option,
- index = elem.selectedIndex,
- values = [],
- options = elem.options,
- one = elem.type === "select-one";
-
- // Nothing was selected
- if ( index < 0 ) {
- return null;
- }
-
- // Loop through all the selected options
- i = one ? index : 0;
- max = one ? index + 1 : options.length;
- for ( ; i < max; i++ ) {
- option = options[ i ];
-
- // Don't return options that are disabled or in a disabled optgroup
- if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
- (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
-
- // Get the specific value for the option
- value = jQuery( option ).val();
-
- // We don't need an array for one selects
- if ( one ) {
- return value;
- }
-
- // Multi-Selects return an array
- values.push( value );
- }
- }
-
- // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
- if ( one && !values.length && options.length ) {
- return jQuery( options[ index ] ).val();
- }
-
- return values;
- },
-
- set: function( elem, value ) {
- var values = jQuery.makeArray( value );
-
- jQuery(elem).find("option").each(function() {
- this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
- });
-
- if ( !values.length ) {
- elem.selectedIndex = -1;
- }
- return values;
- }
- }
- },
-
- // Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9
- attrFn: {},
-
- attr: function( elem, name, value, pass ) {
- var ret, hooks, notxml,
- nType = elem.nodeType;
-
- // don't get/set attributes on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
- return jQuery( elem )[ name ]( value );
- }
-
- // Fallback to prop when attributes are not supported
- if ( typeof elem.getAttribute === "undefined" ) {
- return jQuery.prop( elem, name, value );
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- // All attributes are lowercase
- // Grab necessary hook if one is defined
- if ( notxml ) {
- name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
- }
-
- if ( value !== undefined ) {
-
- if ( value === null ) {
- jQuery.removeAttr( elem, name );
- return;
-
- } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- elem.setAttribute( name, value + "" );
- return value;
- }
-
- } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
-
- ret = elem.getAttribute( name );
-
- // Non-existent attributes return null, we normalize to undefined
- return ret === null ?
- undefined :
- ret;
- }
- },
-
- removeAttr: function( elem, value ) {
- var propName, attrNames, name, isBool,
- i = 0;
-
- if ( value && elem.nodeType === 1 ) {
-
- attrNames = value.split( core_rspace );
-
- for ( ; i < attrNames.length; i++ ) {
- name = attrNames[ i ];
-
- if ( name ) {
- propName = jQuery.propFix[ name ] || name;
- isBool = rboolean.test( name );
-
- // See #9699 for explanation of this approach (setting first, then removal)
- // Do not do this for boolean attributes (see #10870)
- if ( !isBool ) {
- jQuery.attr( elem, name, "" );
- }
- elem.removeAttribute( getSetAttribute ? name : propName );
-
- // Set corresponding property to false for boolean attributes
- if ( isBool && propName in elem ) {
- elem[ propName ] = false;
- }
- }
- }
- }
- },
-
- attrHooks: {
- type: {
- set: function( elem, value ) {
- // We can't allow the type property to be changed (since it causes problems in IE)
- if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
- jQuery.error( "type property can't be changed" );
- } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
- // Setting the type on a radio button after the value resets the value in IE6-9
- // Reset value to it's default in case type is set after value
- // This is for element creation
- var val = elem.value;
- elem.setAttribute( "type", value );
- if ( val ) {
- elem.value = val;
- }
- return value;
- }
- }
- },
- // Use the value property for back compat
- // Use the nodeHook for button elements in IE6/7 (#1954)
- value: {
- get: function( elem, name ) {
- if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
- return nodeHook.get( elem, name );
- }
- return name in elem ?
- elem.value :
- null;
- },
- set: function( elem, value, name ) {
- if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
- return nodeHook.set( elem, value, name );
- }
- // Does not return so that setAttribute is also used
- elem.value = value;
- }
- }
- },
-
- propFix: {
- tabindex: "tabIndex",
- readonly: "readOnly",
- "for": "htmlFor",
- "class": "className",
- maxlength: "maxLength",
- cellspacing: "cellSpacing",
- cellpadding: "cellPadding",
- rowspan: "rowSpan",
- colspan: "colSpan",
- usemap: "useMap",
- frameborder: "frameBorder",
- contenteditable: "contentEditable"
- },
-
- prop: function( elem, name, value ) {
- var ret, hooks, notxml,
- nType = elem.nodeType;
-
- // don't get/set properties on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- if ( notxml ) {
- // Fix name and attach hooks
- name = jQuery.propFix[ name ] || name;
- hooks = jQuery.propHooks[ name ];
- }
-
- if ( value !== undefined ) {
- if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- return ( elem[ name ] = value );
- }
-
- } else {
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- return elem[ name ];
- }
- }
- },
-
- propHooks: {
- tabIndex: {
- get: function( elem ) {
- // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
- // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
- var attributeNode = elem.getAttributeNode("tabindex");
-
- return attributeNode && attributeNode.specified ?
- parseInt( attributeNode.value, 10 ) :
- rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
- 0 :
- undefined;
- }
- }
- }
-});
-
-// Hook for boolean attributes
-boolHook = {
- get: function( elem, name ) {
- // Align boolean attributes with corresponding properties
- // Fall back to attribute presence where some booleans are not supported
- var attrNode,
- property = jQuery.prop( elem, name );
- return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
- name.toLowerCase() :
- undefined;
- },
- set: function( elem, value, name ) {
- var propName;
- if ( value === false ) {
- // Remove boolean attributes when set to false
- jQuery.removeAttr( elem, name );
- } else {
- // value is true since we know at this point it's type boolean and not false
- // Set boolean attributes to the same name and set the DOM property
- propName = jQuery.propFix[ name ] || name;
- if ( propName in elem ) {
- // Only set the IDL specifically if it already exists on the element
- elem[ propName ] = true;
- }
-
- elem.setAttribute( name, name.toLowerCase() );
- }
- return name;
- }
-};
-
-// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !getSetAttribute ) {
-
- fixSpecified = {
- name: true,
- id: true,
- coords: true
- };
-
- // Use this for any attribute in IE6/7
- // This fixes almost every IE6/7 issue
- nodeHook = jQuery.valHooks.button = {
- get: function( elem, name ) {
- var ret;
- ret = elem.getAttributeNode( name );
- return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ?
- ret.value :
- undefined;
- },
- set: function( elem, value, name ) {
- // Set the existing or create a new attribute node
- var ret = elem.getAttributeNode( name );
- if ( !ret ) {
- ret = document.createAttribute( name );
- elem.setAttributeNode( ret );
- }
- return ( ret.value = value + "" );
- }
- };
-
- // Set width and height to auto instead of 0 on empty string( Bug #8150 )
- // This is for removals
- jQuery.each([ "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
- set: function( elem, value ) {
- if ( value === "" ) {
- elem.setAttribute( name, "auto" );
- return value;
- }
- }
- });
- });
-
- // Set contenteditable to false on removals(#10429)
- // Setting to empty string throws an error as an invalid value
- jQuery.attrHooks.contenteditable = {
- get: nodeHook.get,
- set: function( elem, value, name ) {
- if ( value === "" ) {
- value = "false";
- }
- nodeHook.set( elem, value, name );
- }
- };
-}
-
-
-// Some attributes require a special call on IE
-if ( !jQuery.support.hrefNormalized ) {
- jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
- get: function( elem ) {
- var ret = elem.getAttribute( name, 2 );
- return ret === null ? undefined : ret;
- }
- });
- });
-}
-
-if ( !jQuery.support.style ) {
- jQuery.attrHooks.style = {
- get: function( elem ) {
- // Return undefined in the case of empty string
- // Normalize to lowercase since IE uppercases css property names
- return elem.style.cssText.toLowerCase() || undefined;
- },
- set: function( elem, value ) {
- return ( elem.style.cssText = value + "" );
- }
- };
-}
-
-// Safari mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
-if ( !jQuery.support.optSelected ) {
- jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
- get: function( elem ) {
- var parent = elem.parentNode;
-
- if ( parent ) {
- parent.selectedIndex;
-
- // Make sure that it also works with optgroups, see #5701
- if ( parent.parentNode ) {
- parent.parentNode.selectedIndex;
- }
- }
- return null;
- }
- });
-}
-
-// IE6/7 call enctype encoding
-if ( !jQuery.support.enctype ) {
- jQuery.propFix.enctype = "encoding";
-}
-
-// Radios and checkboxes getter/setter
-if ( !jQuery.support.checkOn ) {
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- get: function( elem ) {
- // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- }
- };
- });
-}
-jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- });
-});
-var rformElems = /^(?:textarea|input|select)$/i,
- rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/,
- rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
- rkeyEvent = /^key/,
- rmouseEvent = /^(?:mouse|contextmenu)|click/,
- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- hoverHack = function( events ) {
- return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
- };
-
-/*
- * Helper functions for managing events -- not part of the public interface.
- * Props to Dean Edwards' addEvent library for many of the ideas.
- */
-jQuery.event = {
-
- add: function( elem, types, handler, data, selector ) {
-
- var elemData, eventHandle, events,
- t, tns, type, namespaces, handleObj,
- handleObjIn, handlers, special;
-
- // Don't attach events to noData or text/comment nodes (allow plain objects tho)
- if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
- return;
- }
-
- // Caller can pass in an object of custom data in lieu of the handler
- if ( handler.handler ) {
- handleObjIn = handler;
- handler = handleObjIn.handler;
- selector = handleObjIn.selector;
- }
-
- // Make sure that the handler has a unique ID, used to find/remove it later
- if ( !handler.guid ) {
- handler.guid = jQuery.guid++;
- }
-
- // Init the element's event structure and main handler, if this is the first
- events = elemData.events;
- if ( !events ) {
- elemData.events = events = {};
- }
- eventHandle = elemData.handle;
- if ( !eventHandle ) {
- elemData.handle = eventHandle = function( e ) {
- // Discard the second event of a jQuery.event.trigger() and
- // when an event is called after a page has unloaded
- return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
- jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
- undefined;
- };
- // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
- eventHandle.elem = elem;
- }
-
- // Handle multiple events separated by a space
- // jQuery(...).bind("mouseover mouseout", fn);
- types = jQuery.trim( hoverHack(types) ).split( " " );
- for ( t = 0; t < types.length; t++ ) {
-
- tns = rtypenamespace.exec( types[t] ) || [];
- type = tns[1];
- namespaces = ( tns[2] || "" ).split( "." ).sort();
-
- // If event changes its type, use the special event handlers for the changed type
- special = jQuery.event.special[ type ] || {};
-
- // If selector defined, determine special event api type, otherwise given type
- type = ( selector ? special.delegateType : special.bindType ) || type;
-
- // Update special based on newly reset type
- special = jQuery.event.special[ type ] || {};
-
- // handleObj is passed to all event handlers
- handleObj = jQuery.extend({
- type: type,
- origType: tns[1],
- data: data,
- handler: handler,
- guid: handler.guid,
- selector: selector,
- needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
- namespace: namespaces.join(".")
- }, handleObjIn );
-
- // Init the event handler queue if we're the first
- handlers = events[ type ];
- if ( !handlers ) {
- handlers = events[ type ] = [];
- handlers.delegateCount = 0;
-
- // Only use addEventListener/attachEvent if the special events handler returns false
- if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
- // Bind the global event handler to the element
- if ( elem.addEventListener ) {
- elem.addEventListener( type, eventHandle, false );
-
- } else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, eventHandle );
- }
- }
- }
-
- if ( special.add ) {
- special.add.call( elem, handleObj );
-
- if ( !handleObj.handler.guid ) {
- handleObj.handler.guid = handler.guid;
- }
- }
-
- // Add to the element's handler list, delegates in front
- if ( selector ) {
- handlers.splice( handlers.delegateCount++, 0, handleObj );
- } else {
- handlers.push( handleObj );
- }
-
- // Keep track of which events have ever been used, for event optimization
- jQuery.event.global[ type ] = true;
- }
-
- // Nullify elem to prevent memory leaks in IE
- elem = null;
- },
-
- global: {},
-
- // Detach an event or set of events from an element
- remove: function( elem, types, handler, selector, mappedTypes ) {
-
- var t, tns, type, origType, namespaces, origCount,
- j, events, special, eventType, handleObj,
- elemData = jQuery.hasData( elem ) && jQuery._data( elem );
-
- if ( !elemData || !(events = elemData.events) ) {
- return;
- }
-
- // Once for each type.namespace in types; type may be omitted
- types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
- for ( t = 0; t < types.length; t++ ) {
- tns = rtypenamespace.exec( types[t] ) || [];
- type = origType = tns[1];
- namespaces = tns[2];
-
- // Unbind all events (on this namespace, if provided) for the element
- if ( !type ) {
- for ( type in events ) {
- jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
- }
- continue;
- }
-
- special = jQuery.event.special[ type ] || {};
- type = ( selector? special.delegateType : special.bindType ) || type;
- eventType = events[ type ] || [];
- origCount = eventType.length;
- namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
-
- // Remove matching events
- for ( j = 0; j < eventType.length; j++ ) {
- handleObj = eventType[ j ];
-
- if ( ( mappedTypes || origType === handleObj.origType ) &&
- ( !handler || handler.guid === handleObj.guid ) &&
- ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
- ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
- eventType.splice( j--, 1 );
-
- if ( handleObj.selector ) {
- eventType.delegateCount--;
- }
- if ( special.remove ) {
- special.remove.call( elem, handleObj );
- }
- }
- }
-
- // Remove generic event handler if we removed something and no more handlers exist
- // (avoids potential for endless recursion during removal of special event handlers)
- if ( eventType.length === 0 && origCount !== eventType.length ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
- jQuery.removeEvent( elem, type, elemData.handle );
- }
-
- delete events[ type ];
- }
- }
-
- // Remove the expando if it's no longer used
- if ( jQuery.isEmptyObject( events ) ) {
- delete elemData.handle;
-
- // removeData also checks for emptiness and clears the expando if empty
- // so use it instead of delete
- jQuery.removeData( elem, "events", true );
- }
- },
-
- // Events that are safe to short-circuit if no handlers are attached.
- // Native DOM events should not be added, they may have inline handlers.
- customEvent: {
- "getData": true,
- "setData": true,
- "changeData": true
- },
-
- trigger: function( event, data, elem, onlyHandlers ) {
- // Don't do events on text and comment nodes
- if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
- return;
- }
-
- // Event object or event type
- var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType,
- type = event.type || event,
- namespaces = [];
-
- // focus/blur morphs to focusin/out; ensure we're not firing them right now
- if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
- return;
- }
-
- if ( type.indexOf( "!" ) >= 0 ) {
- // Exclusive events trigger only for the exact event (no namespaces)
- type = type.slice(0, -1);
- exclusive = true;
- }
-
- if ( type.indexOf( "." ) >= 0 ) {
- // Namespaced trigger; create a regexp to match event type in handle()
- namespaces = type.split(".");
- type = namespaces.shift();
- namespaces.sort();
- }
-
- if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
- // No jQuery handlers for this event type, and it can't have inline handlers
- return;
- }
-
- // Caller can pass in an Event, Object, or just an event type string
- event = typeof event === "object" ?
- // jQuery.Event object
- event[ jQuery.expando ] ? event :
- // Object literal
- new jQuery.Event( type, event ) :
- // Just the event type (string)
- new jQuery.Event( type );
-
- event.type = type;
- event.isTrigger = true;
- event.exclusive = exclusive;
- event.namespace = namespaces.join( "." );
- event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
- ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
-
- // Handle a global trigger
- if ( !elem ) {
-
- // TODO: Stop taunting the data cache; remove global events and always attach to document
- cache = jQuery.cache;
- for ( i in cache ) {
- if ( cache[ i ].events && cache[ i ].events[ type ] ) {
- jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
- }
- }
- return;
- }
-
- // Clean up the event in case it is being reused
- event.result = undefined;
- if ( !event.target ) {
- event.target = elem;
- }
-
- // Clone any incoming data and prepend the event, creating the handler arg list
- data = data != null ? jQuery.makeArray( data ) : [];
- data.unshift( event );
-
- // Allow special events to draw outside the lines
- special = jQuery.event.special[ type ] || {};
- if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
- return;
- }
-
- // Determine event propagation path in advance, per W3C events spec (#9951)
- // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
- eventPath = [[ elem, special.bindType || type ]];
- if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
-
- bubbleType = special.delegateType || type;
- cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
- for ( old = elem; cur; cur = cur.parentNode ) {
- eventPath.push([ cur, bubbleType ]);
- old = cur;
- }
-
- // Only add window if we got to document (e.g., not plain obj or detached DOM)
- if ( old === (elem.ownerDocument || document) ) {
- eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
- }
- }
-
- // Fire handlers on the event path
- for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
-
- cur = eventPath[i][0];
- event.type = eventPath[i][1];
-
- handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
- if ( handle ) {
- handle.apply( cur, data );
- }
- // Note that this is a bare JS function and not a jQuery handler
- handle = ontype && cur[ ontype ];
- if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
- event.preventDefault();
- }
- }
- event.type = type;
-
- // If nobody prevented the default action, do it now
- if ( !onlyHandlers && !event.isDefaultPrevented() ) {
-
- if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
- !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
-
- // Call a native DOM method on the target with the same name name as the event.
- // Can't use an .isFunction() check here because IE6/7 fails that test.
- // Don't do default actions on window, that's where global variables be (#6170)
- // IE<9 dies on focus/blur to hidden element (#1486)
- if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
-
- // Don't re-trigger an onFOO event when we call its FOO() method
- old = elem[ ontype ];
-
- if ( old ) {
- elem[ ontype ] = null;
- }
-
- // Prevent re-triggering of the same event, since we already bubbled it above
- jQuery.event.triggered = type;
- elem[ type ]();
- jQuery.event.triggered = undefined;
-
- if ( old ) {
- elem[ ontype ] = old;
- }
- }
- }
- }
-
- return event.result;
- },
-
- dispatch: function( event ) {
-
- // Make a writable jQuery.Event from the native event object
- event = jQuery.event.fix( event || window.event );
-
- var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related,
- handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
- delegateCount = handlers.delegateCount,
- args = core_slice.call( arguments ),
- run_all = !event.exclusive && !event.namespace,
- special = jQuery.event.special[ event.type ] || {},
- handlerQueue = [];
-
- // Use the fix-ed jQuery.Event rather than the (read-only) native event
- args[0] = event;
- event.delegateTarget = this;
-
- // Call the preDispatch hook for the mapped type, and let it bail if desired
- if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
- return;
- }
-
- // Determine handlers that should run if there are delegated events
- // Avoid non-left-click bubbling in Firefox (#3861)
- if ( delegateCount && !(event.button && event.type === "click") ) {
-
- for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
-
- // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
- if ( cur.disabled !== true || event.type !== "click" ) {
- selMatch = {};
- matches = [];
- for ( i = 0; i < delegateCount; i++ ) {
- handleObj = handlers[ i ];
- sel = handleObj.selector;
-
- if ( selMatch[ sel ] === undefined ) {
- selMatch[ sel ] = handleObj.needsContext ?
- jQuery( sel, this ).index( cur ) >= 0 :
- jQuery.find( sel, this, null, [ cur ] ).length;
- }
- if ( selMatch[ sel ] ) {
- matches.push( handleObj );
- }
- }
- if ( matches.length ) {
- handlerQueue.push({ elem: cur, matches: matches });
- }
- }
- }
- }
-
- // Add the remaining (directly-bound) handlers
- if ( handlers.length > delegateCount ) {
- handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
- }
-
- // Run delegates first; they may want to stop propagation beneath us
- for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
- matched = handlerQueue[ i ];
- event.currentTarget = matched.elem;
-
- for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
- handleObj = matched.matches[ j ];
-
- // Triggered event must either 1) be non-exclusive and have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
- if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
-
- event.data = handleObj.data;
- event.handleObj = handleObj;
-
- ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
- .apply( matched.elem, args );
-
- if ( ret !== undefined ) {
- event.result = ret;
- if ( ret === false ) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- }
- }
-
- // Call the postDispatch hook for the mapped type
- if ( special.postDispatch ) {
- special.postDispatch.call( this, event );
- }
-
- return event.result;
- },
-
- // Includes some event props shared by KeyEvent and MouseEvent
- // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
- props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
-
- fixHooks: {},
-
- keyHooks: {
- props: "char charCode key keyCode".split(" "),
- filter: function( event, original ) {
-
- // Add which for key events
- if ( event.which == null ) {
- event.which = original.charCode != null ? original.charCode : original.keyCode;
- }
-
- return event;
- }
- },
-
- mouseHooks: {
- props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
- filter: function( event, original ) {
- var eventDoc, doc, body,
- button = original.button,
- fromElement = original.fromElement;
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && original.clientX != null ) {
- eventDoc = event.target.ownerDocument || document;
- doc = eventDoc.documentElement;
- body = eventDoc.body;
-
- event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
- event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
- }
-
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && fromElement ) {
- event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
- }
-
- // Add which for click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && button !== undefined ) {
- event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
- }
-
- return event;
- }
- },
-
- fix: function( event ) {
- if ( event[ jQuery.expando ] ) {
- return event;
- }
-
- // Create a writable copy of the event object and normalize some properties
- var i, prop,
- originalEvent = event,
- fixHook = jQuery.event.fixHooks[ event.type ] || {},
- copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
-
- event = jQuery.Event( originalEvent );
-
- for ( i = copy.length; i; ) {
- prop = copy[ --i ];
- event[ prop ] = originalEvent[ prop ];
- }
-
- // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
- if ( !event.target ) {
- event.target = originalEvent.srcElement || document;
- }
-
- // Target should not be a text node (#504, Safari)
- if ( event.target.nodeType === 3 ) {
- event.target = event.target.parentNode;
- }
-
- // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8)
- event.metaKey = !!event.metaKey;
-
- return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
- },
-
- special: {
- load: {
- // Prevent triggered image.load events from bubbling to window.load
- noBubble: true
- },
-
- focus: {
- delegateType: "focusin"
- },
- blur: {
- delegateType: "focusout"
- },
-
- beforeunload: {
- setup: function( data, namespaces, eventHandle ) {
- // We only want to do this special case on windows
- if ( jQuery.isWindow( this ) ) {
- this.onbeforeunload = eventHandle;
- }
- },
-
- teardown: function( namespaces, eventHandle ) {
- if ( this.onbeforeunload === eventHandle ) {
- this.onbeforeunload = null;
- }
- }
- }
- },
-
- simulate: function( type, elem, event, bubble ) {
- // Piggyback on a donor event to simulate a different one.
- // Fake originalEvent to avoid donor's stopPropagation, but if the
- // simulated event prevents default then we do the same on the donor.
- var e = jQuery.extend(
- new jQuery.Event(),
- event,
- { type: type,
- isSimulated: true,
- originalEvent: {}
- }
- );
- if ( bubble ) {
- jQuery.event.trigger( e, null, elem );
- } else {
- jQuery.event.dispatch.call( elem, e );
- }
- if ( e.isDefaultPrevented() ) {
- event.preventDefault();
- }
- }
-};
-
-// Some plugins are using, but it's undocumented/deprecated and will be removed.
-// The 1.7 special event interface should provide all the hooks needed now.
-jQuery.event.handle = jQuery.event.dispatch;
-
-jQuery.removeEvent = document.removeEventListener ?
- function( elem, type, handle ) {
- if ( elem.removeEventListener ) {
- elem.removeEventListener( type, handle, false );
- }
- } :
- function( elem, type, handle ) {
- var name = "on" + type;
-
- if ( elem.detachEvent ) {
-
- // #8545, #7054, preventing memory leaks for custom events in IE6-8 –
- // detachEvent needed property on element, by name of that event, to properly expose it to GC
- if ( typeof elem[ name ] === "undefined" ) {
- elem[ name ] = null;
- }
-
- elem.detachEvent( name, handle );
- }
- };
-
-jQuery.Event = function( src, props ) {
- // Allow instantiation without the 'new' keyword
- if ( !(this instanceof jQuery.Event) ) {
- return new jQuery.Event( src, props );
- }
-
- // Event object
- if ( src && src.type ) {
- this.originalEvent = src;
- this.type = src.type;
-
- // Events bubbling up the document may have been marked as prevented
- // by a handler lower down the tree; reflect the correct value.
- this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
- src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
-
- // Event type
- } else {
- this.type = src;
- }
-
- // Put explicitly provided properties onto the event object
- if ( props ) {
- jQuery.extend( this, props );
- }
-
- // Create a timestamp if incoming event doesn't have one
- this.timeStamp = src && src.timeStamp || jQuery.now();
-
- // Mark it as fixed
- this[ jQuery.expando ] = true;
-};
-
-function returnFalse() {
- return false;
-}
-function returnTrue() {
- return true;
-}
-
-// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-jQuery.Event.prototype = {
- preventDefault: function() {
- this.isDefaultPrevented = returnTrue;
-
- var e = this.originalEvent;
- if ( !e ) {
- return;
- }
-
- // if preventDefault exists run it on the original event
- if ( e.preventDefault ) {
- e.preventDefault();
-
- // otherwise set the returnValue property of the original event to false (IE)
- } else {
- e.returnValue = false;
- }
- },
- stopPropagation: function() {
- this.isPropagationStopped = returnTrue;
-
- var e = this.originalEvent;
- if ( !e ) {
- return;
- }
- // if stopPropagation exists run it on the original event
- if ( e.stopPropagation ) {
- e.stopPropagation();
- }
- // otherwise set the cancelBubble property of the original event to true (IE)
- e.cancelBubble = true;
- },
- stopImmediatePropagation: function() {
- this.isImmediatePropagationStopped = returnTrue;
- this.stopPropagation();
- },
- isDefaultPrevented: returnFalse,
- isPropagationStopped: returnFalse,
- isImmediatePropagationStopped: returnFalse
-};
-
-// Create mouseenter/leave events using mouseover/out and event-time checks
-jQuery.each({
- mouseenter: "mouseover",
- mouseleave: "mouseout"
-}, function( orig, fix ) {
- jQuery.event.special[ orig ] = {
- delegateType: fix,
- bindType: fix,
-
- handle: function( event ) {
- var ret,
- target = this,
- related = event.relatedTarget,
- handleObj = event.handleObj,
- selector = handleObj.selector;
-
- // For mousenter/leave call the handler if related is outside the target.
- // NB: No relatedTarget if the mouse left/entered the browser window
- if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
- event.type = handleObj.origType;
- ret = handleObj.handler.apply( this, arguments );
- event.type = fix;
- }
- return ret;
- }
- };
-});
-
-// IE submit delegation
-if ( !jQuery.support.submitBubbles ) {
-
- jQuery.event.special.submit = {
- setup: function() {
- // Only need this for delegated form submit events
- if ( jQuery.nodeName( this, "form" ) ) {
- return false;
- }
-
- // Lazy-add a submit handler when a descendant form may potentially be submitted
- jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
- // Node name check avoids a VML-related crash in IE (#9807)
- var elem = e.target,
- form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
- if ( form && !jQuery._data( form, "_submit_attached" ) ) {
- jQuery.event.add( form, "submit._submit", function( event ) {
- event._submit_bubble = true;
- });
- jQuery._data( form, "_submit_attached", true );
- }
- });
- // return undefined since we don't need an event listener
- },
-
- postDispatch: function( event ) {
- // If form was submitted by the user, bubble the event up the tree
- if ( event._submit_bubble ) {
- delete event._submit_bubble;
- if ( this.parentNode && !event.isTrigger ) {
- jQuery.event.simulate( "submit", this.parentNode, event, true );
- }
- }
- },
-
- teardown: function() {
- // Only need this for delegated form submit events
- if ( jQuery.nodeName( this, "form" ) ) {
- return false;
- }
-
- // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
- jQuery.event.remove( this, "._submit" );
- }
- };
-}
-
-// IE change delegation and checkbox/radio fix
-if ( !jQuery.support.changeBubbles ) {
-
- jQuery.event.special.change = {
-
- setup: function() {
-
- if ( rformElems.test( this.nodeName ) ) {
- // IE doesn't fire change on a check/radio until blur; trigger it on click
- // after a propertychange. Eat the blur-change in special.change.handle.
- // This still fires onchange a second time for check/radio after blur.
- if ( this.type === "checkbox" || this.type === "radio" ) {
- jQuery.event.add( this, "propertychange._change", function( event ) {
- if ( event.originalEvent.propertyName === "checked" ) {
- this._just_changed = true;
- }
- });
- jQuery.event.add( this, "click._change", function( event ) {
- if ( this._just_changed && !event.isTrigger ) {
- this._just_changed = false;
- }
- // Allow triggered, simulated change events (#11500)
- jQuery.event.simulate( "change", this, event, true );
- });
- }
- return false;
- }
- // Delegated event; lazy-add a change handler on descendant inputs
- jQuery.event.add( this, "beforeactivate._change", function( e ) {
- var elem = e.target;
-
- if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) {
- jQuery.event.add( elem, "change._change", function( event ) {
- if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
- jQuery.event.simulate( "change", this.parentNode, event, true );
- }
- });
- jQuery._data( elem, "_change_attached", true );
- }
- });
- },
-
- handle: function( event ) {
- var elem = event.target;
-
- // Swallow native change events from checkbox/radio, we already triggered them above
- if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
- return event.handleObj.handler.apply( this, arguments );
- }
- },
-
- teardown: function() {
- jQuery.event.remove( this, "._change" );
-
- return !rformElems.test( this.nodeName );
- }
- };
-}
-
-// Create "bubbling" focus and blur events
-if ( !jQuery.support.focusinBubbles ) {
- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0,
- handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
- if ( attaches++ === 0 ) {
- document.addEventListener( orig, handler, true );
- }
- },
- teardown: function() {
- if ( --attaches === 0 ) {
- document.removeEventListener( orig, handler, true );
- }
- }
- };
- });
-}
-
-jQuery.fn.extend({
-
- on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
- var origFn, type;
-
- // Types can be a map of types/handlers
- if ( typeof types === "object" ) {
- // ( types-Object, selector, data )
- if ( typeof selector !== "string" ) { // && selector != null
- // ( types-Object, data )
- data = data || selector;
- selector = undefined;
- }
- for ( type in types ) {
- this.on( type, selector, data, types[ type ], one );
- }
- return this;
- }
-
- if ( data == null && fn == null ) {
- // ( types, fn )
- fn = selector;
- data = selector = undefined;
- } else if ( fn == null ) {
- if ( typeof selector === "string" ) {
- // ( types, selector, fn )
- fn = data;
- data = undefined;
- } else {
- // ( types, data, fn )
- fn = data;
- data = selector;
- selector = undefined;
- }
- }
- if ( fn === false ) {
- fn = returnFalse;
- } else if ( !fn ) {
- return this;
- }
-
- if ( one === 1 ) {
- origFn = fn;
- fn = function( event ) {
- // Can use an empty set, since event contains the info
- jQuery().off( event );
- return origFn.apply( this, arguments );
- };
- // Use same guid so caller can remove using origFn
- fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
- }
- return this.each( function() {
- jQuery.event.add( this, types, fn, data, selector );
- });
- },
- one: function( types, selector, data, fn ) {
- return this.on( types, selector, data, fn, 1 );
- },
- off: function( types, selector, fn ) {
- var handleObj, type;
- if ( types && types.preventDefault && types.handleObj ) {
- // ( event ) dispatched jQuery.Event
- handleObj = types.handleObj;
- jQuery( types.delegateTarget ).off(
- handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
- handleObj.selector,
- handleObj.handler
- );
- return this;
- }
- if ( typeof types === "object" ) {
- // ( types-object [, selector] )
- for ( type in types ) {
- this.off( type, selector, types[ type ] );
- }
- return this;
- }
- if ( selector === false || typeof selector === "function" ) {
- // ( types [, fn] )
- fn = selector;
- selector = undefined;
- }
- if ( fn === false ) {
- fn = returnFalse;
- }
- return this.each(function() {
- jQuery.event.remove( this, types, fn, selector );
- });
- },
-
- bind: function( types, data, fn ) {
- return this.on( types, null, data, fn );
- },
- unbind: function( types, fn ) {
- return this.off( types, null, fn );
- },
-
- live: function( types, data, fn ) {
- jQuery( this.context ).on( types, this.selector, data, fn );
- return this;
- },
- die: function( types, fn ) {
- jQuery( this.context ).off( types, this.selector || "**", fn );
- return this;
- },
-
- delegate: function( selector, types, data, fn ) {
- return this.on( types, selector, data, fn );
- },
- undelegate: function( selector, types, fn ) {
- // ( namespace ) or ( selector, types [, fn] )
- return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
- },
-
- trigger: function( type, data ) {
- return this.each(function() {
- jQuery.event.trigger( type, data, this );
- });
- },
- triggerHandler: function( type, data ) {
- if ( this[0] ) {
- return jQuery.event.trigger( type, data, this[0], true );
- }
- },
-
- toggle: function( fn ) {
- // Save reference to arguments for access in closure
- var args = arguments,
- guid = fn.guid || jQuery.guid++,
- i = 0,
- toggler = function( event ) {
- // Figure out which function to execute
- var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
- jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
-
- // Make sure that clicks stop
- event.preventDefault();
-
- // and execute the function
- return args[ lastToggle ].apply( this, arguments ) || false;
- };
-
- // link all the functions, so any of them can unbind this click handler
- toggler.guid = guid;
- while ( i < args.length ) {
- args[ i++ ].guid = guid;
- }
-
- return this.click( toggler );
- },
-
- hover: function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- }
-});
-
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
- "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
-
- // Handle event binding
- jQuery.fn[ name ] = function( data, fn ) {
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.on( name, null, data, fn ) :
- this.trigger( name );
- };
-
- if ( rkeyEvent.test( name ) ) {
- jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
- }
-
- if ( rmouseEvent.test( name ) ) {
- jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
- }
-});
-/*!
- * Sizzle CSS Selector Engine
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license
- * http://sizzlejs.com/
- */
-(function( window, undefined ) {
-
-var cachedruns,
- assertGetIdNotName,
- Expr,
- getText,
- isXML,
- contains,
- compile,
- sortOrder,
- hasDuplicate,
- outermostContext,
-
- baseHasDuplicate = true,
- strundefined = "undefined",
-
- expando = ( "sizcache" + Math.random() ).replace( ".", "" ),
-
- Token = String,
- document = window.document,
- docElem = document.documentElement,
- dirruns = 0,
- done = 0,
- pop = [].pop,
- push = [].push,
- slice = [].slice,
- // Use a stripped-down indexOf if a native one is unavailable
- indexOf = [].indexOf || function( elem ) {
- var i = 0,
- len = this.length;
- for ( ; i < len; i++ ) {
- if ( this[i] === elem ) {
- return i;
- }
- }
- return -1;
- },
-
- // Augment a function for special use by Sizzle
- markFunction = function( fn, value ) {
- fn[ expando ] = value == null || value;
- return fn;
- },
-
- createCache = function() {
- var cache = {},
- keys = [];
-
- return markFunction(function( key, value ) {
- // Only keep the most recent entries
- if ( keys.push( key ) > Expr.cacheLength ) {
- delete cache[ keys.shift() ];
- }
-
- return (cache[ key ] = value);
- }, cache );
- },
-
- classCache = createCache(),
- tokenCache = createCache(),
- compilerCache = createCache(),
-
- // Regex
-
- // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
- whitespace = "[\\x20\\t\\r\\n\\f]",
- // http://www.w3.org/TR/css3-syntax/#characters
- characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",
-
- // Loosely modeled on CSS identifier characters
- // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
- // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
- identifier = characterEncoding.replace( "w", "w#" ),
-
- // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
- operators = "([*^$|!~]?=)",
- attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
- "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
-
- // Prefer arguments not in parens/brackets,
- // then attribute selectors and non-pseudos (denoted by :),
- // then anything else
- // These preferences are here to reduce the number of selectors
- // needing tokenize in the PSEUDO preFilter
- pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)",
-
- // For matchExpr.POS and matchExpr.needsContext
- pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
- "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)",
-
- // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
- rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
-
- rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
- rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
- rpseudo = new RegExp( pseudos ),
-
- // Easily-parseable/retrievable ID or TAG or CLASS selectors
- rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
-
- rnot = /^:not/,
- rsibling = /[\x20\t\r\n\f]*[+~]/,
- rendsWithNot = /:not\($/,
-
- rheader = /h\d/i,
- rinputs = /input|select|textarea|button/i,
-
- rbackslash = /\\(?!\\)/g,
-
- matchExpr = {
- "ID": new RegExp( "^#(" + characterEncoding + ")" ),
- "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
- "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
- "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
- "ATTR": new RegExp( "^" + attributes ),
- "PSEUDO": new RegExp( "^" + pseudos ),
- "POS": new RegExp( pos, "i" ),
- "CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace +
- "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
- "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
- // For use in libraries implementing .is()
- "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" )
- },
-
- // Support
-
- // Used for testing something on an element
- assert = function( fn ) {
- var div = document.createElement("div");
-
- try {
- return fn( div );
- } catch (e) {
- return false;
- } finally {
- // release memory in IE
- div = null;
- }
- },
-
- // Check if getElementsByTagName("*") returns only elements
- assertTagNameNoComments = assert(function( div ) {
- div.appendChild( document.createComment("") );
- return !div.getElementsByTagName("*").length;
- }),
-
- // Check if getAttribute returns normalized href attributes
- assertHrefNotNormalized = assert(function( div ) {
- div.innerHTML = "<a href='#'></a>";
- return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
- div.firstChild.getAttribute("href") === "#";
- }),
-
- // Check if attributes should be retrieved by attribute nodes
- assertAttributes = assert(function( div ) {
- div.innerHTML = "<select></select>";
- var type = typeof div.lastChild.getAttribute("multiple");
- // IE8 returns a string for some attributes even when not present
- return type !== "boolean" && type !== "string";
- }),
-
- // Check if getElementsByClassName can be trusted
- assertUsableClassName = assert(function( div ) {
- // Opera can't find a second classname (in 9.6)
- div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
- if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
- return false;
- }
-
- // Safari 3.2 caches class attributes and doesn't catch changes
- div.lastChild.className = "e";
- return div.getElementsByClassName("e").length === 2;
- }),
-
- // Check if getElementById returns elements by name
- // Check if getElementsByName privileges form controls or returns elements by ID
- assertUsableName = assert(function( div ) {
- // Inject content
- div.id = expando + 0;
- div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
- docElem.insertBefore( div, docElem.firstChild );
-
- // Test
- var pass = document.getElementsByName &&
- // buggy browsers will return fewer than the correct 2
- document.getElementsByName( expando ).length === 2 +
- // buggy browsers will return more than the correct 0
- document.getElementsByName( expando + 0 ).length;
- assertGetIdNotName = !document.getElementById( expando );
-
- // Cleanup
- docElem.removeChild( div );
-
- return pass;
- });
-
-// If slice is not available, provide a backup
-try {
- slice.call( docElem.childNodes, 0 )[0].nodeType;
-} catch ( e ) {
- slice = function( i ) {
- var elem,
- results = [];
- for ( ; (elem = this[i]); i++ ) {
- results.push( elem );
- }
- return results;
- };
-}
-
-function Sizzle( selector, context, results, seed ) {
- results = results || [];
- context = context || document;
- var match, elem, xml, m,
- nodeType = context.nodeType;
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- if ( nodeType !== 1 && nodeType !== 9 ) {
- return [];
- }
-
- xml = isXML( context );
-
- if ( !xml && !seed ) {
- if ( (match = rquickExpr.exec( selector )) ) {
- // Speed-up: Sizzle("#ID")
- if ( (m = match[1]) ) {
- if ( nodeType === 9 ) {
- elem = context.getElementById( m );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE, Opera, and Webkit return items
- // by name instead of ID
- if ( elem.id === m ) {
- results.push( elem );
- return results;
- }
- } else {
- return results;
- }
- } else {
- // Context is not a document
- if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
- contains( context, elem ) && elem.id === m ) {
- results.push( elem );
- return results;
- }
- }
-
- // Speed-up: Sizzle("TAG")
- } else if ( match[2] ) {
- push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
- return results;
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) {
- push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
- return results;
- }
- }
- }
-
- // All others
- return select( selector.replace( rtrim, "$1" ), context, results, seed, xml );
-}
-
-Sizzle.matches = function( expr, elements ) {
- return Sizzle( expr, null, null, elements );
-};
-
-Sizzle.matchesSelector = function( elem, expr ) {
- return Sizzle( expr, null, null, [ elem ] ).length > 0;
-};
-
-// Returns a function to use in pseudos for input types
-function createInputPseudo( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === type;
- };
-}
-
-// Returns a function to use in pseudos for buttons
-function createButtonPseudo( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && elem.type === type;
- };
-}
-
-// Returns a function to use in pseudos for positionals
-function createPositionalPseudo( fn ) {
- return markFunction(function( argument ) {
- argument = +argument;
- return markFunction(function( seed, matches ) {
- var j,
- matchIndexes = fn( [], seed.length, argument ),
- i = matchIndexes.length;
-
- // Match elements found at the specified indexes
- while ( i-- ) {
- if ( seed[ (j = matchIndexes[i]) ] ) {
- seed[j] = !(matches[j] = seed[j]);
- }
- }
- });
- });
-}
-
-/**
- * Utility function for retrieving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-getText = Sizzle.getText = function( elem ) {
- var node,
- ret = "",
- i = 0,
- nodeType = elem.nodeType;
-
- if ( nodeType ) {
- if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
- // Use textContent for elements
- // innerText usage removed for consistency of new lines (see #11153)
- if ( typeof elem.textContent === "string" ) {
- return elem.textContent;
- } else {
- // Traverse its children
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- ret += getText( elem );
- }
- }
- } else if ( nodeType === 3 || nodeType === 4 ) {
- return elem.nodeValue;
- }
- // Do not include comment or processing instruction nodes
- } else {
-
- // If no nodeType, this is expected to be an array
- for ( ; (node = elem[i]); i++ ) {
- // Do not traverse comment nodes
- ret += getText( node );
- }
- }
- return ret;
-};
-
-isXML = Sizzle.isXML = function( elem ) {
- // documentElement is verified for cases where it doesn't yet exist
- // (such as loading iframes in IE - #4833)
- var documentElement = elem && (elem.ownerDocument || elem).documentElement;
- return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-// Element contains another
-contains = Sizzle.contains = docElem.contains ?
- function( a, b ) {
- var adown = a.nodeType === 9 ? a.documentElement : a,
- bup = b && b.parentNode;
- return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) );
- } :
- docElem.compareDocumentPosition ?
- function( a, b ) {
- return b && !!( a.compareDocumentPosition( b ) & 16 );
- } :
- function( a, b ) {
- while ( (b = b.parentNode) ) {
- if ( b === a ) {
- return true;
- }
- }
- return false;
- };
-
-Sizzle.attr = function( elem, name ) {
- var val,
- xml = isXML( elem );
-
- if ( !xml ) {
- name = name.toLowerCase();
- }
- if ( (val = Expr.attrHandle[ name ]) ) {
- return val( elem );
- }
- if ( xml || assertAttributes ) {
- return elem.getAttribute( name );
- }
- val = elem.getAttributeNode( name );
- return val ?
- typeof elem[ name ] === "boolean" ?
- elem[ name ] ? name : null :
- val.specified ? val.value : null :
- null;
-};
-
-Expr = Sizzle.selectors = {
-
- // Can be adjusted by the user
- cacheLength: 50,
-
- createPseudo: markFunction,
-
- match: matchExpr,
-
- // IE6/7 return a modified href
- attrHandle: assertHrefNotNormalized ?
- {} :
- {
- "href": function( elem ) {
- return elem.getAttribute( "href", 2 );
- },
- "type": function( elem ) {
- return elem.getAttribute("type");
- }
- },
-
- find: {
- "ID": assertGetIdNotName ?
- function( id, context, xml ) {
- if ( typeof context.getElementById !== strundefined && !xml ) {
- var m = context.getElementById( id );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- return m && m.parentNode ? [m] : [];
- }
- } :
- function( id, context, xml ) {
- if ( typeof context.getElementById !== strundefined && !xml ) {
- var m = context.getElementById( id );
-
- return m ?
- m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
- [m] :
- undefined :
- [];
- }
- },
-
- "TAG": assertTagNameNoComments ?
- function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
- return context.getElementsByTagName( tag );
- }
- } :
- function( tag, context ) {
- var results = context.getElementsByTagName( tag );
-
- // Filter out possible comments
- if ( tag === "*" ) {
- var elem,
- tmp = [],
- i = 0;
-
- for ( ; (elem = results[i]); i++ ) {
- if ( elem.nodeType === 1 ) {
- tmp.push( elem );
- }
- }
-
- return tmp;
- }
- return results;
- },
-
- "NAME": assertUsableName && function( tag, context ) {
- if ( typeof context.getElementsByName !== strundefined ) {
- return context.getElementsByName( name );
- }
- },
-
- "CLASS": assertUsableClassName && function( className, context, xml ) {
- if ( typeof context.getElementsByClassName !== strundefined && !xml ) {
- return context.getElementsByClassName( className );
- }
- }
- },
-
- relative: {
- ">": { dir: "parentNode", first: true },
- " ": { dir: "parentNode" },
- "+": { dir: "previousSibling", first: true },
- "~": { dir: "previousSibling" }
- },
-
- preFilter: {
- "ATTR": function( match ) {
- match[1] = match[1].replace( rbackslash, "" );
-
- // Move the given value to match[3] whether quoted or unquoted
- match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" );
-
- if ( match[2] === "~=" ) {
- match[3] = " " + match[3] + " ";
- }
-
- return match.slice( 0, 4 );
- },
-
- "CHILD": function( match ) {
- /* matches from matchExpr["CHILD"]
- 1 type (only|nth|...)
- 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
- 3 xn-component of xn+y argument ([+-]?\d*n|)
- 4 sign of xn-component
- 5 x of xn-component
- 6 sign of y-component
- 7 y of y-component
- */
- match[1] = match[1].toLowerCase();
-
- if ( match[1] === "nth" ) {
- // nth-child requires argument
- if ( !match[2] ) {
- Sizzle.error( match[0] );
- }
-
- // numeric x and y parameters for Expr.filter.CHILD
- // remember that false/true cast respectively to 0/1
- match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) );
- match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" );
-
- // other types prohibit arguments
- } else if ( match[2] ) {
- Sizzle.error( match[0] );
- }
-
- return match;
- },
-
- "PSEUDO": function( match ) {
- var unquoted, excess;
- if ( matchExpr["CHILD"].test( match[0] ) ) {
- return null;
- }
-
- if ( match[3] ) {
- match[2] = match[3];
- } else if ( (unquoted = match[4]) ) {
- // Only check arguments that contain a pseudo
- if ( rpseudo.test(unquoted) &&
- // Get excess from tokenize (recursively)
- (excess = tokenize( unquoted, true )) &&
- // advance to the next closing parenthesis
- (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
-
- // excess is a negative index
- unquoted = unquoted.slice( 0, excess );
- match[0] = match[0].slice( 0, excess );
- }
- match[2] = unquoted;
- }
-
- // Return only captures needed by the pseudo filter method (type and argument)
- return match.slice( 0, 3 );
- }
- },
-
- filter: {
- "ID": assertGetIdNotName ?
- function( id ) {
- id = id.replace( rbackslash, "" );
- return function( elem ) {
- return elem.getAttribute("id") === id;
- };
- } :
- function( id ) {
- id = id.replace( rbackslash, "" );
- return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
- return node && node.value === id;
- };
- },
-
- "TAG": function( nodeName ) {
- if ( nodeName === "*" ) {
- return function() { return true; };
- }
- nodeName = nodeName.replace( rbackslash, "" ).toLowerCase();
-
- return function( elem ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
- };
- },
-
- "CLASS": function( className ) {
- var pattern = classCache[ expando ][ className ];
- if ( !pattern ) {
- pattern = classCache( className, new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)") );
- }
- return function( elem ) {
- return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
- };
- },
-
- "ATTR": function( name, operator, check ) {
- return function( elem, context ) {
- var result = Sizzle.attr( elem, name );
-
- if ( result == null ) {
- return operator === "!=";
- }
- if ( !operator ) {
- return true;
- }
-
- result += "";
-
- return operator === "=" ? result === check :
- operator === "!=" ? result !== check :
- operator === "^=" ? check && result.indexOf( check ) === 0 :
- operator === "*=" ? check && result.indexOf( check ) > -1 :
- operator === "$=" ? check && result.substr( result.length - check.length ) === check :
- operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
- operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" :
- false;
- };
- },
-
- "CHILD": function( type, argument, first, last ) {
-
- if ( type === "nth" ) {
- return function( elem ) {
- var node, diff,
- parent = elem.parentNode;
-
- if ( first === 1 && last === 0 ) {
- return true;
- }
-
- if ( parent ) {
- diff = 0;
- for ( node = parent.firstChild; node; node = node.nextSibling ) {
- if ( node.nodeType === 1 ) {
- diff++;
- if ( elem === node ) {
- break;
- }
- }
- }
- }
-
- // Incorporate the offset (or cast to NaN), then check against cycle size
- diff -= last;
- return diff === first || ( diff % first === 0 && diff / first >= 0 );
- };
- }
-
- return function( elem ) {
- var node = elem;
-
- switch ( type ) {
- case "only":
- case "first":
- while ( (node = node.previousSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
- }
- }
-
- if ( type === "first" ) {
- return true;
- }
-
- node = elem;
-
- /* falls through */
- case "last":
- while ( (node = node.nextSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
- }
- }
-
- return true;
- }
- };
- },
-
- "PSEUDO": function( pseudo, argument ) {
- // pseudo-class names are case-insensitive
- // http://www.w3.org/TR/selectors/#pseudo-classes
- // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
- // Remember that setFilters inherits from pseudos
- var args,
- fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
- Sizzle.error( "unsupported pseudo: " + pseudo );
-
- // The user may use createPseudo to indicate that
- // arguments are needed to create the filter function
- // just as Sizzle does
- if ( fn[ expando ] ) {
- return fn( argument );
- }
-
- // But maintain support for old signatures
- if ( fn.length > 1 ) {
- args = [ pseudo, pseudo, "", argument ];
- return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
- markFunction(function( seed, matches ) {
- var idx,
- matched = fn( seed, argument ),
- i = matched.length;
- while ( i-- ) {
- idx = indexOf.call( seed, matched[i] );
- seed[ idx ] = !( matches[ idx ] = matched[i] );
- }
- }) :
- function( elem ) {
- return fn( elem, 0, args );
- };
- }
-
- return fn;
- }
- },
-
- pseudos: {
- "not": markFunction(function( selector ) {
- // Trim the selector passed to compile
- // to avoid treating leading and trailing
- // spaces as combinators
- var input = [],
- results = [],
- matcher = compile( selector.replace( rtrim, "$1" ) );
-
- return matcher[ expando ] ?
- markFunction(function( seed, matches, context, xml ) {
- var elem,
- unmatched = matcher( seed, null, xml, [] ),
- i = seed.length;
-
- // Match elements unmatched by `matcher`
- while ( i-- ) {
- if ( (elem = unmatched[i]) ) {
- seed[i] = !(matches[i] = elem);
- }
- }
- }) :
- function( elem, context, xml ) {
- input[0] = elem;
- matcher( input, null, xml, results );
- return !results.pop();
- };
- }),
-
- "has": markFunction(function( selector ) {
- return function( elem ) {
- return Sizzle( selector, elem ).length > 0;
- };
- }),
-
- "contains": markFunction(function( text ) {
- return function( elem ) {
- return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
- };
- }),
-
- "enabled": function( elem ) {
- return elem.disabled === false;
- },
-
- "disabled": function( elem ) {
- return elem.disabled === true;
- },
-
- "checked": function( elem ) {
- // In CSS3, :checked should return both checked and selected elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- var nodeName = elem.nodeName.toLowerCase();
- return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
- },
-
- "selected": function( elem ) {
- // Accessing this property makes selected-by-default
- // options in Safari work properly
- if ( elem.parentNode ) {
- elem.parentNode.selectedIndex;
- }
-
- return elem.selected === true;
- },
-
- "parent": function( elem ) {
- return !Expr.pseudos["empty"]( elem );
- },
-
- "empty": function( elem ) {
- // http://www.w3.org/TR/selectors/#empty-pseudo
- // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
- // not comment, processing instructions, or others
- // Thanks to Diego Perini for the nodeName shortcut
- // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
- var nodeType;
- elem = elem.firstChild;
- while ( elem ) {
- if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) {
- return false;
- }
- elem = elem.nextSibling;
- }
- return true;
- },
-
- "header": function( elem ) {
- return rheader.test( elem.nodeName );
- },
-
- "text": function( elem ) {
- var type, attr;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
- // use getAttribute instead to test this case
- return elem.nodeName.toLowerCase() === "input" &&
- (type = elem.type) === "text" &&
- ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type );
- },
-
- // Input types
- "radio": createInputPseudo("radio"),
- "checkbox": createInputPseudo("checkbox"),
- "file": createInputPseudo("file"),
- "password": createInputPseudo("password"),
- "image": createInputPseudo("image"),
-
- "submit": createButtonPseudo("submit"),
- "reset": createButtonPseudo("reset"),
-
- "button": function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === "button" || name === "button";
- },
-
- "input": function( elem ) {
- return rinputs.test( elem.nodeName );
- },
-
- "focus": function( elem ) {
- var doc = elem.ownerDocument;
- return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href);
- },
-
- "active": function( elem ) {
- return elem === elem.ownerDocument.activeElement;
- },
-
- // Positional types
- "first": createPositionalPseudo(function( matchIndexes, length, argument ) {
- return [ 0 ];
- }),
-
- "last": createPositionalPseudo(function( matchIndexes, length, argument ) {
- return [ length - 1 ];
- }),
-
- "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
- return [ argument < 0 ? argument + length : argument ];
- }),
-
- "even": createPositionalPseudo(function( matchIndexes, length, argument ) {
- for ( var i = 0; i < length; i += 2 ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "odd": createPositionalPseudo(function( matchIndexes, length, argument ) {
- for ( var i = 1; i < length; i += 2 ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
- for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
- for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- })
- }
-};
-
-function siblingCheck( a, b, ret ) {
- if ( a === b ) {
- return ret;
- }
-
- var cur = a.nextSibling;
-
- while ( cur ) {
- if ( cur === b ) {
- return -1;
- }
-
- cur = cur.nextSibling;
- }
-
- return 1;
-}
-
-sortOrder = docElem.compareDocumentPosition ?
- function( a, b ) {
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
- a.compareDocumentPosition :
- a.compareDocumentPosition(b) & 4
- ) ? -1 : 1;
- } :
- function( a, b ) {
- // The nodes are identical, we can exit early
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
-
- // Fallback to using sourceIndex (in IE) if it's available on both nodes
- } else if ( a.sourceIndex && b.sourceIndex ) {
- return a.sourceIndex - b.sourceIndex;
- }
-
- var al, bl,
- ap = [],
- bp = [],
- aup = a.parentNode,
- bup = b.parentNode,
- cur = aup;
-
- // If the nodes are siblings (or identical) we can do a quick check
- if ( aup === bup ) {
- return siblingCheck( a, b );
-
- // If no parents were found then the nodes are disconnected
- } else if ( !aup ) {
- return -1;
-
- } else if ( !bup ) {
- return 1;
- }
-
- // Otherwise they're somewhere else in the tree so we need
- // to build up a full list of the parentNodes for comparison
- while ( cur ) {
- ap.unshift( cur );
- cur = cur.parentNode;
- }
-
- cur = bup;
-
- while ( cur ) {
- bp.unshift( cur );
- cur = cur.parentNode;
- }
-
- al = ap.length;
- bl = bp.length;
-
- // Start walking down the tree looking for a discrepancy
- for ( var i = 0; i < al && i < bl; i++ ) {
- if ( ap[i] !== bp[i] ) {
- return siblingCheck( ap[i], bp[i] );
- }
- }
-
- // We ended someplace up the tree so do a sibling check
- return i === al ?
- siblingCheck( a, bp[i], -1 ) :
- siblingCheck( ap[i], b, 1 );
- };
-
-// Always assume the presence of duplicates if sort doesn't
-// pass them to our comparison function (as in Google Chrome).
-[0, 0].sort( sortOrder );
-baseHasDuplicate = !hasDuplicate;
-
-// Document sorting and removing duplicates
-Sizzle.uniqueSort = function( results ) {
- var elem,
- i = 1;
-
- hasDuplicate = baseHasDuplicate;
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- for ( ; (elem = results[i]); i++ ) {
- if ( elem === results[ i - 1 ] ) {
- results.splice( i--, 1 );
- }
- }
- }
-
- return results;
-};
-
-Sizzle.error = function( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
-};
-
-function tokenize( selector, parseOnly ) {
- var matched, match, tokens, type, soFar, groups, preFilters,
- cached = tokenCache[ expando ][ selector ];
-
- if ( cached ) {
- return parseOnly ? 0 : cached.slice( 0 );
- }
-
- soFar = selector;
- groups = [];
- preFilters = Expr.preFilter;
-
- while ( soFar ) {
-
- // Comma and first run
- if ( !matched || (match = rcomma.exec( soFar )) ) {
- if ( match ) {
- soFar = soFar.slice( match[0].length );
- }
- groups.push( tokens = [] );
- }
-
- matched = false;
-
- // Combinators
- if ( (match = rcombinators.exec( soFar )) ) {
- tokens.push( matched = new Token( match.shift() ) );
- soFar = soFar.slice( matched.length );
-
- // Cast descendant combinators to space
- matched.type = match[0].replace( rtrim, " " );
- }
-
- // Filters
- for ( type in Expr.filter ) {
- if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
- // The last two arguments here are (context, xml) for backCompat
- (match = preFilters[ type ]( match, document, true ))) ) {
-
- tokens.push( matched = new Token( match.shift() ) );
- soFar = soFar.slice( matched.length );
- matched.type = type;
- matched.matches = match;
- }
- }
-
- if ( !matched ) {
- break;
- }
- }
-
- // Return the length of the invalid excess
- // if we're just parsing
- // Otherwise, throw an error or return tokens
- return parseOnly ?
- soFar.length :
- soFar ?
- Sizzle.error( selector ) :
- // Cache the tokens
- tokenCache( selector, groups ).slice( 0 );
-}
-
-function addCombinator( matcher, combinator, base ) {
- var dir = combinator.dir,
- checkNonElements = base && combinator.dir === "parentNode",
- doneName = done++;
-
- return combinator.first ?
- // Check against closest ancestor/preceding element
- function( elem, context, xml ) {
- while ( (elem = elem[ dir ]) ) {
- if ( checkNonElements || elem.nodeType === 1 ) {
- return matcher( elem, context, xml );
- }
- }
- } :
-
- // Check against all ancestor/preceding elements
- function( elem, context, xml ) {
- // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
- if ( !xml ) {
- var cache,
- dirkey = dirruns + " " + doneName + " ",
- cachedkey = dirkey + cachedruns;
- while ( (elem = elem[ dir ]) ) {
- if ( checkNonElements || elem.nodeType === 1 ) {
- if ( (cache = elem[ expando ]) === cachedkey ) {
- return elem.sizset;
- } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) {
- if ( elem.sizset ) {
- return elem;
- }
- } else {
- elem[ expando ] = cachedkey;
- if ( matcher( elem, context, xml ) ) {
- elem.sizset = true;
- return elem;
- }
- elem.sizset = false;
- }
- }
- }
- } else {
- while ( (elem = elem[ dir ]) ) {
- if ( checkNonElements || elem.nodeType === 1 ) {
- if ( matcher( elem, context, xml ) ) {
- return elem;
- }
- }
- }
- }
- };
-}
-
-function elementMatcher( matchers ) {
- return matchers.length > 1 ?
- function( elem, context, xml ) {
- var i = matchers.length;
- while ( i-- ) {
- if ( !matchers[i]( elem, context, xml ) ) {
- return false;
- }
- }
- return true;
- } :
- matchers[0];
-}
-
-function condense( unmatched, map, filter, context, xml ) {
- var elem,
- newUnmatched = [],
- i = 0,
- len = unmatched.length,
- mapped = map != null;
-
- for ( ; i < len; i++ ) {
- if ( (elem = unmatched[i]) ) {
- if ( !filter || filter( elem, context, xml ) ) {
- newUnmatched.push( elem );
- if ( mapped ) {
- map.push( i );
- }
- }
- }
- }
-
- return newUnmatched;
-}
-
-function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
- if ( postFilter && !postFilter[ expando ] ) {
- postFilter = setMatcher( postFilter );
- }
- if ( postFinder && !postFinder[ expando ] ) {
- postFinder = setMatcher( postFinder, postSelector );
- }
- return markFunction(function( seed, results, context, xml ) {
- // Positional selectors apply to seed elements, so it is invalid to follow them with relative ones
- if ( seed && postFinder ) {
- return;
- }
-
- var i, elem, postFilterIn,
- preMap = [],
- postMap = [],
- preexisting = results.length,
-
- // Get initial elements from seed or context
- elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [], seed ),
-
- // Prefilter to get matcher input, preserving a map for seed-results synchronization
- matcherIn = preFilter && ( seed || !selector ) ?
- condense( elems, preMap, preFilter, context, xml ) :
- elems,
-
- matcherOut = matcher ?
- // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
- postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
-
- // ...intermediate processing is necessary
- [] :
-
- // ...otherwise use results directly
- results :
- matcherIn;
-
- // Find primary matches
- if ( matcher ) {
- matcher( matcherIn, matcherOut, context, xml );
- }
-
- // Apply postFilter
- if ( postFilter ) {
- postFilterIn = condense( matcherOut, postMap );
- postFilter( postFilterIn, [], context, xml );
-
- // Un-match failing elements by moving them back to matcherIn
- i = postFilterIn.length;
- while ( i-- ) {
- if ( (elem = postFilterIn[i]) ) {
- matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
- }
- }
- }
-
- // Keep seed and results synchronized
- if ( seed ) {
- // Ignore postFinder because it can't coexist with seed
- i = preFilter && matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) ) {
- seed[ preMap[i] ] = !(results[ preMap[i] ] = elem);
- }
- }
- } else {
- matcherOut = condense(
- matcherOut === results ?
- matcherOut.splice( preexisting, matcherOut.length ) :
- matcherOut
- );
- if ( postFinder ) {
- postFinder( null, results, matcherOut, xml );
- } else {
- push.apply( results, matcherOut );
- }
- }
- });
-}
-
-function matcherFromTokens( tokens ) {
- var checkContext, matcher, j,
- len = tokens.length,
- leadingRelative = Expr.relative[ tokens[0].type ],
- implicitRelative = leadingRelative || Expr.relative[" "],
- i = leadingRelative ? 1 : 0,
-
- // The foundational matcher ensures that elements are reachable from top-level context(s)
- matchContext = addCombinator( function( elem ) {
- return elem === checkContext;
- }, implicitRelative, true ),
- matchAnyContext = addCombinator( function( elem ) {
- return indexOf.call( checkContext, elem ) > -1;
- }, implicitRelative, true ),
- matchers = [ function( elem, context, xml ) {
- return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
- (checkContext = context).nodeType ?
- matchContext( elem, context, xml ) :
- matchAnyContext( elem, context, xml ) );
- } ];
-
- for ( ; i < len; i++ ) {
- if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
- matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
- } else {
- // The concatenated values are (context, xml) for backCompat
- matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
-
- // Return special upon seeing a positional matcher
- if ( matcher[ expando ] ) {
- // Find the next relative operator (if any) for proper handling
- j = ++i;
- for ( ; j < len; j++ ) {
- if ( Expr.relative[ tokens[j].type ] ) {
- break;
- }
- }
- return setMatcher(
- i > 1 && elementMatcher( matchers ),
- i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ),
- matcher,
- i < j && matcherFromTokens( tokens.slice( i, j ) ),
- j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
- j < len && tokens.join("")
- );
- }
- matchers.push( matcher );
- }
- }
-
- return elementMatcher( matchers );
-}
-
-function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
- var bySet = setMatchers.length > 0,
- byElement = elementMatchers.length > 0,
- superMatcher = function( seed, context, xml, results, expandContext ) {
- var elem, j, matcher,
- setMatched = [],
- matchedCount = 0,
- i = "0",
- unmatched = seed && [],
- outermost = expandContext != null,
- contextBackup = outermostContext,
- // We must always have either seed elements or context
- elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
- // Nested matchers should use non-integer dirruns
- dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);
-
- if ( outermost ) {
- outermostContext = context !== document && context;
- cachedruns = superMatcher.el;
- }
-
- // Add elements passing elementMatchers directly to results
- for ( ; (elem = elems[i]) != null; i++ ) {
- if ( byElement && elem ) {
- for ( j = 0; (matcher = elementMatchers[j]); j++ ) {
- if ( matcher( elem, context, xml ) ) {
- results.push( elem );
- break;
- }
- }
- if ( outermost ) {
- dirruns = dirrunsUnique;
- cachedruns = ++superMatcher.el;
- }
- }
-
- // Track unmatched elements for set filters
- if ( bySet ) {
- // They will have gone through all possible matchers
- if ( (elem = !matcher && elem) ) {
- matchedCount--;
- }
-
- // Lengthen the array for every element, matched or not
- if ( seed ) {
- unmatched.push( elem );
- }
- }
- }
-
- // Apply set filters to unmatched elements
- matchedCount += i;
- if ( bySet && i !== matchedCount ) {
- for ( j = 0; (matcher = setMatchers[j]); j++ ) {
- matcher( unmatched, setMatched, context, xml );
- }
-
- if ( seed ) {
- // Reintegrate element matches to eliminate the need for sorting
- if ( matchedCount > 0 ) {
- while ( i-- ) {
- if ( !(unmatched[i] || setMatched[i]) ) {
- setMatched[i] = pop.call( results );
- }
- }
- }
-
- // Discard index placeholder values to get only actual matches
- setMatched = condense( setMatched );
- }
-
- // Add matches to results
- push.apply( results, setMatched );
-
- // Seedless set matches succeeding multiple successful matchers stipulate sorting
- if ( outermost && !seed && setMatched.length > 0 &&
- ( matchedCount + setMatchers.length ) > 1 ) {
-
- Sizzle.uniqueSort( results );
- }
- }
-
- // Override manipulation of globals by nested matchers
- if ( outermost ) {
- dirruns = dirrunsUnique;
- outermostContext = contextBackup;
- }
-
- return unmatched;
- };
-
- superMatcher.el = 0;
- return bySet ?
- markFunction( superMatcher ) :
- superMatcher;
-}
-
-compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
- var i,
- setMatchers = [],
- elementMatchers = [],
- cached = compilerCache[ expando ][ selector ];
-
- if ( !cached ) {
- // Generate a function of recursive functions that can be used to check each element
- if ( !group ) {
- group = tokenize( selector );
- }
- i = group.length;
- while ( i-- ) {
- cached = matcherFromTokens( group[i] );
- if ( cached[ expando ] ) {
- setMatchers.push( cached );
- } else {
- elementMatchers.push( cached );
- }
- }
-
- // Cache the compiled function
- cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
- }
- return cached;
-};
-
-function multipleContexts( selector, contexts, results, seed ) {
- var i = 0,
- len = contexts.length;
- for ( ; i < len; i++ ) {
- Sizzle( selector, contexts[i], results, seed );
- }
- return results;
-}
-
-function select( selector, context, results, seed, xml ) {
- var i, tokens, token, type, find,
- match = tokenize( selector ),
- j = match.length;
-
- if ( !seed ) {
- // Try to minimize operations if there is only one group
- if ( match.length === 1 ) {
-
- // Take a shortcut and set the context if the root selector is an ID
- tokens = match[0] = match[0].slice( 0 );
- if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
- context.nodeType === 9 && !xml &&
- Expr.relative[ tokens[1].type ] ) {
-
- context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0];
- if ( !context ) {
- return results;
- }
-
- selector = selector.slice( tokens.shift().length );
- }
-
- // Fetch a seed set for right-to-left matching
- for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) {
- token = tokens[i];
-
- // Abort if we hit a combinator
- if ( Expr.relative[ (type = token.type) ] ) {
- break;
- }
- if ( (find = Expr.find[ type ]) ) {
- // Search, expanding context for leading sibling combinators
- if ( (seed = find(
- token.matches[0].replace( rbackslash, "" ),
- rsibling.test( tokens[0].type ) && context.parentNode || context,
- xml
- )) ) {
-
- // If seed is empty or no tokens remain, we can return early
- tokens.splice( i, 1 );
- selector = seed.length && tokens.join("");
- if ( !selector ) {
- push.apply( results, slice.call( seed, 0 ) );
- return results;
- }
-
- break;
- }
- }
- }
- }
- }
-
- // Compile and execute a filtering function
- // Provide `match` to avoid retokenization if we modified the selector above
- compile( selector, match )(
- seed,
- context,
- xml,
- results,
- rsibling.test( selector )
- );
- return results;
-}
-
-if ( document.querySelectorAll ) {
- (function() {
- var disconnectedMatch,
- oldSelect = select,
- rescape = /'|\\/g,
- rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
-
- // qSa(:focus) reports false when true (Chrome 21),
- // A support test would require too much code (would include document ready)
- rbuggyQSA = [":focus"],
-
- // matchesSelector(:focus) reports false when true (Chrome 21),
- // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
- // A support test would require too much code (would include document ready)
- // just skip matchesSelector for :active
- rbuggyMatches = [ ":active", ":focus" ],
- matches = docElem.matchesSelector ||
- docElem.mozMatchesSelector ||
- docElem.webkitMatchesSelector ||
- docElem.oMatchesSelector ||
- docElem.msMatchesSelector;
-
- // Build QSA regex
- // Regex strategy adopted from Diego Perini
- assert(function( div ) {
- // Select is set to empty string on purpose
- // This is to test IE's treatment of not explictly
- // setting a boolean content attribute,
- // since its presence should be enough
- // http://bugs.jquery.com/ticket/12359
- div.innerHTML = "<select><option selected=''></option></select>";
-
- // IE8 - Some boolean attributes are not treated correctly
- if ( !div.querySelectorAll("[selected]").length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
- }
-
- // Webkit/Opera - :checked should return selected option elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- // IE8 throws error here (do not put tests after this one)
- if ( !div.querySelectorAll(":checked").length ) {
- rbuggyQSA.push(":checked");
- }
- });
-
- assert(function( div ) {
-
- // Opera 10-12/IE9 - ^= $= *= and empty values
- // Should not select anything
- div.innerHTML = "<p test=''></p>";
- if ( div.querySelectorAll("[test^='']").length ) {
- rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
- }
-
- // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
- // IE8 throws error here (do not put tests after this one)
- div.innerHTML = "<input type='hidden'/>";
- if ( !div.querySelectorAll(":enabled").length ) {
- rbuggyQSA.push(":enabled", ":disabled");
- }
- });
-
- // rbuggyQSA always contains :focus, so no need for a length check
- rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") );
-
- select = function( selector, context, results, seed, xml ) {
- // Only use querySelectorAll when not filtering,
- // when this is not xml,
- // and when no QSA bugs apply
- if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
- var groups, i,
- old = true,
- nid = expando,
- newContext = context,
- newSelector = context.nodeType === 9 && selector;
-
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- groups = tokenize( selector );
-
- if ( (old = context.getAttribute("id")) ) {
- nid = old.replace( rescape, "\\$&" );
- } else {
- context.setAttribute( "id", nid );
- }
- nid = "[id='" + nid + "'] ";
-
- i = groups.length;
- while ( i-- ) {
- groups[i] = nid + groups[i].join("");
- }
- newContext = rsibling.test( selector ) && context.parentNode || context;
- newSelector = groups.join(",");
- }
-
- if ( newSelector ) {
- try {
- push.apply( results, slice.call( newContext.querySelectorAll(
- newSelector
- ), 0 ) );
- return results;
- } catch(qsaError) {
- } finally {
- if ( !old ) {
- context.removeAttribute("id");
- }
- }
- }
- }
-
- return oldSelect( selector, context, results, seed, xml );
- };
-
- if ( matches ) {
- assert(function( div ) {
- // Check to see if it's possible to do matchesSelector
- // on a disconnected node (IE 9)
- disconnectedMatch = matches.call( div, "div" );
-
- // This should fail with an exception
- // Gecko does not error, returns false instead
- try {
- matches.call( div, "[test!='']:sizzle" );
- rbuggyMatches.push( "!=", pseudos );
- } catch ( e ) {}
- });
-
- // rbuggyMatches always contains :active and :focus, so no need for a length check
- rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") );
-
- Sizzle.matchesSelector = function( elem, expr ) {
- // Make sure that attribute selectors are quoted
- expr = expr.replace( rattributeQuotes, "='$1']" );
-
- // rbuggyMatches always contains :active, so no need for an existence check
- if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) {
- try {
- var ret = matches.call( elem, expr );
-
- // IE 9's matchesSelector returns false on disconnected nodes
- if ( ret || disconnectedMatch ||
- // As well, disconnected nodes are said to be in a document
- // fragment in IE 9
- elem.document && elem.document.nodeType !== 11 ) {
- return ret;
- }
- } catch(e) {}
- }
-
- return Sizzle( expr, null, null, [ elem ] ).length > 0;
- };
- }
- })();
-}
-
-// Deprecated
-Expr.pseudos["nth"] = Expr.pseudos["eq"];
-
-// Back-compat
-function setFilters() {}
-Expr.filters = setFilters.prototype = Expr.pseudos;
-Expr.setFilters = new setFilters();
-
-// Override sizzle attribute retrieval
-Sizzle.attr = jQuery.attr;
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.pseudos;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-})( window );
-var runtil = /Until$/,
- rparentsprev = /^(?:parents|prev(?:Until|All))/,
- isSimple = /^.[^:#\[\.,]*$/,
- rneedsContext = jQuery.expr.match.needsContext,
- // methods guaranteed to produce a unique set when starting from a unique set
- guaranteedUnique = {
- children: true,
- contents: true,
- next: true,
- prev: true
- };
-
-jQuery.fn.extend({
- find: function( selector ) {
- var i, l, length, n, r, ret,
- self = this;
-
- if ( typeof selector !== "string" ) {
- return jQuery( selector ).filter(function() {
- for ( i = 0, l = self.length; i < l; i++ ) {
- if ( jQuery.contains( self[ i ], this ) ) {
- return true;
- }
- }
- });
- }
-
- ret = this.pushStack( "", "find", selector );
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- length = ret.length;
- jQuery.find( selector, this[i], ret );
-
- if ( i > 0 ) {
- // Make sure that the results are unique
- for ( n = length; n < ret.length; n++ ) {
- for ( r = 0; r < length; r++ ) {
- if ( ret[r] === ret[n] ) {
- ret.splice(n--, 1);
- break;
- }
- }
- }
- }
- }
-
- return ret;
- },
-
- has: function( target ) {
- var i,
- targets = jQuery( target, this ),
- len = targets.length;
-
- return this.filter(function() {
- for ( i = 0; i < len; i++ ) {
- if ( jQuery.contains( this, targets[i] ) ) {
- return true;
- }
- }
- });
- },
-
- not: function( selector ) {
- return this.pushStack( winnow(this, selector, false), "not", selector);
- },
-
- filter: function( selector ) {
- return this.pushStack( winnow(this, selector, true), "filter", selector );
- },
-
- is: function( selector ) {
- return !!selector && (
- typeof selector === "string" ?
- // If this is a positional/relative selector, check membership in the returned set
- // so $("p:first").is("p:last") won't return true for a doc with two "p".
- rneedsContext.test( selector ) ?
- jQuery( selector, this.context ).index( this[0] ) >= 0 :
- jQuery.filter( selector, this ).length > 0 :
- this.filter( selector ).length > 0 );
- },
-
- closest: function( selectors, context ) {
- var cur,
- i = 0,
- l = this.length,
- ret = [],
- pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
- jQuery( selectors, context || this.context ) :
- 0;
-
- for ( ; i < l; i++ ) {
- cur = this[i];
-
- while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
- if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
- ret.push( cur );
- break;
- }
- cur = cur.parentNode;
- }
- }
-
- ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
-
- return this.pushStack( ret, "closest", selectors );
- },
-
- // Determine the position of an element within
- // the matched set of elements
- index: function( elem ) {
-
- // No argument, return index in parent
- if ( !elem ) {
- return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
- }
-
- // index in selector
- if ( typeof elem === "string" ) {
- return jQuery.inArray( this[0], jQuery( elem ) );
- }
-
- // Locate the position of the desired element
- return jQuery.inArray(
- // If it receives a jQuery object, the first element is used
- elem.jquery ? elem[0] : elem, this );
- },
-
- add: function( selector, context ) {
- var set = typeof selector === "string" ?
- jQuery( selector, context ) :
- jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
- all = jQuery.merge( this.get(), set );
-
- return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
- all :
- jQuery.unique( all ) );
- },
-
- addBack: function( selector ) {
- return this.add( selector == null ?
- this.prevObject : this.prevObject.filter(selector)
- );
- }
-});
-
-jQuery.fn.andSelf = jQuery.fn.addBack;
-
-// A painfully simple check to see if an element is disconnected
-// from a document (should be improved, where feasible).
-function isDisconnected( node ) {
- return !node || !node.parentNode || node.parentNode.nodeType === 11;
-}
-
-function sibling( cur, dir ) {
- do {
- cur = cur[ dir ];
- } while ( cur && cur.nodeType !== 1 );
-
- return cur;
-}
-
-jQuery.each({
- parent: function( elem ) {
- var parent = elem.parentNode;
- return parent && parent.nodeType !== 11 ? parent : null;
- },
- parents: function( elem ) {
- return jQuery.dir( elem, "parentNode" );
- },
- parentsUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "parentNode", until );
- },
- next: function( elem ) {
- return sibling( elem, "nextSibling" );
- },
- prev: function( elem ) {
- return sibling( elem, "previousSibling" );
- },
- nextAll: function( elem ) {
- return jQuery.dir( elem, "nextSibling" );
- },
- prevAll: function( elem ) {
- return jQuery.dir( elem, "previousSibling" );
- },
- nextUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "nextSibling", until );
- },
- prevUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "previousSibling", until );
- },
- siblings: function( elem ) {
- return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
- },
- children: function( elem ) {
- return jQuery.sibling( elem.firstChild );
- },
- contents: function( elem ) {
- return jQuery.nodeName( elem, "iframe" ) ?
- elem.contentDocument || elem.contentWindow.document :
- jQuery.merge( [], elem.childNodes );
- }
-}, function( name, fn ) {
- jQuery.fn[ name ] = function( until, selector ) {
- var ret = jQuery.map( this, fn, until );
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( this.length > 1 && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, core_slice.call( arguments ).join(",") );
- };
-});
-
-jQuery.extend({
- filter: function( expr, elems, not ) {
- if ( not ) {
- expr = ":not(" + expr + ")";
- }
-
- return elems.length === 1 ?
- jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
- jQuery.find.matches(expr, elems);
- },
-
- dir: function( elem, dir, until ) {
- var matched = [],
- cur = elem[ dir ];
-
- while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
- if ( cur.nodeType === 1 ) {
- matched.push( cur );
- }
- cur = cur[dir];
- }
- return matched;
- },
-
- sibling: function( n, elem ) {
- var r = [];
-
- for ( ; n; n = n.nextSibling ) {
- if ( n.nodeType === 1 && n !== elem ) {
- r.push( n );
- }
- }
-
- return r;
- }
-});
-
-// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, keep ) {
-
- // Can't pass null or undefined to indexOf in Firefox 4
- // Set to 0 to skip string check
- qualifier = qualifier || 0;
-
- if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep(elements, function( elem, i ) {
- var retVal = !!qualifier.call( elem, i, elem );
- return retVal === keep;
- });
-
- } else if ( qualifier.nodeType ) {
- return jQuery.grep(elements, function( elem, i ) {
- return ( elem === qualifier ) === keep;
- });
-
- } else if ( typeof qualifier === "string" ) {
- var filtered = jQuery.grep(elements, function( elem ) {
- return elem.nodeType === 1;
- });
-
- if ( isSimple.test( qualifier ) ) {
- return jQuery.filter(qualifier, filtered, !keep);
- } else {
- qualifier = jQuery.filter( qualifier, filtered );
- }
- }
-
- return jQuery.grep(elements, function( elem, i ) {
- return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
- });
-}
-function createSafeFragment( document ) {
- var list = nodeNames.split( "|" ),
- safeFrag = document.createDocumentFragment();
-
- if ( safeFrag.createElement ) {
- while ( list.length ) {
- safeFrag.createElement(
- list.pop()
- );
- }
- }
- return safeFrag;
-}
-
-var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
- "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
- rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
- rleadingWhitespace = /^\s+/,
- rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
- rtagName = /<([\w:]+)/,
- rtbody = /<tbody/i,
- rhtml = /<|&#?\w+;/,
- rnoInnerhtml = /<(?:script|style|link)/i,
- rnocache = /<(?:script|object|embed|option|style)/i,
- rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
- rcheckableType = /^(?:checkbox|radio)$/,
- // checked="checked" or checked
- rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
- rscriptType = /\/(java|ecma)script/i,
- rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,
- wrapMap = {
- option: [ 1, "<select multiple='multiple'>", "</select>" ],
- legend: [ 1, "<fieldset>", "</fieldset>" ],
- thead: [ 1, "<table>", "</table>" ],
- tr: [ 2, "<table><tbody>", "</tbody></table>" ],
- td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
- col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
- area: [ 1, "<map>", "</map>" ],
- _default: [ 0, "", "" ]
- },
- safeFragment = createSafeFragment( document ),
- fragmentDiv = safeFragment.appendChild( document.createElement("div") );
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
-// unless wrapped in a div with non-breaking characters in front of it.
-if ( !jQuery.support.htmlSerialize ) {
- wrapMap._default = [ 1, "X<div>", "</div>" ];
-}
-
-jQuery.fn.extend({
- text: function( value ) {
- return jQuery.access( this, function( value ) {
- return value === undefined ?
- jQuery.text( this ) :
- this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
- }, null, value, arguments.length );
- },
-
- wrapAll: function( html ) {
- if ( jQuery.isFunction( html ) ) {
- return this.each(function(i) {
- jQuery(this).wrapAll( html.call(this, i) );
- });
- }
-
- if ( this[0] ) {
- // The elements to wrap the target around
- var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
-
- if ( this[0].parentNode ) {
- wrap.insertBefore( this[0] );
- }
-
- wrap.map(function() {
- var elem = this;
-
- while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
- elem = elem.firstChild;
- }
-
- return elem;
- }).append( this );
- }
-
- return this;
- },
-
- wrapInner: function( html ) {
- if ( jQuery.isFunction( html ) ) {
- return this.each(function(i) {
- jQuery(this).wrapInner( html.call(this, i) );
- });
- }
-
- return this.each(function() {
- var self = jQuery( this ),
- contents = self.contents();
-
- if ( contents.length ) {
- contents.wrapAll( html );
-
- } else {
- self.append( html );
- }
- });
- },
-
- wrap: function( html ) {
- var isFunction = jQuery.isFunction( html );
-
- return this.each(function(i) {
- jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
- });
- },
-
- unwrap: function() {
- return this.parent().each(function() {
- if ( !jQuery.nodeName( this, "body" ) ) {
- jQuery( this ).replaceWith( this.childNodes );
- }
- }).end();
- },
-
- append: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 ) {
- this.appendChild( elem );
- }
- });
- },
-
- prepend: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 ) {
- this.insertBefore( elem, this.firstChild );
- }
- });
- },
-
- before: function() {
- if ( !isDisconnected( this[0] ) ) {
- return this.domManip(arguments, false, function( elem ) {
- this.parentNode.insertBefore( elem, this );
- });
- }
-
- if ( arguments.length ) {
- var set = jQuery.clean( arguments );
- return this.pushStack( jQuery.merge( set, this ), "before", this.selector );
- }
- },
-
- after: function() {
- if ( !isDisconnected( this[0] ) ) {
- return this.domManip(arguments, false, function( elem ) {
- this.parentNode.insertBefore( elem, this.nextSibling );
- });
- }
-
- if ( arguments.length ) {
- var set = jQuery.clean( arguments );
- return this.pushStack( jQuery.merge( this, set ), "after", this.selector );
- }
- },
-
- // keepData is for internal use only--do not document
- remove: function( selector, keepData ) {
- var elem,
- i = 0;
-
- for ( ; (elem = this[i]) != null; i++ ) {
- if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
- if ( !keepData && elem.nodeType === 1 ) {
- jQuery.cleanData( elem.getElementsByTagName("*") );
- jQuery.cleanData( [ elem ] );
- }
-
- if ( elem.parentNode ) {
- elem.parentNode.removeChild( elem );
- }
- }
- }
-
- return this;
- },
-
- empty: function() {
- var elem,
- i = 0;
-
- for ( ; (elem = this[i]) != null; i++ ) {
- // Remove element nodes and prevent memory leaks
- if ( elem.nodeType === 1 ) {
- jQuery.cleanData( elem.getElementsByTagName("*") );
- }
-
- // Remove any remaining nodes
- while ( elem.firstChild ) {
- elem.removeChild( elem.firstChild );
- }
- }
-
- return this;
- },
-
- clone: function( dataAndEvents, deepDataAndEvents ) {
- dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
- deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
-
- return this.map( function () {
- return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
- });
- },
-
- html: function( value ) {
- return jQuery.access( this, function( value ) {
- var elem = this[0] || {},
- i = 0,
- l = this.length;
-
- if ( value === undefined ) {
- return elem.nodeType === 1 ?
- elem.innerHTML.replace( rinlinejQuery, "" ) :
- undefined;
- }
-
- // See if we can take a shortcut and just use innerHTML
- if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
- ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
- ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
- !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
-
- value = value.replace( rxhtmlTag, "<$1></$2>" );
-
- try {
- for (; i < l; i++ ) {
- // Remove element nodes and prevent memory leaks
- elem = this[i] || {};
- if ( elem.nodeType === 1 ) {
- jQuery.cleanData( elem.getElementsByTagName( "*" ) );
- elem.innerHTML = value;
- }
- }
-
- elem = 0;
-
- // If using innerHTML throws an exception, use the fallback method
- } catch(e) {}
- }
-
- if ( elem ) {
- this.empty().append( value );
- }
- }, null, value, arguments.length );
- },
-
- replaceWith: function( value ) {
- if ( !isDisconnected( this[0] ) ) {
- // Make sure that the elements are removed from the DOM before they are inserted
- // this can help fix replacing a parent with child elements
- if ( jQuery.isFunction( value ) ) {
- return this.each(function(i) {
- var self = jQuery(this), old = self.html();
- self.replaceWith( value.call( this, i, old ) );
- });
- }
-
- if ( typeof value !== "string" ) {
- value = jQuery( value ).detach();
- }
-
- return this.each(function() {
- var next = this.nextSibling,
- parent = this.parentNode;
-
- jQuery( this ).remove();
-
- if ( next ) {
- jQuery(next).before( value );
- } else {
- jQuery(parent).append( value );
- }
- });
- }
-
- return this.length ?
- this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
- this;
- },
-
- detach: function( selector ) {
- return this.remove( selector, true );
- },
-
- domManip: function( args, table, callback ) {
-
- // Flatten any nested arrays
- args = [].concat.apply( [], args );
-
- var results, first, fragment, iNoClone,
- i = 0,
- value = args[0],
- scripts = [],
- l = this.length;
-
- // We can't cloneNode fragments that contain checked, in WebKit
- if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) {
- return this.each(function() {
- jQuery(this).domManip( args, table, callback );
- });
- }
-
- if ( jQuery.isFunction(value) ) {
- return this.each(function(i) {
- var self = jQuery(this);
- args[0] = value.call( this, i, table ? self.html() : undefined );
- self.domManip( args, table, callback );
- });
- }
-
- if ( this[0] ) {
- results = jQuery.buildFragment( args, this, scripts );
- fragment = results.fragment;
- first = fragment.firstChild;
-
- if ( fragment.childNodes.length === 1 ) {
- fragment = first;
- }
-
- if ( first ) {
- table = table && jQuery.nodeName( first, "tr" );
-
- // Use the original fragment for the last item instead of the first because it can end up
- // being emptied incorrectly in certain situations (#8070).
- // Fragments from the fragment cache must always be cloned and never used in place.
- for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) {
- callback.call(
- table && jQuery.nodeName( this[i], "table" ) ?
- findOrAppend( this[i], "tbody" ) :
- this[i],
- i === iNoClone ?
- fragment :
- jQuery.clone( fragment, true, true )
- );
- }
- }
-
- // Fix #11809: Avoid leaking memory
- fragment = first = null;
-
- if ( scripts.length ) {
- jQuery.each( scripts, function( i, elem ) {
- if ( elem.src ) {
- if ( jQuery.ajax ) {
- jQuery.ajax({
- url: elem.src,
- type: "GET",
- dataType: "script",
- async: false,
- global: false,
- "throws": true
- });
- } else {
- jQuery.error("no ajax");
- }
- } else {
- jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) );
- }
-
- if ( elem.parentNode ) {
- elem.parentNode.removeChild( elem );
- }
- });
- }
- }
-
- return this;
- }
-});
-
-function findOrAppend( elem, tag ) {
- return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
-}
-
-function cloneCopyEvent( src, dest ) {
-
- if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
- return;
- }
-
- var type, i, l,
- oldData = jQuery._data( src ),
- curData = jQuery._data( dest, oldData ),
- events = oldData.events;
-
- if ( events ) {
- delete curData.handle;
- curData.events = {};
-
- for ( type in events ) {
- for ( i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( dest, type, events[ type ][ i ] );
- }
- }
- }
-
- // make the cloned public data object a copy from the original
- if ( curData.data ) {
- curData.data = jQuery.extend( {}, curData.data );
- }
-}
-
-function cloneFixAttributes( src, dest ) {
- var nodeName;
-
- // We do not need to do anything for non-Elements
- if ( dest.nodeType !== 1 ) {
- return;
- }
-
- // clearAttributes removes the attributes, which we don't want,
- // but also removes the attachEvent events, which we *do* want
- if ( dest.clearAttributes ) {
- dest.clearAttributes();
- }
-
- // mergeAttributes, in contrast, only merges back on the
- // original attributes, not the events
- if ( dest.mergeAttributes ) {
- dest.mergeAttributes( src );
- }
-
- nodeName = dest.nodeName.toLowerCase();
-
- if ( nodeName === "object" ) {
- // IE6-10 improperly clones children of object elements using classid.
- // IE10 throws NoModificationAllowedError if parent is null, #12132.
- if ( dest.parentNode ) {
- dest.outerHTML = src.outerHTML;
- }
-
- // This path appears unavoidable for IE9. When cloning an object
- // element in IE9, the outerHTML strategy above is not sufficient.
- // If the src has innerHTML and the destination does not,
- // copy the src.innerHTML into the dest.innerHTML. #10324
- if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) {
- dest.innerHTML = src.innerHTML;
- }
-
- } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
- // IE6-8 fails to persist the checked state of a cloned checkbox
- // or radio button. Worse, IE6-7 fail to give the cloned element
- // a checked appearance if the defaultChecked value isn't also set
-
- dest.defaultChecked = dest.checked = src.checked;
-
- // IE6-7 get confused and end up setting the value of a cloned
- // checkbox/radio button to an empty string instead of "on"
- if ( dest.value !== src.value ) {
- dest.value = src.value;
- }
-
- // IE6-8 fails to return the selected option to the default selected
- // state when cloning options
- } else if ( nodeName === "option" ) {
- dest.selected = src.defaultSelected;
-
- // IE6-8 fails to set the defaultValue to the correct value when
- // cloning other types of input fields
- } else if ( nodeName === "input" || nodeName === "textarea" ) {
- dest.defaultValue = src.defaultValue;
-
- // IE blanks contents when cloning scripts
- } else if ( nodeName === "script" && dest.text !== src.text ) {
- dest.text = src.text;
- }
-
- // Event data gets referenced instead of copied if the expando
- // gets copied too
- dest.removeAttribute( jQuery.expando );
-}
-
-jQuery.buildFragment = function( args, context, scripts ) {
- var fragment, cacheable, cachehit,
- first = args[ 0 ];
-
- // Set context from what may come in as undefined or a jQuery collection or a node
- // Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 &
- // also doubles as fix for #8950 where plain objects caused createDocumentFragment exception
- context = context || document;
- context = !context.nodeType && context[0] || context;
- context = context.ownerDocument || context;
-
- // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
- // Cloning options loses the selected state, so don't cache them
- // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
- // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
- // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
- if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document &&
- first.charAt(0) === "<" && !rnocache.test( first ) &&
- (jQuery.support.checkClone || !rchecked.test( first )) &&
- (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
-
- // Mark cacheable and look for a hit
- cacheable = true;
- fragment = jQuery.fragments[ first ];
- cachehit = fragment !== undefined;
- }
-
- if ( !fragment ) {
- fragment = context.createDocumentFragment();
- jQuery.clean( args, context, fragment, scripts );
-
- // Update the cache, but only store false
- // unless this is a second parsing of the same content
- if ( cacheable ) {
- jQuery.fragments[ first ] = cachehit && fragment;
- }
- }
-
- return { fragment: fragment, cacheable: cacheable };
-};
-
-jQuery.fragments = {};
-
-jQuery.each({
- appendTo: "append",
- prependTo: "prepend",
- insertBefore: "before",
- insertAfter: "after",
- replaceAll: "replaceWith"
-}, function( name, original ) {
- jQuery.fn[ name ] = function( selector ) {
- var elems,
- i = 0,
- ret = [],
- insert = jQuery( selector ),
- l = insert.length,
- parent = this.length === 1 && this[0].parentNode;
-
- if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) {
- insert[ original ]( this[0] );
- return this;
- } else {
- for ( ; i < l; i++ ) {
- elems = ( i > 0 ? this.clone(true) : this ).get();
- jQuery( insert[i] )[ original ]( elems );
- ret = ret.concat( elems );
- }
-
- return this.pushStack( ret, name, insert.selector );
- }
- };
-});
-
-function getAll( elem ) {
- if ( typeof elem.getElementsByTagName !== "undefined" ) {
- return elem.getElementsByTagName( "*" );
-
- } else if ( typeof elem.querySelectorAll !== "undefined" ) {
- return elem.querySelectorAll( "*" );
-
- } else {
- return [];
- }
-}
-
-// Used in clean, fixes the defaultChecked property
-function fixDefaultChecked( elem ) {
- if ( rcheckableType.test( elem.type ) ) {
- elem.defaultChecked = elem.checked;
- }
-}
-
-jQuery.extend({
- clone: function( elem, dataAndEvents, deepDataAndEvents ) {
- var srcElements,
- destElements,
- i,
- clone;
-
- if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
- clone = elem.cloneNode( true );
-
- // IE<=8 does not properly clone detached, unknown element nodes
- } else {
- fragmentDiv.innerHTML = elem.outerHTML;
- fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
- }
-
- if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
- (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
- // IE copies events bound via attachEvent when using cloneNode.
- // Calling detachEvent on the clone will also remove the events
- // from the original. In order to get around this, we use some
- // proprietary methods to clear the events. Thanks to MooTools
- // guys for this hotness.
-
- cloneFixAttributes( elem, clone );
-
- // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
- srcElements = getAll( elem );
- destElements = getAll( clone );
-
- // Weird iteration because IE will replace the length property
- // with an element if you are cloning the body and one of the
- // elements on the page has a name or id of "length"
- for ( i = 0; srcElements[i]; ++i ) {
- // Ensure that the destination node is not null; Fixes #9587
- if ( destElements[i] ) {
- cloneFixAttributes( srcElements[i], destElements[i] );
- }
- }
- }
-
- // Copy the events from the original to the clone
- if ( dataAndEvents ) {
- cloneCopyEvent( elem, clone );
-
- if ( deepDataAndEvents ) {
- srcElements = getAll( elem );
- destElements = getAll( clone );
-
- for ( i = 0; srcElements[i]; ++i ) {
- cloneCopyEvent( srcElements[i], destElements[i] );
- }
- }
- }
-
- srcElements = destElements = null;
-
- // Return the cloned set
- return clone;
- },
-
- clean: function( elems, context, fragment, scripts ) {
- var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
- safe = context === document && safeFragment,
- ret = [];
-
- // Ensure that context is a document
- if ( !context || typeof context.createDocumentFragment === "undefined" ) {
- context = document;
- }
-
- // Use the already-created safe fragment if context permits
- for ( i = 0; (elem = elems[i]) != null; i++ ) {
- if ( typeof elem === "number" ) {
- elem += "";
- }
-
- if ( !elem ) {
- continue;
- }
-
- // Convert html string into DOM nodes
- if ( typeof elem === "string" ) {
- if ( !rhtml.test( elem ) ) {
- elem = context.createTextNode( elem );
- } else {
- // Ensure a safe container in which to render the html
- safe = safe || createSafeFragment( context );
- div = context.createElement("div");
- safe.appendChild( div );
-
- // Fix "XHTML"-style tags in all browsers
- elem = elem.replace(rxhtmlTag, "<$1></$2>");
-
- // Go to html and back, then peel off extra wrappers
- tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
- wrap = wrapMap[ tag ] || wrapMap._default;
- depth = wrap[0];
- div.innerHTML = wrap[1] + elem + wrap[2];
-
- // Move to the right depth
- while ( depth-- ) {
- div = div.lastChild;
- }
-
- // Remove IE's autoinserted <tbody> from table fragments
- if ( !jQuery.support.tbody ) {
-
- // String was a <table>, *may* have spurious <tbody>
- hasBody = rtbody.test(elem);
- tbody = tag === "table" && !hasBody ?
- div.firstChild && div.firstChild.childNodes :
-
- // String was a bare <thead> or <tfoot>
- wrap[1] === "<table>" && !hasBody ?
- div.childNodes :
- [];
-
- for ( j = tbody.length - 1; j >= 0 ; --j ) {
- if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
- tbody[ j ].parentNode.removeChild( tbody[ j ] );
- }
- }
- }
-
- // IE completely kills leading whitespace when innerHTML is used
- if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
- div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
- }
-
- elem = div.childNodes;
-
- // Take out of fragment container (we need a fresh div each time)
- div.parentNode.removeChild( div );
- }
- }
-
- if ( elem.nodeType ) {
- ret.push( elem );
- } else {
- jQuery.merge( ret, elem );
- }
- }
-
- // Fix #11356: Clear elements from safeFragment
- if ( div ) {
- elem = div = safe = null;
- }
-
- // Reset defaultChecked for any radios and checkboxes
- // about to be appended to the DOM in IE 6/7 (#8060)
- if ( !jQuery.support.appendChecked ) {
- for ( i = 0; (elem = ret[i]) != null; i++ ) {
- if ( jQuery.nodeName( elem, "input" ) ) {
- fixDefaultChecked( elem );
- } else if ( typeof elem.getElementsByTagName !== "undefined" ) {
- jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
- }
- }
- }
-
- // Append elements to a provided document fragment
- if ( fragment ) {
- // Special handling of each script element
- handleScript = function( elem ) {
- // Check if we consider it executable
- if ( !elem.type || rscriptType.test( elem.type ) ) {
- // Detach the script and store it in the scripts array (if provided) or the fragment
- // Return truthy to indicate that it has been handled
- return scripts ?
- scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
- fragment.appendChild( elem );
- }
- };
-
- for ( i = 0; (elem = ret[i]) != null; i++ ) {
- // Check if we're done after handling an executable script
- if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
- // Append to fragment and handle embedded scripts
- fragment.appendChild( elem );
- if ( typeof elem.getElementsByTagName !== "undefined" ) {
- // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
- jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
-
- // Splice the scripts into ret after their former ancestor and advance our index beyond them
- ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
- i += jsTags.length;
- }
- }
- }
- }
-
- return ret;
- },
-
- cleanData: function( elems, /* internal */ acceptData ) {
- var data, id, elem, type,
- i = 0,
- internalKey = jQuery.expando,
- cache = jQuery.cache,
- deleteExpando = jQuery.support.deleteExpando,
- special = jQuery.event.special;
-
- for ( ; (elem = elems[i]) != null; i++ ) {
-
- if ( acceptData || jQuery.acceptData( elem ) ) {
-
- id = elem[ internalKey ];
- data = id && cache[ id ];
-
- if ( data ) {
- if ( data.events ) {
- for ( type in data.events ) {
- if ( special[ type ] ) {
- jQuery.event.remove( elem, type );
-
- // This is a shortcut to avoid jQuery.event.remove's overhead
- } else {
- jQuery.removeEvent( elem, type, data.handle );
- }
- }
- }
-
- // Remove cache only if it was not already removed by jQuery.event.remove
- if ( cache[ id ] ) {
-
- delete cache[ id ];
-
- // IE does not allow us to delete expando properties from nodes,
- // nor does it have a removeAttribute function on Document nodes;
- // we must handle all of these cases
- if ( deleteExpando ) {
- delete elem[ internalKey ];
-
- } else if ( elem.removeAttribute ) {
- elem.removeAttribute( internalKey );
-
- } else {
- elem[ internalKey ] = null;
- }
-
- jQuery.deletedIds.push( id );
- }
- }
- }
- }
- }
-});
-// Limit scope pollution from any deprecated API
-(function() {
-
-var matched, browser;
-
-// Use of jQuery.browser is frowned upon.
-// More details: http://api.jquery.com/jQuery.browser
-// jQuery.uaMatch maintained for back-compat
-jQuery.uaMatch = function( ua ) {
- ua = ua.toLowerCase();
-
- var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
- /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
- /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
- /(msie) ([\w.]+)/.exec( ua ) ||
- ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
- [];
-
- return {
- browser: match[ 1 ] || "",
- version: match[ 2 ] || "0"
- };
-};
-
-matched = jQuery.uaMatch( navigator.userAgent );
-browser = {};
-
-if ( matched.browser ) {
- browser[ matched.browser ] = true;
- browser.version = matched.version;
-}
-
-// Chrome is Webkit, but Webkit is also Safari.
-if ( browser.chrome ) {
- browser.webkit = true;
-} else if ( browser.webkit ) {
- browser.safari = true;
-}
-
-jQuery.browser = browser;
-
-jQuery.sub = function() {
- function jQuerySub( selector, context ) {
- return new jQuerySub.fn.init( selector, context );
- }
- jQuery.extend( true, jQuerySub, this );
- jQuerySub.superclass = this;
- jQuerySub.fn = jQuerySub.prototype = this();
- jQuerySub.fn.constructor = jQuerySub;
- jQuerySub.sub = this.sub;
- jQuerySub.fn.init = function init( selector, context ) {
- if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
- context = jQuerySub( context );
- }
-
- return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
- };
- jQuerySub.fn.init.prototype = jQuerySub.fn;
- var rootjQuerySub = jQuerySub(document);
- return jQuerySub;
-};
-
-})();
-var curCSS, iframe, iframeDoc,
- ralpha = /alpha\([^)]*\)/i,
- ropacity = /opacity=([^)]*)/,
- rposition = /^(top|right|bottom|left)$/,
- // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
- // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
- rdisplayswap = /^(none|table(?!-c[ea]).+)/,
- rmargin = /^margin/,
- rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
- rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
- rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ),
- elemdisplay = {},
-
- cssShow = { position: "absolute", visibility: "hidden", display: "block" },
- cssNormalTransform = {
- letterSpacing: 0,
- fontWeight: 400
- },
-
- cssExpand = [ "Top", "Right", "Bottom", "Left" ],
- cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
-
- eventsToggle = jQuery.fn.toggle;
-
-// return a css property mapped to a potentially vendor prefixed property
-function vendorPropName( style, name ) {
-
- // shortcut for names that are not vendor prefixed
- if ( name in style ) {
- return name;
- }
-
- // check for vendor prefixed names
- var capName = name.charAt(0).toUpperCase() + name.slice(1),
- origName = name,
- i = cssPrefixes.length;
-
- while ( i-- ) {
- name = cssPrefixes[ i ] + capName;
- if ( name in style ) {
- return name;
- }
- }
-
- return origName;
-}
-
-function isHidden( elem, el ) {
- elem = el || elem;
- return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
-}
-
-function showHide( elements, show ) {
- var elem, display,
- values = [],
- index = 0,
- length = elements.length;
-
- for ( ; index < length; index++ ) {
- elem = elements[ index ];
- if ( !elem.style ) {
- continue;
- }
- values[ index ] = jQuery._data( elem, "olddisplay" );
- if ( show ) {
- // Reset the inline display of this element to learn if it is
- // being hidden by cascaded rules or not
- if ( !values[ index ] && elem.style.display === "none" ) {
- elem.style.display = "";
- }
-
- // Set elements which have been overridden with display: none
- // in a stylesheet to whatever the default browser style is
- // for such an element
- if ( elem.style.display === "" && isHidden( elem ) ) {
- values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
- }
- } else {
- display = curCSS( elem, "display" );
-
- if ( !values[ index ] && display !== "none" ) {
- jQuery._data( elem, "olddisplay", display );
- }
- }
- }
-
- // Set the display of most of the elements in a second loop
- // to avoid the constant reflow
- for ( index = 0; index < length; index++ ) {
- elem = elements[ index ];
- if ( !elem.style ) {
- continue;
- }
- if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
- elem.style.display = show ? values[ index ] || "" : "none";
- }
- }
-
- return elements;
-}
-
-jQuery.fn.extend({
- css: function( name, value ) {
- return jQuery.access( this, function( elem, name, value ) {
- return value !== undefined ?
- jQuery.style( elem, name, value ) :
- jQuery.css( elem, name );
- }, name, value, arguments.length > 1 );
- },
- show: function() {
- return showHide( this, true );
- },
- hide: function() {
- return showHide( this );
- },
- toggle: function( state, fn2 ) {
- var bool = typeof state === "boolean";
-
- if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) {
- return eventsToggle.apply( this, arguments );
- }
-
- return this.each(function() {
- if ( bool ? state : isHidden( this ) ) {
- jQuery( this ).show();
- } else {
- jQuery( this ).hide();
- }
- });
- }
-});
-
-jQuery.extend({
- // Add in style property hooks for overriding the default
- // behavior of getting and setting a style property
- cssHooks: {
- opacity: {
- get: function( elem, computed ) {
- if ( computed ) {
- // We should always get a number back from opacity
- var ret = curCSS( elem, "opacity" );
- return ret === "" ? "1" : ret;
-
- }
- }
- }
- },
-
- // Exclude the following css properties to add px
- cssNumber: {
- "fillOpacity": true,
- "fontWeight": true,
- "lineHeight": true,
- "opacity": true,
- "orphans": true,
- "widows": true,
- "zIndex": true,
- "zoom": true
- },
-
- // Add in properties whose names you wish to fix before
- // setting or getting the value
- cssProps: {
- // normalize float css property
- "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
- },
-
- // Get and set the style property on a DOM Node
- style: function( elem, name, value, extra ) {
- // Don't set styles on text and comment nodes
- if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
- return;
- }
-
- // Make sure that we're working with the right name
- var ret, type, hooks,
- origName = jQuery.camelCase( name ),
- style = elem.style;
-
- name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
-
- // gets hook for the prefixed version
- // followed by the unprefixed version
- hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
-
- // Check if we're setting a value
- if ( value !== undefined ) {
- type = typeof value;
-
- // convert relative number strings (+= or -=) to relative numbers. #7345
- if ( type === "string" && (ret = rrelNum.exec( value )) ) {
- value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
- // Fixes bug #9237
- type = "number";
- }
-
- // Make sure that NaN and null values aren't set. See: #7116
- if ( value == null || type === "number" && isNaN( value ) ) {
- return;
- }
-
- // If a number was passed in, add 'px' to the (except for certain CSS properties)
- if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
- value += "px";
- }
-
- // If a hook was provided, use that value, otherwise just set the specified value
- if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
- // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
- // Fixes bug #5509
- try {
- style[ name ] = value;
- } catch(e) {}
- }
-
- } else {
- // If a hook was provided get the non-computed value from there
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
- return ret;
- }
-
- // Otherwise just get the value from the style object
- return style[ name ];
- }
- },
-
- css: function( elem, name, numeric, extra ) {
- var val, num, hooks,
- origName = jQuery.camelCase( name );
-
- // Make sure that we're working with the right name
- name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
-
- // gets hook for the prefixed version
- // followed by the unprefixed version
- hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
-
- // If a hook was provided get the computed value from there
- if ( hooks && "get" in hooks ) {
- val = hooks.get( elem, true, extra );
- }
-
- // Otherwise, if a way to get the computed value exists, use that
- if ( val === undefined ) {
- val = curCSS( elem, name );
- }
-
- //convert "normal" to computed value
- if ( val === "normal" && name in cssNormalTransform ) {
- val = cssNormalTransform[ name ];
- }
-
- // Return, converting to number if forced or a qualifier was provided and val looks numeric
- if ( numeric || extra !== undefined ) {
- num = parseFloat( val );
- return numeric || jQuery.isNumeric( num ) ? num || 0 : val;
- }
- return val;
- },
-
- // A method for quickly swapping in/out CSS properties to get correct calculations
- swap: function( elem, options, callback ) {
- var ret, name,
- old = {};
-
- // Remember the old values, and insert the new ones
- for ( name in options ) {
- old[ name ] = elem.style[ name ];
- elem.style[ name ] = options[ name ];
- }
-
- ret = callback.call( elem );
-
- // Revert the old values
- for ( name in options ) {
- elem.style[ name ] = old[ name ];
- }
-
- return ret;
- }
-});
-
-// NOTE: To any future maintainer, we've window.getComputedStyle
-// because jsdom on node.js will break without it.
-if ( window.getComputedStyle ) {
- curCSS = function( elem, name ) {
- var ret, width, minWidth, maxWidth,
- computed = window.getComputedStyle( elem, null ),
- style = elem.style;
-
- if ( computed ) {
-
- ret = computed[ name ];
- if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
- ret = jQuery.style( elem, name );
- }
-
- // A tribute to the "awesome hack by Dean Edwards"
- // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
- // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
- // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
- if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
- width = style.width;
- minWidth = style.minWidth;
- maxWidth = style.maxWidth;
-
- style.minWidth = style.maxWidth = style.width = ret;
- ret = computed.width;
-
- style.width = width;
- style.minWidth = minWidth;
- style.maxWidth = maxWidth;
- }
- }
-
- return ret;
- };
-} else if ( document.documentElement.currentStyle ) {
- curCSS = function( elem, name ) {
- var left, rsLeft,
- ret = elem.currentStyle && elem.currentStyle[ name ],
- style = elem.style;
-
- // Avoid setting ret to empty string here
- // so we don't default to auto
- if ( ret == null && style && style[ name ] ) {
- ret = style[ name ];
- }
-
- // From the awesome hack by Dean Edwards
- // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
- // If we're not dealing with a regular pixel number
- // but a number that has a weird ending, we need to convert it to pixels
- // but not position css attributes, as those are proportional to the parent element instead
- // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
- if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
-
- // Remember the original values
- left = style.left;
- rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
-
- // Put in the new values to get a computed value out
- if ( rsLeft ) {
- elem.runtimeStyle.left = elem.currentStyle.left;
- }
- style.left = name === "fontSize" ? "1em" : ret;
- ret = style.pixelLeft + "px";
-
- // Revert the changed values
- style.left = left;
- if ( rsLeft ) {
- elem.runtimeStyle.left = rsLeft;
- }
- }
-
- return ret === "" ? "auto" : ret;
- };
-}
-
-function setPositiveNumber( elem, value, subtract ) {
- var matches = rnumsplit.exec( value );
- return matches ?
- Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
- value;
-}
-
-function augmentWidthOrHeight( elem, name, extra, isBorderBox ) {
- var i = extra === ( isBorderBox ? "border" : "content" ) ?
- // If we already have the right measurement, avoid augmentation
- 4 :
- // Otherwise initialize for horizontal or vertical properties
- name === "width" ? 1 : 0,
-
- val = 0;
-
- for ( ; i < 4; i += 2 ) {
- // both box models exclude margin, so add it if we want it
- if ( extra === "margin" ) {
- // we use jQuery.css instead of curCSS here
- // because of the reliableMarginRight CSS hook!
- val += jQuery.css( elem, extra + cssExpand[ i ], true );
- }
-
- // From this point on we use curCSS for maximum performance (relevant in animations)
- if ( isBorderBox ) {
- // border-box includes padding, so remove it if we want content
- if ( extra === "content" ) {
- val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
- }
-
- // at this point, extra isn't border nor margin, so remove border
- if ( extra !== "margin" ) {
- val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
- }
- } else {
- // at this point, extra isn't content, so add padding
- val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0;
-
- // at this point, extra isn't content nor padding, so add border
- if ( extra !== "padding" ) {
- val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
- }
- }
- }
-
- return val;
-}
-
-function getWidthOrHeight( elem, name, extra ) {
-
- // Start with offset property, which is equivalent to the border-box value
- var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
- valueIsBorderBox = true,
- isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box";
-
- // some non-html elements return undefined for offsetWidth, so check for null/undefined
- // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
- // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
- if ( val <= 0 || val == null ) {
- // Fall back to computed then uncomputed css if necessary
- val = curCSS( elem, name );
- if ( val < 0 || val == null ) {
- val = elem.style[ name ];
- }
-
- // Computed unit is not pixels. Stop here and return.
- if ( rnumnonpx.test(val) ) {
- return val;
- }
-
- // we need the check for style in case a browser which returns unreliable values
- // for getComputedStyle silently falls back to the reliable elem.style
- valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
-
- // Normalize "", auto, and prepare for extra
- val = parseFloat( val ) || 0;
- }
-
- // use the active box-sizing model to add/subtract irrelevant styles
- return ( val +
- augmentWidthOrHeight(
- elem,
- name,
- extra || ( isBorderBox ? "border" : "content" ),
- valueIsBorderBox
- )
- ) + "px";
-}
-
-
-// Try to determine the default display value of an element
-function css_defaultDisplay( nodeName ) {
- if ( elemdisplay[ nodeName ] ) {
- return elemdisplay[ nodeName ];
- }
-
- var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ),
- display = elem.css("display");
- elem.remove();
-
- // If the simple way fails,
- // get element's real default display by attaching it to a temp iframe
- if ( display === "none" || display === "" ) {
- // Use the already-created iframe if possible
- iframe = document.body.appendChild(
- iframe || jQuery.extend( document.createElement("iframe"), {
- frameBorder: 0,
- width: 0,
- height: 0
- })
- );
-
- // Create a cacheable copy of the iframe document on first call.
- // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
- // document to it; WebKit & Firefox won't allow reusing the iframe document.
- if ( !iframeDoc || !iframe.createElement ) {
- iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
- iframeDoc.write("<!doctype html><html><body>");
- iframeDoc.close();
- }
-
- elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) );
-
- display = curCSS( elem, "display" );
- document.body.removeChild( iframe );
- }
-
- // Store the correct default display
- elemdisplay[ nodeName ] = display;
-
- return display;
-}
-
-jQuery.each([ "height", "width" ], function( i, name ) {
- jQuery.cssHooks[ name ] = {
- get: function( elem, computed, extra ) {
- if ( computed ) {
- // certain elements can have dimension info if we invisibly show them
- // however, it must have a current display style that would benefit from this
- if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) {
- return jQuery.swap( elem, cssShow, function() {
- return getWidthOrHeight( elem, name, extra );
- });
- } else {
- return getWidthOrHeight( elem, name, extra );
- }
- }
- },
-
- set: function( elem, value, extra ) {
- return setPositiveNumber( elem, value, extra ?
- augmentWidthOrHeight(
- elem,
- name,
- extra,
- jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"
- ) : 0
- );
- }
- };
-});
-
-if ( !jQuery.support.opacity ) {
- jQuery.cssHooks.opacity = {
- get: function( elem, computed ) {
- // IE uses filters for opacity
- return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
- ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
- computed ? "1" : "";
- },
-
- set: function( elem, value ) {
- var style = elem.style,
- currentStyle = elem.currentStyle,
- opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
- filter = currentStyle && currentStyle.filter || style.filter || "";
-
- // IE has trouble with opacity if it does not have layout
- // Force it by setting the zoom level
- style.zoom = 1;
-
- // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
- if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
- style.removeAttribute ) {
-
- // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
- // if "filter:" is present at all, clearType is disabled, we want to avoid this
- // style.removeAttribute is IE Only, but so apparently is this code path...
- style.removeAttribute( "filter" );
-
- // if there there is no filter style applied in a css rule, we are done
- if ( currentStyle && !currentStyle.filter ) {
- return;
- }
- }
-
- // otherwise, set new filter values
- style.filter = ralpha.test( filter ) ?
- filter.replace( ralpha, opacity ) :
- filter + " " + opacity;
- }
- };
-}
-
-// These hooks cannot be added until DOM ready because the support test
-// for it is not run until after DOM ready
-jQuery(function() {
- if ( !jQuery.support.reliableMarginRight ) {
- jQuery.cssHooks.marginRight = {
- get: function( elem, computed ) {
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- // Work around by temporarily setting element display to inline-block
- return jQuery.swap( elem, { "display": "inline-block" }, function() {
- if ( computed ) {
- return curCSS( elem, "marginRight" );
- }
- });
- }
- };
- }
-
- // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
- // getComputedStyle returns percent when specified for top/left/bottom/right
- // rather than make the css module depend on the offset module, we just check for it here
- if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
- jQuery.each( [ "top", "left" ], function( i, prop ) {
- jQuery.cssHooks[ prop ] = {
- get: function( elem, computed ) {
- if ( computed ) {
- var ret = curCSS( elem, prop );
- // if curCSS returns percentage, fallback to offset
- return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret;
- }
- }
- };
- });
- }
-
-});
-
-if ( jQuery.expr && jQuery.expr.filters ) {
- jQuery.expr.filters.hidden = function( elem ) {
- return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none");
- };
-
- jQuery.expr.filters.visible = function( elem ) {
- return !jQuery.expr.filters.hidden( elem );
- };
-}
-
-// These hooks are used by animate to expand properties
-jQuery.each({
- margin: "",
- padding: "",
- border: "Width"
-}, function( prefix, suffix ) {
- jQuery.cssHooks[ prefix + suffix ] = {
- expand: function( value ) {
- var i,
-
- // assumes a single number if not a string
- parts = typeof value === "string" ? value.split(" ") : [ value ],
- expanded = {};
-
- for ( i = 0; i < 4; i++ ) {
- expanded[ prefix + cssExpand[ i ] + suffix ] =
- parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
- }
-
- return expanded;
- }
- };
-
- if ( !rmargin.test( prefix ) ) {
- jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
- }
-});
-var r20 = /%20/g,
- rbracket = /\[\]$/,
- rCRLF = /\r?\n/g,
- rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
- rselectTextarea = /^(?:select|textarea)/i;
-
-jQuery.fn.extend({
- serialize: function() {
- return jQuery.param( this.serializeArray() );
- },
- serializeArray: function() {
- return this.map(function(){
- return this.elements ? jQuery.makeArray( this.elements ) : this;
- })
- .filter(function(){
- return this.name && !this.disabled &&
- ( this.checked || rselectTextarea.test( this.nodeName ) ||
- rinput.test( this.type ) );
- })
- .map(function( i, elem ){
- var val = jQuery( this ).val();
-
- return val == null ?
- null :
- jQuery.isArray( val ) ?
- jQuery.map( val, function( val, i ){
- return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }) :
- { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }).get();
- }
-});
-
-//Serialize an array of form elements or a set of
-//key/values into a query string
-jQuery.param = function( a, traditional ) {
- var prefix,
- s = [],
- add = function( key, value ) {
- // If value is a function, invoke it and return its value
- value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
- s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
- };
-
- // Set traditional to true for jQuery <= 1.3.2 behavior.
- if ( traditional === undefined ) {
- traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
- }
-
- // If an array was passed in, assume that it is an array of form elements.
- if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
- // Serialize the form elements
- jQuery.each( a, function() {
- add( this.name, this.value );
- });
-
- } else {
- // If traditional, encode the "old" way (the way 1.3.2 or older
- // did it), otherwise encode params recursively.
- for ( prefix in a ) {
- buildParams( prefix, a[ prefix ], traditional, add );
- }
- }
-
- // Return the resulting serialization
- return s.join( "&" ).replace( r20, "+" );
-};
-
-function buildParams( prefix, obj, traditional, add ) {
- var name;
-
- if ( jQuery.isArray( obj ) ) {
- // Serialize array item.
- jQuery.each( obj, function( i, v ) {
- if ( traditional || rbracket.test( prefix ) ) {
- // Treat each array item as a scalar.
- add( prefix, v );
-
- } else {
- // If array item is non-scalar (array or object), encode its
- // numeric index to resolve deserialization ambiguity issues.
- // Note that rack (as of 1.0.0) can't currently deserialize
- // nested arrays properly, and attempting to do so may cause
- // a server error. Possible fixes are to modify rack's
- // deserialization algorithm or to provide an option or flag
- // to force array serialization to be shallow.
- buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
- }
- });
-
- } else if ( !traditional && jQuery.type( obj ) === "object" ) {
- // Serialize object item.
- for ( name in obj ) {
- buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
- }
-
- } else {
- // Serialize scalar item.
- add( prefix, obj );
- }
-}
-var
- // Document location
- ajaxLocParts,
- ajaxLocation,
-
- rhash = /#.*$/,
- rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
- // #7653, #8125, #8152: local protocol detection
- rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
- rnoContent = /^(?:GET|HEAD)$/,
- rprotocol = /^\/\//,
- rquery = /\?/,
- rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
- rts = /([?&])_=[^&]*/,
- rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
-
- // Keep a copy of the old load method
- _load = jQuery.fn.load,
-
- /* Prefilters
- * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
- * 2) These are called:
- * - BEFORE asking for a transport
- * - AFTER param serialization (s.data is a string if s.processData is true)
- * 3) key is the dataType
- * 4) the catchall symbol "*" can be used
- * 5) execution will start with transport dataType and THEN continue down to "*" if needed
- */
- prefilters = {},
-
- /* Transports bindings
- * 1) key is the dataType
- * 2) the catchall symbol "*" can be used
- * 3) selection will start with transport dataType and THEN go to "*" if needed
- */
- transports = {},
-
- // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
- allTypes = ["*/"] + ["*"];
-
-// #8138, IE may throw an exception when accessing
-// a field from window.location if document.domain has been set
-try {
- ajaxLocation = location.href;
-} catch( e ) {
- // Use the href attribute of an A element
- // since IE will modify it given document.location
- ajaxLocation = document.createElement( "a" );
- ajaxLocation.href = "";
- ajaxLocation = ajaxLocation.href;
-}
-
-// Segment location into parts
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
-
-// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
-function addToPrefiltersOrTransports( structure ) {
-
- // dataTypeExpression is optional and defaults to "*"
- return function( dataTypeExpression, func ) {
-
- if ( typeof dataTypeExpression !== "string" ) {
- func = dataTypeExpression;
- dataTypeExpression = "*";
- }
-
- var dataType, list, placeBefore,
- dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ),
- i = 0,
- length = dataTypes.length;
-
- if ( jQuery.isFunction( func ) ) {
- // For each dataType in the dataTypeExpression
- for ( ; i < length; i++ ) {
- dataType = dataTypes[ i ];
- // We control if we're asked to add before
- // any existing element
- placeBefore = /^\+/.test( dataType );
- if ( placeBefore ) {
- dataType = dataType.substr( 1 ) || "*";
- }
- list = structure[ dataType ] = structure[ dataType ] || [];
- // then we add to the structure accordingly
- list[ placeBefore ? "unshift" : "push" ]( func );
- }
- }
- };
-}
-
-// Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
- dataType /* internal */, inspected /* internal */ ) {
-
- dataType = dataType || options.dataTypes[ 0 ];
- inspected = inspected || {};
-
- inspected[ dataType ] = true;
-
- var selection,
- list = structure[ dataType ],
- i = 0,
- length = list ? list.length : 0,
- executeOnly = ( structure === prefilters );
-
- for ( ; i < length && ( executeOnly || !selection ); i++ ) {
- selection = list[ i ]( options, originalOptions, jqXHR );
- // If we got redirected to another dataType
- // we try there if executing only and not done already
- if ( typeof selection === "string" ) {
- if ( !executeOnly || inspected[ selection ] ) {
- selection = undefined;
- } else {
- options.dataTypes.unshift( selection );
- selection = inspectPrefiltersOrTransports(
- structure, options, originalOptions, jqXHR, selection, inspected );
- }
- }
- }
- // If we're only executing or nothing was selected
- // we try the catchall dataType if not done already
- if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
- selection = inspectPrefiltersOrTransports(
- structure, options, originalOptions, jqXHR, "*", inspected );
- }
- // unnecessary when only executing (prefilters)
- // but it'll be ignored by the caller in that case
- return selection;
-}
-
-// A special extend for ajax options
-// that takes "flat" options (not to be deep extended)
-// Fixes #9887
-function ajaxExtend( target, src ) {
- var key, deep,
- flatOptions = jQuery.ajaxSettings.flatOptions || {};
- for ( key in src ) {
- if ( src[ key ] !== undefined ) {
- ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
- }
- }
- if ( deep ) {
- jQuery.extend( true, target, deep );
- }
-}
-
-jQuery.fn.load = function( url, params, callback ) {
- if ( typeof url !== "string" && _load ) {
- return _load.apply( this, arguments );
- }
-
- // Don't do a request if no elements are being requested
- if ( !this.length ) {
- return this;
- }
-
- var selector, type, response,
- self = this,
- off = url.indexOf(" ");
-
- if ( off >= 0 ) {
- selector = url.slice( off, url.length );
- url = url.slice( 0, off );
- }
-
- // If it's a function
- if ( jQuery.isFunction( params ) ) {
-
- // We assume that it's the callback
- callback = params;
- params = undefined;
-
- // Otherwise, build a param string
- } else if ( params && typeof params === "object" ) {
- type = "POST";
- }
-
- // Request the remote document
- jQuery.ajax({
- url: url,
-
- // if "type" variable is undefined, then "GET" method will be used
- type: type,
- dataType: "html",
- data: params,
- complete: function( jqXHR, status ) {
- if ( callback ) {
- self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
- }
- }
- }).done(function( responseText ) {
-
- // Save response for use in complete callback
- response = arguments;
-
- // See if a selector was specified
- self.html( selector ?
-
- // Create a dummy div to hold the results
- jQuery("<div>")
-
- // inject the contents of the document in, removing the scripts
- // to avoid any 'Permission Denied' errors in IE
- .append( responseText.replace( rscript, "" ) )
-
- // Locate the specified elements
- .find( selector ) :
-
- // If not, just inject the full result
- responseText );
-
- });
-
- return this;
-};
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
- jQuery.fn[ o ] = function( f ){
- return this.on( o, f );
- };
-});
-
-jQuery.each( [ "get", "post" ], function( i, method ) {
- jQuery[ method ] = function( url, data, callback, type ) {
- // shift arguments if data argument was omitted
- if ( jQuery.isFunction( data ) ) {
- type = type || callback;
- callback = data;
- data = undefined;
- }
-
- return jQuery.ajax({
- type: method,
- url: url,
- data: data,
- success: callback,
- dataType: type
- });
- };
-});
-
-jQuery.extend({
-
- getScript: function( url, callback ) {
- return jQuery.get( url, undefined, callback, "script" );
- },
-
- getJSON: function( url, data, callback ) {
- return jQuery.get( url, data, callback, "json" );
- },
-
- // Creates a full fledged settings object into target
- // with both ajaxSettings and settings fields.
- // If target is omitted, writes into ajaxSettings.
- ajaxSetup: function( target, settings ) {
- if ( settings ) {
- // Building a settings object
- ajaxExtend( target, jQuery.ajaxSettings );
- } else {
- // Extending ajaxSettings
- settings = target;
- target = jQuery.ajaxSettings;
- }
- ajaxExtend( target, settings );
- return target;
- },
-
- ajaxSettings: {
- url: ajaxLocation,
- isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
- global: true,
- type: "GET",
- contentType: "application/x-www-form-urlencoded; charset=UTF-8",
- processData: true,
- async: true,
- /*
- timeout: 0,
- data: null,
- dataType: null,
- username: null,
- password: null,
- cache: null,
- throws: false,
- traditional: false,
- headers: {},
- */
-
- accepts: {
- xml: "application/xml, text/xml",
- html: "text/html",
- text: "text/plain",
- json: "application/json, text/javascript",
- "*": allTypes
- },
-
- contents: {
- xml: /xml/,
- html: /html/,
- json: /json/
- },
-
- responseFields: {
- xml: "responseXML",
- text: "responseText"
- },
-
- // List of data converters
- // 1) key format is "source_type destination_type" (a single space in-between)
- // 2) the catchall symbol "*" can be used for source_type
- converters: {
-
- // Convert anything to text
- "* text": window.String,
-
- // Text to html (true = no transformation)
- "text html": true,
-
- // Evaluate text as a json expression
- "text json": jQuery.parseJSON,
-
- // Parse text as xml
- "text xml": jQuery.parseXML
- },
-
- // For options that shouldn't be deep extended:
- // you can add your own custom options here if
- // and when you create one that shouldn't be
- // deep extended (see ajaxExtend)
- flatOptions: {
- context: true,
- url: true
- }
- },
-
- ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
- ajaxTransport: addToPrefiltersOrTransports( transports ),
-
- // Main method
- ajax: function( url, options ) {
-
- // If url is an object, simulate pre-1.5 signature
- if ( typeof url === "object" ) {
- options = url;
- url = undefined;
- }
-
- // Force options to be an object
- options = options || {};
-
- var // ifModified key
- ifModifiedKey,
- // Response headers
- responseHeadersString,
- responseHeaders,
- // transport
- transport,
- // timeout handle
- timeoutTimer,
- // Cross-domain detection vars
- parts,
- // To know if global events are to be dispatched
- fireGlobals,
- // Loop variable
- i,
- // Create the final options object
- s = jQuery.ajaxSetup( {}, options ),
- // Callbacks context
- callbackContext = s.context || s,
- // Context for global events
- // It's the callbackContext if one was provided in the options
- // and if it's a DOM node or a jQuery collection
- globalEventContext = callbackContext !== s &&
- ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
- jQuery( callbackContext ) : jQuery.event,
- // Deferreds
- deferred = jQuery.Deferred(),
- completeDeferred = jQuery.Callbacks( "once memory" ),
- // Status-dependent callbacks
- statusCode = s.statusCode || {},
- // Headers (they are sent all at once)
- requestHeaders = {},
- requestHeadersNames = {},
- // The jqXHR state
- state = 0,
- // Default abort message
- strAbort = "canceled",
- // Fake xhr
- jqXHR = {
-
- readyState: 0,
-
- // Caches the header
- setRequestHeader: function( name, value ) {
- if ( !state ) {
- var lname = name.toLowerCase();
- name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
- requestHeaders[ name ] = value;
- }
- return this;
- },
-
- // Raw string
- getAllResponseHeaders: function() {
- return state === 2 ? responseHeadersString : null;
- },
-
- // Builds headers hashtable if needed
- getResponseHeader: function( key ) {
- var match;
- if ( state === 2 ) {
- if ( !responseHeaders ) {
- responseHeaders = {};
- while( ( match = rheaders.exec( responseHeadersString ) ) ) {
- responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
- }
- }
- match = responseHeaders[ key.toLowerCase() ];
- }
- return match === undefined ? null : match;
- },
-
- // Overrides response content-type header
- overrideMimeType: function( type ) {
- if ( !state ) {
- s.mimeType = type;
- }
- return this;
- },
-
- // Cancel the request
- abort: function( statusText ) {
- statusText = statusText || strAbort;
- if ( transport ) {
- transport.abort( statusText );
- }
- done( 0, statusText );
- return this;
- }
- };
-
- // Callback for when everything is done
- // It is defined here because jslint complains if it is declared
- // at the end of the function (which would be more logical and readable)
- function done( status, nativeStatusText, responses, headers ) {
- var isSuccess, success, error, response, modified,
- statusText = nativeStatusText;
-
- // Called once
- if ( state === 2 ) {
- return;
- }
-
- // State is "done" now
- state = 2;
-
- // Clear timeout if it exists
- if ( timeoutTimer ) {
- clearTimeout( timeoutTimer );
- }
-
- // Dereference transport for early garbage collection
- // (no matter how long the jqXHR object will be used)
- transport = undefined;
-
- // Cache response headers
- responseHeadersString = headers || "";
-
- // Set readyState
- jqXHR.readyState = status > 0 ? 4 : 0;
-
- // Get response data
- if ( responses ) {
- response = ajaxHandleResponses( s, jqXHR, responses );
- }
-
- // If successful, handle type chaining
- if ( status >= 200 && status < 300 || status === 304 ) {
-
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- if ( s.ifModified ) {
-
- modified = jqXHR.getResponseHeader("Last-Modified");
- if ( modified ) {
- jQuery.lastModified[ ifModifiedKey ] = modified;
- }
- modified = jqXHR.getResponseHeader("Etag");
- if ( modified ) {
- jQuery.etag[ ifModifiedKey ] = modified;
- }
- }
-
- // If not modified
- if ( status === 304 ) {
-
- statusText = "notmodified";
- isSuccess = true;
-
- // If we have data
- } else {
-
- isSuccess = ajaxConvert( s, response );
- statusText = isSuccess.state;
- success = isSuccess.data;
- error = isSuccess.error;
- isSuccess = !error;
- }
- } else {
- // We extract error from statusText
- // then normalize statusText and status for non-aborts
- error = statusText;
- if ( !statusText || status ) {
- statusText = "error";
- if ( status < 0 ) {
- status = 0;
- }
- }
- }
-
- // Set data for the fake xhr object
- jqXHR.status = status;
- jqXHR.statusText = ( nativeStatusText || statusText ) + "";
-
- // Success/Error
- if ( isSuccess ) {
- deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
- } else {
- deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
- }
-
- // Status-dependent callbacks
- jqXHR.statusCode( statusCode );
- statusCode = undefined;
-
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
- [ jqXHR, s, isSuccess ? success : error ] );
- }
-
- // Complete
- completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
-
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
- // Handle the global AJAX counter
- if ( !( --jQuery.active ) ) {
- jQuery.event.trigger( "ajaxStop" );
- }
- }
- }
-
- // Attach deferreds
- deferred.promise( jqXHR );
- jqXHR.success = jqXHR.done;
- jqXHR.error = jqXHR.fail;
- jqXHR.complete = completeDeferred.add;
-
- // Status-dependent callbacks
- jqXHR.statusCode = function( map ) {
- if ( map ) {
- var tmp;
- if ( state < 2 ) {
- for ( tmp in map ) {
- statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
- }
- } else {
- tmp = map[ jqXHR.status ];
- jqXHR.always( tmp );
- }
- }
- return this;
- };
-
- // Remove hash character (#7531: and string promotion)
- // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
- // We also use the url parameter if available
- s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
-
- // Extract dataTypes list
- s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace );
-
- // A cross-domain request is in order when we have a protocol:host:port mismatch
- if ( s.crossDomain == null ) {
- parts = rurl.exec( s.url.toLowerCase() ) || false;
- s.crossDomain = parts && ( parts.join(":") + ( parts[ 3 ] ? "" : parts[ 1 ] === "http:" ? 80 : 443 ) ) !==
- ( ajaxLocParts.join(":") + ( ajaxLocParts[ 3 ] ? "" : ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) );
- }
-
- // Convert data if not already a string
- if ( s.data && s.processData && typeof s.data !== "string" ) {
- s.data = jQuery.param( s.data, s.traditional );
- }
-
- // Apply prefilters
- inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
- // If request was aborted inside a prefilter, stop there
- if ( state === 2 ) {
- return jqXHR;
- }
-
- // We can fire global events as of now if asked to
- fireGlobals = s.global;
-
- // Uppercase the type
- s.type = s.type.toUpperCase();
-
- // Determine if request has content
- s.hasContent = !rnoContent.test( s.type );
-
- // Watch for a new set of requests
- if ( fireGlobals && jQuery.active++ === 0 ) {
- jQuery.event.trigger( "ajaxStart" );
- }
-
- // More options handling for requests with no content
- if ( !s.hasContent ) {
-
- // If data is available, append data to url
- if ( s.data ) {
- s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
- // #9682: remove data so that it's not used in an eventual retry
- delete s.data;
- }
-
- // Get ifModifiedKey before adding the anti-cache parameter
- ifModifiedKey = s.url;
-
- // Add anti-cache in url if needed
- if ( s.cache === false ) {
-
- var ts = jQuery.now(),
- // try replacing _= if it is there
- ret = s.url.replace( rts, "$1_=" + ts );
-
- // if nothing was replaced, add timestamp to the end
- s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
- }
- }
-
- // Set the correct header, if data is being sent
- if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
- jqXHR.setRequestHeader( "Content-Type", s.contentType );
- }
-
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- if ( s.ifModified ) {
- ifModifiedKey = ifModifiedKey || s.url;
- if ( jQuery.lastModified[ ifModifiedKey ] ) {
- jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
- }
- if ( jQuery.etag[ ifModifiedKey ] ) {
- jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
- }
- }
-
- // Set the Accepts header for the server, depending on the dataType
- jqXHR.setRequestHeader(
- "Accept",
- s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
- s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
- s.accepts[ "*" ]
- );
-
- // Check for headers option
- for ( i in s.headers ) {
- jqXHR.setRequestHeader( i, s.headers[ i ] );
- }
-
- // Allow custom headers/mimetypes and early abort
- if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
- // Abort if not done already and return
- return jqXHR.abort();
-
- }
-
- // aborting is no longer a cancellation
- strAbort = "abort";
-
- // Install callbacks on deferreds
- for ( i in { success: 1, error: 1, complete: 1 } ) {
- jqXHR[ i ]( s[ i ] );
- }
-
- // Get transport
- transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
-
- // If no transport, we auto-abort
- if ( !transport ) {
- done( -1, "No Transport" );
- } else {
- jqXHR.readyState = 1;
- // Send global event
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
- }
- // Timeout
- if ( s.async && s.timeout > 0 ) {
- timeoutTimer = setTimeout( function(){
- jqXHR.abort( "timeout" );
- }, s.timeout );
- }
-
- try {
- state = 1;
- transport.send( requestHeaders, done );
- } catch (e) {
- // Propagate exception as error if not done
- if ( state < 2 ) {
- done( -1, e );
- // Simply rethrow otherwise
- } else {
- throw e;
- }
- }
- }
-
- return jqXHR;
- },
-
- // Counter for holding the number of active queries
- active: 0,
-
- // Last-Modified header cache for next request
- lastModified: {},
- etag: {}
-
-});
-
-/* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
- * - finds the right dataType (mediates between content-type and expected dataType)
- * - returns the corresponding response
- */
-function ajaxHandleResponses( s, jqXHR, responses ) {
-
- var ct, type, finalDataType, firstDataType,
- contents = s.contents,
- dataTypes = s.dataTypes,
- responseFields = s.responseFields;
-
- // Fill responseXXX fields
- for ( type in responseFields ) {
- if ( type in responses ) {
- jqXHR[ responseFields[type] ] = responses[ type ];
- }
- }
-
- // Remove auto dataType and get content-type in the process
- while( dataTypes[ 0 ] === "*" ) {
- dataTypes.shift();
- if ( ct === undefined ) {
- ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
- }
- }
-
- // Check if we're dealing with a known content-type
- if ( ct ) {
- for ( type in contents ) {
- if ( contents[ type ] && contents[ type ].test( ct ) ) {
- dataTypes.unshift( type );
- break;
- }
- }
- }
-
- // Check to see if we have a response for the expected dataType
- if ( dataTypes[ 0 ] in responses ) {
- finalDataType = dataTypes[ 0 ];
- } else {
- // Try convertible dataTypes
- for ( type in responses ) {
- if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
- finalDataType = type;
- break;
- }
- if ( !firstDataType ) {
- firstDataType = type;
- }
- }
- // Or just use first one
- finalDataType = finalDataType || firstDataType;
- }
-
- // If we found a dataType
- // We add the dataType to the list if needed
- // and return the corresponding response
- if ( finalDataType ) {
- if ( finalDataType !== dataTypes[ 0 ] ) {
- dataTypes.unshift( finalDataType );
- }
- return responses[ finalDataType ];
- }
-}
-
-// Chain conversions given the request and the original response
-function ajaxConvert( s, response ) {
-
- var conv, conv2, current, tmp,
- // Work with a copy of dataTypes in case we need to modify it for conversion
- dataTypes = s.dataTypes.slice(),
- prev = dataTypes[ 0 ],
- converters = {},
- i = 0;
-
- // Apply the dataFilter if provided
- if ( s.dataFilter ) {
- response = s.dataFilter( response, s.dataType );
- }
-
- // Create converters map with lowercased keys
- if ( dataTypes[ 1 ] ) {
- for ( conv in s.converters ) {
- converters[ conv.toLowerCase() ] = s.converters[ conv ];
- }
- }
-
- // Convert to each sequential dataType, tolerating list modification
- for ( ; (current = dataTypes[++i]); ) {
-
- // There's only work to do if current dataType is non-auto
- if ( current !== "*" ) {
-
- // Convert response if prev dataType is non-auto and differs from current
- if ( prev !== "*" && prev !== current ) {
-
- // Seek a direct converter
- conv = converters[ prev + " " + current ] || converters[ "* " + current ];
-
- // If none found, seek a pair
- if ( !conv ) {
- for ( conv2 in converters ) {
-
- // If conv2 outputs current
- tmp = conv2.split(" ");
- if ( tmp[ 1 ] === current ) {
-
- // If prev can be converted to accepted input
- conv = converters[ prev + " " + tmp[ 0 ] ] ||
- converters[ "* " + tmp[ 0 ] ];
- if ( conv ) {
- // Condense equivalence converters
- if ( conv === true ) {
- conv = converters[ conv2 ];
-
- // Otherwise, insert the intermediate dataType
- } else if ( converters[ conv2 ] !== true ) {
- current = tmp[ 0 ];
- dataTypes.splice( i--, 0, current );
- }
-
- break;
- }
- }
- }
- }
-
- // Apply converter (if not an equivalence)
- if ( conv !== true ) {
-
- // Unless errors are allowed to bubble, catch and return them
- if ( conv && s["throws"] ) {
- response = conv( response );
- } else {
- try {
- response = conv( response );
- } catch ( e ) {
- return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
- }
- }
- }
- }
-
- // Update prev for next iteration
- prev = current;
- }
- }
-
- return { state: "success", data: response };
-}
-var oldCallbacks = [],
- rquestion = /\?/,
- rjsonp = /(=)\?(?=&|$)|\?\?/,
- nonce = jQuery.now();
-
-// Default jsonp settings
-jQuery.ajaxSetup({
- jsonp: "callback",
- jsonpCallback: function() {
- var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
- this[ callback ] = true;
- return callback;
- }
-});
-
-// Detect, normalize options and install callbacks for jsonp requests
-jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
-
- var callbackName, overwritten, responseContainer,
- data = s.data,
- url = s.url,
- hasCallback = s.jsonp !== false,
- replaceInUrl = hasCallback && rjsonp.test( url ),
- replaceInData = hasCallback && !replaceInUrl && typeof data === "string" &&
- !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") &&
- rjsonp.test( data );
-
- // Handle iff the expected data type is "jsonp" or we have a parameter to set
- if ( s.dataTypes[ 0 ] === "jsonp" || replaceInUrl || replaceInData ) {
-
- // Get callback name, remembering preexisting value associated with it
- callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
- s.jsonpCallback() :
- s.jsonpCallback;
- overwritten = window[ callbackName ];
-
- // Insert callback into url or form data
- if ( replaceInUrl ) {
- s.url = url.replace( rjsonp, "$1" + callbackName );
- } else if ( replaceInData ) {
- s.data = data.replace( rjsonp, "$1" + callbackName );
- } else if ( hasCallback ) {
- s.url += ( rquestion.test( url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
- }
-
- // Use data converter to retrieve json after script execution
- s.converters["script json"] = function() {
- if ( !responseContainer ) {
- jQuery.error( callbackName + " was not called" );
- }
- return responseContainer[ 0 ];
- };
-
- // force json dataType
- s.dataTypes[ 0 ] = "json";
-
- // Install callback
- window[ callbackName ] = function() {
- responseContainer = arguments;
- };
-
- // Clean-up function (fires after converters)
- jqXHR.always(function() {
- // Restore preexisting value
- window[ callbackName ] = overwritten;
-
- // Save back as free
- if ( s[ callbackName ] ) {
- // make sure that re-using the options doesn't screw things around
- s.jsonpCallback = originalSettings.jsonpCallback;
-
- // save the callback name for future use
- oldCallbacks.push( callbackName );
- }
-
- // Call if it was a function and we have a response
- if ( responseContainer && jQuery.isFunction( overwritten ) ) {
- overwritten( responseContainer[ 0 ] );
- }
-
- responseContainer = overwritten = undefined;
- });
-
- // Delegate to script
- return "script";
- }
-});
-// Install script dataType
-jQuery.ajaxSetup({
- accepts: {
- script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
- },
- contents: {
- script: /javascript|ecmascript/
- },
- converters: {
- "text script": function( text ) {
- jQuery.globalEval( text );
- return text;
- }
- }
-});
-
-// Handle cache's special case and global
-jQuery.ajaxPrefilter( "script", function( s ) {
- if ( s.cache === undefined ) {
- s.cache = false;
- }
- if ( s.crossDomain ) {
- s.type = "GET";
- s.global = false;
- }
-});
-
-// Bind script tag hack transport
-jQuery.ajaxTransport( "script", function(s) {
-
- // This transport only deals with cross domain requests
- if ( s.crossDomain ) {
-
- var script,
- head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
-
- return {
-
- send: function( _, callback ) {
-
- script = document.createElement( "script" );
-
- script.async = "async";
-
- if ( s.scriptCharset ) {
- script.charset = s.scriptCharset;
- }
-
- script.src = s.url;
-
- // Attach handlers for all browsers
- script.onload = script.onreadystatechange = function( _, isAbort ) {
-
- if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
-
- // Handle memory leak in IE
- script.onload = script.onreadystatechange = null;
-
- // Remove the script
- if ( head && script.parentNode ) {
- head.removeChild( script );
- }
-
- // Dereference the script
- script = undefined;
-
- // Callback if not abort
- if ( !isAbort ) {
- callback( 200, "success" );
- }
- }
- };
- // Use insertBefore instead of appendChild to circumvent an IE6 bug.
- // This arises when a base node is used (#2709 and #4378).
- head.insertBefore( script, head.firstChild );
- },
-
- abort: function() {
- if ( script ) {
- script.onload( 0, 1 );
- }
- }
- };
- }
-});
-var xhrCallbacks,
- // #5280: Internet Explorer will keep connections alive if we don't abort on unload
- xhrOnUnloadAbort = window.ActiveXObject ? function() {
- // Abort all pending requests
- for ( var key in xhrCallbacks ) {
- xhrCallbacks[ key ]( 0, 1 );
- }
- } : false,
- xhrId = 0;
-
-// Functions to create xhrs
-function createStandardXHR() {
- try {
- return new window.XMLHttpRequest();
- } catch( e ) {}
-}
-
-function createActiveXHR() {
- try {
- return new window.ActiveXObject( "Microsoft.XMLHTTP" );
- } catch( e ) {}
-}
-
-// Create the request object
-// (This is still attached to ajaxSettings for backward compatibility)
-jQuery.ajaxSettings.xhr = window.ActiveXObject ?
- /* Microsoft failed to properly
- * implement the XMLHttpRequest in IE7 (can't request local files),
- * so we use the ActiveXObject when it is available
- * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
- * we need a fallback.
- */
- function() {
- return !this.isLocal && createStandardXHR() || createActiveXHR();
- } :
- // For all other browsers, use the standard XMLHttpRequest object
- createStandardXHR;
-
-// Determine support properties
-(function( xhr ) {
- jQuery.extend( jQuery.support, {
- ajax: !!xhr,
- cors: !!xhr && ( "withCredentials" in xhr )
- });
-})( jQuery.ajaxSettings.xhr() );
-
-// Create transport if the browser can provide an xhr
-if ( jQuery.support.ajax ) {
-
- jQuery.ajaxTransport(function( s ) {
- // Cross domain only allowed if supported through XMLHttpRequest
- if ( !s.crossDomain || jQuery.support.cors ) {
-
- var callback;
-
- return {
- send: function( headers, complete ) {
-
- // Get a new xhr
- var handle, i,
- xhr = s.xhr();
-
- // Open the socket
- // Passing null username, generates a login popup on Opera (#2865)
- if ( s.username ) {
- xhr.open( s.type, s.url, s.async, s.username, s.password );
- } else {
- xhr.open( s.type, s.url, s.async );
- }
-
- // Apply custom fields if provided
- if ( s.xhrFields ) {
- for ( i in s.xhrFields ) {
- xhr[ i ] = s.xhrFields[ i ];
- }
- }
-
- // Override mime type if needed
- if ( s.mimeType && xhr.overrideMimeType ) {
- xhr.overrideMimeType( s.mimeType );
- }
-
- // X-Requested-With header
- // For cross-domain requests, seeing as conditions for a preflight are
- // akin to a jigsaw puzzle, we simply never set it to be sure.
- // (it can always be set on a per-request basis or even using ajaxSetup)
- // For same-domain requests, won't change header if already provided.
- if ( !s.crossDomain && !headers["X-Requested-With"] ) {
- headers[ "X-Requested-With" ] = "XMLHttpRequest";
- }
-
- // Need an extra try/catch for cross domain requests in Firefox 3
- try {
- for ( i in headers ) {
- xhr.setRequestHeader( i, headers[ i ] );
- }
- } catch( _ ) {}
-
- // Do send the request
- // This may raise an exception which is actually
- // handled in jQuery.ajax (so no try/catch here)
- xhr.send( ( s.hasContent && s.data ) || null );
-
- // Listener
- callback = function( _, isAbort ) {
-
- var status,
- statusText,
- responseHeaders,
- responses,
- xml;
-
- // Firefox throws exceptions when accessing properties
- // of an xhr when a network error occurred
- // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
- try {
-
- // Was never called and is aborted or complete
- if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-
- // Only called once
- callback = undefined;
-
- // Do not keep as active anymore
- if ( handle ) {
- xhr.onreadystatechange = jQuery.noop;
- if ( xhrOnUnloadAbort ) {
- delete xhrCallbacks[ handle ];
- }
- }
-
- // If it's an abort
- if ( isAbort ) {
- // Abort it manually if needed
- if ( xhr.readyState !== 4 ) {
- xhr.abort();
- }
- } else {
- status = xhr.status;
- responseHeaders = xhr.getAllResponseHeaders();
- responses = {};
- xml = xhr.responseXML;
-
- // Construct response list
- if ( xml && xml.documentElement /* #4958 */ ) {
- responses.xml = xml;
- }
-
- // When requesting binary data, IE6-9 will throw an exception
- // on any attempt to access responseText (#11426)
- try {
- responses.text = xhr.responseText;
- } catch( _ ) {
- }
-
- // Firefox throws an exception when accessing
- // statusText for faulty cross-domain requests
- try {
- statusText = xhr.statusText;
- } catch( e ) {
- // We normalize with Webkit giving an empty statusText
- statusText = "";
- }
-
- // Filter status for non standard behaviors
-
- // If the request is local and we have data: assume a success
- // (success with no data won't get notified, that's the best we
- // can do given current implementations)
- if ( !status && s.isLocal && !s.crossDomain ) {
- status = responses.text ? 200 : 404;
- // IE - #1450: sometimes returns 1223 when it should be 204
- } else if ( status === 1223 ) {
- status = 204;
- }
- }
- }
- } catch( firefoxAccessException ) {
- if ( !isAbort ) {
- complete( -1, firefoxAccessException );
- }
- }
-
- // Call complete if needed
- if ( responses ) {
- complete( status, statusText, responses, responseHeaders );
- }
- };
-
- if ( !s.async ) {
- // if we're in sync mode we fire the callback
- callback();
- } else if ( xhr.readyState === 4 ) {
- // (IE6 & IE7) if it's in cache and has been
- // retrieved directly we need to fire the callback
- setTimeout( callback, 0 );
- } else {
- handle = ++xhrId;
- if ( xhrOnUnloadAbort ) {
- // Create the active xhrs callbacks list if needed
- // and attach the unload handler
- if ( !xhrCallbacks ) {
- xhrCallbacks = {};
- jQuery( window ).unload( xhrOnUnloadAbort );
- }
- // Add to list of active xhrs callbacks
- xhrCallbacks[ handle ] = callback;
- }
- xhr.onreadystatechange = callback;
- }
- },
-
- abort: function() {
- if ( callback ) {
- callback(0,1);
- }
- }
- };
- }
- });
-}
-var fxNow, timerId,
- rfxtypes = /^(?:toggle|show|hide)$/,
- rfxnum = new RegExp( "^(?:([-+])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
- rrun = /queueHooks$/,
- animationPrefilters = [ defaultPrefilter ],
- tweeners = {
- "*": [function( prop, value ) {
- var end, unit,
- tween = this.createTween( prop, value ),
- parts = rfxnum.exec( value ),
- target = tween.cur(),
- start = +target || 0,
- scale = 1,
- maxIterations = 20;
-
- if ( parts ) {
- end = +parts[2];
- unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
-
- // We need to compute starting value
- if ( unit !== "px" && start ) {
- // Iteratively approximate from a nonzero starting point
- // Prefer the current property, because this process will be trivial if it uses the same units
- // Fallback to end or a simple constant
- start = jQuery.css( tween.elem, prop, true ) || end || 1;
-
- do {
- // If previous iteration zeroed out, double until we get *something*
- // Use a string for doubling factor so we don't accidentally see scale as unchanged below
- scale = scale || ".5";
-
- // Adjust and apply
- start = start / scale;
- jQuery.style( tween.elem, prop, start + unit );
-
- // Update scale, tolerating zero or NaN from tween.cur()
- // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
- } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
- }
-
- tween.unit = unit;
- tween.start = start;
- // If a +=/-= token was provided, we're doing a relative animation
- tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
- }
- return tween;
- }]
- };
-
-// Animations created synchronously will run synchronously
-function createFxNow() {
- setTimeout(function() {
- fxNow = undefined;
- }, 0 );
- return ( fxNow = jQuery.now() );
-}
-
-function createTweens( animation, props ) {
- jQuery.each( props, function( prop, value ) {
- var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
- index = 0,
- length = collection.length;
- for ( ; index < length; index++ ) {
- if ( collection[ index ].call( animation, prop, value ) ) {
-
- // we're done with this property
- return;
- }
- }
- });
-}
-
-function Animation( elem, properties, options ) {
- var result,
- index = 0,
- tweenerIndex = 0,
- length = animationPrefilters.length,
- deferred = jQuery.Deferred().always( function() {
- // don't match elem in the :animated selector
- delete tick.elem;
- }),
- tick = function() {
- var currentTime = fxNow || createFxNow(),
- remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
- percent = 1 - ( remaining / animation.duration || 0 ),
- index = 0,
- length = animation.tweens.length;
-
- for ( ; index < length ; index++ ) {
- animation.tweens[ index ].run( percent );
- }
-
- deferred.notifyWith( elem, [ animation, percent, remaining ]);
-
- if ( percent < 1 && length ) {
- return remaining;
- } else {
- deferred.resolveWith( elem, [ animation ] );
- return false;
- }
- },
- animation = deferred.promise({
- elem: elem,
- props: jQuery.extend( {}, properties ),
- opts: jQuery.extend( true, { specialEasing: {} }, options ),
- originalProperties: properties,
- originalOptions: options,
- startTime: fxNow || createFxNow(),
- duration: options.duration,
- tweens: [],
- createTween: function( prop, end, easing ) {
- var tween = jQuery.Tween( elem, animation.opts, prop, end,
- animation.opts.specialEasing[ prop ] || animation.opts.easing );
- animation.tweens.push( tween );
- return tween;
- },
- stop: function( gotoEnd ) {
- var index = 0,
- // if we are going to the end, we want to run all the tweens
- // otherwise we skip this part
- length = gotoEnd ? animation.tweens.length : 0;
-
- for ( ; index < length ; index++ ) {
- animation.tweens[ index ].run( 1 );
- }
-
- // resolve when we played the last frame
- // otherwise, reject
- if ( gotoEnd ) {
- deferred.resolveWith( elem, [ animation, gotoEnd ] );
- } else {
- deferred.rejectWith( elem, [ animation, gotoEnd ] );
- }
- return this;
- }
- }),
- props = animation.props;
-
- propFilter( props, animation.opts.specialEasing );
-
- for ( ; index < length ; index++ ) {
- result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
- if ( result ) {
- return result;
- }
- }
-
- createTweens( animation, props );
-
- if ( jQuery.isFunction( animation.opts.start ) ) {
- animation.opts.start.call( elem, animation );
- }
-
- jQuery.fx.timer(
- jQuery.extend( tick, {
- anim: animation,
- queue: animation.opts.queue,
- elem: elem
- })
- );
-
- // attach callbacks from options
- return animation.progress( animation.opts.progress )
- .done( animation.opts.done, animation.opts.complete )
- .fail( animation.opts.fail )
- .always( animation.opts.always );
-}
-
-function propFilter( props, specialEasing ) {
- var index, name, easing, value, hooks;
-
- // camelCase, specialEasing and expand cssHook pass
- for ( index in props ) {
- name = jQuery.camelCase( index );
- easing = specialEasing[ name ];
- value = props[ index ];
- if ( jQuery.isArray( value ) ) {
- easing = value[ 1 ];
- value = props[ index ] = value[ 0 ];
- }
-
- if ( index !== name ) {
- props[ name ] = value;
- delete props[ index ];
- }
-
- hooks = jQuery.cssHooks[ name ];
- if ( hooks && "expand" in hooks ) {
- value = hooks.expand( value );
- delete props[ name ];
-
- // not quite $.extend, this wont overwrite keys already present.
- // also - reusing 'index' from above because we have the correct "name"
- for ( index in value ) {
- if ( !( index in props ) ) {
- props[ index ] = value[ index ];
- specialEasing[ index ] = easing;
- }
- }
- } else {
- specialEasing[ name ] = easing;
- }
- }
-}
-
-jQuery.Animation = jQuery.extend( Animation, {
-
- tweener: function( props, callback ) {
- if ( jQuery.isFunction( props ) ) {
- callback = props;
- props = [ "*" ];
- } else {
- props = props.split(" ");
- }
-
- var prop,
- index = 0,
- length = props.length;
-
- for ( ; index < length ; index++ ) {
- prop = props[ index ];
- tweeners[ prop ] = tweeners[ prop ] || [];
- tweeners[ prop ].unshift( callback );
- }
- },
-
- prefilter: function( callback, prepend ) {
- if ( prepend ) {
- animationPrefilters.unshift( callback );
- } else {
- animationPrefilters.push( callback );
- }
- }
-});
-
-function defaultPrefilter( elem, props, opts ) {
- var index, prop, value, length, dataShow, tween, hooks, oldfire,
- anim = this,
- style = elem.style,
- orig = {},
- handled = [],
- hidden = elem.nodeType && isHidden( elem );
-
- // handle queue: false promises
- if ( !opts.queue ) {
- hooks = jQuery._queueHooks( elem, "fx" );
- if ( hooks.unqueued == null ) {
- hooks.unqueued = 0;
- oldfire = hooks.empty.fire;
- hooks.empty.fire = function() {
- if ( !hooks.unqueued ) {
- oldfire();
- }
- };
- }
- hooks.unqueued++;
-
- anim.always(function() {
- // doing this makes sure that the complete handler will be called
- // before this completes
- anim.always(function() {
- hooks.unqueued--;
- if ( !jQuery.queue( elem, "fx" ).length ) {
- hooks.empty.fire();
- }
- });
- });
- }
-
- // height/width overflow pass
- if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
- // Make sure that nothing sneaks out
- // Record all 3 overflow attributes because IE does not
- // change the overflow attribute when overflowX and
- // overflowY are set to the same value
- opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
-
- // Set display property to inline-block for height/width
- // animations on inline elements that are having width/height animated
- if ( jQuery.css( elem, "display" ) === "inline" &&
- jQuery.css( elem, "float" ) === "none" ) {
-
- // inline-level elements accept inline-block;
- // block-level elements need to be inline with layout
- if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
- style.display = "inline-block";
-
- } else {
- style.zoom = 1;
- }
- }
- }
-
- if ( opts.overflow ) {
- style.overflow = "hidden";
- if ( !jQuery.support.shrinkWrapBlocks ) {
- anim.done(function() {
- style.overflow = opts.overflow[ 0 ];
- style.overflowX = opts.overflow[ 1 ];
- style.overflowY = opts.overflow[ 2 ];
- });
- }
- }
-
-
- // show/hide pass
- for ( index in props ) {
- value = props[ index ];
- if ( rfxtypes.exec( value ) ) {
- delete props[ index ];
- if ( value === ( hidden ? "hide" : "show" ) ) {
- continue;
- }
- handled.push( index );
- }
- }
-
- length = handled.length;
- if ( length ) {
- dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
- if ( hidden ) {
- jQuery( elem ).show();
- } else {
- anim.done(function() {
- jQuery( elem ).hide();
- });
- }
- anim.done(function() {
- var prop;
- jQuery.removeData( elem, "fxshow", true );
- for ( prop in orig ) {
- jQuery.style( elem, prop, orig[ prop ] );
- }
- });
- for ( index = 0 ; index < length ; index++ ) {
- prop = handled[ index ];
- tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
- orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
-
- if ( !( prop in dataShow ) ) {
- dataShow[ prop ] = tween.start;
- if ( hidden ) {
- tween.end = tween.start;
- tween.start = prop === "width" || prop === "height" ? 1 : 0;
- }
- }
- }
- }
-}
-
-function Tween( elem, options, prop, end, easing ) {
- return new Tween.prototype.init( elem, options, prop, end, easing );
-}
-jQuery.Tween = Tween;
-
-Tween.prototype = {
- constructor: Tween,
- init: function( elem, options, prop, end, easing, unit ) {
- this.elem = elem;
- this.prop = prop;
- this.easing = easing || "swing";
- this.options = options;
- this.start = this.now = this.cur();
- this.end = end;
- this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
- },
- cur: function() {
- var hooks = Tween.propHooks[ this.prop ];
-
- return hooks && hooks.get ?
- hooks.get( this ) :
- Tween.propHooks._default.get( this );
- },
- run: function( percent ) {
- var eased,
- hooks = Tween.propHooks[ this.prop ];
-
- if ( this.options.duration ) {
- this.pos = eased = jQuery.easing[ this.easing ](
- percent, this.options.duration * percent, 0, 1, this.options.duration
- );
- } else {
- this.pos = eased = percent;
- }
- this.now = ( this.end - this.start ) * eased + this.start;
-
- if ( this.options.step ) {
- this.options.step.call( this.elem, this.now, this );
- }
-
- if ( hooks && hooks.set ) {
- hooks.set( this );
- } else {
- Tween.propHooks._default.set( this );
- }
- return this;
- }
-};
-
-Tween.prototype.init.prototype = Tween.prototype;
-
-Tween.propHooks = {
- _default: {
- get: function( tween ) {
- var result;
-
- if ( tween.elem[ tween.prop ] != null &&
- (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
- return tween.elem[ tween.prop ];
- }
-
- // passing any value as a 4th parameter to .css will automatically
- // attempt a parseFloat and fallback to a string if the parse fails
- // so, simple values such as "10px" are parsed to Float.
- // complex values such as "rotate(1rad)" are returned as is.
- result = jQuery.css( tween.elem, tween.prop, false, "" );
- // Empty strings, null, undefined and "auto" are converted to 0.
- return !result || result === "auto" ? 0 : result;
- },
- set: function( tween ) {
- // use step hook for back compat - use cssHook if its there - use .style if its
- // available and use plain properties where available
- if ( jQuery.fx.step[ tween.prop ] ) {
- jQuery.fx.step[ tween.prop ]( tween );
- } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
- jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
- } else {
- tween.elem[ tween.prop ] = tween.now;
- }
- }
- }
-};
-
-// Remove in 2.0 - this supports IE8's panic based approach
-// to setting things on disconnected nodes
-
-Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
- set: function( tween ) {
- if ( tween.elem.nodeType && tween.elem.parentNode ) {
- tween.elem[ tween.prop ] = tween.now;
- }
- }
-};
-
-jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
- var cssFn = jQuery.fn[ name ];
- jQuery.fn[ name ] = function( speed, easing, callback ) {
- return speed == null || typeof speed === "boolean" ||
- // special check for .toggle( handler, handler, ... )
- ( !i && jQuery.isFunction( speed ) && jQuery.isFunction( easing ) ) ?
- cssFn.apply( this, arguments ) :
- this.animate( genFx( name, true ), speed, easing, callback );
- };
-});
-
-jQuery.fn.extend({
- fadeTo: function( speed, to, easing, callback ) {
-
- // show any hidden elements after setting opacity to 0
- return this.filter( isHidden ).css( "opacity", 0 ).show()
-
- // animate to the value specified
- .end().animate({ opacity: to }, speed, easing, callback );
- },
- animate: function( prop, speed, easing, callback ) {
- var empty = jQuery.isEmptyObject( prop ),
- optall = jQuery.speed( speed, easing, callback ),
- doAnimation = function() {
- // Operate on a copy of prop so per-property easing won't be lost
- var anim = Animation( this, jQuery.extend( {}, prop ), optall );
-
- // Empty animations resolve immediately
- if ( empty ) {
- anim.stop( true );
- }
- };
-
- return empty || optall.queue === false ?
- this.each( doAnimation ) :
- this.queue( optall.queue, doAnimation );
- },
- stop: function( type, clearQueue, gotoEnd ) {
- var stopQueue = function( hooks ) {
- var stop = hooks.stop;
- delete hooks.stop;
- stop( gotoEnd );
- };
-
- if ( typeof type !== "string" ) {
- gotoEnd = clearQueue;
- clearQueue = type;
- type = undefined;
- }
- if ( clearQueue && type !== false ) {
- this.queue( type || "fx", [] );
- }
-
- return this.each(function() {
- var dequeue = true,
- index = type != null && type + "queueHooks",
- timers = jQuery.timers,
- data = jQuery._data( this );
-
- if ( index ) {
- if ( data[ index ] && data[ index ].stop ) {
- stopQueue( data[ index ] );
- }
- } else {
- for ( index in data ) {
- if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
- stopQueue( data[ index ] );
- }
- }
- }
-
- for ( index = timers.length; index--; ) {
- if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
- timers[ index ].anim.stop( gotoEnd );
- dequeue = false;
- timers.splice( index, 1 );
- }
- }
-
- // start the next in the queue if the last step wasn't forced
- // timers currently will call their complete callbacks, which will dequeue
- // but only if they were gotoEnd
- if ( dequeue || !gotoEnd ) {
- jQuery.dequeue( this, type );
- }
- });
- }
-});
-
-// Generate parameters to create a standard animation
-function genFx( type, includeWidth ) {
- var which,
- attrs = { height: type },
- i = 0;
-
- // if we include width, step value is 1 to do all cssExpand values,
- // if we don't include width, step value is 2 to skip over Left and Right
- includeWidth = includeWidth? 1 : 0;
- for( ; i < 4 ; i += 2 - includeWidth ) {
- which = cssExpand[ i ];
- attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
- }
-
- if ( includeWidth ) {
- attrs.opacity = attrs.width = type;
- }
-
- return attrs;
-}
-
-// Generate shortcuts for custom animations
-jQuery.each({
- slideDown: genFx("show"),
- slideUp: genFx("hide"),
- slideToggle: genFx("toggle"),
- fadeIn: { opacity: "show" },
- fadeOut: { opacity: "hide" },
- fadeToggle: { opacity: "toggle" }
-}, function( name, props ) {
- jQuery.fn[ name ] = function( speed, easing, callback ) {
- return this.animate( props, speed, easing, callback );
- };
-});
-
-jQuery.speed = function( speed, easing, fn ) {
- var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
- complete: fn || !fn && easing ||
- jQuery.isFunction( speed ) && speed,
- duration: speed,
- easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
- };
-
- opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
- opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
-
- // normalize opt.queue - true/undefined/null -> "fx"
- if ( opt.queue == null || opt.queue === true ) {
- opt.queue = "fx";
- }
-
- // Queueing
- opt.old = opt.complete;
-
- opt.complete = function() {
- if ( jQuery.isFunction( opt.old ) ) {
- opt.old.call( this );
- }
-
- if ( opt.queue ) {
- jQuery.dequeue( this, opt.queue );
- }
- };
-
- return opt;
-};
-
-jQuery.easing = {
- linear: function( p ) {
- return p;
- },
- swing: function( p ) {
- return 0.5 - Math.cos( p*Math.PI ) / 2;
- }
-};
-
-jQuery.timers = [];
-jQuery.fx = Tween.prototype.init;
-jQuery.fx.tick = function() {
- var timer,
- timers = jQuery.timers,
- i = 0;
-
- for ( ; i < timers.length; i++ ) {
- timer = timers[ i ];
- // Checks the timer has not already been removed
- if ( !timer() && timers[ i ] === timer ) {
- timers.splice( i--, 1 );
- }
- }
-
- if ( !timers.length ) {
- jQuery.fx.stop();
- }
-};
-
-jQuery.fx.timer = function( timer ) {
- if ( timer() && jQuery.timers.push( timer ) && !timerId ) {
- timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
- }
-};
-
-jQuery.fx.interval = 13;
-
-jQuery.fx.stop = function() {
- clearInterval( timerId );
- timerId = null;
-};
-
-jQuery.fx.speeds = {
- slow: 600,
- fast: 200,
- // Default speed
- _default: 400
-};
-
-// Back Compat <1.8 extension point
-jQuery.fx.step = {};
-
-if ( jQuery.expr && jQuery.expr.filters ) {
- jQuery.expr.filters.animated = function( elem ) {
- return jQuery.grep(jQuery.timers, function( fn ) {
- return elem === fn.elem;
- }).length;
- };
-}
-var rroot = /^(?:body|html)$/i;
-
-jQuery.fn.offset = function( options ) {
- if ( arguments.length ) {
- return options === undefined ?
- this :
- this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
-
- var docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft,
- box = { top: 0, left: 0 },
- elem = this[ 0 ],
- doc = elem && elem.ownerDocument;
-
- if ( !doc ) {
- return;
- }
-
- if ( (body = doc.body) === elem ) {
- return jQuery.offset.bodyOffset( elem );
- }
-
- docElem = doc.documentElement;
-
- // Make sure it's not a disconnected DOM node
- if ( !jQuery.contains( docElem, elem ) ) {
- return box;
- }
-
- // If we don't have gBCR, just use 0,0 rather than error
- // BlackBerry 5, iOS 3 (original iPhone)
- if ( typeof elem.getBoundingClientRect !== "undefined" ) {
- box = elem.getBoundingClientRect();
- }
- win = getWindow( doc );
- clientTop = docElem.clientTop || body.clientTop || 0;
- clientLeft = docElem.clientLeft || body.clientLeft || 0;
- scrollTop = win.pageYOffset || docElem.scrollTop;
- scrollLeft = win.pageXOffset || docElem.scrollLeft;
- return {
- top: box.top + scrollTop - clientTop,
- left: box.left + scrollLeft - clientLeft
- };
-};
-
-jQuery.offset = {
-
- bodyOffset: function( body ) {
- var top = body.offsetTop,
- left = body.offsetLeft;
-
- if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
- top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
- left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
- }
-
- return { top: top, left: left };
- },
-
- setOffset: function( elem, options, i ) {
- var position = jQuery.css( elem, "position" );
-
- // set position first, in-case top/left are set even on static elem
- if ( position === "static" ) {
- elem.style.position = "relative";
- }
-
- var curElem = jQuery( elem ),
- curOffset = curElem.offset(),
- curCSSTop = jQuery.css( elem, "top" ),
- curCSSLeft = jQuery.css( elem, "left" ),
- calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
- props = {}, curPosition = {}, curTop, curLeft;
-
- // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
- if ( calculatePosition ) {
- curPosition = curElem.position();
- curTop = curPosition.top;
- curLeft = curPosition.left;
- } else {
- curTop = parseFloat( curCSSTop ) || 0;
- curLeft = parseFloat( curCSSLeft ) || 0;
- }
-
- if ( jQuery.isFunction( options ) ) {
- options = options.call( elem, i, curOffset );
- }
-
- if ( options.top != null ) {
- props.top = ( options.top - curOffset.top ) + curTop;
- }
- if ( options.left != null ) {
- props.left = ( options.left - curOffset.left ) + curLeft;
- }
-
- if ( "using" in options ) {
- options.using.call( elem, props );
- } else {
- curElem.css( props );
- }
- }
-};
-
-
-jQuery.fn.extend({
-
- position: function() {
- if ( !this[0] ) {
- return;
- }
-
- var elem = this[0],
-
- // Get *real* offsetParent
- offsetParent = this.offsetParent(),
-
- // Get correct offsets
- offset = this.offset(),
- parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
-
- // Subtract element margins
- // note: when an element has margin: auto the offsetLeft and marginLeft
- // are the same in Safari causing offset.left to incorrectly be 0
- offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
- offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
-
- // Add offsetParent borders
- parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
- parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
-
- // Subtract the two offsets
- return {
- top: offset.top - parentOffset.top,
- left: offset.left - parentOffset.left
- };
- },
-
- offsetParent: function() {
- return this.map(function() {
- var offsetParent = this.offsetParent || document.body;
- while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
- offsetParent = offsetParent.offsetParent;
- }
- return offsetParent || document.body;
- });
- }
-});
-
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
- var top = /Y/.test( prop );
-
- jQuery.fn[ method ] = function( val ) {
- return jQuery.access( this, function( elem, method, val ) {
- var win = getWindow( elem );
-
- if ( val === undefined ) {
- return win ? (prop in win) ? win[ prop ] :
- win.document.documentElement[ method ] :
- elem[ method ];
- }
-
- if ( win ) {
- win.scrollTo(
- !top ? val : jQuery( win ).scrollLeft(),
- top ? val : jQuery( win ).scrollTop()
- );
-
- } else {
- elem[ method ] = val;
- }
- }, method, val, arguments.length, null );
- };
-});
-
-function getWindow( elem ) {
- return jQuery.isWindow( elem ) ?
- elem :
- elem.nodeType === 9 ?
- elem.defaultView || elem.parentWindow :
- false;
-}
-// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
-jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
- jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
- // margin is only for outerHeight, outerWidth
- jQuery.fn[ funcName ] = function( margin, value ) {
- var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
- extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
-
- return jQuery.access( this, function( elem, type, value ) {
- var doc;
-
- if ( jQuery.isWindow( elem ) ) {
- // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
- // isn't a whole lot we can do. See pull request at this URL for discussion:
- // https://github.com/jquery/jquery/pull/764
- return elem.document.documentElement[ "client" + name ];
- }
-
- // Get document width or height
- if ( elem.nodeType === 9 ) {
- doc = elem.documentElement;
-
- // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
- // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
- return Math.max(
- elem.body[ "scroll" + name ], doc[ "scroll" + name ],
- elem.body[ "offset" + name ], doc[ "offset" + name ],
- doc[ "client" + name ]
- );
- }
-
- return value === undefined ?
- // Get width or height on the element, requesting but not forcing parseFloat
- jQuery.css( elem, type, value, extra ) :
-
- // Set width or height on the element
- jQuery.style( elem, type, value, extra );
- }, type, chainable ? margin : undefined, chainable, null );
- };
- });
-});
-// Expose jQuery to the global object
-window.jQuery = window.$ = jQuery;
-
-// Expose jQuery as an AMD module, but only for AMD loaders that
-// understand the issues with loading multiple versions of jQuery
-// in a page that all might call define(). The loader will indicate
-// they have special allowances for multiple jQuery versions by
-// specifying define.amd.jQuery = true. Register as a named module,
-// since jQuery can be concatenated with other files that may use define,
-// but not use a proper concatenation script that understands anonymous
-// AMD modules. A named AMD is safest and most robust way to register.
-// Lowercase jquery is used because AMD module names are derived from
-// file names, and jQuery is normally delivered in a lowercase file name.
-// Do this after creating the global so that if an AMD module wants to call
-// noConflict to hide this version of jQuery, it will work.
-if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
- define( "jquery", [], function () { return jQuery; } );
-}
-
-})( window );
diff --git a/vendor/json-js/json2.js b/vendor/json-js/json2.js
index d89ecc7..deb88ec 100644
--- a/vendor/json-js/json2.js
+++ b/vendor/json-js/json2.js
@@ -1,6 +1,6 @@
/*
json2.js
- 2013-05-26
+ 2014-02-04
Public Domain.
@@ -192,19 +192,11 @@ if (typeof JSON !== 'object') {
};
}
- var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ var cx,
+ escapable,
gap,
indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
+ meta,
rep;
@@ -356,6 +348,16 @@ if (typeof JSON !== 'object') {
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ };
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
@@ -403,6 +405,7 @@ if (typeof JSON !== 'object') {
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
+ cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
diff --git a/vendor/platform.js/LICENSE.txt b/vendor/platform.js/LICENSE.txt
deleted file mode 100644
index a7501f9..0000000
--- a/vendor/platform.js/LICENSE.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright 2011-2013 John-David Dalton <http://allyoucanleet.com/>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/vendor/platform.js/platform.js b/vendor/platform.js/platform.js
deleted file mode 100644
index 94ec918..0000000
--- a/vendor/platform.js/platform.js
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*!
- * Platform.js v1.0.0 <http://mths.be/platform>
- * Copyright 2010-2013 John-David Dalton <http://allyoucanleet.com/>
- * Available under MIT license <http://mths.be/mit>
- */
-;(function(root) {
- 'use strict';
-
- /** Backup possible global object */
- var oldRoot = root;
-
- /** Detect free variable `exports` */
- var freeExports = typeof exports == 'object' && exports;
-
- /** Detect free variable `global` */
- var freeGlobal = typeof global == 'object' && global &&
- (global == global.global ? (root = global) : global);
-
- /** Opera regexp */
- var reOpera = /Opera/;
-
- /** Used to resolve a value's internal [[Class]] */
- var toString = Object.prototype.toString;
-
- /** Detect Java environment */
- var java = /Java/.test(getClassOf(root.java)) && root.java;
-
- /** Detect Rhino */
- var rhino = java && getClassOf(root.environment) == 'Environment';
-
- /** A character to represent alpha */
- var alpha = java ? 'a' : '\u03b1';
-
- /** A character to represent beta */
- var beta = java ? 'b' : '\u03b2';
-
- /** Browser document object */
- var doc = root.document || {};
-
- /** Used to check for own properties of an object */
- var hasOwnProperty = {}.hasOwnProperty;
-
- /** Browser navigator object */
- var nav = root.navigator || {};
-
- /**
- * Detect Opera browser
- * http://www.howtocreate.co.uk/operaStuff/operaObject.html
- * http://dev.opera.com/articles/view/opera-mini-web-content-authoring-guidelines/#operamini
- */
- var opera = root.operamini || root.opera;
-
- /** Opera [[Class]] */
- var operaClass = reOpera.test(operaClass = getClassOf(opera)) ? operaClass : (opera = null);
-
- /** Possible global object */
- var thisBinding = this;
-
- /** Browser user agent string */
- var userAgent = nav.userAgent || '';
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Capitalizes a string value.
- *
- * @private
- * @param {string} string The string to capitalize.
- * @returns {string} The capitalized string.
- */
- function capitalize(string) {
- string = String(string);
- return string.charAt(0).toUpperCase() + string.slice(1);
- }
-
- /**
- * An iteration utility for arrays and objects.
- *
- * @private
- * @param {Array|Object} object The object to iterate over.
- * @param {Function} callback The function called per iteration.
- */
- function each(object, callback) {
- var index = -1,
- length = object.length;
-
- if (length == length >>> 0) {
- while (++index < length) {
- callback(object[index], index, object);
- }
- } else {
- forOwn(object, callback);
- }
- }
-
- /**
- * Trim and conditionally capitalize string values.
- *
- * @private
- * @param {string} string The string to format.
- * @returns {string} The formatted string.
- */
- function format(string) {
- string = trim(string);
- return /^(?:webOS|i(?:OS|P))/.test(string)
- ? string
- : capitalize(string);
- }
-
- /**
- * Iterates over an object's own properties, executing the `callback` for each.
- *
- * @private
- * @param {Object} object The object to iterate over.
- * @param {Function} callback The function executed per own property.
- */
- function forOwn(object, callback) {
- for (var key in object) {
- hasKey(object, key) && callback(object[key], key, object);
- }
- }
-
- /**
- * Gets the internal [[Class]] of a value.
- *
- * @private
- * @param {*} value The value.
- * @returns {string} The [[Class]].
- */
- function getClassOf(value) {
- return value == null
- ? capitalize(value)
- : toString.call(value).slice(8, -1);
- }
-
- /**
- * Checks if an object has the specified key as a direct property.
- *
- * @private
- * @param {Object} object The object to check.
- * @param {string} key The key to check for.
- * @returns {boolean} Returns `true` if key is a direct property, else `false`.
- */
- function hasKey() {
- // lazy define for others (not as accurate)
- hasKey = function(object, key) {
- var parent = object != null && (object.constructor || Object).prototype;
- return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]);
- };
- // for modern browsers
- if (getClassOf(hasOwnProperty) == 'Function') {
- hasKey = function(object, key) {
- return object != null && hasOwnProperty.call(object, key);
- };
- }
- // for Safari 2
- else if ({}.__proto__ == Object.prototype) {
- hasKey = function(object, key) {
- var result = false;
- if (object != null) {
- object = Object(object);
- object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0];
- }
- return result;
- };
- }
- return hasKey.apply(this, arguments);
- }
-
- /**
- * Host objects can return type values that are different from their actual
- * data type. The objects we are concerned with usually return non-primitive
- * types of object, function, or unknown.
- *
- * @private
- * @param {*} object The owner of the property.
- * @param {string} property The property to check.
- * @returns {boolean} Returns `true` if the property value is a non-primitive, else `false`.
- */
- function isHostType(object, property) {
- var type = object != null ? typeof object[property] : 'number';
- return !/^(?:boolean|number|string|undefined)$/.test(type) &&
- (type == 'object' ? !!object[property] : true);
- }
-
- /**
- * Prepares a string for use in a RegExp constructor by making hyphens and
- * spaces optional.
- *
- * @private
- * @param {string} string The string to qualify.
- * @returns {string} The qualified string.
- */
- function qualify(string) {
- return String(string).replace(/([ -])(?!$)/g, '$1?');
- }
-
- /**
- * A bare-bones` Array#reduce` like utility function.
- *
- * @private
- * @param {Array} array The array to iterate over.
- * @param {Function} callback The function called per iteration.
- * @param {*} accumulator Initial value of the accumulator.
- * @returns {*} The accumulator.
- */
- function reduce(array, callback) {
- var accumulator = null;
- each(array, function(value, index) {
- accumulator = callback(accumulator, value, index, array);
- });
- return accumulator;
- }
-
- /**
- * Removes leading and trailing whitespace from a string.
- *
- * @private
- * @param {string} string The string to trim.
- * @returns {string} The trimmed string.
- */
- function trim(string) {
- return String(string).replace(/^ +| +$/g, '');
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Creates a new platform object.
- *
- * @memberOf platform
- * @param {string} [ua = navigator.userAgent] The user agent string.
- * @returns {Object} A platform object.
- */
- function parse(ua) {
-
- ua || (ua = userAgent);
-
- /** Temporary variable used over the script's lifetime */
- var data;
-
- /** The CPU architecture */
- var arch = ua;
-
- /** Platform description array */
- var description = [];
-
- /** Platform alpha/beta indicator */
- var prerelease = null;
-
- /** A flag to indicate that environment features should be used to resolve the platform */
- var useFeatures = ua == userAgent;
-
- /** The browser/environment version */
- var version = useFeatures && opera && typeof opera.version == 'function' && opera.version();
-
- /* Detectable layout engines (order is important) */
- var layout = getLayout([
- { 'label': 'WebKit', 'pattern': 'AppleWebKit' },
- 'iCab',
- 'Presto',
- 'NetFront',
- 'Tasman',
- 'Trident',
- 'KHTML',
- 'Gecko'
- ]);
-
- /* Detectable browser names (order is important) */
- var name = getName([
- 'Adobe AIR',
- 'Arora',
- 'Avant Browser',
- 'Camino',
- 'Epiphany',
- 'Fennec',
- 'Flock',
- 'Galeon',
- 'GreenBrowser',
- 'iCab',
- 'Iceweasel',
- 'Iron',
- 'K-Meleon',
- 'Konqueror',
- 'Lunascape',
- 'Maxthon',
- 'Midori',
- 'Nook Browser',
- 'PhantomJS',
- 'Raven',
- 'Rekonq',
- 'RockMelt',
- 'SeaMonkey',
- { 'label': 'Silk', 'pattern': '(?:Cloud9|Silk-Accelerated)' },
- 'Sleipnir',
- 'SlimBrowser',
- 'Sunrise',
- 'Swiftfox',
- 'WebPositive',
- 'Opera Mini',
- 'Opera',
- { 'label': 'Opera', 'pattern': 'OPR' },
- 'Chrome',
- { 'label': 'Chrome Mobile', 'pattern': '(?:CriOS|CrMo)' },
- { 'label': 'Firefox', 'pattern': '(?:Firefox|Minefield)' },
- { 'label': 'IE', 'pattern': 'MSIE' },
- 'Safari'
- ]);
-
- /* Detectable products (order is important) */
- var product = getProduct([
- 'BlackBerry',
- { 'label': 'Galaxy S', 'pattern': 'GT-I9000' },
- { 'label': 'Galaxy S2', 'pattern': 'GT-I9100' },
- 'Google TV',
- 'iPad',
- 'iPod',
- 'iPhone',
- 'Kindle',
- { 'label': 'Kindle Fire', 'pattern': '(?:Cloud9|Silk-Accelerated)' },
- 'Nook',
- 'PlayBook',
- 'PlayStation Vita',
- 'TouchPad',
- 'Transformer',
- 'Xoom'
- ]);
-
- /* Detectable manufacturers */
- var manufacturer = getManufacturer({
- 'Apple': { 'iPad': 1, 'iPhone': 1, 'iPod': 1 },
- 'Amazon': { 'Kindle': 1, 'Kindle Fire': 1 },
- 'Asus': { 'Transformer': 1 },
- 'Barnes & Noble': { 'Nook': 1 },
- 'BlackBerry': { 'PlayBook': 1 },
- 'Google': { 'Google TV': 1 },
- 'HP': { 'TouchPad': 1 },
- 'LG': { },
- 'Motorola': { 'Xoom': 1 },
- 'Nokia': { },
- 'Samsung': { 'Galaxy S': 1, 'Galaxy S2': 1 },
- 'Sony': { 'PlayStation Vita': 1 }
- });
-
- /* Detectable OSes (order is important) */
- var os = getOS([
- 'Android',
- 'CentOS',
- 'Debian',
- 'Fedora',
- 'FreeBSD',
- 'Gentoo',
- 'Haiku',
- 'Kubuntu',
- 'Linux Mint',
- 'Red Hat',
- 'SuSE',
- 'Ubuntu',
- 'Xubuntu',
- 'Cygwin',
- 'Symbian OS',
- 'hpwOS',
- 'webOS ',
- 'webOS',
- 'Tablet OS',
- 'Linux',
- 'Mac OS X',
- 'Macintosh',
- 'Mac',
- 'Windows 98;',
- 'Windows '
- ]);
-
- /*------------------------------------------------------------------------*/
-
- /**
- * Picks the layout engine from an array of guesses.
- *
- * @private
- * @param {Array} guesses An array of guesses.
- * @returns {null|string} The detected layout engine.
- */
- function getLayout(guesses) {
- return reduce(guesses, function(result, guess) {
- return result || RegExp('\\b' + (
- guess.pattern || qualify(guess)
- ) + '\\b', 'i').exec(ua) && (guess.label || guess);
- });
- }
-
- /**
- * Picks the manufacturer from an array of guesses.
- *
- * @private
- * @param {Array} guesses An array of guesses.
- * @returns {null|string} The detected manufacturer.
- */
- function getManufacturer(guesses) {
- return reduce(guesses, function(result, value, key) {
- // lookup the manufacturer by product or scan the UA for the manufacturer
- return result || (
- value[product] ||
- value[0/*Opera 9.25 fix*/, /^[a-z]+(?: +[a-z]+\b)*/i.exec(product)] ||
- RegExp('\\b' + (key.pattern || qualify(key)) + '(?:\\b|\\w*\\d)', 'i').exec(ua)
- ) && (key.label || key);
- });
- }
-
- /**
- * Picks the browser name from an array of guesses.
- *
- * @private
- * @param {Array} guesses An array of guesses.
- * @returns {null|string} The detected browser name.
- */
- function getName(guesses) {
- return reduce(guesses, function(result, guess) {
- return result || RegExp('\\b' + (
- guess.pattern || qualify(guess)
- ) + '\\b', 'i').exec(ua) && (guess.label || guess);
- });
- }
-
- /**
- * Picks the OS name from an array of guesses.
- *
- * @private
- * @param {Array} guesses An array of guesses.
- * @returns {null|string} The detected OS name.
- */
- function getOS(guesses) {
- return reduce(guesses, function(result, guess) {
- var pattern = guess.pattern || qualify(guess);
- if (!result && (result =
- RegExp('\\b' + pattern + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(ua))) {
- // platform tokens defined at
- // http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx
- // http://web.archive.org/web/20081122053950/http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx
- data = {
- '6.2': '8',
- '6.1': 'Server 2008 R2 / 7',
- '6.0': 'Server 2008 / Vista',
- '5.2': 'Server 2003 / XP 64-bit',
- '5.1': 'XP',
- '5.01': '2000 SP1',
- '5.0': '2000',
- '4.0': 'NT',
- '4.90': 'ME'
- };
- // detect Windows version from platform tokens
- if (/^Win/i.test(result) &&
- (data = data[0/*Opera 9.25 fix*/, /[\d.]+$/.exec(result)])) {
- result = 'Windows ' + data;
- }
- // correct character case and cleanup
- result = format(String(result)
- .replace(RegExp(pattern, 'i'), guess.label || guess)
- .replace(/ ce$/i, ' CE')
- .replace(/hpw/i, 'web')
- .replace(/Macintosh/, 'Mac OS')
- .replace(/_PowerPC/i, ' OS')
- .replace(/(OS X) [^ \d]+/i, '$1')
- .replace(/Mac (OS X)/, '$1')
- .replace(/\/(\d)/, ' $1')
- .replace(/_/g, '.')
- .replace(/(?: BePC|[ .]*fc[ \d.]+)$/i, '')
- .replace(/x86\.64/gi, 'x86_64')
- .split(' on ')[0]);
- }
- return result;
- });
- }
-
- /**
- * Picks the product name from an array of guesses.
- *
- * @private
- * @param {Array} guesses An array of guesses.
- * @returns {null|string} The detected product name.
- */
- function getProduct(guesses) {
- return reduce(guesses, function(result, guess) {
- var pattern = guess.pattern || qualify(guess);
- if (!result && (result =
- RegExp('\\b' + pattern + ' *\\d+[.\\w_]*', 'i').exec(ua) ||
- RegExp('\\b' + pattern + '(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)', 'i').exec(ua)
- )) {
- // split by forward slash and append product version if needed
- if ((result = String(guess.label || result).split('/'))[1] && !/[\d.]+/.test(result[0])) {
- result[0] += ' ' + result[1];
- }
- // correct character case and cleanup
- guess = guess.label || guess;
- result = format(result[0]
- .replace(RegExp(pattern, 'i'), guess)
- .replace(RegExp('; *(?:' + guess + '[_-])?', 'i'), ' ')
- .replace(RegExp('(' + guess + ')(\\w)', 'i'), '$1 $2'));
- }
- return result;
- });
- }
-
- /**
- * Resolves the version using an array of UA patterns.
- *
- * @private
- * @param {Array} patterns An array of UA patterns.
- * @returns {null|string} The detected version.
- */
- function getVersion(patterns) {
- return reduce(patterns, function(result, pattern) {
- return result || (RegExp(pattern +
- '(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)', 'i').exec(ua) || 0)[1] || null;
- });
- }
-
- /*------------------------------------------------------------------------*/
-
- /**
- * Returns `platform.description` when the platform object is coerced to a string.
- *
- * @name toString
- * @memberOf platform
- * @returns {string} Returns `platform.description` if available, else an empty string.
- */
- function toStringPlatform() {
- return this.description || '';
- }
-
- /*------------------------------------------------------------------------*/
-
- // convert layout to an array so we can add extra details
- layout && (layout = [layout]);
-
- // detect product names that contain their manufacturer's name
- if (manufacturer && !product) {
- product = getProduct([manufacturer]);
- }
- // clean up Google TV
- if ((data = /Google TV/.exec(product))) {
- product = data[0];
- }
- // detect simulators
- if (/\bSimulator\b/i.test(ua)) {
- product = (product ? product + ' ' : '') + 'Simulator';
- }
- // detect iOS
- if (/^iP/.test(product)) {
- name || (name = 'Safari');
- os = 'iOS' + ((data = / OS ([\d_]+)/i.exec(ua))
- ? ' ' + data[1].replace(/_/g, '.')
- : '');
- }
- // detect Kubuntu
- else if (name == 'Konqueror' && !/buntu/i.test(os)) {
- os = 'Kubuntu';
- }
- // detect Android browsers
- else if (manufacturer && manufacturer != 'Google' &&
- ((/Chrome/.test(name) && !/Mobile Safari/.test(ua)) || /Vita/.test(product))) {
- name = 'Android Browser';
- os = /Android/.test(os) ? os : 'Android';
- }
- // detect false positives for Firefox/Safari
- else if (!name || (data = !/\bMinefield\b/i.test(ua) && /Firefox|Safari/.exec(name))) {
- // escape the `/` for Firefox 1
- if (name && !product && /[\/,]|^[^(]+?\)/.test(ua.slice(ua.indexOf(data + '/') + 8))) {
- // clear name of false positives
- name = null;
- }
- // reassign a generic name
- if ((data = product || manufacturer || os) &&
- (product || manufacturer || /Android|Symbian OS|Tablet OS|webOS/.test(os))) {
- name = /[a-z]+(?: Hat)?/i.exec(/Android/.test(os) ? os : data) + ' Browser';
- }
- }
- // detect non-Opera versions (order is important)
- if (!version) {
- version = getVersion([
- '(?:Cloud9|CriOS|CrMo|Opera ?Mini|OPR|Raven|Silk(?!/[\\d.]+$))',
- 'Version',
- qualify(name),
- '(?:Firefox|Minefield|NetFront)'
- ]);
- }
- // detect stubborn layout engines
- if (layout == 'iCab' && parseFloat(version) > 3) {
- layout = ['WebKit'];
- } else if ((data =
- /Opera/.test(name) && (/OPR/.test(ua) ? 'Blink' : 'Presto') ||
- /\b(?:Midori|Nook|Safari)\b/i.test(ua) && 'WebKit' ||
- !layout && /\bMSIE\b/i.test(ua) && (os == 'Mac OS' ? 'Tasman' : 'Trident')
- )) {
- layout = [data];
- }
- // leverage environment features
- if (useFeatures) {
- // detect server-side environments
- // Rhino has a global function while others have a global object
- if (isHostType(root, 'global')) {
- if (java) {
- data = java.lang.System;
- arch = data.getProperty('os.arch');
- os = os || data.getProperty('os.name') + ' ' + data.getProperty('os.version');
- }
- if (freeExports) {
- // if `thisBinding` is the [ModuleScope]
- if (thisBinding == oldRoot && typeof system == 'object' && (data = [system])[0]) {
- os || (os = data[0].os || null);
- try {
- data[1] = require('ringo/engine').version;
- version = data[1].join('.');
- name = 'RingoJS';
- } catch(e) {
- if (data[0].global == freeGlobal) {
- name = 'Narwhal';
- }
- }
- }
- else if (typeof process == 'object' && (data = process)) {
- name = 'Node.js';
- arch = data.arch;
- os = data.platform;
- version = /[\d.]+/.exec(data.version)[0];
- }
- else if (rhino) {
- name = 'Rhino';
- }
- }
- else if (rhino) {
- name = 'Rhino';
- }
- }
- // detect Adobe AIR
- else if (getClassOf((data = root.runtime)) == 'ScriptBridgingProxyObject') {
- name = 'Adobe AIR';
- os = data.flash.system.Capabilities.os;
- }
- // detect PhantomJS
- else if (getClassOf((data = root.phantom)) == 'RuntimeObject') {
- name = 'PhantomJS';
- version = (data = data.version || null) && (data.major + '.' + data.minor + '.' + data.patch);
- }
- // detect IE compatibility modes
- else if (typeof doc.documentMode == 'number' && (data = /\bTrident\/(\d+)/i.exec(ua))) {
- // we're in compatibility mode when the Trident version + 4 doesn't
- // equal the document mode
- version = [version, doc.documentMode];
- if ((data = +data[1] + 4) != version[1]) {
- description.push('IE ' + version[1] + ' mode');
- layout[1] = '';
- version[1] = data;
- }
- version = name == 'IE' ? String(version[1].toFixed(1)) : version[0];
- }
- os = os && format(os);
- }
- // detect prerelease phases
- if (version && (data =
- /(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(version) ||
- /(?:alpha|beta)(?: ?\d)?/i.exec(ua + ';' + (useFeatures && nav.appMinorVersion)) ||
- /\bMinefield\b/i.test(ua) && 'a'
- )) {
- prerelease = /b/i.test(data) ? 'beta' : 'alpha';
- version = version.replace(RegExp(data + '\\+?$'), '') +
- (prerelease == 'beta' ? beta : alpha) + (/\d+\+?/.exec(data) || '');
- }
- // rename code name "Fennec"
- if (name == 'Fennec') {
- name = 'Firefox Mobile';
- }
- // obscure Maxthon's unreliable version
- else if (name == 'Maxthon' && version) {
- version = version.replace(/\.[\d.]+/, '.x');
- }
- // detect Silk desktop/accelerated modes
- else if (name == 'Silk') {
- if (!/Mobi/i.test(ua)) {
- os = 'Android';
- description.unshift('desktop mode');
- }
- if (/Accelerated *= *true/i.test(ua)) {
- description.unshift('accelerated');
- }
- }
- // detect Windows Phone desktop mode
- else if (name == 'IE' && (data = (/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(ua) || 0)[1])) {
- name += ' Mobile';
- os = 'Windows Phone OS ' + data + '.x';
- description.unshift('desktop mode');
- }
- // add mobile postfix
- else if ((name == 'Chrome' || name == 'IE' || name && !product && !/Browser|Mobi/.test(name)) &&
- (os == 'Windows CE' || /Mobi/i.test(ua))) {
- name += ' Mobile';
- }
- // detect IE platform preview
- else if (name == 'IE' && useFeatures && typeof external == 'object' && !external) {
- description.unshift('platform preview');
- }
- // detect BlackBerry OS version
- // http://docs.blackberry.com/en/developers/deliverables/18169/HTTP_headers_sent_by_BB_Browser_1234911_11.jsp
- else if (/BlackBerry/.test(product) && (data =
- (RegExp(product.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(ua) || 0)[1] ||
- version
- )) {
- os = 'Device Software ' + data;
- version = null;
- }
- // detect Opera identifying/masking itself as another browser
- // http://www.opera.com/support/kb/view/843/
- else if (this != forOwn && (
- (useFeatures && opera) ||
- (/Opera/.test(name) && /\b(?:MSIE|Firefox)\b/i.test(ua)) ||
- (name == 'Firefox' && /OS X (?:\d+\.){2,}/.test(os)) ||
- (name == 'IE' && (
- (os && !/^Win/.test(os) && version > 5.5) ||
- /Windows XP/.test(os) && version > 8 ||
- version == 8 && !/Trident/.test(ua)
- ))
- ) && !reOpera.test((data = parse.call(forOwn, ua.replace(reOpera, '') + ';'))) && data.name) {
-
- // when "indentifying", the UA contains both Opera and the other browser's name
- data = 'ing as ' + data.name + ((data = data.version) ? ' ' + data : '');
- if (reOpera.test(name)) {
- if (/IE/.test(data) && os == 'Mac OS') {
- os = null;
- }
- data = 'identify' + data;
- }
- // when "masking", the UA contains only the other browser's name
- else {
- data = 'mask' + data;
- if (operaClass) {
- name = format(operaClass.replace(/([a-z])([A-Z])/g, '$1 $2'));
- } else {
- name = 'Opera';
- }
- if (/IE/.test(data)) {
- os = null;
- }
- if (!useFeatures) {
- version = null;
- }
- }
- layout = ['Presto'];
- description.push(data);
- }
- // detect WebKit Nightly and approximate Chrome/Safari versions
- if ((data = (/\bAppleWebKit\/([\d.]+\+?)/i.exec(ua) || 0)[1])) {
- // correct build for numeric comparison
- // (e.g. "532.5" becomes "532.05")
- data = [parseFloat(data.replace(/\.(\d)$/, '.0$1')), data];
- // nightly builds are postfixed with a `+`
- if (name == 'Safari' && data[1].slice(-1) == '+') {
- name = 'WebKit Nightly';
- prerelease = 'alpha';
- version = data[1].slice(0, -1);
- }
- // clear incorrect browser versions
- else if (version == data[1] ||
- version == (/\bSafari\/([\d.]+\+?)/i.exec(ua) || 0)[1]) {
- version = null;
- }
- // use the full Chrome version when available
- data = [data[0], (/\bChrome\/([\d.]+)/i.exec(ua) || 0)[1]];
-
- // detect JavaScriptCore
- // http://stackoverflow.com/questions/6768474/how-can-i-detect-which-javascript-engine-v8-or-jsc-is-used-at-runtime-in-androi
- if (!useFeatures || (/internal|\n/i.test(toString.toString()) && !data[1])) {
- layout[1] = 'like Safari';
- data = (data = data[0], data < 400 ? 1 : data < 500 ? 2 : data < 526 ? 3 : data < 533 ? 4 : data < 534 ? '4+' : data < 535 ? 5 : '5');
- } else {
- layout[1] = 'like Chrome';
- data = data[1] || (data = data[0], data < 530 ? 1 : data < 532 ? 2 : data < 532.05 ? 3 : data < 533 ? 4 : data < 534.03 ? 5 : data < 534.07 ? 6 : data < 534.10 ? 7 : data < 534.13 ? 8 : data < 534.16 ? 9 : data < 534.24 ? 10 : data < 534.30 ? 11 : data < 535.01 ? 12 : data < 535.02 ? '13+' : data < 535.07 ? 15 : data < 535.11 ? 16 : data < 535.19 ? 17 : data < 536.05 ? 18 : data < 536.10 ? 19 : data < 537.01 ? 20 : '21');
- }
- // add the postfix of ".x" or "+" for approximate versions
- layout[1] += ' ' + (data += typeof data == 'number' ? '.x' : /[.+]/.test(data) ? '' : '+');
- // obscure version for some Safari 1-2 releases
- if (name == 'Safari' && (!version || parseInt(version) > 45)) {
- version = data;
- }
- }
- // detect Opera desktop modes
- if (name == 'Opera' && (data = /(?:zbov|zvav)$/.exec(os))) {
- name += ' ';
- description.unshift('desktop mode');
- if (data == 'zvav') {
- name += 'Mini';
- version = null;
- } else {
- name += 'Mobile';
- }
- }
- // detect Chrome desktop mode
- else if (name == 'Safari' && /Chrome/.exec(layout[1])) {
- description.unshift('desktop mode');
- name = 'Chrome Mobile';
- version = null;
-
- if (/OS X/.test(os)) {
- manufacturer = 'Apple';
- os = 'iOS 4.3+';
- } else {
- os = null;
- }
- }
- // strip incorrect OS versions
- if (version && version.indexOf((data = /[\d.]+$/.exec(os))) == 0 &&
- ua.indexOf('/' + data + '-') > -1) {
- os = trim(os.replace(data, ''));
- }
- // add layout engine
- if (layout && !/Avant|Nook/.test(name) && (
- /Browser|Lunascape|Maxthon/.test(name) ||
- /^(?:Adobe|Arora|Midori|Phantom|Rekonq|Rock|Sleipnir|Web)/.test(name) && layout[1])) {
- // don't add layout details to description if they are falsey
- (data = layout[layout.length - 1]) && description.push(data);
- }
- // combine contextual information
- if (description.length) {
- description = ['(' + description.join('; ') + ')'];
- }
- // append manufacturer
- if (manufacturer && product && product.indexOf(manufacturer) < 0) {
- description.push('on ' + manufacturer);
- }
- // append product
- if (product) {
- description.push((/^on /.test(description[description.length -1]) ? '' : 'on ') + product);
- }
- // parse OS into an object
- if (os) {
- data = / ([\d.+]+)$/.exec(os);
- os = {
- 'architecture': 32,
- 'family': data ? os.replace(data[0], '') : os,
- 'version': data ? data[1] : null,
- 'toString': function() {
- var version = this.version;
- return this.family + (version ? ' ' + version : '') + (this.architecture == 64 ? ' 64-bit' : '');
- }
- };
- }
- // add browser/OS architecture
- if ((data = /\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) {
- if (os) {
- os.architecture = 64;
- os.family = os.family.replace(RegExp(' *' + data), '');
- }
- if (name && (/WOW64/i.test(ua) ||
- (useFeatures && /\w(?:86|32)$/.test(nav.cpuClass || nav.platform)))) {
- description.unshift('32-bit');
- }
- }
-
- ua || (ua = null);
-
- /*------------------------------------------------------------------------*/
-
- /**
- * The platform object.
- *
- * @name platform
- * @type Object
- */
- return {
-
- /**
- * The browser/environment version.
- *
- * @memberOf platform
- * @type string|null
- */
- 'version': name && version && (description.unshift(version), version),
-
- /**
- * The name of the browser/environment.
- *
- * @memberOf platform
- * @type string|null
- */
- 'name': name && (description.unshift(name), name),
-
- /**
- * The name of the operating system.
- *
- * @memberOf platform
- * @type Object
- */
- 'os': os
- ? (name &&
- !(os == String(os).split(' ')[0] && (os == name.split(' ')[0] || product)) &&
- description.push(product ? '(' + os + ')' : 'on ' + os), os)
- : {
-
- /**
- * The CPU architecture the OS is built for.
- *
- * @memberOf platform.os
- * @type number|null
- */
- 'architecture': null,
-
- /**
- * The family of the OS.
- *
- * @memberOf platform.os
- * @type string|null
- */
- 'family': null,
-
- /**
- * The version of the OS.
- *
- * @memberOf platform.os
- * @type string|null
- */
- 'version': null,
-
- /**
- * Returns the OS string.
- *
- * @memberOf platform.os
- * @returns {string} The OS string.
- */
- 'toString': function() { return 'null'; }
- },
-
- /**
- * The platform description.
- *
- * @memberOf platform
- * @type string|null
- */
- 'description': description.length ? description.join(' ') : ua,
-
- /**
- * The name of the browser layout engine.
- *
- * @memberOf platform
- * @type string|null
- */
- 'layout': layout && layout[0],
-
- /**
- * The name of the product's manufacturer.
- *
- * @memberOf platform
- * @type string|null
- */
- 'manufacturer': manufacturer,
-
- /**
- * The alpha/beta release indicator.
- *
- * @memberOf platform
- * @type string|null
- */
- 'prerelease': prerelease,
-
- /**
- * The name of the product hosting the browser.
- *
- * @memberOf platform
- * @type string|null
- */
- 'product': product,
-
- /**
- * The browser's user agent string.
- *
- * @memberOf platform
- * @type string|null
- */
- 'ua': ua,
-
- // parses a user agent string into a platform object
- 'parse': parse,
-
- // returns the platform description
- 'toString': toStringPlatform
- };
- }
-
- /*--------------------------------------------------------------------------*/
-
- // expose platform
- // some AMD build optimizers, like r.js, check for condition patterns like the following:
- if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
- // define as an anonymous module so, through path mapping, it can be aliased
- define(function() {
- return parse();
- });
- }
- // check for `exports` after `define` in case a build optimizer adds an `exports` object
- else if (freeExports && !freeExports.nodeType) {
- // in Narwhal, Node.js, or RingoJS
- forOwn(parse(), function(value, key) {
- freeExports[key] = value;
- });
- }
- // in a browser or Rhino
- else {
- root.platform = parse();
- }
-}(this));
diff --git a/vendor/qunit-extras/LICENSE.txt b/vendor/qunit-extras/LICENSE.txt
deleted file mode 100644
index a7501f9..0000000
--- a/vendor/qunit-extras/LICENSE.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright 2011-2013 John-David Dalton <http://allyoucanleet.com/>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/vendor/qunit-extras/qunit-extras.js b/vendor/qunit-extras/qunit-extras.js
deleted file mode 100644
index 074d45f..0000000
--- a/vendor/qunit-extras/qunit-extras.js
+++ /dev/null
@@ -1,570 +0,0 @@
-/*!
- * QUnit Extras v1.0.0
- * Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/>
- * Based on a gist by Jörn Zaefferer <https://gist.github.com/722381>
- * Available under MIT license <http://mths.be/mit>
- */
-;(function(root, undefined) {
- 'use strict';
-
- /** Native method shortcut */
- var unshift = Array.prototype.unshift;
-
- /** Used to match HTML entities */
- var reEscapedHtml = /(&|<|>|"|')/g;
-
- /** Used to match parts of the assert message */
- var reDied = /^Died on test #\d+/,
- reExpected = /Expected: *<\/th><td><pre>([\s\S]*?)<\/pre>/,
- reMessage = /^<span class='test-message'>([\s\S]*?)<\/span>/;
-
- /** Used to convert HTML entities to characters */
- var htmlUnescapes = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- ''': "'"
- };
-
- /** Used as a horizontal rule in console output */
- var hr = '----------------------------------------';
-
- /** Detect free variable `exports` */
- var freeExports = typeof exports == 'object' && exports;
-
- /** Detect free variable `global`, from Node.js or Browserified code, and use it as `root` */
- var freeGlobal = typeof global == 'object' && global;
- if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
- root = freeGlobal;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Checks if a given value is present in an array using strict equality
- * for comparisons, i.e. `===`.
- *
- * @oruvate
- * @param {Array} array The array to iterate over.
- * @param {*} target The value to check for.
- * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
- */
- function contains(array, value) {
- var index = -1,
- length = array ? array.length : 0;
-
- while (++index < length) {
- if (array[index] === value) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Creates a string with `text` repeated `n` number of times.
- *
- * @private
- * @param {string} text The text to repeat.
- * @param {number} n The number of times to repeat `text`.
- * @returns {string} The created string.
- */
- function repeat(text, n) {
- return Array(n + 1).join(text);
- }
-
- /**
- * Resolves the value of `property` on `object`. If `object` is falsey then
- * `undefined` is returned.
- *
- * @private
- * @param {Object} object The object to inspect.
- * @param {string} property The property to get the value of.
- * @returns {*} Returns the resolved value.
- */
- function result(object, property) {
- return object ? object[property] : undefined;
- }
-
- /**
- * Converts the HTML entities `&`, `<`, `>`, `"`, and `'`
- * in `string` to their corresponding characters.
- *
- * @private
- * @param {string} string The string to unescape.
- * @returns {string} Returns the unescaped string.
- */
- function unescape(string) {
- return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
- }
-
- /**
- * Used by `unescape` to convert HTML entities to characters.
- *
- * @private
- * @param {string} match The matched character to unescape.
- * @returns {string} Returns the unescaped character.
- */
- function unescapeHtmlChar(match) {
- return htmlUnescapes[match];
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Installs the QUnit additions on the given `context` object.
- *
- * @memberOf exports
- * @param {Object} context The context object.
- */
- function runInContext(context) {
- // exit early if no `context` is provided or if `QUnit` does not exist
- if (!context || !context.QUnit) {
- return;
- }
-
- /** Used to report the test module for failing tests */
- var moduleName,
- modulePrinted;
-
- /** Object shortcuts */
- var console = context.console,
- phantom = context.phantom,
- process = phantom || context.process,
- document = !phantom && context.document;
-
- /** Detects if running in a PhantomJS web page */
- var isPhantomPage = typeof context.callPhantom == 'function';
-
- /** Used to display the wait throbber */
- var throbberId,
- throbberDelay = 500,
- waitCount = -1;
-
- /** Shorten `context.QUnit.QUnit` to `context.QUnit` */
- var QUnit = context.QUnit = context.QUnit.QUnit || context.QUnit;
-
- /*------------------------------------------------------------------------*/
-
- /**
- * Schedules timer-based callbacks.
- *
- * @private
- * @param {Function|string} fn The function to call.
- * @param {number} delay The number of milliseconds to delay the `fn` call.
- * @param [arg1, arg2, ...] Arguments to invoke `fn` with.
- * @param {boolean} repeated A flag to specify whether `fn` is called repeatedly.
- * @returns {number} The the ID of the timeout.
- */
- function schedule(fn, delay, args, repeated) {
- // Rhino 1.7RC4 will error assigning `task` below
- // https://bugzilla.mozilla.org/show_bug.cgi?id=775566
- var task = ids[++counter] = new JavaAdapter(java.util.TimerTask, {
- 'run': function() {
- fn.apply(context, args);
- }
- });
- // support non-functions
- if (typeof fn != 'function') {
- fn = (function(code) {
- code = String(code);
- return function() { eval(code); };
- }(fn));
- }
- // used by setInterval
- if (repeated) {
- timer.schedule(task, delay, delay);
- }
- // used by setTimeout
- else {
- timer.schedule(task, delay);
- }
- return counter;
- }
-
- /**
- * Clears the delay set by `setInterval` or `setTimeout`.
- *
- * @memberOf context
- * @param {number} id The ID of the timeout to be cleared.
- */
- function clearTimer(id) {
- if (ids[id]) {
- ids[id].cancel();
- timer.purge();
- delete ids[id];
- }
- }
-
- /**
- * Executes a code snippet or function repeatedly, with a delay between each call.
- *
- * @memberOf context
- * @param {Function|string} fn The function to call or string to evaluate.
- * @param {number} delay The number of milliseconds to delay each `fn` call.
- * @param [arg1, arg2, ...] Arguments to invoke `fn` with.
- * @returns {number} The the ID of the timeout.
- */
- function setInterval(fn, delay) {
- return schedule(fn, delay, slice.call(arguments, 2), true);
- }
-
- /**
- * Executes a code snippet or a function after specified delay.
- *
- * @memberOf context
- * @param {Function|string} fn The function to call or string to evaluate.
- * @param {number} delay The number of milliseconds to delay the `fn` call.
- * @param [arg1, arg2, ...] Arguments to invoke `fn` with.
- * @returns {number} The the ID of the timeout.
- */
- function setTimeout(fn, delay) {
- return schedule(fn, delay, slice.call(arguments, 2));
- }
-
- /*------------------------------------------------------------------------*/
-
- /**
- * Writes an inline message to standard output.
- *
- * @private
- * @param {string} text The text to log.
- */
- var logInline = (function() {
- // exit early if not Node.js
- if (!(typeof process == 'object' && process &&
- process.on && process.stdout && process.platform != 'win32')) {
- return function() {};
- }
- // cleanup any inline logs when exited via `ctrl+c`
- process.on('SIGINT', function() {
- logInline('');
- process.exit();
- });
-
- var prevLine = '';
- return function(text) {
- var blankLine = repeat(' ', prevLine.length);
- if (text.length > hr.length) {
- text = text.slice(0, hr.length - 3) + '...';
- }
- prevLine = text;
- process.stdout.write(text + blankLine.slice(text.length) + '\r');
- }
- }());
-
- /**
- * Writes the wait throbber to standard output.
- *
- * @private
- */
- function logThrobber() {
- logInline('Please wait' + repeat('.', (++waitCount % 3) + 1));
- }
-
- /*------------------------------------------------------------------------*/
-
- /**
- * The number of retries async tests have to succeed.
- *
- * @memberOf QUnit.config
- * @type number
- */
- QUnit.config.asyncRetries = 0;
-
- /**
- * An object of excused tests and assertions.
- *
- * @memberOf QUnit.config
- * @type Object
- */
- QUnit.config.excused = {};
-
- /**
- * An object used to hold information about the current running test.
- *
- * @memberOf QUnit.config
- * @type Object
- */
- QUnit.config.testStats = {
-
- /**
- * An array of test summaries.
- *
- * @memberOf QUnit.config.testStats
- * @type Array
- */
- 'assertions': []
- };
-
- /**
- * A callback triggered at the start of every test.
- *
- * @memberOf QUnit
- * @param {Object} details An object with `module` and `name` properties.
- */
- QUnit.testStart(function(details) {
- var excused = QUnit.config.excused || {},
- excusedTests = excused[details.module],
- excusedAsserts = excusedTests && excusedTests[details.name];
-
- var test = QUnit.config.current,
- finish = test.finish;
-
- // allow async tests to retry
- if (test.async && !test.retries) {
- test.retries = 0;
- test.finish = function() {
- var asserts = this.assertions,
- index = -1,
- length = asserts.length,
- queue = QUnit.config.queue;
-
- while (++index < length) {
- var assert = asserts[index];
- if (!assert.result && this.retries < QUnit.config.asyncRetries) {
- this.retries++;
- asserts.length = 0;
-
- var oldLength = queue.length;
- this.queue();
- unshift.apply(queue, queue.splice(oldLength, queue.length - oldLength));
- return;
- }
- }
- finish.call(this);
- };
- }
- // nothing to excuse
- if (!excusedAsserts) {
- return;
- }
- // excuse the entire test
- if (excusedAsserts === true) {
- test.async = false;
- test.callback = function() {};
- test.expected = 0;
- return;
- }
- // excuse specific assertions
- test.finish = function() {
- var asserts = this.assertions,
- index = -1,
- length = asserts.length;
-
- while (++index < length) {
- var assert = asserts[index],
- message = unescape(result(reMessage.exec(assert.message), 1)),
- died = result(reDied.exec(message), 0),
- expected = unescape(result(reExpected.exec(assert.message), 1));
-
- if ((message && contains(excusedAsserts, message)) ||
- (died && contains(excusedAsserts, died)) ||
- (expected && (
- contains(excusedAsserts, expected) ||
- contains(excusedAsserts, expected.replace(/\s+/g, ''))
- ))) {
- assert.result = true;
- }
- }
- finish.call(this);
- };
- });
-
- /*------------------------------------------------------------------------*/
-
- // add logging extras
- if (isPhantomPage || !document) {
-
- /**
- * A logging callback triggered when all testing is completed.
- *
- * @memberOf QUnit
- * @param {Object} details An object with properties `failed`, `passed`, `runtime`, and `total`.
- */
- QUnit.done(function() {
- var ran;
- return function(details) {
- // stop `asyncTest()` from erroneously calling `done()` twice in
- // environments w/o timeouts
- if (ran) {
- return;
- }
- ran = true;
-
- logInline('');
- console.log(hr);
- console.log(' PASS: ' + details.passed + ' FAIL: ' + details.failed + ' TOTAL: ' + details.total);
- console.log(' Finished in ' + details.runtime + ' milliseconds.');
- console.log(hr);
-
- // exit out of Node.js or PhantomJS
- try {
- if (details.failed) {
- process.exit(1);
- } else {
- process.exit(0);
- }
- } catch(e) { }
-
- // exit out of Narwhal, Rhino, or RingoJS
- try {
- if (details.failed) {
- java.lang.System.exit(1);
- } else {
- quit();
- }
- } catch(e) { }
- };
- }());
-
- /**
- * A logging callback triggered after every assertion.
- *
- * @memberOf QUnit
- * @param {Object} details An object with properties `actual`, `expected`, `message`, and `result`.
- */
- QUnit.log(function(details) {
- var expected = details.expected,
- result = details.result,
- type = typeof expected != 'undefined' ? 'EQ' : 'OK';
-
- var assertion = [
- result ? 'PASS' : 'FAIL',
- type,
- details.message || 'ok'
- ];
-
- if (!result && type == 'EQ') {
- assertion.push('Expected: ' + expected + ', Actual: ' + details.actual);
- }
- QUnit.config.testStats.assertions.push(assertion.join(' | '));
- });
-
- /**
- * A logging callback triggered at the start of every test module.
- *
- * @memberOf QUnit
- * @param {Object} details An object with property `name`.
- */
- QUnit.moduleStart(function(details) {
- // reset the `modulePrinted` flag
- var newModuleName = details.name;
- if (moduleName != newModuleName) {
- moduleName = newModuleName;
- modulePrinted = false;
- }
- // initialize the wait throbber
- if (!throbberId) {
- throbberId = context.setInterval(logThrobber, throbberDelay);
- logThrobber();
- }
- });
-
- /**
- * A logging callback triggered after a test is completed.
- *
- * @memberOf QUnit
- * @param {Object} details An object with properties `failed`, `name`, `passed`, and `total`.
- */
- QUnit.testDone(function(details) {
- var assertions = QUnit.config.testStats.assertions,
- testName = details.name;
-
- if (details.failed > 0) {
- logInline('');
- if (!modulePrinted) {
- modulePrinted = true;
- console.log(hr);
- console.log(moduleName);
- console.log(hr);
- }
- console.log(' FAIL - '+ testName);
- assertions.forEach(function(value) {
- console.log(' ' + value);
- });
- }
- assertions.length = 0;
- });
-
- /**
- * Converts an object into a string representation.
- *
- * @memberOf QUnit
- * @type Function
- * @param {Object} object The object to stringify.
- * @returns {string} The result string.
- */
- QUnit.jsDump.parsers.object = (function() {
- var func = QUnit.jsDump.parsers.object;
- return function(object) {
- // fork to support Rhino's error objects
- if (typeof object.rhinoException == 'object') {
- return object.name +
- ' { message: "' + object.message +
- '", fileName: "' + object.fileName +
- '", lineNumber: ' + object.lineNumber + ' }';
- }
- return func(object);
- };
- }());
- }
-
- /*------------------------------------------------------------------------*/
-
- // add CLI extras
- if (!document) {
- // Timeout fallbacks based on the work of Andrea Giammarchi and Weston C.
- // https://github.com/WebReflection/wru/blob/master/src/rhinoTimers.js
- // http://stackoverflow.com/questions/2261705/how-to-run-a-javascript-function-asynchronously-without-using-settimeout
- try {
- var counter = 0,
- ids = {},
- slice = Array.prototype.slice,
- timer = new java.util.Timer;
-
- (function() {
- var getDescriptor = Object.getOwnPropertyDescriptor || function() {
- return { 'writable': true };
- };
-
- var descriptor;
- if ((!context.clearInterval || ((descriptor = getDescriptor(context, 'clearInterval')) && (descriptor.writable || descriptor.set))) &&
- (!context.setInterval || ((descriptor = getDescriptor(context, 'setInterval')) && (descriptor.writable || descriptor.set)))) {
- context.clearInterval = clearTimer;
- context.setInterval = setInterval;
- }
- if ((!context.clearTimeout || ((descriptor = getDescriptor(context, 'clearTimeout')) && (descriptor.writable || descriptor.set))) &&
- (!context.setTimeout || ((descriptor = getDescriptor(context, 'setTimeout')) && (descriptor.writable || descriptor.set)))) {
- context.clearTimeout = clearTimer;
- context.setTimeout = setTimeout;
- }
- }());
- } catch(e) { }
-
- // add `console.log` support to Narwhal, Rhino, and RingoJS
- console || (console = context.console = { 'log': context.print });
-
- // expose shortcuts
- // exclude `module` because some environments have it as a built-in object
- ('asyncTest deepEqual equal equals expect notDeepEqual notEqual notStrictEqual ' +
- 'ok raises same start stop strictEqual test throws').replace(/\S+/g, function(methodName) {
- context[methodName] = QUnit[methodName];
- });
-
- // must call `QUnit.start` in the test file if not loaded in a browser
- QUnit.config.autostart = false;
- QUnit.init();
- }
- }
-
- /*--------------------------------------------------------------------------*/
-
- // expose QUnit extras
- if (freeExports && !freeExports.nodeType) {
- freeExports.runInContext = runInContext;
- } else {
- runInContext(root);
- }
-}(this));
diff --git a/vendor/qunit/MIT-LICENSE.txt b/vendor/qunit/MIT-LICENSE.txt
deleted file mode 100644
index 957f26d..0000000
--- a/vendor/qunit/MIT-LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Copyright 2013 jQuery Foundation and other contributors
-http://jquery.com/
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/qunit/qunit/qunit.css b/vendor/qunit/qunit/qunit.css
deleted file mode 100644
index d7fc0c8..0000000
--- a/vendor/qunit/qunit/qunit.css
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-testrunner-toolbar label {
- display: inline-block;
- padding: 0 .5em 0 .1em;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
- overflow: hidden;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-#qunit-modulefilter-container {
- float: right;
-}
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests li .runtime {
- float: right;
- font-size: smaller;
-}
-
-.qunit-assert-list {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.qunit-collapsed {
- display: none;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- padding: 5px;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
- border-left: 10px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 10px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-#qunit-testresult .module-name {
- font-weight: bold;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 1000px;
- height: 1000px;
-}
diff --git a/vendor/qunit/qunit/qunit.js b/vendor/qunit/qunit/qunit.js
deleted file mode 100644
index 302545f..0000000
--- a/vendor/qunit/qunit/qunit.js
+++ /dev/null
@@ -1,2152 +0,0 @@
-/**
- * QUnit v1.11.0 - A JavaScript Unit Testing Framework
- *
- * http://qunitjs.com
- *
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if ( this.module !== config.previousModule ) {
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- } else if ( config.autorun ) {
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running: <br/>" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Asssert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-// We attach it to the QUnit object *after* we expose the public API,
-// otherwise `assert` will become a global variable in browsers (#341).
-assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = escapeText( msg || (result ? "okay" : "failed" ) );
- msg = "<span class='test-message'>" + msg + "</span>";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr></table>";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, 'No exception was thrown.' );
- }
- }
-};
-
-/**
- * @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept root "raises()" for backwards compatibility.
- * (Note that we don't introduce assert.raises).
- */
-QUnit.raises = assert[ "throws" ];
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// We want access to the constructor's prototype
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-// Extend QUnit object,
-// these after set here because they should not be exposed as global functions
-extend( QUnit, {
- assert: assert,
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
- "<h2 id='qunit-banner'></h2>" +
- "<div id='qunit-testrunner-toolbar'></div>" +
- "<h2 id='qunit-userAgent'></h2>" +
- "<ol id='qunit-tests'></ol>";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...<br/> ";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Trigger an event on an element.
- // @example triggerEvent( document.body, "click" );
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent( "MouseEvents" );
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-
- elem.dispatchEvent( event );
- } else if ( elem.fireEvent ) {
- elem.fireEvent( "on" + type );
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- // consider: typeof null === object
- }
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "<span class='test-message'>" + message + "</span>";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
-
- if ( actual !== expected ) {
- output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
- output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
- }
-
- output += "</table>";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "<span class='test-message'>" + message + "</span>";
- output = message;
-
- output += "<table>";
-
- if ( actual ) {
- output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
- }
-
- if ( source ) {
- details.source = source;
- output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
- }
-
- output += "</table>";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
- "' name='" + escapeText( val.id ) +
- "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
- " title='" + escapeText( val.tooltip ) +
- "'><label for='qunit-urlconfig-" + escapeText( val.id ) +
- "' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
- }
-
- moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
- ( config.module === undefined ? "selected='selected'" : "" ) +
- ">< All Modules ></option>";
-
- for ( i in config.modules ) {
- if ( config.modules.hasOwnProperty( i ) ) {
- numModules += 1;
- moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(i) ) + "' " +
- ( config.module === i ? "selected='selected'" : "" ) +
- ">" + escapeText(i) + "</option>";
- }
- }
- moduleFilterHtml += "</select>";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.<br/>",
- "<span class='passed'>",
- passed,
- "</span> assertions of <span class='total'>",
- config.stats.all,
- "</span> passed, <span class='failed'>",
- config.stats.bad,
- "</span> failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé <prathe at gmail.com>
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "<del>" + out.o[i] + oSpace[i] + "</del>";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "<del>" + out.o[n] + oSpace[n] + "</del>";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "<ins>" + out.n[i] + nSpace[i] + "</ins>";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "<del>" + out.o[n] + oSpace[n] + "</del>";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/vendor/requirejs/LICENSE b/vendor/requirejs/LICENSE
deleted file mode 100644
index ffaf317..0000000
--- a/vendor/requirejs/LICENSE
+++ /dev/null
@@ -1,58 +0,0 @@
-RequireJS is released under two licenses: new BSD, and MIT. You may pick the
-license that best suits your development needs. The text of both licenses are
-provided below.
-
-
-The "New" BSD License:
-----------------------
-
-Copyright (c) 2010-2011, The Dojo Foundation
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the Dojo Foundation nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-
-MIT License
------------
-
-Copyright (c) 2010-2011, The Dojo Foundation
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/vendor/requirejs/require.js b/vendor/requirejs/require.js
deleted file mode 100644
index 2ce09b5..0000000
--- a/vendor/requirejs/require.js
+++ /dev/null
@@ -1,2054 +0,0 @@
-/** vim: et:ts=4:sw=4:sts=4
- * @license RequireJS 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
- * Available via the MIT or new BSD license.
- * see: http://github.com/jrburke/requirejs for details
- */
-//Not using strict: uneven strict support in browsers, #392, and causes
-//problems with requirejs.exec()/transpiler plugins that may not be strict.
-/*jslint regexp: true, nomen: true, sloppy: true */
-/*global window, navigator, document, importScripts, setTimeout, opera */
-
-var requirejs, require, define;
-(function (global) {
- var req, s, head, baseElement, dataMain, src,
- interactiveScript, currentlyAddingScript, mainScript, subPath,
- version = '2.1.9',
- commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
- cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
- jsSuffixRegExp = /\.js$/,
- currDirRegExp = /^\.\//,
- op = Object.prototype,
- ostring = op.toString,
- hasOwn = op.hasOwnProperty,
- ap = Array.prototype,
- apsp = ap.splice,
- isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
- isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
- //PS3 indicates loaded and complete, but need to wait for complete
- //specifically. Sequence is 'loading', 'loaded', execution,
- // then 'complete'. The UA check is unfortunate, but not sure how
- //to feature test w/o causing perf issues.
- readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
- /^complete$/ : /^(complete|loaded)$/,
- defContextName = '_',
- //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
- isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
- contexts = {},
- cfg = {},
- globalDefQueue = [],
- useInteractive = false;
-
- function isFunction(it) {
- return ostring.call(it) === '[object Function]';
- }
-
- function isArray(it) {
- return ostring.call(it) === '[object Array]';
- }
-
- /**
- * Helper function for iterating over an array. If the func returns
- * a true value, it will break out of the loop.
- */
- function each(ary, func) {
- if (ary) {
- var i;
- for (i = 0; i < ary.length; i += 1) {
- if (ary[i] && func(ary[i], i, ary)) {
- break;
- }
- }
- }
- }
-
- /**
- * Helper function for iterating over an array backwards. If the func
- * returns a true value, it will break out of the loop.
- */
- function eachReverse(ary, func) {
- if (ary) {
- var i;
- for (i = ary.length - 1; i > -1; i -= 1) {
- if (ary[i] && func(ary[i], i, ary)) {
- break;
- }
- }
- }
- }
-
- function hasProp(obj, prop) {
- return hasOwn.call(obj, prop);
- }
-
- function getOwn(obj, prop) {
- return hasProp(obj, prop) && obj[prop];
- }
-
- /**
- * Cycles over properties in an object and calls a function for each
- * property value. If the function returns a truthy value, then the
- * iteration is stopped.
- */
- function eachProp(obj, func) {
- var prop;
- for (prop in obj) {
- if (hasProp(obj, prop)) {
- if (func(obj[prop], prop)) {
- break;
- }
- }
- }
- }
-
- /**
- * Simple function to mix in properties from source into target,
- * but only if target does not already have a property of the same name.
- */
- function mixin(target, source, force, deepStringMixin) {
- if (source) {
- eachProp(source, function (value, prop) {
- if (force || !hasProp(target, prop)) {
- if (deepStringMixin && typeof value !== 'string') {
- if (!target[prop]) {
- target[prop] = {};
- }
- mixin(target[prop], value, force, deepStringMixin);
- } else {
- target[prop] = value;
- }
- }
- });
- }
- return target;
- }
-
- //Similar to Function.prototype.bind, but the 'this' object is specified
- //first, since it is easier to read/figure out what 'this' will be.
- function bind(obj, fn) {
- return function () {
- return fn.apply(obj, arguments);
- };
- }
-
- function scripts() {
- return document.getElementsByTagName('script');
- }
-
- function defaultOnError(err) {
- throw err;
- }
-
- //Allow getting a global that expressed in
- //dot notation, like 'a.b.c'.
- function getGlobal(value) {
- if (!value) {
- return value;
- }
- var g = global;
- each(value.split('.'), function (part) {
- g = g[part];
- });
- return g;
- }
-
- /**
- * Constructs an error with a pointer to an URL with more information.
- * @param {String} id the error ID that maps to an ID on a web page.
- * @param {String} message human readable error.
- * @param {Error} [err] the original error, if there is one.
- *
- * @returns {Error}
- */
- function makeError(id, msg, err, requireModules) {
- var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
- e.requireType = id;
- e.requireModules = requireModules;
- if (err) {
- e.originalError = err;
- }
- return e;
- }
-
- if (typeof define !== 'undefined') {
- //If a define is already in play via another AMD loader,
- //do not overwrite.
- return;
- }
-
- if (typeof requirejs !== 'undefined') {
- if (isFunction(requirejs)) {
- //Do not overwrite and existing requirejs instance.
- return;
- }
- cfg = requirejs;
- requirejs = undefined;
- }
-
- //Allow for a require config object
- if (typeof require !== 'undefined' && !isFunction(require)) {
- //assume it is a config object.
- cfg = require;
- require = undefined;
- }
-
- function newContext(contextName) {
- var inCheckLoaded, Module, context, handlers,
- checkLoadedTimeoutId,
- config = {
- //Defaults. Do not set a default for map
- //config to speed up normalize(), which
- //will run faster if there is no default.
- waitSeconds: 7,
- baseUrl: './',
- paths: {},
- pkgs: {},
- shim: {},
- config: {}
- },
- registry = {},
- //registry of just enabled modules, to speed
- //cycle breaking code when lots of modules
- //are registered, but not activated.
- enabledRegistry = {},
- undefEvents = {},
- defQueue = [],
- defined = {},
- urlFetched = {},
- requireCounter = 1,
- unnormalizedCounter = 1;
-
- /**
- * Trims the . and .. from an array of path segments.
- * It will keep a leading path segment if a .. will become
- * the first path segment, to help with module name lookups,
- * which act like paths, but can be remapped. But the end result,
- * all paths that use this function should look normalized.
- * NOTE: this method MODIFIES the input array.
- * @param {Array} ary the array of path segments.
- */
- function trimDots(ary) {
- var i, part;
- for (i = 0; ary[i]; i += 1) {
- part = ary[i];
- if (part === '.') {
- ary.splice(i, 1);
- i -= 1;
- } else if (part === '..') {
- if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
- //End of the line. Keep at least one non-dot
- //path segment at the front so it can be mapped
- //correctly to disk. Otherwise, there is likely
- //no path mapping for a path starting with '..'.
- //This can still fail, but catches the most reasonable
- //uses of ..
- break;
- } else if (i > 0) {
- ary.splice(i - 1, 2);
- i -= 2;
- }
- }
- }
- }
-
- /**
- * Given a relative module name, like ./something, normalize it to
- * a real name that can be mapped to a path.
- * @param {String} name the relative name
- * @param {String} baseName a real name that the name arg is relative
- * to.
- * @param {Boolean} applyMap apply the map config to the value. Should
- * only be done if this normalization is for a dependency ID.
- * @returns {String} normalized name
- */
- function normalize(name, baseName, applyMap) {
- var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment,
- foundMap, foundI, foundStarMap, starI,
- baseParts = baseName && baseName.split('/'),
- normalizedBaseParts = baseParts,
- map = config.map,
- starMap = map && map['*'];
-
- //Adjust any relative paths.
- if (name && name.charAt(0) === '.') {
- //If have a base name, try to normalize against it,
- //otherwise, assume it is a top-level require that will
- //be relative to baseUrl in the end.
- if (baseName) {
- if (getOwn(config.pkgs, baseName)) {
- //If the baseName is a package name, then just treat it as one
- //name to concat the name with.
- normalizedBaseParts = baseParts = [baseName];
- } else {
- //Convert baseName to array, and lop off the last part,
- //so that . matches that 'directory' and not name of the baseName's
- //module. For instance, baseName of 'one/two/three', maps to
- //'one/two/three.js', but we want the directory, 'one/two' for
- //this normalization.
- normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
- }
-
- name = normalizedBaseParts.concat(name.split('/'));
- trimDots(name);
-
- //Some use of packages may use a . path to reference the
- //'main' module name, so normalize for that.
- pkgConfig = getOwn(config.pkgs, (pkgName = name[0]));
- name = name.join('/');
- if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
- name = pkgName;
- }
- } else if (name.indexOf('./') === 0) {
- // No baseName, so this is ID is resolved relative
- // to baseUrl, pull off the leading dot.
- name = name.substring(2);
- }
- }
-
- //Apply map config if available.
- if (applyMap && map && (baseParts || starMap)) {
- nameParts = name.split('/');
-
- for (i = nameParts.length; i > 0; i -= 1) {
- nameSegment = nameParts.slice(0, i).join('/');
-
- if (baseParts) {
- //Find the longest baseName segment match in the config.
- //So, do joins on the biggest to smallest lengths of baseParts.
- for (j = baseParts.length; j > 0; j -= 1) {
- mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
-
- //baseName segment has config, find if it has one for
- //this name.
- if (mapValue) {
- mapValue = getOwn(mapValue, nameSegment);
- if (mapValue) {
- //Match, update name to the new value.
- foundMap = mapValue;
- foundI = i;
- break;
- }
- }
- }
- }
-
- if (foundMap) {
- break;
- }
-
- //Check for a star map match, but just hold on to it,
- //if there is a shorter segment match later in a matching
- //config, then favor over this star map.
- if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
- foundStarMap = getOwn(starMap, nameSegment);
- starI = i;
- }
- }
-
- if (!foundMap && foundStarMap) {
- foundMap = foundStarMap;
- foundI = starI;
- }
-
- if (foundMap) {
- nameParts.splice(0, foundI, foundMap);
- name = nameParts.join('/');
- }
- }
-
- return name;
- }
-
- function removeScript(name) {
- if (isBrowser) {
- each(scripts(), function (scriptNode) {
- if (scriptNode.getAttribute('data-requiremodule') === name &&
- scriptNode.getAttribute('data-requirecontext') === context.contextName) {
- scriptNode.parentNode.removeChild(scriptNode);
- return true;
- }
- });
- }
- }
-
- function hasPathFallback(id) {
- var pathConfig = getOwn(config.paths, id);
- if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
- //Pop off the first array value, since it failed, and
- //retry
- pathConfig.shift();
- context.require.undef(id);
- context.require([id]);
- return true;
- }
- }
-
- //Turns a plugin!resource to [plugin, resource]
- //with the plugin being undefined if the name
- //did not have a plugin prefix.
- function splitPrefix(name) {
- var prefix,
- index = name ? name.indexOf('!') : -1;
- if (index > -1) {
- prefix = name.substring(0, index);
- name = name.substring(index + 1, name.length);
- }
- return [prefix, name];
- }
-
- /**
- * Creates a module mapping that includes plugin prefix, module
- * name, and path. If parentModuleMap is provided it will
- * also normalize the name via require.normalize()
- *
- * @param {String} name the module name
- * @param {String} [parentModuleMap] parent module map
- * for the module name, used to resolve relative names.
- * @param {Boolean} isNormalized: is the ID already normalized.
- * This is true if this call is done for a define() module ID.
- * @param {Boolean} applyMap: apply the map config to the ID.
- * Should only be true if this map is for a dependency.
- *
- * @returns {Object}
- */
- function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
- var url, pluginModule, suffix, nameParts,
- prefix = null,
- parentName = parentModuleMap ? parentModuleMap.name : null,
- originalName = name,
- isDefine = true,
- normalizedName = '';
-
- //If no name, then it means it is a require call, generate an
- //internal name.
- if (!name) {
- isDefine = false;
- name = '_ at r' + (requireCounter += 1);
- }
-
- nameParts = splitPrefix(name);
- prefix = nameParts[0];
- name = nameParts[1];
-
- if (prefix) {
- prefix = normalize(prefix, parentName, applyMap);
- pluginModule = getOwn(defined, prefix);
- }
-
- //Account for relative paths if there is a base name.
- if (name) {
- if (prefix) {
- if (pluginModule && pluginModule.normalize) {
- //Plugin is loaded, use its normalize method.
- normalizedName = pluginModule.normalize(name, function (name) {
- return normalize(name, parentName, applyMap);
- });
- } else {
- normalizedName = normalize(name, parentName, applyMap);
- }
- } else {
- //A regular module.
- normalizedName = normalize(name, parentName, applyMap);
-
- //Normalized name may be a plugin ID due to map config
- //application in normalize. The map config values must
- //already be normalized, so do not need to redo that part.
- nameParts = splitPrefix(normalizedName);
- prefix = nameParts[0];
- normalizedName = nameParts[1];
- isNormalized = true;
-
- url = context.nameToUrl(normalizedName);
- }
- }
-
- //If the id is a plugin id that cannot be determined if it needs
- //normalization, stamp it with a unique ID so two matching relative
- //ids that may conflict can be separate.
- suffix = prefix && !pluginModule && !isNormalized ?
- '_unnormalized' + (unnormalizedCounter += 1) :
- '';
-
- return {
- prefix: prefix,
- name: normalizedName,
- parentMap: parentModuleMap,
- unnormalized: !!suffix,
- url: url,
- originalName: originalName,
- isDefine: isDefine,
- id: (prefix ?
- prefix + '!' + normalizedName :
- normalizedName) + suffix
- };
- }
-
- function getModule(depMap) {
- var id = depMap.id,
- mod = getOwn(registry, id);
-
- if (!mod) {
- mod = registry[id] = new context.Module(depMap);
- }
-
- return mod;
- }
-
- function on(depMap, name, fn) {
- var id = depMap.id,
- mod = getOwn(registry, id);
-
- if (hasProp(defined, id) &&
- (!mod || mod.defineEmitComplete)) {
- if (name === 'defined') {
- fn(defined[id]);
- }
- } else {
- mod = getModule(depMap);
- if (mod.error && name === 'error') {
- fn(mod.error);
- } else {
- mod.on(name, fn);
- }
- }
- }
-
- function onError(err, errback) {
- var ids = err.requireModules,
- notified = false;
-
- if (errback) {
- errback(err);
- } else {
- each(ids, function (id) {
- var mod = getOwn(registry, id);
- if (mod) {
- //Set error on module, so it skips timeout checks.
- mod.error = err;
- if (mod.events.error) {
- notified = true;
- mod.emit('error', err);
- }
- }
- });
-
- if (!notified) {
- req.onError(err);
- }
- }
- }
-
- /**
- * Internal method to transfer globalQueue items to this context's
- * defQueue.
- */
- function takeGlobalQueue() {
- //Push all the globalDefQueue items into the context's defQueue
- if (globalDefQueue.length) {
- //Array splice in the values since the context code has a
- //local var ref to defQueue, so cannot just reassign the one
- //on context.
- apsp.apply(defQueue,
- [defQueue.length - 1, 0].concat(globalDefQueue));
- globalDefQueue = [];
- }
- }
-
- handlers = {
- 'require': function (mod) {
- if (mod.require) {
- return mod.require;
- } else {
- return (mod.require = context.makeRequire(mod.map));
- }
- },
- 'exports': function (mod) {
- mod.usingExports = true;
- if (mod.map.isDefine) {
- if (mod.exports) {
- return mod.exports;
- } else {
- return (mod.exports = defined[mod.map.id] = {});
- }
- }
- },
- 'module': function (mod) {
- if (mod.module) {
- return mod.module;
- } else {
- return (mod.module = {
- id: mod.map.id,
- uri: mod.map.url,
- config: function () {
- var c,
- pkg = getOwn(config.pkgs, mod.map.id);
- // For packages, only support config targeted
- // at the main module.
- c = pkg ? getOwn(config.config, mod.map.id + '/' + pkg.main) :
- getOwn(config.config, mod.map.id);
- return c || {};
- },
- exports: defined[mod.map.id]
- });
- }
- }
- };
-
- function cleanRegistry(id) {
- //Clean up machinery used for waiting modules.
- delete registry[id];
- delete enabledRegistry[id];
- }
-
- function breakCycle(mod, traced, processed) {
- var id = mod.map.id;
-
- if (mod.error) {
- mod.emit('error', mod.error);
- } else {
- traced[id] = true;
- each(mod.depMaps, function (depMap, i) {
- var depId = depMap.id,
- dep = getOwn(registry, depId);
-
- //Only force things that have not completed
- //being defined, so still in the registry,
- //and only if it has not been matched up
- //in the module already.
- if (dep && !mod.depMatched[i] && !processed[depId]) {
- if (getOwn(traced, depId)) {
- mod.defineDep(i, defined[depId]);
- mod.check(); //pass false?
- } else {
- breakCycle(dep, traced, processed);
- }
- }
- });
- processed[id] = true;
- }
- }
-
- function checkLoaded() {
- var map, modId, err, usingPathFallback,
- waitInterval = config.waitSeconds * 1000,
- //It is possible to disable the wait interval by using waitSeconds of 0.
- expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
- noLoads = [],
- reqCalls = [],
- stillLoading = false,
- needCycleCheck = true;
-
- //Do not bother if this call was a result of a cycle break.
- if (inCheckLoaded) {
- return;
- }
-
- inCheckLoaded = true;
-
- //Figure out the state of all the modules.
- eachProp(enabledRegistry, function (mod) {
- map = mod.map;
- modId = map.id;
-
- //Skip things that are not enabled or in error state.
- if (!mod.enabled) {
- return;
- }
-
- if (!map.isDefine) {
- reqCalls.push(mod);
- }
-
- if (!mod.error) {
- //If the module should be executed, and it has not
- //been inited and time is up, remember it.
- if (!mod.inited && expired) {
- if (hasPathFallback(modId)) {
- usingPathFallback = true;
- stillLoading = true;
- } else {
- noLoads.push(modId);
- removeScript(modId);
- }
- } else if (!mod.inited && mod.fetched && map.isDefine) {
- stillLoading = true;
- if (!map.prefix) {
- //No reason to keep looking for unfinished
- //loading. If the only stillLoading is a
- //plugin resource though, keep going,
- //because it may be that a plugin resource
- //is waiting on a non-plugin cycle.
- return (needCycleCheck = false);
- }
- }
- }
- });
-
- if (expired && noLoads.length) {
- //If wait time expired, throw error of unloaded modules.
- err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
- err.contextName = context.contextName;
- return onError(err);
- }
-
- //Not expired, check for a cycle.
- if (needCycleCheck) {
- each(reqCalls, function (mod) {
- breakCycle(mod, {}, {});
- });
- }
-
- //If still waiting on loads, and the waiting load is something
- //other than a plugin resource, or there are still outstanding
- //scripts, then just try back later.
- if ((!expired || usingPathFallback) && stillLoading) {
- //Something is still waiting to load. Wait for it, but only
- //if a timeout is not already in effect.
- if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
- checkLoadedTimeoutId = setTimeout(function () {
- checkLoadedTimeoutId = 0;
- checkLoaded();
- }, 50);
- }
- }
-
- inCheckLoaded = false;
- }
-
- Module = function (map) {
- this.events = getOwn(undefEvents, map.id) || {};
- this.map = map;
- this.shim = getOwn(config.shim, map.id);
- this.depExports = [];
- this.depMaps = [];
- this.depMatched = [];
- this.pluginMaps = {};
- this.depCount = 0;
-
- /* this.exports this.factory
- this.depMaps = [],
- this.enabled, this.fetched
- */
- };
-
- Module.prototype = {
- init: function (depMaps, factory, errback, options) {
- options = options || {};
-
- //Do not do more inits if already done. Can happen if there
- //are multiple define calls for the same module. That is not
- //a normal, common case, but it is also not unexpected.
- if (this.inited) {
- return;
- }
-
- this.factory = factory;
-
- if (errback) {
- //Register for errors on this module.
- this.on('error', errback);
- } else if (this.events.error) {
- //If no errback already, but there are error listeners
- //on this module, set up an errback to pass to the deps.
- errback = bind(this, function (err) {
- this.emit('error', err);
- });
- }
-
- //Do a copy of the dependency array, so that
- //source inputs are not modified. For example
- //"shim" deps are passed in here directly, and
- //doing a direct modification of the depMaps array
- //would affect that config.
- this.depMaps = depMaps && depMaps.slice(0);
-
- this.errback = errback;
-
- //Indicate this module has be initialized
- this.inited = true;
-
- this.ignore = options.ignore;
-
- //Could have option to init this module in enabled mode,
- //or could have been previously marked as enabled. However,
- //the dependencies are not known until init is called. So
- //if enabled previously, now trigger dependencies as enabled.
- if (options.enabled || this.enabled) {
- //Enable this module and dependencies.
- //Will call this.check()
- this.enable();
- } else {
- this.check();
- }
- },
-
- defineDep: function (i, depExports) {
- //Because of cycles, defined callback for a given
- //export can be called more than once.
- if (!this.depMatched[i]) {
- this.depMatched[i] = true;
- this.depCount -= 1;
- this.depExports[i] = depExports;
- }
- },
-
- fetch: function () {
- if (this.fetched) {
- return;
- }
- this.fetched = true;
-
- context.startTime = (new Date()).getTime();
-
- var map = this.map;
-
- //If the manager is for a plugin managed resource,
- //ask the plugin to load it now.
- if (this.shim) {
- context.makeRequire(this.map, {
- enableBuildCallback: true
- })(this.shim.deps || [], bind(this, function () {
- return map.prefix ? this.callPlugin() : this.load();
- }));
- } else {
- //Regular dependency.
- return map.prefix ? this.callPlugin() : this.load();
- }
- },
-
- load: function () {
- var url = this.map.url;
-
- //Regular dependency.
- if (!urlFetched[url]) {
- urlFetched[url] = true;
- context.load(this.map.id, url);
- }
- },
-
- /**
- * Checks if the module is ready to define itself, and if so,
- * define it.
- */
- check: function () {
- if (!this.enabled || this.enabling) {
- return;
- }
-
- var err, cjsModule,
- id = this.map.id,
- depExports = this.depExports,
- exports = this.exports,
- factory = this.factory;
-
- if (!this.inited) {
- this.fetch();
- } else if (this.error) {
- this.emit('error', this.error);
- } else if (!this.defining) {
- //The factory could trigger another require call
- //that would result in checking this module to
- //define itself again. If already in the process
- //of doing that, skip this work.
- this.defining = true;
-
- if (this.depCount < 1 && !this.defined) {
- if (isFunction(factory)) {
- //If there is an error listener, favor passing
- //to that instead of throwing an error. However,
- //only do it for define()'d modules. require
- //errbacks should not be called for failures in
- //their callbacks (#699). However if a global
- //onError is set, use that.
- if ((this.events.error && this.map.isDefine) ||
- req.onError !== defaultOnError) {
- try {
- exports = context.execCb(id, factory, depExports, exports);
- } catch (e) {
- err = e;
- }
- } else {
- exports = context.execCb(id, factory, depExports, exports);
- }
-
- if (this.map.isDefine) {
- //If setting exports via 'module' is in play,
- //favor that over return value and exports. After that,
- //favor a non-undefined return value over exports use.
- cjsModule = this.module;
- if (cjsModule &&
- cjsModule.exports !== undefined &&
- //Make sure it is not already the exports value
- cjsModule.exports !== this.exports) {
- exports = cjsModule.exports;
- } else if (exports === undefined && this.usingExports) {
- //exports already set the defined value.
- exports = this.exports;
- }
- }
-
- if (err) {
- err.requireMap = this.map;
- err.requireModules = this.map.isDefine ? [this.map.id] : null;
- err.requireType = this.map.isDefine ? 'define' : 'require';
- return onError((this.error = err));
- }
-
- } else {
- //Just a literal value
- exports = factory;
- }
-
- this.exports = exports;
-
- if (this.map.isDefine && !this.ignore) {
- defined[id] = exports;
-
- if (req.onResourceLoad) {
- req.onResourceLoad(context, this.map, this.depMaps);
- }
- }
-
- //Clean up
- cleanRegistry(id);
-
- this.defined = true;
- }
-
- //Finished the define stage. Allow calling check again
- //to allow define notifications below in the case of a
- //cycle.
- this.defining = false;
-
- if (this.defined && !this.defineEmitted) {
- this.defineEmitted = true;
- this.emit('defined', this.exports);
- this.defineEmitComplete = true;
- }
-
- }
- },
-
- callPlugin: function () {
- var map = this.map,
- id = map.id,
- //Map already normalized the prefix.
- pluginMap = makeModuleMap(map.prefix);
-
- //Mark this as a dependency for this plugin, so it
- //can be traced for cycles.
- this.depMaps.push(pluginMap);
-
- on(pluginMap, 'defined', bind(this, function (plugin) {
- var load, normalizedMap, normalizedMod,
- name = this.map.name,
- parentName = this.map.parentMap ? this.map.parentMap.name : null,
- localRequire = context.makeRequire(map.parentMap, {
- enableBuildCallback: true
- });
-
- //If current map is not normalized, wait for that
- //normalized name to load instead of continuing.
- if (this.map.unnormalized) {
- //Normalize the ID if the plugin allows it.
- if (plugin.normalize) {
- name = plugin.normalize(name, function (name) {
- return normalize(name, parentName, true);
- }) || '';
- }
-
- //prefix and name should already be normalized, no need
- //for applying map config again either.
- normalizedMap = makeModuleMap(map.prefix + '!' + name,
- this.map.parentMap);
- on(normalizedMap,
- 'defined', bind(this, function (value) {
- this.init([], function () { return value; }, null, {
- enabled: true,
- ignore: true
- });
- }));
-
- normalizedMod = getOwn(registry, normalizedMap.id);
- if (normalizedMod) {
- //Mark this as a dependency for this plugin, so it
- //can be traced for cycles.
- this.depMaps.push(normalizedMap);
-
- if (this.events.error) {
- normalizedMod.on('error', bind(this, function (err) {
- this.emit('error', err);
- }));
- }
- normalizedMod.enable();
- }
-
- return;
- }
-
- load = bind(this, function (value) {
- this.init([], function () { return value; }, null, {
- enabled: true
- });
- });
-
- load.error = bind(this, function (err) {
- this.inited = true;
- this.error = err;
- err.requireModules = [id];
-
- //Remove temp unnormalized modules for this module,
- //since they will never be resolved otherwise now.
- eachProp(registry, function (mod) {
- if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
- cleanRegistry(mod.map.id);
- }
- });
-
- onError(err);
- });
-
- //Allow plugins to load other code without having to know the
- //context or how to 'complete' the load.
- load.fromText = bind(this, function (text, textAlt) {
- /*jslint evil: true */
- var moduleName = map.name,
- moduleMap = makeModuleMap(moduleName),
- hasInteractive = useInteractive;
-
- //As of 2.1.0, support just passing the text, to reinforce
- //fromText only being called once per resource. Still
- //support old style of passing moduleName but discard
- //that moduleName in favor of the internal ref.
- if (textAlt) {
- text = textAlt;
- }
-
- //Turn off interactive script matching for IE for any define
- //calls in the text, then turn it back on at the end.
- if (hasInteractive) {
- useInteractive = false;
- }
-
- //Prime the system by creating a module instance for
- //it.
- getModule(moduleMap);
-
- //Transfer any config to this other module.
- if (hasProp(config.config, id)) {
- config.config[moduleName] = config.config[id];
- }
-
- try {
- req.exec(text);
- } catch (e) {
- return onError(makeError('fromtexteval',
- 'fromText eval for ' + id +
- ' failed: ' + e,
- e,
- [id]));
- }
-
- if (hasInteractive) {
- useInteractive = true;
- }
-
- //Mark this as a dependency for the plugin
- //resource
- this.depMaps.push(moduleMap);
-
- //Support anonymous modules.
- context.completeLoad(moduleName);
-
- //Bind the value of that module to the value for this
- //resource ID.
- localRequire([moduleName], load);
- });
-
- //Use parentName here since the plugin's name is not reliable,
- //could be some weird string with no path that actually wants to
- //reference the parentName's path.
- plugin.load(map.name, localRequire, load, config);
- }));
-
- context.enable(pluginMap, this);
- this.pluginMaps[pluginMap.id] = pluginMap;
- },
-
- enable: function () {
- enabledRegistry[this.map.id] = this;
- this.enabled = true;
-
- //Set flag mentioning that the module is enabling,
- //so that immediate calls to the defined callbacks
- //for dependencies do not trigger inadvertent load
- //with the depCount still being zero.
- this.enabling = true;
-
- //Enable each dependency
- each(this.depMaps, bind(this, function (depMap, i) {
- var id, mod, handler;
-
- if (typeof depMap === 'string') {
- //Dependency needs to be converted to a depMap
- //and wired up to this module.
- depMap = makeModuleMap(depMap,
- (this.map.isDefine ? this.map : this.map.parentMap),
- false,
- !this.skipMap);
- this.depMaps[i] = depMap;
-
- handler = getOwn(handlers, depMap.id);
-
- if (handler) {
- this.depExports[i] = handler(this);
- return;
- }
-
- this.depCount += 1;
-
- on(depMap, 'defined', bind(this, function (depExports) {
- this.defineDep(i, depExports);
- this.check();
- }));
-
- if (this.errback) {
- on(depMap, 'error', bind(this, this.errback));
- }
- }
-
- id = depMap.id;
- mod = registry[id];
-
- //Skip special modules like 'require', 'exports', 'module'
- //Also, don't call enable if it is already enabled,
- //important in circular dependency cases.
- if (!hasProp(handlers, id) && mod && !mod.enabled) {
- context.enable(depMap, this);
- }
- }));
-
- //Enable each plugin that is used in
- //a dependency
- eachProp(this.pluginMaps, bind(this, function (pluginMap) {
- var mod = getOwn(registry, pluginMap.id);
- if (mod && !mod.enabled) {
- context.enable(pluginMap, this);
- }
- }));
-
- this.enabling = false;
-
- this.check();
- },
-
- on: function (name, cb) {
- var cbs = this.events[name];
- if (!cbs) {
- cbs = this.events[name] = [];
- }
- cbs.push(cb);
- },
-
- emit: function (name, evt) {
- each(this.events[name], function (cb) {
- cb(evt);
- });
- if (name === 'error') {
- //Now that the error handler was triggered, remove
- //the listeners, since this broken Module instance
- //can stay around for a while in the registry.
- delete this.events[name];
- }
- }
- };
-
- function callGetModule(args) {
- //Skip modules already defined.
- if (!hasProp(defined, args[0])) {
- getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
- }
- }
-
- function removeListener(node, func, name, ieName) {
- //Favor detachEvent because of IE9
- //issue, see attachEvent/addEventListener comment elsewhere
- //in this file.
- if (node.detachEvent && !isOpera) {
- //Probably IE. If not it will throw an error, which will be
- //useful to know.
- if (ieName) {
- node.detachEvent(ieName, func);
- }
- } else {
- node.removeEventListener(name, func, false);
- }
- }
-
- /**
- * Given an event from a script node, get the requirejs info from it,
- * and then removes the event listeners on the node.
- * @param {Event} evt
- * @returns {Object}
- */
- function getScriptData(evt) {
- //Using currentTarget instead of target for Firefox 2.0's sake. Not
- //all old browsers will be supported, but this one was easy enough
- //to support and still makes sense.
- var node = evt.currentTarget || evt.srcElement;
-
- //Remove the listeners once here.
- removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
- removeListener(node, context.onScriptError, 'error');
-
- return {
- node: node,
- id: node && node.getAttribute('data-requiremodule')
- };
- }
-
- function intakeDefines() {
- var args;
-
- //Any defined modules in the global queue, intake them now.
- takeGlobalQueue();
-
- //Make sure any remaining defQueue items get properly processed.
- while (defQueue.length) {
- args = defQueue.shift();
- if (args[0] === null) {
- return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
- } else {
- //args are id, deps, factory. Should be normalized by the
- //define() function.
- callGetModule(args);
- }
- }
- }
-
- context = {
- config: config,
- contextName: contextName,
- registry: registry,
- defined: defined,
- urlFetched: urlFetched,
- defQueue: defQueue,
- Module: Module,
- makeModuleMap: makeModuleMap,
- nextTick: req.nextTick,
- onError: onError,
-
- /**
- * Set a configuration for the context.
- * @param {Object} cfg config object to integrate.
- */
- configure: function (cfg) {
- //Make sure the baseUrl ends in a slash.
- if (cfg.baseUrl) {
- if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
- cfg.baseUrl += '/';
- }
- }
-
- //Save off the paths and packages since they require special processing,
- //they are additive.
- var pkgs = config.pkgs,
- shim = config.shim,
- objs = {
- paths: true,
- config: true,
- map: true
- };
-
- eachProp(cfg, function (value, prop) {
- if (objs[prop]) {
- if (prop === 'map') {
- if (!config.map) {
- config.map = {};
- }
- mixin(config[prop], value, true, true);
- } else {
- mixin(config[prop], value, true);
- }
- } else {
- config[prop] = value;
- }
- });
-
- //Merge shim
- if (cfg.shim) {
- eachProp(cfg.shim, function (value, id) {
- //Normalize the structure
- if (isArray(value)) {
- value = {
- deps: value
- };
- }
- if ((value.exports || value.init) && !value.exportsFn) {
- value.exportsFn = context.makeShimExports(value);
- }
- shim[id] = value;
- });
- config.shim = shim;
- }
-
- //Adjust packages if necessary.
- if (cfg.packages) {
- each(cfg.packages, function (pkgObj) {
- var location;
-
- pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
- location = pkgObj.location;
-
- //Create a brand new object on pkgs, since currentPackages can
- //be passed in again, and config.pkgs is the internal transformed
- //state for all package configs.
- pkgs[pkgObj.name] = {
- name: pkgObj.name,
- location: location || pkgObj.name,
- //Remove leading dot in main, so main paths are normalized,
- //and remove any trailing .js, since different package
- //envs have different conventions: some use a module name,
- //some use a file name.
- main: (pkgObj.main || 'main')
- .replace(currDirRegExp, '')
- .replace(jsSuffixRegExp, '')
- };
- });
-
- //Done with modifications, assing packages back to context config
- config.pkgs = pkgs;
- }
-
- //If there are any "waiting to execute" modules in the registry,
- //update the maps for them, since their info, like URLs to load,
- //may have changed.
- eachProp(registry, function (mod, id) {
- //If module already has init called, since it is too
- //late to modify them, and ignore unnormalized ones
- //since they are transient.
- if (!mod.inited && !mod.map.unnormalized) {
- mod.map = makeModuleMap(id);
- }
- });
-
- //If a deps array or a config callback is specified, then call
- //require with those args. This is useful when require is defined as a
- //config object before require.js is loaded.
- if (cfg.deps || cfg.callback) {
- context.require(cfg.deps || [], cfg.callback);
- }
- },
-
- makeShimExports: function (value) {
- function fn() {
- var ret;
- if (value.init) {
- ret = value.init.apply(global, arguments);
- }
- return ret || (value.exports && getGlobal(value.exports));
- }
- return fn;
- },
-
- makeRequire: function (relMap, options) {
- options = options || {};
-
- function localRequire(deps, callback, errback) {
- var id, map, requireMod;
-
- if (options.enableBuildCallback && callback && isFunction(callback)) {
- callback.__requireJsBuild = true;
- }
-
- if (typeof deps === 'string') {
- if (isFunction(callback)) {
- //Invalid call
- return onError(makeError('requireargs', 'Invalid require call'), errback);
- }
-
- //If require|exports|module are requested, get the
- //value for them from the special handlers. Caveat:
- //this only works while module is being defined.
- if (relMap && hasProp(handlers, deps)) {
- return handlers[deps](registry[relMap.id]);
- }
-
- //Synchronous access to one module. If require.get is
- //available (as in the Node adapter), prefer that.
- if (req.get) {
- return req.get(context, deps, relMap, localRequire);
- }
-
- //Normalize module name, if it contains . or ..
- map = makeModuleMap(deps, relMap, false, true);
- id = map.id;
-
- if (!hasProp(defined, id)) {
- return onError(makeError('notloaded', 'Module name "' +
- id +
- '" has not been loaded yet for context: ' +
- contextName +
- (relMap ? '' : '. Use require([])')));
- }
- return defined[id];
- }
-
- //Grab defines waiting in the global queue.
- intakeDefines();
-
- //Mark all the dependencies as needing to be loaded.
- context.nextTick(function () {
- //Some defines could have been added since the
- //require call, collect them.
- intakeDefines();
-
- requireMod = getModule(makeModuleMap(null, relMap));
-
- //Store if map config should be applied to this require
- //call for dependencies.
- requireMod.skipMap = options.skipMap;
-
- requireMod.init(deps, callback, errback, {
- enabled: true
- });
-
- checkLoaded();
- });
-
- return localRequire;
- }
-
- mixin(localRequire, {
- isBrowser: isBrowser,
-
- /**
- * Converts a module name + .extension into an URL path.
- * *Requires* the use of a module name. It does not support using
- * plain URLs like nameToUrl.
- */
- toUrl: function (moduleNamePlusExt) {
- var ext,
- index = moduleNamePlusExt.lastIndexOf('.'),
- segment = moduleNamePlusExt.split('/')[0],
- isRelative = segment === '.' || segment === '..';
-
- //Have a file extension alias, and it is not the
- //dots from a relative path.
- if (index !== -1 && (!isRelative || index > 1)) {
- ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
- moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
- }
-
- return context.nameToUrl(normalize(moduleNamePlusExt,
- relMap && relMap.id, true), ext, true);
- },
-
- defined: function (id) {
- return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
- },
-
- specified: function (id) {
- id = makeModuleMap(id, relMap, false, true).id;
- return hasProp(defined, id) || hasProp(registry, id);
- }
- });
-
- //Only allow undef on top level require calls
- if (!relMap) {
- localRequire.undef = function (id) {
- //Bind any waiting define() calls to this context,
- //fix for #408
- takeGlobalQueue();
-
- var map = makeModuleMap(id, relMap, true),
- mod = getOwn(registry, id);
-
- removeScript(id);
-
- delete defined[id];
- delete urlFetched[map.url];
- delete undefEvents[id];
-
- if (mod) {
- //Hold on to listeners in case the
- //module will be attempted to be reloaded
- //using a different config.
- if (mod.events.defined) {
- undefEvents[id] = mod.events;
- }
-
- cleanRegistry(id);
- }
- };
- }
-
- return localRequire;
- },
-
- /**
- * Called to enable a module if it is still in the registry
- * awaiting enablement. A second arg, parent, the parent module,
- * is passed in for context, when this method is overriden by
- * the optimizer. Not shown here to keep code compact.
- */
- enable: function (depMap) {
- var mod = getOwn(registry, depMap.id);
- if (mod) {
- getModule(depMap).enable();
- }
- },
-
- /**
- * Internal method used by environment adapters to complete a load event.
- * A load event could be a script load or just a load pass from a synchronous
- * load call.
- * @param {String} moduleName the name of the module to potentially complete.
- */
- completeLoad: function (moduleName) {
- var found, args, mod,
- shim = getOwn(config.shim, moduleName) || {},
- shExports = shim.exports;
-
- takeGlobalQueue();
-
- while (defQueue.length) {
- args = defQueue.shift();
- if (args[0] === null) {
- args[0] = moduleName;
- //If already found an anonymous module and bound it
- //to this name, then this is some other anon module
- //waiting for its completeLoad to fire.
- if (found) {
- break;
- }
- found = true;
- } else if (args[0] === moduleName) {
- //Found matching define call for this script!
- found = true;
- }
-
- callGetModule(args);
- }
-
- //Do this after the cycle of callGetModule in case the result
- //of those calls/init calls changes the registry.
- mod = getOwn(registry, moduleName);
-
- if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
- if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
- if (hasPathFallback(moduleName)) {
- return;
- } else {
- return onError(makeError('nodefine',
- 'No define call for ' + moduleName,
- null,
- [moduleName]));
- }
- } else {
- //A script that does not call define(), so just simulate
- //the call for it.
- callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
- }
- }
-
- checkLoaded();
- },
-
- /**
- * Converts a module name to a file path. Supports cases where
- * moduleName may actually be just an URL.
- * Note that it **does not** call normalize on the moduleName,
- * it is assumed to have already been normalized. This is an
- * internal API, not a public one. Use toUrl for the public API.
- */
- nameToUrl: function (moduleName, ext, skipExt) {
- var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
- parentPath;
-
- //If a colon is in the URL, it indicates a protocol is used and it is just
- //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
- //or ends with .js, then assume the user meant to use an url and not a module id.
- //The slash is important for protocol-less URLs as well as full paths.
- if (req.jsExtRegExp.test(moduleName)) {
- //Just a plain path, not module name lookup, so just return it.
- //Add extension if it is included. This is a bit wonky, only non-.js things pass
- //an extension, this method probably needs to be reworked.
- url = moduleName + (ext || '');
- } else {
- //A module that needs to be converted to a path.
- paths = config.paths;
- pkgs = config.pkgs;
-
- syms = moduleName.split('/');
- //For each module name segment, see if there is a path
- //registered for it. Start with most specific name
- //and work up from it.
- for (i = syms.length; i > 0; i -= 1) {
- parentModule = syms.slice(0, i).join('/');
- pkg = getOwn(pkgs, parentModule);
- parentPath = getOwn(paths, parentModule);
- if (parentPath) {
- //If an array, it means there are a few choices,
- //Choose the one that is desired
- if (isArray(parentPath)) {
- parentPath = parentPath[0];
- }
- syms.splice(0, i, parentPath);
- break;
- } else if (pkg) {
- //If module name is just the package name, then looking
- //for the main module.
- if (moduleName === pkg.name) {
- pkgPath = pkg.location + '/' + pkg.main;
- } else {
- pkgPath = pkg.location;
- }
- syms.splice(0, i, pkgPath);
- break;
- }
- }
-
- //Join the path parts together, then figure out if baseUrl is needed.
- url = syms.join('/');
- url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js'));
- url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
- }
-
- return config.urlArgs ? url +
- ((url.indexOf('?') === -1 ? '?' : '&') +
- config.urlArgs) : url;
- },
-
- //Delegates to req.load. Broken out as a separate function to
- //allow overriding in the optimizer.
- load: function (id, url) {
- req.load(context, id, url);
- },
-
- /**
- * Executes a module callback function. Broken out as a separate function
- * solely to allow the build system to sequence the files in the built
- * layer in the right sequence.
- *
- * @private
- */
- execCb: function (name, callback, args, exports) {
- return callback.apply(exports, args);
- },
-
- /**
- * callback for script loads, used to check status of loading.
- *
- * @param {Event} evt the event from the browser for the script
- * that was loaded.
- */
- onScriptLoad: function (evt) {
- //Using currentTarget instead of target for Firefox 2.0's sake. Not
- //all old browsers will be supported, but this one was easy enough
- //to support and still makes sense.
- if (evt.type === 'load' ||
- (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
- //Reset interactive script so a script node is not held onto for
- //to long.
- interactiveScript = null;
-
- //Pull out the name of the module and the context.
- var data = getScriptData(evt);
- context.completeLoad(data.id);
- }
- },
-
- /**
- * Callback for script errors.
- */
- onScriptError: function (evt) {
- var data = getScriptData(evt);
- if (!hasPathFallback(data.id)) {
- return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id]));
- }
- }
- };
-
- context.require = context.makeRequire();
- return context;
- }
-
- /**
- * Main entry point.
- *
- * If the only argument to require is a string, then the module that
- * is represented by that string is fetched for the appropriate context.
- *
- * If the first argument is an array, then it will be treated as an array
- * of dependency string names to fetch. An optional function callback can
- * be specified to execute when all of those dependencies are available.
- *
- * Make a local req variable to help Caja compliance (it assumes things
- * on a require that are not standardized), and to give a short
- * name for minification/local scope use.
- */
- req = requirejs = function (deps, callback, errback, optional) {
-
- //Find the right context, use default
- var context, config,
- contextName = defContextName;
-
- // Determine if have config object in the call.
- if (!isArray(deps) && typeof deps !== 'string') {
- // deps is a config object
- config = deps;
- if (isArray(callback)) {
- // Adjust args if there are dependencies
- deps = callback;
- callback = errback;
- errback = optional;
- } else {
- deps = [];
- }
- }
-
- if (config && config.context) {
- contextName = config.context;
- }
-
- context = getOwn(contexts, contextName);
- if (!context) {
- context = contexts[contextName] = req.s.newContext(contextName);
- }
-
- if (config) {
- context.configure(config);
- }
-
- return context.require(deps, callback, errback);
- };
-
- /**
- * Support require.config() to make it easier to cooperate with other
- * AMD loaders on globally agreed names.
- */
- req.config = function (config) {
- return req(config);
- };
-
- /**
- * Execute something after the current tick
- * of the event loop. Override for other envs
- * that have a better solution than setTimeout.
- * @param {Function} fn function to execute later.
- */
- req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
- setTimeout(fn, 4);
- } : function (fn) { fn(); };
-
- /**
- * Export require as a global, but only if it does not already exist.
- */
- if (!require) {
- require = req;
- }
-
- req.version = version;
-
- //Used to filter out dependencies that are already paths.
- req.jsExtRegExp = /^\/|:|\?|\.js$/;
- req.isBrowser = isBrowser;
- s = req.s = {
- contexts: contexts,
- newContext: newContext
- };
-
- //Create default context.
- req({});
-
- //Exports some context-sensitive methods on global require.
- each([
- 'toUrl',
- 'undef',
- 'defined',
- 'specified'
- ], function (prop) {
- //Reference from contexts instead of early binding to default context,
- //so that during builds, the latest instance of the default context
- //with its config gets used.
- req[prop] = function () {
- var ctx = contexts[defContextName];
- return ctx.require[prop].apply(ctx, arguments);
- };
- });
-
- if (isBrowser) {
- head = s.head = document.getElementsByTagName('head')[0];
- //If BASE tag is in play, using appendChild is a problem for IE6.
- //When that browser dies, this can be removed. Details in this jQuery bug:
- //http://dev.jquery.com/ticket/2709
- baseElement = document.getElementsByTagName('base')[0];
- if (baseElement) {
- head = s.head = baseElement.parentNode;
- }
- }
-
- /**
- * Any errors that require explicitly generates will be passed to this
- * function. Intercept/override it if you want custom error handling.
- * @param {Error} err the error object.
- */
- req.onError = defaultOnError;
-
- /**
- * Creates the node for the load command. Only used in browser envs.
- */
- req.createNode = function (config, moduleName, url) {
- var node = config.xhtml ?
- document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
- document.createElement('script');
- node.type = config.scriptType || 'text/javascript';
- node.charset = 'utf-8';
- node.async = true;
- return node;
- };
-
- /**
- * Does the request to load a module for the browser case.
- * Make this a separate function to allow other environments
- * to override it.
- *
- * @param {Object} context the require context to find state.
- * @param {String} moduleName the name of the module.
- * @param {Object} url the URL to the module.
- */
- req.load = function (context, moduleName, url) {
- var config = (context && context.config) || {},
- node;
- if (isBrowser) {
- //In the browser so use a script tag
- node = req.createNode(config, moduleName, url);
-
- node.setAttribute('data-requirecontext', context.contextName);
- node.setAttribute('data-requiremodule', moduleName);
-
- //Set up load listener. Test attachEvent first because IE9 has
- //a subtle issue in its addEventListener and script onload firings
- //that do not match the behavior of all other browsers with
- //addEventListener support, which fire the onload event for a
- //script right after the script execution. See:
- //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
- //UNFORTUNATELY Opera implements attachEvent but does not follow the script
- //script execution mode.
- if (node.attachEvent &&
- //Check if node.attachEvent is artificially added by custom script or
- //natively supported by browser
- //read https://github.com/jrburke/requirejs/issues/187
- //if we can NOT find [native code] then it must NOT natively supported.
- //in IE8, node.attachEvent does not have toString()
- //Note the test for "[native code" with no closing brace, see:
- //https://github.com/jrburke/requirejs/issues/273
- !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
- !isOpera) {
- //Probably IE. IE (at least 6-8) do not fire
- //script onload right after executing the script, so
- //we cannot tie the anonymous define call to a name.
- //However, IE reports the script as being in 'interactive'
- //readyState at the time of the define call.
- useInteractive = true;
-
- node.attachEvent('onreadystatechange', context.onScriptLoad);
- //It would be great to add an error handler here to catch
- //404s in IE9+. However, onreadystatechange will fire before
- //the error handler, so that does not help. If addEventListener
- //is used, then IE will fire error before load, but we cannot
- //use that pathway given the connect.microsoft.com issue
- //mentioned above about not doing the 'script execute,
- //then fire the script load event listener before execute
- //next script' that other browsers do.
- //Best hope: IE10 fixes the issues,
- //and then destroys all installs of IE 6-9.
- //node.attachEvent('onerror', context.onScriptError);
- } else {
- node.addEventListener('load', context.onScriptLoad, false);
- node.addEventListener('error', context.onScriptError, false);
- }
- node.src = url;
-
- //For some cache cases in IE 6-8, the script executes before the end
- //of the appendChild execution, so to tie an anonymous define
- //call to the module name (which is stored on the node), hold on
- //to a reference to this node, but clear after the DOM insertion.
- currentlyAddingScript = node;
- if (baseElement) {
- head.insertBefore(node, baseElement);
- } else {
- head.appendChild(node);
- }
- currentlyAddingScript = null;
-
- return node;
- } else if (isWebWorker) {
- try {
- //In a web worker, use importScripts. This is not a very
- //efficient use of importScripts, importScripts will block until
- //its script is downloaded and evaluated. However, if web workers
- //are in play, the expectation that a build has been done so that
- //only one script needs to be loaded anyway. This may need to be
- //reevaluated if other use cases become common.
- importScripts(url);
-
- //Account for anonymous modules
- context.completeLoad(moduleName);
- } catch (e) {
- context.onError(makeError('importscripts',
- 'importScripts failed for ' +
- moduleName + ' at ' + url,
- e,
- [moduleName]));
- }
- }
- };
-
- function getInteractiveScript() {
- if (interactiveScript && interactiveScript.readyState === 'interactive') {
- return interactiveScript;
- }
-
- eachReverse(scripts(), function (script) {
- if (script.readyState === 'interactive') {
- return (interactiveScript = script);
- }
- });
- return interactiveScript;
- }
-
- //Look for a data-main script attribute, which could also adjust the baseUrl.
- if (isBrowser && !cfg.skipDataMain) {
- //Figure out baseUrl. Get it from the script tag with require.js in it.
- eachReverse(scripts(), function (script) {
- //Set the 'head' where we can append children by
- //using the script's parent.
- if (!head) {
- head = script.parentNode;
- }
-
- //Look for a data-main attribute to set main script for the page
- //to load. If it is there, the path to data main becomes the
- //baseUrl, if it is not already set.
- dataMain = script.getAttribute('data-main');
- if (dataMain) {
- //Preserve dataMain in case it is a path (i.e. contains '?')
- mainScript = dataMain;
-
- //Set final baseUrl if there is not already an explicit one.
- if (!cfg.baseUrl) {
- //Pull off the directory of data-main for use as the
- //baseUrl.
- src = mainScript.split('/');
- mainScript = src.pop();
- subPath = src.length ? src.join('/') + '/' : './';
-
- cfg.baseUrl = subPath;
- }
-
- //Strip off any trailing .js since mainScript is now
- //like a module name.
- mainScript = mainScript.replace(jsSuffixRegExp, '');
-
- //If mainScript is still a path, fall back to dataMain
- if (req.jsExtRegExp.test(mainScript)) {
- mainScript = dataMain;
- }
-
- //Put the data-main script in the files to load.
- cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
-
- return true;
- }
- });
- }
-
- /**
- * The function that handles definitions of modules. Differs from
- * require() in that a string for the module should be the first argument,
- * and the function to execute after dependencies are loaded should
- * return a value to define the module corresponding to the first argument's
- * name.
- */
- define = function (name, deps, callback) {
- var node, context;
-
- //Allow for anonymous modules
- if (typeof name !== 'string') {
- //Adjust args appropriately
- callback = deps;
- deps = name;
- name = null;
- }
-
- //This module may not have dependencies
- if (!isArray(deps)) {
- callback = deps;
- deps = null;
- }
-
- //If no name, and callback is a function, then figure out if it a
- //CommonJS thing with dependencies.
- if (!deps && isFunction(callback)) {
- deps = [];
- //Remove comments from the callback string,
- //look for require calls, and pull them into the dependencies,
- //but only if there are function args.
- if (callback.length) {
- callback
- .toString()
- .replace(commentRegExp, '')
- .replace(cjsRequireRegExp, function (match, dep) {
- deps.push(dep);
- });
-
- //May be a CommonJS thing even without require calls, but still
- //could use exports, and module. Avoid doing exports and module
- //work though if it just needs require.
- //REQUIRES the function to expect the CommonJS variables in the
- //order listed below.
- deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
- }
- }
-
- //If in IE 6-8 and hit an anonymous define() call, do the interactive
- //work.
- if (useInteractive) {
- node = currentlyAddingScript || getInteractiveScript();
- if (node) {
- if (!name) {
- name = node.getAttribute('data-requiremodule');
- }
- context = contexts[node.getAttribute('data-requirecontext')];
- }
- }
-
- //Always save off evaluating the def call until the script onload handler.
- //This allows multiple modules to be in a file without prematurely
- //tracing dependencies, and allows for anonymous module support,
- //where the module name is not known until the script onload event
- //occurs. If no context, use the global queue, and get it processed
- //in the onscript load callback.
- (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
- };
-
- define.amd = {
- jQuery: true
- };
-
-
- /**
- * Executes the text. Normally just uses eval, but can be modified
- * to use a better, environment-specific call. Only used for transpiling
- * loader plugins, not for plain JS modules.
- * @param {String} text the text to execute/evaluate.
- */
- req.exec = function (text) {
- /*jslint evil: true */
- return eval(text);
- };
-
- //Set up with config info.
- req(cfg);
-}(this));
diff --git a/vendor/underscore/LICENSE b/vendor/underscore/LICENSE
index 3acf908..0d6b873 100644
--- a/vendor/underscore/LICENSE
+++ b/vendor/underscore/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative
+Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative
Reporters & Editors
Permission is hereby granted, free of charge, to any person
diff --git a/vendor/underscore/test/arrays.js b/vendor/underscore/test/arrays.js
index f9ed132..975015f 100644
--- a/vendor/underscore/test/arrays.js
+++ b/vendor/underscore/test/arrays.js
@@ -1,177 +1,233 @@
-$(document).ready(function() {
+(function() {
- module("Arrays");
+ module('Arrays');
- test("first", function() {
- equal(_.first([1,2,3]), 1, 'can pull out the first element of an array');
+ test('first', function() {
+ equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array');
equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"');
- equal(_.first([1,2,3], 0).join(', '), "", 'can pass an index to first');
- equal(_.first([1,2,3], 2).join(', '), '1, 2', 'can pass an index to first');
- equal(_.first([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to first');
- var result = (function(){ return _.first(arguments); })(4, 3, 2, 1);
+ deepEqual(_.first([1, 2, 3], 0), [], 'can pass an index to first');
+ deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can pass an index to first');
+ deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'can pass an index to first');
+ var result = (function(){ return _.first(arguments); }(4, 3, 2, 1));
equal(result, 4, 'works on an arguments object.');
- result = _.map([[1,2,3],[1,2,3]], _.first);
- equal(result.join(','), '1,1', 'works well with _.map');
- result = (function() { return _.take([1,2,3], 2); })();
- equal(result.join(','), '1,2', 'aliased as take');
+ result = _.map([[1, 2, 3], [1, 2, 3]], _.first);
+ deepEqual(result, [1, 1], 'works well with _.map');
+ result = (function() { return _.first([1, 2, 3], 2); }());
+ deepEqual(result, [1, 2]);
equal(_.first(null), undefined, 'handles nulls');
+ strictEqual(_.first([1, 2, 3], -1).length, 0);
});
- test("rest", function() {
+ test('head', function() {
+ strictEqual(_.first, _.head, 'alias for first');
+ });
+
+ test('take', function() {
+ strictEqual(_.first, _.take, 'alias for first');
+ });
+
+ test('rest', function() {
var numbers = [1, 2, 3, 4];
- equal(_.rest(numbers).join(", "), "2, 3, 4", 'working rest()');
- equal(_.rest(numbers, 0).join(", "), "1, 2, 3, 4", 'working rest(0)');
- equal(_.rest(numbers, 2).join(', '), '3, 4', 'rest can take an index');
- var result = (function(){ return _(arguments).tail(); })(1, 2, 3, 4);
- equal(result.join(', '), '2, 3, 4', 'aliased as tail and works on arguments object');
- result = _.map([[1,2,3],[1,2,3]], _.rest);
- equal(_.flatten(result).join(','), '2,3,2,3', 'works well with _.map');
- result = (function(){ return _(arguments).drop(); })(1, 2, 3, 4);
- equal(result.join(', '), '2, 3, 4', 'aliased as drop and works on arguments object');
- });
-
- test("initial", function() {
- equal(_.initial([1,2,3,4,5]).join(", "), "1, 2, 3, 4", 'working initial()');
- equal(_.initial([1,2,3,4],2).join(", "), "1, 2", 'initial can take an index');
- var result = (function(){ return _(arguments).initial(); })(1, 2, 3, 4);
- equal(result.join(", "), "1, 2, 3", 'initial works on arguments object');
- result = _.map([[1,2,3],[1,2,3]], _.initial);
- equal(_.flatten(result).join(','), '1,2,1,2', 'initial works with _.map');
- });
-
- test("last", function() {
- equal(_.last([1,2,3]), 3, 'can pull out the last element of an array');
- equal(_.last([1,2,3], 0).join(', '), "", 'can pass an index to last');
- equal(_.last([1,2,3], 2).join(', '), '2, 3', 'can pass an index to last');
- equal(_.last([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to last');
- var result = (function(){ return _(arguments).last(); })(1, 2, 3, 4);
+ deepEqual(_.rest(numbers), [2, 3, 4], 'working rest()');
+ deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'working rest(0)');
+ deepEqual(_.rest(numbers, 2), [3, 4], 'rest can take an index');
+ var result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4));
+ deepEqual(result, [2, 3, 4], 'works on arguments object');
+ result = _.map([[1, 2, 3], [1, 2, 3]], _.rest);
+ deepEqual(_.flatten(result), [2, 3, 2, 3], 'works well with _.map');
+ result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4));
+ deepEqual(result, [2, 3, 4], 'works on arguments object');
+ });
+
+ test('tail', function() {
+ strictEqual(_.rest, _.tail, 'alias for rest');
+ });
+
+ test('drop', function() {
+ strictEqual(_.rest, _.drop, 'alias for rest');
+ });
+
+ test('initial', function() {
+ deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'working initial()');
+ deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'initial can take an index');
+ deepEqual(_.initial([1, 2, 3, 4], 6), [], 'initial can take a large index');
+ var result = (function(){ return _(arguments).initial(); }(1, 2, 3, 4));
+ deepEqual(result, [1, 2, 3], 'initial works on arguments object');
+ result = _.map([[1, 2, 3], [1, 2, 3]], _.initial);
+ deepEqual(_.flatten(result), [1, 2, 1, 2], 'initial works with _.map');
+ });
+
+ test('last', function() {
+ equal(_.last([1, 2, 3]), 3, 'can pull out the last element of an array');
+ deepEqual(_.last([1, 2, 3], 0), [], 'can pass an index to last');
+ deepEqual(_.last([1, 2, 3], 2), [2, 3], 'can pass an index to last');
+ deepEqual(_.last([1, 2, 3], 5), [1, 2, 3], 'can pass an index to last');
+ var result = (function(){ return _(arguments).last(); }(1, 2, 3, 4));
equal(result, 4, 'works on an arguments object');
- result = _.map([[1,2,3],[1,2,3]], _.last);
- equal(result.join(','), '3,3', 'works well with _.map');
+ result = _.map([[1, 2, 3], [1, 2, 3]], _.last);
+ deepEqual(result, [3, 3], 'works well with _.map');
equal(_.last(null), undefined, 'handles nulls');
+ strictEqual(_.last([1, 2, 3], -1).length, 0);
});
- test("compact", function() {
+ test('compact', function() {
equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values');
- var result = (function(){ return _.compact(arguments).length; })(0, 1, false, 2, false, 3);
+ var result = (function(){ return _.compact(arguments).length; }(0, 1, false, 2, false, 3));
equal(result, 3, 'works on an arguments object');
});
- test("flatten", function() {
+ test('flatten', function() {
var list = [1, [2], [3, [[[4]]]]];
- deepEqual(_.flatten(list), [1,2,3,4], 'can flatten nested arrays');
- deepEqual(_.flatten(list, true), [1,2,3,[[[4]]]], 'can shallowly flatten nested arrays');
- var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]);
- deepEqual(result, [1,2,3,4], 'works on an arguments object');
+ deepEqual(_.flatten(list), [1, 2, 3, 4], 'can flatten nested arrays');
+ deepEqual(_.flatten(list, true), [1, 2, 3, [[[4]]]], 'can shallowly flatten nested arrays');
+ var result = (function(){ return _.flatten(arguments); }(1, [2], [3, [[[4]]]]));
+ deepEqual(result, [1, 2, 3, 4], 'works on an arguments object');
list = [[1], [2], [3], [[4]]];
deepEqual(_.flatten(list, true), [1, 2, 3, [4]], 'can shallowly flatten arrays containing only other arrays');
});
- test("without", function() {
+ test('without', function() {
var list = [1, 2, 1, 0, 3, 1, 4];
- equal(_.without(list, 0, 1).join(', '), '2, 3, 4', 'can remove all instances of an object');
- var result = (function(){ return _.without(arguments, 0, 1); })(1, 2, 1, 0, 3, 1, 4);
- equal(result.join(', '), '2, 3, 4', 'works on an arguments object');
+ deepEqual(_.without(list, 0, 1), [2, 3, 4], 'can remove all instances of an object');
+ var result = (function(){ return _.without(arguments, 0, 1); }(1, 2, 1, 0, 3, 1, 4));
+ deepEqual(result, [2, 3, 4], 'works on an arguments object');
list = [{one : 1}, {two : 2}];
- ok(_.without(list, {one : 1}).length == 2, 'uses real object identity for comparisons.');
- ok(_.without(list, list[0]).length == 1, 'ditto.');
+ equal(_.without(list, {one : 1}).length, 2, 'uses real object identity for comparisons.');
+ equal(_.without(list, list[0]).length, 1, 'ditto.');
});
- test("uniq", function() {
+ test('uniq', function() {
var list = [1, 2, 1, 3, 1, 4];
- equal(_.uniq(list).join(', '), '1, 2, 3, 4', 'can find the unique values of an unsorted array');
+ deepEqual(_.uniq(list), [1, 2, 3, 4], 'can find the unique values of an unsorted array');
list = [1, 1, 1, 2, 2, 3];
- equal(_.uniq(list, true).join(', '), '1, 2, 3', 'can find the unique values of a sorted array faster');
+ deepEqual(_.uniq(list, true), [1, 2, 3], 'can find the unique values of a sorted array faster');
- list = [{name:'moe'}, {name:'curly'}, {name:'larry'}, {name:'curly'}];
+ list = [{name: 'moe'}, {name: 'curly'}, {name: 'larry'}, {name: 'curly'}];
var iterator = function(value) { return value.name; };
- equal(_.map(_.uniq(list, false, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator');
+ deepEqual(_.map(_.uniq(list, false, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator');
- equal(_.map(_.uniq(list, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator without specifying whether array is sorted');
+ deepEqual(_.map(_.uniq(list, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator without specifying whether array is sorted');
- iterator = function(value) { return value +1; };
+ iterator = function(value) { return value + 1; };
list = [1, 2, 2, 3, 4, 4];
- equal(_.uniq(list, true, iterator).join(', '), '1, 2, 3, 4', 'iterator works with sorted array');
+ deepEqual(_.uniq(list, true, iterator), [1, 2, 3, 4], 'iterator works with sorted array');
+
+ var result = (function(){ return _.uniq(arguments); }(1, 2, 1, 3, 1, 4));
+ deepEqual(result, [1, 2, 3, 4], 'works on an arguments object');
+
+ var a = {}, b = {}, c = {};
+ deepEqual(_.uniq([a, b, a, b, c]), [a, b, c], 'works on values that can be tested for equivalency but not ordered');
+
+ deepEqual(_.uniq(null), []);
+
+ var context = {};
+ list = [3];
+ _.uniq(list, function(value, index, array) {
+ strictEqual(this, context);
+ strictEqual(value, 3);
+ strictEqual(index, 0);
+ strictEqual(array, list);
+ }, context);
- var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4);
- equal(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
+ deepEqual(_.uniq([{a: 1, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}, {a: 2, b: 1}], 'a'), [{a: 1, b: 1}, {a: 2, b: 1}], 'can use pluck like iterator');
+ deepEqual(_.uniq([{0: 1, b: 1}, {0: 1, b: 2}, {0: 1, b: 3}, {0: 2, b: 1}], 0), [{0: 1, b: 1}, {0: 2, b: 1}], 'can use falsey pluck like iterator');
});
- test("intersection", function() {
+ test('unique', function() {
+ strictEqual(_.uniq, _.unique, 'alias for uniq');
+ });
+
+ test('intersection', function() {
var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho'];
- equal(_.intersection(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
- equal(_(stooges).intersection(leaders).join(''), 'moe', 'can perform an OO-style intersection');
- var result = (function(){ return _.intersection(arguments, leaders); })('moe', 'curly', 'larry');
- equal(result.join(''), 'moe', 'works on an arguments object');
+ deepEqual(_.intersection(stooges, leaders), ['moe'], 'can take the set intersection of two arrays');
+ deepEqual(_(stooges).intersection(leaders), ['moe'], 'can perform an OO-style intersection');
+ var result = (function(){ return _.intersection(arguments, leaders); }('moe', 'curly', 'larry'));
+ deepEqual(result, ['moe'], 'works on an arguments object');
var theSixStooges = ['moe', 'moe', 'curly', 'curly', 'larry', 'larry'];
- equal(_.intersection(theSixStooges, leaders).join(''), 'moe', 'returns a duplicate-free array');
+ deepEqual(_.intersection(theSixStooges, leaders), ['moe'], 'returns a duplicate-free array');
+ result = _.intersection([2, 4, 3, 1], [1, 2, 3]);
+ deepEqual(result, [2, 3, 1], 'preserves order of first array');
+ result = _.intersection(null, [1, 2, 3]);
+ equal(Object.prototype.toString.call(result), '[object Array]', 'returns an empty array when passed null as first argument');
+ equal(result.length, 0, 'returns an empty array when passed null as first argument');
+ result = _.intersection([1, 2, 3], null);
+ equal(Object.prototype.toString.call(result), '[object Array]', 'returns an empty array when passed null as argument beyond the first');
+ equal(result.length, 0, 'returns an empty array when passed null as argument beyond the first');
});
- test("union", function() {
+ test('union', function() {
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]);
- equal(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays');
+ deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays');
result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]);
- equal(result.join(' '), '1 2 3 30 40 1', 'takes the union of a list of nested arrays');
+ deepEqual(result, [1, 2, 3, 30, 40, [1]], 'takes the union of a list of nested arrays');
var args = null;
- (function(){ args = arguments; })(1, 2, 3);
+ (function(){ args = arguments; }(1, 2, 3));
result = _.union(args, [2, 30, 1], [1, 40]);
- equal(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays');
+ deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays');
- result = _.union(null, [1, 2, 3]);
- deepEqual(result, [null, 1, 2, 3]);
+ result = _.union([1, 2, 3], 4);
+ deepEqual(result, [1, 2, 3], 'restrict the union to arrays only');
});
- test("difference", function() {
+ test('difference', function() {
var result = _.difference([1, 2, 3], [2, 30, 40]);
- equal(result.join(' '), '1 3', 'takes the difference of two arrays');
+ deepEqual(result, [1, 3], 'takes the difference of two arrays');
result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]);
- equal(result.join(' '), '3 4', 'takes the difference of three arrays');
+ deepEqual(result, [3, 4], 'takes the difference of three arrays');
+
+ result = _.difference([1, 2, 3], 1);
+ deepEqual(result, [1, 2, 3], 'restrict the difference to arrays only');
});
test('zip', function() {
var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];
- var stooges = _.zip(names, ages, leaders);
- equal(String(stooges), 'moe,30,true,larry,40,,curly,50,', 'zipped together arrays of different lengths');
+ deepEqual(_.zip(names, ages, leaders), [
+ ['moe', 30, true],
+ ['larry', 40, undefined],
+ ['curly', 50, undefined]
+ ], 'zipped together arrays of different lengths');
- stooges = _.zip(['moe',30, 'stooge 1'],['larry',40, 'stooge 2'],['curly',50, 'stooge 3']);
- deepEqual(stooges, [['moe','larry','curly'],[30,40,50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs');
+ var stooges = _.zip(['moe', 30, 'stooge 1'], ['larry', 40, 'stooge 2'], ['curly', 50, 'stooge 3']);
+ deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs');
// In the case of difference lengths of the tuples undefineds
// should be used as placeholder
- stooges = _.zip(['moe',30],['larry',40],['curly',50, 'extra data']);
- deepEqual(stooges, [['moe','larry','curly'],[30,40,50], [undefined, undefined, 'extra data']], 'zipped pairs with empties');
+ stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']);
+ deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [undefined, undefined, 'extra data']], 'zipped pairs with empties');
var empty = _.zip([]);
deepEqual(empty, [], 'unzipped empty');
+
+ deepEqual(_.zip(null), [], 'handles null');
+ deepEqual(_.zip(), [], '_.zip() returns []');
});
test('object', function() {
var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
var shouldBe = {moe: 30, larry: 40, curly: 50};
- ok(_.isEqual(result, shouldBe), 'two arrays zipped together into an object');
+ deepEqual(result, shouldBe, 'two arrays zipped together into an object');
result = _.object([['one', 1], ['two', 2], ['three', 3]]);
shouldBe = {one: 1, two: 2, three: 3};
- ok(_.isEqual(result, shouldBe), 'an array of pairs zipped together into an object');
+ deepEqual(result, shouldBe, 'an array of pairs zipped together into an object');
var stooges = {moe: 30, larry: 40, curly: 50};
- ok(_.isEqual(_.object(_.pairs(stooges)), stooges), 'an object converted to pairs and back to an object');
+ deepEqual(_.object(_.pairs(stooges)), stooges, 'an object converted to pairs and back to an object');
- ok(_.isEqual(_.object(null), {}), 'handles nulls');
+ deepEqual(_.object(null), {}, 'handles nulls');
});
- test("indexOf", function() {
+ test('indexOf', function() {
var numbers = [1, 2, 3];
- numbers.indexOf = null;
- equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
- var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
+ equal(_.indexOf(numbers, 2), 1, 'can compute indexOf');
+ var result = (function(){ return _.indexOf(arguments, 2); }(1, 2, 3));
equal(result, 1, 'works on an arguments object');
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
@@ -185,40 +241,90 @@ $(document).ready(function() {
equal(index, 3, '40 is in the list');
numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40;
- index = _.indexOf(numbers, num, true);
- equal(index, 1, '40 is in the list');
+ equal(_.indexOf(numbers, num, true), 1, '40 is in the list');
+ equal(_.indexOf(numbers, 6, true), -1, '6 isnt in the list');
+ equal(_.indexOf([1, 2, 5, 4, 6, 7], 5, true), -1, 'sorted indexOf doesn\'t uses binary search');
+ ok(_.every(['1', [], {}, null], function() {
+ return _.indexOf(numbers, num, {}) === 1;
+ }), 'non-nums as fromIndex make indexOf assume sorted');
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
index = _.indexOf(numbers, 2, 5);
equal(index, 7, 'supports the fromIndex argument');
+
+ index = _.indexOf([,,,], undefined);
+ equal(index, 0, 'treats sparse arrays as if they were dense');
+
+ var array = [1, 2, 3, 1, 2, 3];
+ strictEqual(_.indexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index');
+ strictEqual(_.indexOf(array, 1, -2), -1, 'neg `fromIndex` starts at the right index');
+ strictEqual(_.indexOf(array, 2, -3), 4);
+ _.each([-6, -8, -Infinity], function(fromIndex) {
+ strictEqual(_.indexOf(array, 1, fromIndex), 0);
+ });
+ strictEqual(_.indexOf([1, 2, 3], 1, true), 0);
});
- test("lastIndexOf", function() {
+ test('lastIndexOf', function() {
var numbers = [1, 0, 1];
+ var falsey = [void 0, '', 0, false, NaN, null, undefined];
equal(_.lastIndexOf(numbers, 1), 2);
numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0];
numbers.lastIndexOf = null;
equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function');
equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
- var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0);
+ var result = (function(){ return _.lastIndexOf(arguments, 1); }(1, 0, 1, 0, 0, 1, 0, 0, 0));
equal(result, 5, 'works on an arguments object');
equal(_.lastIndexOf(null, 2), -1, 'handles nulls properly');
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
var index = _.lastIndexOf(numbers, 2, 2);
equal(index, 1, 'supports the fromIndex argument');
+
+ var array = [1, 2, 3, 1, 2, 3];
+
+ strictEqual(_.lastIndexOf(array, 1, 0), 0, 'starts at the correct from idx');
+ strictEqual(_.lastIndexOf(array, 3), 5, 'should return the index of the last matched value');
+ strictEqual(_.lastIndexOf(array, 4), -1, 'should return `-1` for an unmatched value');
+
+ strictEqual(_.lastIndexOf(array, 1, 2), 0, 'should work with a positive `fromIndex`');
+
+ _.each([6, 8, Math.pow(2, 32), Infinity], function(fromIndex) {
+ strictEqual(_.lastIndexOf(array, undefined, fromIndex), -1);
+ strictEqual(_.lastIndexOf(array, 1, fromIndex), 3);
+ strictEqual(_.lastIndexOf(array, '', fromIndex), -1);
+ });
+
+ var expected = _.map(falsey, function(value) {
+ return typeof value == 'number' ? -1 : 5;
+ });
+
+ var actual = _.map(falsey, function(fromIndex) {
+ return _.lastIndexOf(array, 3, fromIndex);
+ });
+
+ deepEqual(actual, expected, 'should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`');
+ strictEqual(_.lastIndexOf(array, 3, '1'), 5, 'should treat non-number `fromIndex` values as `array.length`');
+ strictEqual(_.lastIndexOf(array, 3, true), 5, 'should treat non-number `fromIndex` values as `array.length`');
+
+ strictEqual(_.lastIndexOf(array, 2, -3), 1, 'should work with a negative `fromIndex`');
+ strictEqual(_.lastIndexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index');
+
+ deepEqual(_.map([-6, -8, -Infinity], function(fromIndex) {
+ return _.lastIndexOf(array, 1, fromIndex);
+ }), [0, -1, -1]);
});
- test("range", function() {
- equal(_.range(0).join(''), '', 'range with 0 as a first argument generates an empty array');
- equal(_.range(4).join(' '), '0 1 2 3', 'range with a single positive argument generates an array of elements 0,1,2,...,n-1');
- equal(_.range(5, 8).join(' '), '5 6 7', 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1');
- equal(_.range(8, 5).join(''), '', 'range with two arguments a & b, b<a generates an empty array');
- equal(_.range(3, 10, 3).join(' '), '3 6 9', 'range with three arguments a & b & c, c < b-a, a < b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) < c');
- equal(_.range(3, 10, 15).join(''), '3', 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a');
- equal(_.range(12, 7, -2).join(' '), '12 10 8', 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b');
- equal(_.range(0, -10, -1).join(' '), '0 -1 -2 -3 -4 -5 -6 -7 -8 -9', 'final example in the Python docs');
+ test('range', function() {
+ deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array');
+ deepEqual(_.range(4), [0, 1, 2, 3], 'range with a single positive argument generates an array of elements 0,1,2,...,n-1');
+ deepEqual(_.range(5, 8), [5, 6, 7], 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1');
+ deepEqual(_.range(8, 5), [], 'range with two arguments a & b, b<a generates an empty array');
+ deepEqual(_.range(3, 10, 3), [3, 6, 9], 'range with three arguments a & b & c, c < b-a, a < b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) < c');
+ deepEqual(_.range(3, 10, 15), [3], 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a');
+ deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b');
+ deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs');
});
-});
+}());
diff --git a/vendor/underscore/test/chaining.js b/vendor/underscore/test/chaining.js
index 6eeef0f..770b884 100644
--- a/vendor/underscore/test/chaining.js
+++ b/vendor/underscore/test/chaining.js
@@ -1,13 +1,13 @@
-$(document).ready(function() {
+(function() {
- module("Chaining");
+ module('Chaining');
- test("map/flatten/reduce", function() {
+ test('map/flatten/reduce', function() {
var lyrics = [
- "I'm a lumberjack and I'm okay",
- "I sleep all night and I work all day",
- "He's a lumberjack and he's okay",
- "He sleeps all night and he works all day"
+ 'I\'m a lumberjack and I\'m okay',
+ 'I sleep all night and I work all day',
+ 'He\'s a lumberjack and he\'s okay',
+ 'He sleeps all night and he works all day'
];
var counts = _(lyrics).chain()
.map(function(line) { return line.split(''); })
@@ -17,11 +17,12 @@ $(document).ready(function() {
hash[l]++;
return hash;
}, {}).value();
- ok(counts.a == 16 && counts.e == 10, 'counted all the letters in the song');
+ equal(counts.a, 16, 'counted all the letters in the song');
+ equal(counts.e, 10, 'counted all the letters in the song');
});
- test("select/reject/sortBy", function() {
- var numbers = [1,2,3,4,5,6,7,8,9,10];
+ test('select/reject/sortBy', function() {
+ var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
numbers = _(numbers).chain().select(function(n) {
return n % 2 === 0;
}).reject(function(n) {
@@ -29,11 +30,11 @@ $(document).ready(function() {
}).sortBy(function(n) {
return -n;
}).value();
- equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
+ deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers');
});
- test("select/reject/sortBy in functional style", function() {
- var numbers = [1,2,3,4,5,6,7,8,9,10];
+ test('select/reject/sortBy in functional style', function() {
+ var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
numbers = _.chain(numbers).select(function(n) {
return n % 2 === 0;
}).reject(function(n) {
@@ -41,11 +42,11 @@ $(document).ready(function() {
}).sortBy(function(n) {
return -n;
}).value();
- equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
+ deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers');
});
- test("reverse/concat/unshift/pop/map", function() {
- var numbers = [1,2,3,4,5];
+ test('reverse/concat/unshift/pop/map', function() {
+ var numbers = [1, 2, 3, 4, 5];
numbers = _(numbers).chain()
.reverse()
.concat([5, 5, 5])
@@ -53,13 +54,13 @@ $(document).ready(function() {
.pop()
.map(function(n){ return n * 2; })
.value();
- equal(numbers.join(', '), "34, 10, 8, 6, 4, 2, 10, 10", 'can chain together array functions.');
+ deepEqual(numbers, [34, 10, 8, 6, 4, 2, 10, 10], 'can chain together array functions.');
});
- test("chaining works in small stages", function() {
+ test('chaining works in small stages', function() {
var o = _([1, 2, 3, 4]).chain();
deepEqual(o.filter(function(i) { return i < 3; }).value(), [1, 2]);
deepEqual(o.filter(function(i) { return i > 2; }).value(), [3, 4]);
});
-});
+}());
diff --git a/vendor/underscore/test/collections.js b/vendor/underscore/test/collections.js
index 82176ad..c74e5ea 100644
--- a/vendor/underscore/test/collections.js
+++ b/vendor/underscore/test/collections.js
@@ -1,25 +1,25 @@
-$(document).ready(function() {
+(function() {
- module("Collections");
+ module('Collections');
- test("each", function() {
+ test('each', function() {
_.each([1, 2, 3], function(num, i) {
equal(num, i + 1, 'each iterators provide value and iteration count');
});
var answers = [];
_.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5});
- equal(answers.join(', '), '5, 10, 15', 'context object property accessed');
+ deepEqual(answers, [5, 10, 15], 'context object property accessed');
answers = [];
- _.forEach([1, 2, 3], function(num){ answers.push(num); });
- equal(answers.join(', '), '1, 2, 3', 'aliased as "forEach"');
+ _.each([1, 2, 3], function(num){ answers.push(num); });
+ deepEqual(answers, [1, 2, 3], 'aliased as "forEach"');
answers = [];
var obj = {one : 1, two : 2, three : 3};
obj.constructor.prototype.four = 4;
_.each(obj, function(value, key){ answers.push(key); });
- equal(answers.join(", "), 'one, two, three', 'iterating over objects works, and ignores the object prototype.');
+ deepEqual(answers, ['one', 'two', 'three'], 'iterating over objects works, and ignores the object prototype.');
delete obj.constructor.prototype.four;
var answer = null;
@@ -29,34 +29,65 @@ $(document).ready(function() {
answers = 0;
_.each(null, function(){ ++answers; });
equal(answers, 0, 'handles a null properly');
+
+ _.each(false, function(){});
+
+ var a = [1, 2, 3];
+ strictEqual(_.each(a, function(){}), a);
+ strictEqual(_.each(null, function(){}), null);
+
+ var b = [1, 2, 3];
+ b.length = 100;
+ answers = 0;
+ _.each(b, function(){ ++answers; });
+ equal(answers, 100, 'enumerates [0, length)');
+ });
+
+ test('forEach', function() {
+ strictEqual(_.each, _.forEach, 'alias for each');
+ });
+
+ test('lookupIterator with contexts', function() {
+ _.each([true, false, 'yes', '', 0, 1, {}], function(context) {
+ _.each([1], function() {
+ equal(this, context);
+ }, context);
+ });
});
test('map', function() {
var doubled = _.map([1, 2, 3], function(num){ return num * 2; });
- equal(doubled.join(', '), '2, 4, 6', 'doubled numbers');
-
- doubled = _.collect([1, 2, 3], function(num){ return num * 2; });
- equal(doubled.join(', '), '2, 4, 6', 'aliased as "collect"');
+ deepEqual(doubled, [2, 4, 6], 'doubled numbers');
var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3});
- equal(tripled.join(', '), '3, 6, 9', 'tripled numbers with context');
+ deepEqual(tripled, [3, 6, 9], 'tripled numbers with context');
- var doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
- equal(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers');
+ doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
+ deepEqual(doubled, [2, 4, 6], 'OO-style doubled numbers');
if (document.querySelectorAll) {
var ids = _.map(document.querySelectorAll('#map-test *'), function(n){ return n.id; });
deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on NodeLists.');
}
- var ids = _.map($('#map-test').children(), function(n){ return n.id; });
- deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on jQuery Array-likes.');
+ ids = _.map({length: 2, 0: {id: '1'}, 1: {id: '2'}}, function(n){
+ return n.id;
+ });
+ deepEqual(ids, ['1', '2'], 'Can use collection methods on Array-likes.');
+
+ deepEqual(_.map(null, _.noop), [], 'handles a null properly');
+
+ deepEqual(_.map([1], function() {
+ return this.length;
+ }, [5]), [1], 'called with context');
- var ids = _.map(document.images, function(n){ return n.id; });
- ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections');
+ // Passing a property name like _.pluck.
+ var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}];
+ deepEqual(_.map(people, 'name'), ['moe', 'curly'], 'predicate string map to object properties');
+ });
- var ifnull = _.map(null, function(){});
- ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly');
+ test('collect', function() {
+ strictEqual(_.map, _.collect, 'alias for map');
});
test('reduce', function() {
@@ -73,50 +104,41 @@ $(document).ready(function() {
sum = _([1, 2, 3]).reduce(function(sum, num){ return sum + num; }, 0);
equal(sum, 6, 'OO-style reduce');
- var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
+ sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
equal(sum, 6, 'default initial value');
var prod = _.reduce([1, 2, 3, 4], function(prod, num){ return prod * num; });
equal(prod, 24, 'can reduce via multiplication');
- var ifnull;
- try {
- _.reduce(null, function(){});
- } catch (ex) {
- ifnull = ex;
- }
- ok(ifnull instanceof TypeError, 'handles a null (without initial value) properly');
+ ok(_.reduce(null, _.noop, 138) === 138, 'handles a null (with initial value) properly');
+ equal(_.reduce([], _.noop, undefined), undefined, 'undefined can be passed as a special case');
+ equal(_.reduce([_], _.noop), _, 'collection of length one with no initial value returns the first item');
- ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
- equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
- raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
+ raises(function() { _.reduce([], _.noop); }, TypeError, 'throws an error for empty arrays with no initial value');
+ raises(function() {_.reduce(null, _.noop);}, TypeError, 'handles a null (without initial value) properly');
+ });
+
+ test('foldl', function() {
+ strictEqual(_.reduce, _.foldl, 'alias for reduce');
});
test('reduceRight', function() {
- var list = _.reduceRight(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
+ var list = _.reduceRight(['foo', 'bar', 'baz'], function(memo, str){ return memo + str; }, '');
equal(list, 'bazbarfoo', 'can perform right folds');
- var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
- equal(list, 'bazbarfoo', 'aliased as "foldr"');
-
- var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; });
+ list = _.reduceRight(['foo', 'bar', 'baz'], function(memo, str){ return memo + str; });
equal(list, 'bazbarfoo', 'default initial value');
- var ifnull;
- try {
- _.reduceRight(null, function(){});
- } catch (ex) {
- ifnull = ex;
- }
- ok(ifnull instanceof TypeError, 'handles a null (without initial value) properly');
-
var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; });
equal(sum, 6, 'default initial value on object');
- ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
+ ok(_.reduceRight(null, _.noop, 138) === 138, 'handles a null (with initial value) properly');
+ equal(_.reduceRight([_], _.noop), _, 'collection of length one with no initial value returns the first item');
- equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
- raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
+ equal(_.reduceRight([], _.noop, undefined), undefined, 'undefined can be passed as a special case');
+
+ raises(function() { _.reduceRight([], _.noop); }, TypeError, 'throws an error for empty arrays with no initial value');
+ raises(function() {_.reduceRight(null, _.noop);}, TypeError, 'handles a null (without initial value) properly');
// Assert that the correct arguments are being passed.
@@ -125,12 +147,12 @@ $(document).ready(function() {
object = {a: 1, b: 2},
lastKey = _.keys(object).pop();
- var expected = lastKey == 'a'
+ var expected = lastKey === 'a'
? [memo, 1, 'a', object]
: [memo, 2, 'b', object];
_.reduceRight(object, function() {
- args || (args = _.toArray(arguments));
+ if (!args) args = _.toArray(arguments);
}, memo);
deepEqual(args, expected);
@@ -141,96 +163,169 @@ $(document).ready(function() {
lastKey = _.keys(object).pop();
args = null;
- expected = lastKey == '2'
+ expected = lastKey === '2'
? [memo, 'a', '2', object]
: [memo, 'b', '1', object];
_.reduceRight(object, function() {
- args || (args = _.toArray(arguments));
+ if (!args) args = _.toArray(arguments);
}, memo);
deepEqual(args, expected);
});
+ test('foldr', function() {
+ strictEqual(_.reduceRight, _.foldr, 'alias for reduceRight');
+ });
+
test('find', function() {
var array = [1, 2, 3, 4];
strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`');
strictEqual(_.find(array, function() { return false; }), void 0, 'should return `undefined` if `value` is not found');
+
+ // Matching an object like _.findWhere.
+ var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}];
+ deepEqual(_.find(list, {a: 1}), {a: 1, b: 2}, 'can be used as findWhere');
+ deepEqual(_.find(list, {b: 4}), {a: 1, b: 4});
+ ok(!_.find(list, {c: 1}), 'undefined when not found');
+ ok(!_.find([], {c: 1}), 'undefined when searching empty list');
+
+ var result = _.find([1, 2, 3], function(num){ return num * 2 === 4; });
+ equal(result, 2, 'found the first "2" and broke the loop');
});
test('detect', function() {
- var result = _.detect([1, 2, 3], function(num){ return num * 2 == 4; });
- equal(result, 2, 'found the first "2" and broke the loop');
+ strictEqual(_.detect, _.find, 'alias for detect');
});
- test('select', function() {
- var evens = _.select([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
- equal(evens.join(', '), '2, 4, 6', 'selected each even number');
+ test('filter', function() {
+ var evenArray = [1, 2, 3, 4, 5, 6];
+ var evenObject = {one: 1, two: 2, three: 3};
+ var isEven = function(num){ return num % 2 === 0; };
+
+ deepEqual(_.filter(evenArray, isEven), [2, 4, 6]);
+ deepEqual(_.filter(evenObject, isEven), [2], 'can filter objects');
+ deepEqual(_.filter([{}, evenObject, []], 'two'), [evenObject], 'predicate string map to object properties');
- evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
- equal(evens.join(', '), '2, 4, 6', 'aliased as "filter"');
+ _.filter([1], function() {
+ equal(this, evenObject, 'given context');
+ }, evenObject);
+
+ // Can be used like _.where.
+ var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
+ deepEqual(_.filter(list, {a: 1}), [{a: 1, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]);
+ deepEqual(_.filter(list, {b: 2}), [{a: 1, b: 2}, {a: 2, b: 2}]);
+ deepEqual(_.filter(list, {}), list, 'Empty object accepts all items');
+ deepEqual(_(list).filter({}), list, 'OO-filter');
+ });
+
+ test('select', function() {
+ strictEqual(_.filter, _.select, 'alias for filter');
});
test('reject', function() {
- var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
- equal(odds.join(', '), '1, 3, 5', 'rejected each even number');
+ var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 === 0; });
+ deepEqual(odds, [1, 3, 5], 'rejected each even number');
- var context = "obj";
+ var context = 'obj';
var evens = _.reject([1, 2, 3, 4, 5, 6], function(num){
- equal(context, "obj");
- return num % 2 != 0;
+ equal(context, 'obj');
+ return num % 2 !== 0;
}, context);
- equal(evens.join(', '), '2, 4, 6', 'rejected each odd number');
+ deepEqual(evens, [2, 4, 6], 'rejected each odd number');
+
+ deepEqual(_.reject([odds, {one: 1, two: 2, three: 3}], 'two'), [odds], 'predicate string map to object properties');
+
+ // Can be used like _.where.
+ var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
+ deepEqual(_.reject(list, {a: 1}), [{a: 2, b: 2}]);
+ deepEqual(_.reject(list, {b: 2}), [{a: 1, b: 3}, {a: 1, b: 4}]);
+ deepEqual(_.reject(list, {}), [], 'Returns empty list given empty object');
+ deepEqual(_.reject(list, []), [], 'Returns empty list given empty array');
+ });
+
+ test('every', function() {
+ ok(_.every([], _.identity), 'the empty set');
+ ok(_.every([true, true, true], _.identity), 'every true values');
+ ok(!_.every([true, false, true], _.identity), 'one false value');
+ ok(_.every([0, 10, 28], function(num){ return num % 2 === 0; }), 'even numbers');
+ ok(!_.every([0, 11, 28], function(num){ return num % 2 === 0; }), 'an odd number');
+ ok(_.every([1], _.identity) === true, 'cast to boolean - true');
+ ok(_.every([0], _.identity) === false, 'cast to boolean - false');
+ ok(!_.every([undefined, undefined, undefined], _.identity), 'works with arrays of undefined');
+
+ var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
+ ok(!_.every(list, {a: 1, b: 2}), 'Can be called with object');
+ ok(_.every(list, 'a'), 'String mapped to object property');
+
+ list = [{a: 1, b: 2}, {a: 2, b: 2, c: true}];
+ ok(_.every(list, {b: 2}), 'Can be called with object');
+ ok(!_.every(list, 'c'), 'String mapped to object property');
+
+ ok(_.every({a: 1, b: 2, c: 3, d: 4}, _.isNumber), 'takes objects');
+ ok(!_.every({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects');
+ ok(_.every(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works');
+ ok(!_.every(['a', 'b', 'c', 'd', 'f'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works');
});
test('all', function() {
- ok(_.all([], _.identity), 'the empty set');
- ok(_.all([true, true, true], _.identity), 'all true values');
- ok(!_.all([true, false, true], _.identity), 'one false value');
- ok(_.all([0, 10, 28], function(num){ return num % 2 == 0; }), 'even numbers');
- ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number');
- ok(_.all([1], _.identity) === true, 'cast to boolean - true');
- ok(_.all([0], _.identity) === false, 'cast to boolean - false');
- ok(_.every([true, true, true], _.identity), 'aliased as "every"');
- ok(!_.all([undefined, undefined, undefined], _.identity), 'works with arrays of undefined');
+ strictEqual(_.all, _.every, 'alias for all');
+ });
+
+ test('some', function() {
+ ok(!_.some([]), 'the empty set');
+ ok(!_.some([false, false, false]), 'all false values');
+ ok(_.some([false, false, true]), 'one true value');
+ ok(_.some([null, 0, 'yes', false]), 'a string');
+ ok(!_.some([null, 0, '', false]), 'falsy values');
+ ok(!_.some([1, 11, 29], function(num){ return num % 2 === 0; }), 'all odd numbers');
+ ok(_.some([1, 10, 29], function(num){ return num % 2 === 0; }), 'an even number');
+ ok(_.some([1], _.identity) === true, 'cast to boolean - true');
+ ok(_.some([0], _.identity) === false, 'cast to boolean - false');
+ ok(_.some([false, false, true]));
+
+ var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
+ ok(!_.some(list, {a: 5, b: 2}), 'Can be called with object');
+ ok(_.some(list, 'a'), 'String mapped to object property');
+
+ list = [{a: 1, b: 2}, {a: 2, b: 2, c: true}];
+ ok(_.some(list, {b: 2}), 'Can be called with object');
+ ok(!_.some(list, 'd'), 'String mapped to object property');
+
+ ok(_.some({a: '1', b: '2', c: '3', d: '4', e: 6}, _.isNumber), 'takes objects');
+ ok(!_.some({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects');
+ ok(_.some(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works');
+ ok(!_.some(['x', 'y', 'z'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works');
});
test('any', function() {
- var nativeSome = Array.prototype.some;
- Array.prototype.some = null;
- ok(!_.any([]), 'the empty set');
- ok(!_.any([false, false, false]), 'all false values');
- ok(_.any([false, false, true]), 'one true value');
- ok(_.any([null, 0, 'yes', false]), 'a string');
- ok(!_.any([null, 0, '', false]), 'falsy values');
- ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers');
- ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number');
- ok(_.any([1], _.identity) === true, 'cast to boolean - true');
- ok(_.any([0], _.identity) === false, 'cast to boolean - false');
- ok(_.some([false, false, true]), 'aliased as "some"');
- Array.prototype.some = nativeSome;
+ strictEqual(_.any, _.some, 'alias for any');
+ });
+
+ test('contains', function() {
+ ok(_.contains([1, 2, 3], 2), 'two is in the array');
+ ok(!_.contains([1, 3, 9], 2), 'two is not in the array');
+ ok(_.contains({moe: 1, larry: 3, curly: 9}, 3) === true, '_.contains on objects checks their values');
+ ok(_([1, 2, 3]).contains(2), 'OO-style contains');
});
test('include', function() {
- ok(_.include([1,2,3], 2), 'two is in the array');
- ok(!_.include([1,3,9], 2), 'two is not in the array');
- ok(_.contains({moe:1, larry:3, curly:9}, 3) === true, '_.include on objects checks their values');
- ok(_([1,2,3]).include(2), 'OO-style include');
+ strictEqual(_.contains, _.include, 'alias for contains');
});
test('invoke', function() {
var list = [[5, 1, 7], [3, 2, 1]];
var result = _.invoke(list, 'sort');
- equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
- equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
+ deepEqual(result[0], [1, 5, 7], 'first array sorted');
+ deepEqual(result[1], [1, 2, 3], 'second array sorted');
});
test('invoke w/ function reference', function() {
var list = [[5, 1, 7], [3, 2, 1]];
var result = _.invoke(list, Array.prototype.sort);
- equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
- equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
+ deepEqual(result[0], [1, 5, 7], 'first array sorted');
+ deepEqual(result[1], [1, 2, 3], 'second array sorted');
});
// Relevant when using ClojureScript
@@ -239,18 +334,20 @@ $(document).ready(function() {
return 42;
};
var list = [[5, 1, 7], [3, 2, 1]];
- var s = "foo";
- equal(s.call(), 42, "call function exists");
+ var s = 'foo';
+ equal(s.call(), 42, 'call function exists');
var result = _.invoke(list, 'sort');
- equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
- equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
+ deepEqual(result[0], [1, 5, 7], 'first array sorted');
+ deepEqual(result[1], [1, 2, 3], 'second array sorted');
delete String.prototype.call;
- equal(s.call, undefined, "call function removed");
+ equal(s.call, undefined, 'call function removed');
});
test('pluck', function() {
- var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}];
- equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'pulls names out of objects');
+ var people = [{name: 'moe', age: 30}, {name: 'curly', age: 50}];
+ deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'pulls names out of objects');
+ //compat: most flexible handling of edge cases
+ deepEqual(_.pluck([{'[object Object]': 1}], {}), [1]);
});
test('where', function() {
@@ -261,11 +358,12 @@ $(document).ready(function() {
result = _.where(list, {b: 2});
equal(result.length, 2);
equal(result[0].a, 1);
+ result = _.where(list, {});
+ equal(result.length, list.length);
- result = _.where(list, {a: 1}, true);
- equal(result.b, 2, "Only get the first object matched.")
- result = _.where(list, {a: 1}, false);
- equal(result.length, 3);
+ function test() {}
+ test.map = _.map;
+ deepEqual(_.where([_, {a: 1, b: 2}, _], test), [_, _], 'checks properties given function');
});
test('findWhere', function() {
@@ -275,14 +373,29 @@ $(document).ready(function() {
result = _.findWhere(list, {b: 4});
deepEqual(result, {a: 1, b: 4});
- result = _.findWhere(list, {c:1})
- ok(_.isUndefined(result), "undefined when not found");
+ result = _.findWhere(list, {c: 1});
+ ok(_.isUndefined(result), 'undefined when not found');
+
+ result = _.findWhere([], {c: 1});
+ ok(_.isUndefined(result), 'undefined when searching empty list');
- result = _.findWhere([], {c:1});
- ok(_.isUndefined(result), "undefined when searching empty list");
+ function test() {}
+ test.map = _.map;
+ equal(_.findWhere([_, {a: 1, b: 2}, _], test), _, 'checks properties given function');
+
+ function TestClass() {
+ this.y = 5;
+ this.x = 'foo';
+ }
+ var expect = {c: 1, x: 'foo', y: 5};
+ deepEqual(_.findWhere([{y: 5, b: 6}, expect], new TestClass()), expect, 'uses class instance properties');
});
test('max', function() {
+ equal(-Infinity, _.max(null), 'can handle null/undefined');
+ equal(-Infinity, _.max(undefined), 'can handle null/undefined');
+ equal(-Infinity, _.max(null, _.identity), 'can handle null/undefined');
+
equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max');
var neg = _.max([1, 2, 3], function(num){ return -num; });
@@ -292,10 +405,28 @@ $(document).ready(function() {
equal(-Infinity, _.max([]), 'Maximum value of an empty array');
equal(_.max({'a': 'a'}), -Infinity, 'Maximum value of a non-numeric collection');
- equal(299999, _.max(_.range(1,300000)), "Maximum value of a too-big array");
+ equal(299999, _.max(_.range(1, 300000)), 'Maximum value of a too-big array');
+
+ equal(3, _.max([1, 2, 3, 'test']), 'Finds correct max in array starting with num and containing a NaN');
+ equal(3, _.max(['test', 1, 2, 3]), 'Finds correct max in array starting with NaN');
+
+ var a = {x: -Infinity};
+ var b = {x: -Infinity};
+ var iterator = function(o){ return o.x; };
+ equal(_.max([a, b], iterator), a, 'Respects iterator return value of -Infinity');
+
+ deepEqual(_.max([{'a': 1}, {'a': 0, 'b': 3}, {'a': 4}, {'a': 2}], 'a'), {'a': 4}, 'String keys use property iterator');
+
+ deepEqual(_.max([0, 2], function(a){ return a * this.x; }, {x: 1}), 2, 'Iterator context');
+ deepEqual(_.max([[1], [2, 3], [-1, 4], [5]], 0), [5], 'Lookup falsy iterator');
+ deepEqual(_.max([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: 2}, 'Lookup falsy iterator');
});
test('min', function() {
+ equal(Infinity, _.min(null), 'can handle null/undefined');
+ equal(Infinity, _.min(undefined), 'can handle null/undefined');
+ equal(Infinity, _.min(null, _.identity), 'can handle null/undefined');
+
equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min');
var neg = _.min([1, 2, 3], function(num){ return -num; });
@@ -309,20 +440,34 @@ $(document).ready(function() {
var then = new Date(0);
equal(_.min([now, then]), then);
- equal(1, _.min(_.range(1,300000)), "Minimum value of a too-big array");
+ equal(1, _.min(_.range(1, 300000)), 'Minimum value of a too-big array');
+
+ equal(1, _.min([1, 2, 3, 'test']), 'Finds correct min in array starting with num and containing a NaN');
+ equal(1, _.min(['test', 1, 2, 3]), 'Finds correct min in array starting with NaN');
+
+ var a = {x: Infinity};
+ var b = {x: Infinity};
+ var iterator = function(o){ return o.x; };
+ equal(_.min([a, b], iterator), a, 'Respects iterator return value of Infinity');
+
+ deepEqual(_.min([{'a': 1}, {'a': 0, 'b': 3}, {'a': 4}, {'a': 2}], 'a'), {'a': 0, 'b': 3}, 'String keys use property iterator');
+
+ deepEqual(_.min([0, 2], function(a){ return a * this.x; }, {x: -1}), 2, 'Iterator context');
+ deepEqual(_.min([[1], [2, 3], [-1, 4], [5]], 0), [-1, 4], 'Lookup falsy iterator');
+ deepEqual(_.min([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: -1}, 'Lookup falsy iterator');
});
test('sortBy', function() {
var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}];
people = _.sortBy(people, function(person){ return person.age; });
- equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
+ deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'stooges sorted by age');
var list = [undefined, 4, 1, undefined, 3, 2];
- equal(_.sortBy(list, _.identity).join(','), '1,2,3,4,,', 'sortBy with undefined values');
+ deepEqual(_.sortBy(list, _.identity), [1, 2, 3, 4, undefined, undefined], 'sortBy with undefined values');
- var list = ["one", "two", "three", "four", "five"];
+ list = ['one', 'two', 'three', 'four', 'five'];
var sorted = _.sortBy(list, 'length');
- equal(sorted.join(' '), 'one two four five three', 'sorted by length');
+ deepEqual(sorted, ['one', 'two', 'four', 'five', 'three'], 'sorted by length');
function Pair(x, y) {
this.x = x;
@@ -346,18 +491,23 @@ $(document).ready(function() {
});
deepEqual(actual, collection, 'sortBy should be stable');
+
+ deepEqual(_.sortBy(collection, 'x'), collection, 'sortBy accepts property string');
+
+ list = ['q', 'w', 'e', 'r', 't', 'y'];
+ deepEqual(_.sortBy(list), ['e', 'q', 'r', 't', 'w', 'y'], 'uses _.identity if iterator is not specified');
});
test('groupBy', function() {
var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
ok('0' in parity && '1' in parity, 'created a group for each value');
- equal(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
+ deepEqual(parity[0], [2, 4, 6], 'put each even number in the right group');
- var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
+ var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'];
var grouped = _.groupBy(list, 'length');
- equal(grouped['3'].join(' '), 'one two six ten');
- equal(grouped['4'].join(' '), 'four five nine');
- equal(grouped['5'].join(' '), 'three seven eight');
+ deepEqual(grouped['3'], ['one', 'two', 'six', 'ten']);
+ deepEqual(grouped['4'], ['four', 'five', 'nine']);
+ deepEqual(grouped['5'], ['three', 'seven', 'eight']);
var context = {};
_.groupBy([{}], function(){ ok(this === context); }, context);
@@ -371,44 +521,44 @@ $(document).ready(function() {
var array = [{}];
_.groupBy(array, function(value, index, obj){ ok(obj === array); });
- var array = [1, 2, 1, 2, 3];
- var grouped = _.groupBy(array);
+ array = [1, 2, 1, 2, 3];
+ grouped = _.groupBy(array);
equal(grouped['1'].length, 2);
equal(grouped['3'].length, 1);
var matrix = [
- [1,2],
- [1,3],
- [2,3]
+ [1, 2],
+ [1, 3],
+ [2, 3]
];
- deepEqual(_.groupBy(matrix, 0), {1: [[1,2], [1,3]], 2: [[2,3]]})
- deepEqual(_.groupBy(matrix, 1), {2: [[1,2]], 3: [[1,3], [2,3]]})
+ deepEqual(_.groupBy(matrix, 0), {1: [[1, 2], [1, 3]], 2: [[2, 3]]});
+ deepEqual(_.groupBy(matrix, 1), {2: [[1, 2]], 3: [[1, 3], [2, 3]]});
});
test('indexBy', function() {
- var parity = _.indexBy([1, 2, 3, 4, 5], function(num){ return num % 2 == 0; });
+ var parity = _.indexBy([1, 2, 3, 4, 5], function(num){ return num % 2 === 0; });
equal(parity['true'], 4);
equal(parity['false'], 5);
- var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
+ var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'];
var grouped = _.indexBy(list, 'length');
equal(grouped['3'], 'ten');
equal(grouped['4'], 'nine');
equal(grouped['5'], 'eight');
var array = [1, 2, 1, 2, 3];
- var grouped = _.indexBy(array);
+ grouped = _.indexBy(array);
equal(grouped['1'], 1);
equal(grouped['2'], 2);
equal(grouped['3'], 3);
});
test('countBy', function() {
- var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 == 0; });
+ var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 === 0; });
equal(parity['true'], 2);
equal(parity['false'], 3);
- var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
+ var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'];
var grouped = _.countBy(list, 'length');
equal(grouped['3'], 4);
equal(grouped['4'], 3);
@@ -426,8 +576,8 @@ $(document).ready(function() {
var array = [{}];
_.countBy(array, function(value, index, obj){ ok(obj === array); });
- var array = [1, 2, 1, 2, 3];
- var grouped = _.countBy(array);
+ array = [1, 2, 1, 2, 3];
+ grouped = _.countBy(array);
equal(grouped['1'], 2);
equal(grouped['3'], 1);
});
@@ -452,33 +602,40 @@ $(document).ready(function() {
test('shuffle', function() {
var numbers = _.range(10);
- var shuffled = _.shuffle(numbers).sort();
+ var shuffled = _.shuffle(numbers);
notStrictEqual(numbers, shuffled, 'original object is unmodified');
- equal(shuffled.join(','), numbers.join(','), 'contains the same members before and after shuffle');
+ ok(_.every(_.range(10), function() { //appears consistent?
+ return _.every(numbers, _.partial(_.contains, numbers));
+ }), 'contains the same members before and after shuffle');
+
+ shuffled = _.shuffle({a: 1, b: 2, c: 3, d: 4});
+ equal(shuffled.length, 4);
+ deepEqual(shuffled.sort(), [1, 2, 3, 4], 'works on objects');
});
test('sample', function() {
var numbers = _.range(10);
- var all_sampled = _.sample(numbers, 10).sort();
- equal(all_sampled.join(','), numbers.join(','), 'contains the same members before and after sample');
- all_sampled = _.sample(numbers, 20).sort();
- equal(all_sampled.join(','), numbers.join(','), 'also works when sampling more objects than are present');
+ var allSampled = _.sample(numbers, 10).sort();
+ deepEqual(allSampled, numbers, 'contains the same members before and after sample');
+ allSampled = _.sample(numbers, 20).sort();
+ deepEqual(allSampled, numbers, 'also works when sampling more objects than are present');
ok(_.contains(numbers, _.sample(numbers)), 'sampling a single element returns something from the array');
strictEqual(_.sample([]), undefined, 'sampling empty array with no number returns undefined');
notStrictEqual(_.sample([], 5), [], 'sampling empty array with a number returns an empty array');
notStrictEqual(_.sample([1, 2, 3], 0), [], 'sampling an array with 0 picks returns an empty array');
deepEqual(_.sample([1, 2], -1), [], 'sampling a negative number of picks returns an empty array');
+ ok(_.contains([1, 2, 3], _.sample({a: 1, b: 2, c: 3})), 'sample one value from an object');
});
test('toArray', function() {
ok(!_.isArray(arguments), 'arguments object is not an array');
ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array');
- var a = [1,2,3];
+ var a = [1, 2, 3];
ok(_.toArray(a) !== a, 'array is cloned');
- equal(_.toArray(a).join(', '), '1, 2, 3', 'cloned array contains same elements');
+ deepEqual(_.toArray(a), [1, 2, 3], 'cloned array contains same elements');
var numbers = _.toArray({one : 1, two : 2, three : 3});
- equal(numbers.join(', '), '1, 2, 3', 'object flattened into array');
+ deepEqual(numbers, [1, 2, 3], 'object flattened into array');
// test in IE < 9
try {
@@ -491,7 +648,7 @@ $(document).ready(function() {
test('size', function() {
equal(_.size({one : 1, two : 2, three : 3}), 3, 'can compute the size of an object');
equal(_.size([1, 2, 3]), 3, 'can compute the size of an array');
- equal(_.size($('<div>').add('<span>').add('<span>')), 3, 'can compute the size of jQuery objects');
+ equal(_.size({length: 3, 0: 0, 1: 0, 2: 0}), 3, 'can compute the size of Array-likes');
var func = function() {
return _.size(arguments);
@@ -505,4 +662,35 @@ $(document).ready(function() {
equal(_.size(null), 0, 'handles nulls');
});
-});
+ test('partition', function() {
+ var list = [0, 1, 2, 3, 4, 5];
+ deepEqual(_.partition(list, function(x) { return x < 4; }), [[0, 1, 2, 3], [4, 5]], 'handles bool return values');
+ deepEqual(_.partition(list, function(x) { return x & 1; }), [[1, 3, 5], [0, 2, 4]], 'handles 0 and 1 return values');
+ deepEqual(_.partition(list, function(x) { return x - 3; }), [[0, 1, 2, 4, 5], [3]], 'handles other numeric return values');
+ deepEqual(_.partition(list, function(x) { return x > 1 ? null : true; }), [[0, 1], [2, 3, 4, 5]], 'handles null return values');
+ deepEqual(_.partition(list, function(x) { if (x < 2) return true; }), [[0, 1], [2, 3, 4, 5]], 'handles undefined return values');
+ deepEqual(_.partition({a: 1, b: 2, c: 3}, function(x) { return x > 1; }), [[2, 3], [1]], 'handles objects');
+
+ deepEqual(_.partition(list, function(x, index) { return index % 2; }), [[1, 3, 5], [0, 2, 4]], 'can reference the array index');
+ deepEqual(_.partition(list, function(x, index, arr) { return x === arr.length - 1; }), [[5], [0, 1, 2, 3, 4]], 'can reference the collection');
+
+ // Default iterator
+ deepEqual(_.partition([1, false, true, '']), [[1, true], [false, '']], 'Default iterator');
+ deepEqual(_.partition([{x: 1}, {x: 0}, {x: 1}], 'x'), [[{x: 1}, {x: 1}], [{x: 0}]], 'Takes a string');
+
+ // Context
+ var predicate = function(x){ return x === this.x; };
+ deepEqual(_.partition([1, 2, 3], predicate, {x: 2}), [[2], [1, 3]], 'partition takes a context argument');
+
+ deepEqual(_.partition([{a: 1}, {b: 2}, {a: 1, b: 2}], {a: 1}), [[{a: 1}, {a: 1, b: 2}], [{b: 2}]], 'predicate can be object');
+
+ var object = {a: 1};
+ _.partition(object, function(val, key, obj) {
+ equal(val, 1);
+ equal(key, 'a');
+ equal(obj, object);
+ equal(this, predicate);
+ }, predicate);
+ });
+
+}());
diff --git a/vendor/underscore/test/functions.js b/vendor/underscore/test/functions.js
index 7a773f3..37511b6 100644
--- a/vendor/underscore/test/functions.js
+++ b/vendor/underscore/test/functions.js
@@ -1,10 +1,10 @@
-$(document).ready(function() {
+(function() {
- module("Functions");
+ module('Functions');
- test("bind", function() {
+ test('bind', function() {
var context = {name : 'moe'};
- var func = function(arg) { return "name: " + (this.name || arg); };
+ var func = function(arg) { return 'name: ' + (this.name || arg); };
var bound = _.bind(func, context);
equal(bound(), 'name: moe', 'can bind a function to a context');
@@ -33,22 +33,35 @@ $(document).ready(function() {
// These tests are only meaningful when using a browser without a native bind function
// To test this with a modern browser, set underscore's nativeBind to undefined
var F = function () { return this; };
- var Boundf = _.bind(F, {hello: "moe curly"});
+ var boundf = _.bind(F, {hello: 'moe curly'});
+ var Boundf = boundf; // make eslint happy.
var newBoundf = new Boundf();
- equal(newBoundf.hello, undefined, "function should not be bound to the context, to comply with ECMAScript 5");
- equal(Boundf().hello, "moe curly", "When called without the new operator, it's OK to be bound to the context");
- ok(newBoundf instanceof F, "a bound instance is an instance of the original function");
+ equal(newBoundf.hello, undefined, 'function should not be bound to the context, to comply with ECMAScript 5');
+ equal(boundf().hello, 'moe curly', "When called without the new operator, it's OK to be bound to the context");
+ ok(newBoundf instanceof F, 'a bound instance is an instance of the original function');
+
+ raises(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function');
});
- test("partial", function() {
+ test('partial', function() {
var obj = {name: 'moe'};
var func = function() { return this.name + ' ' + _.toArray(arguments).join(' '); };
obj.func = _.partial(func, 'a', 'b');
equal(obj.func('c', 'd'), 'moe a b c d', 'can partially apply');
+
+ obj.func = _.partial(func, _, 'b', _, 'd');
+ equal(obj.func('a', 'c'), 'moe a b c d', 'can partially apply with placeholders');
+
+ func = _.partial(function() { return arguments.length; }, _, 'b', _, 'd');
+ equal(func('a', 'c', 'e'), 5, 'accepts more arguments than the number of placeholders');
+ equal(func('a'), 4, 'accepts fewer arguments than the number of placeholders');
+
+ func = _.partial(function() { return typeof arguments[2]; }, _, 'b', _, 'd');
+ equal(func('a'), 'undefined', 'unfilled placeholders are undefined');
});
- test("bindAll", function() {
+ test('bindAll', function() {
var curly = {name : 'curly'}, moe = {
name : 'moe',
getName : function() { return 'name: ' + this.name; },
@@ -64,17 +77,23 @@ $(document).ready(function() {
moe = {
name : 'moe',
getName : function() { return 'name: ' + this.name; },
- sayHi : function() { return 'hi: ' + this.name; }
+ sayHi : function() { return 'hi: ' + this.name; },
+ sayLast : function() { return this.sayHi(_.last(arguments)); }
};
raises(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named');
+ raises(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined');
+ raises(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function');
- _.bindAll(moe, 'sayHi');
+ _.bindAll(moe, 'sayHi', 'sayLast');
curly.sayHi = moe.sayHi;
equal(curly.sayHi(), 'hi: moe');
+
+ var sayLast = moe.sayLast;
+ equal(sayLast(1, 2, 3, 4, 5, 6, 7, 'Tom'), 'hi: moe', 'createCallback works with any number of arguments');
});
- test("memoize", function() {
+ test('memoize', function() {
var fib = function(n) {
return n < 2 ? n : fib(n - 1) + fib(n - 2);
};
@@ -88,75 +107,108 @@ $(document).ready(function() {
var fastO = _.memoize(o);
equal(o('toString'), 'toString', 'checks hasOwnProperty');
equal(fastO('toString'), 'toString', 'checks hasOwnProperty');
+
+ // Expose the cache.
+ var upper = _.memoize(function(s) {
+ return s.toUpperCase();
+ });
+ equal(upper('foo'), 'FOO');
+ equal(upper('bar'), 'BAR');
+ deepEqual(upper.cache, {foo: 'FOO', bar: 'BAR'});
+ upper.cache = {foo: 'BAR', bar: 'FOO'};
+ equal(upper('foo'), 'BAR');
+ equal(upper('bar'), 'FOO');
+
+ var hashed = _.memoize(function(key) {
+ //https://github.com/jashkenas/underscore/pull/1679#discussion_r13736209
+ ok(/[a-z]+/.test(key), 'hasher doesn\'t change keys');
+ return key;
+ }, function(key) {
+ return key.toUpperCase();
+ });
+ hashed('yep');
+ deepEqual(hashed.cache, {'YEP': 'yep'}, 'takes a hasher');
+
+ // Test that the hash function can be used to swizzle the key.
+ var objCacher = _.memoize(function(value, key) {
+ return {key: key, value: value};
+ }, function(value, key) {
+ return key;
+ });
+ var myObj = objCacher('a', 'alpha');
+ var myObjAlias = objCacher('b', 'alpha');
+ notStrictEqual(myObj, undefined, 'object is created if second argument used as key');
+ strictEqual(myObj, myObjAlias, 'object is cached if second argument used as key');
+ strictEqual(myObj.value, 'a', 'object is not modified if second argument used as key');
});
- asyncTest("delay", 2, function() {
+ asyncTest('delay', 2, function() {
var delayed = false;
_.delay(function(){ delayed = true; }, 100);
setTimeout(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
setTimeout(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
});
- asyncTest("defer", 1, function() {
+ asyncTest('defer', 1, function() {
var deferred = false;
_.defer(function(bool){ deferred = bool; }, true);
- _.delay(function(){ ok(deferred, "deferred the function"); start(); }, 50);
+ _.delay(function(){ ok(deferred, 'deferred the function'); start(); }, 50);
});
- asyncTest("throttle", 2, function() {
+ asyncTest('throttle', 2, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 32);
throttledIncr(); throttledIncr();
- equal(counter, 1, "incr was called immediately");
- _.delay(function(){ equal(counter, 2, "incr was throttled"); start(); }, 64);
+ equal(counter, 1, 'incr was called immediately');
+ _.delay(function(){ equal(counter, 2, 'incr was throttled'); start(); }, 64);
});
- asyncTest("throttle arguments", 2, function() {
+ asyncTest('throttle arguments', 2, function() {
var value = 0;
var update = function(val){ value = val; };
var throttledUpdate = _.throttle(update, 32);
throttledUpdate(1); throttledUpdate(2);
_.delay(function(){ throttledUpdate(3); }, 64);
- equal(value, 1, "updated to latest value");
- _.delay(function(){ equal(value, 3, "updated to latest value"); start(); }, 96);
+ equal(value, 1, 'updated to latest value');
+ _.delay(function(){ equal(value, 3, 'updated to latest value'); start(); }, 96);
});
- asyncTest("throttle once", 2, function() {
+ asyncTest('throttle once', 2, function() {
var counter = 0;
var incr = function(){ return ++counter; };
var throttledIncr = _.throttle(incr, 32);
var result = throttledIncr();
_.delay(function(){
- equal(result, 1, "throttled functions return their value");
- equal(counter, 1, "incr was called once"); start();
+ equal(result, 1, 'throttled functions return their value');
+ equal(counter, 1, 'incr was called once'); start();
}, 64);
});
- asyncTest("throttle twice", 1, function() {
+ asyncTest('throttle twice', 1, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 32);
throttledIncr(); throttledIncr();
- _.delay(function(){ equal(counter, 2, "incr was called twice"); start(); }, 64);
+ _.delay(function(){ equal(counter, 2, 'incr was called twice'); start(); }, 64);
});
- asyncTest("more throttling", 3, function() {
+ asyncTest('more throttling', 3, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 30);
throttledIncr(); throttledIncr();
- ok(counter == 1);
+ equal(counter, 1);
_.delay(function(){
- ok(counter == 2);
+ equal(counter, 2);
throttledIncr();
- ok(counter == 3);
+ equal(counter, 3);
start();
}, 85);
});
- asyncTest("throttle repeatedly with results", 6, function() {
+ asyncTest('throttle repeatedly with results', 6, function() {
var counter = 0;
var incr = function(){ return ++counter; };
var throttledIncr = _.throttle(incr, 100);
@@ -168,24 +220,24 @@ $(document).ready(function() {
_.delay(saveResult, 160);
_.delay(saveResult, 230);
_.delay(function() {
- equal(results[0], 1, "incr was called once");
- equal(results[1], 1, "incr was throttled");
- equal(results[2], 1, "incr was throttled");
- equal(results[3], 2, "incr was called twice");
- equal(results[4], 2, "incr was throttled");
- equal(results[5], 3, "incr was called trailing");
+ equal(results[0], 1, 'incr was called once');
+ equal(results[1], 1, 'incr was throttled');
+ equal(results[2], 1, 'incr was throttled');
+ equal(results[3], 2, 'incr was called twice');
+ equal(results[4], 2, 'incr was throttled');
+ equal(results[5], 3, 'incr was called trailing');
start();
}, 300);
});
- asyncTest("throttle triggers trailing call when invoked repeatedly", 2, function() {
+ asyncTest('throttle triggers trailing call when invoked repeatedly', 2, function() {
var counter = 0;
var limit = 48;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 32);
var stamp = new Date;
- while ((new Date - stamp) < limit) {
+ while (new Date - stamp < limit) {
throttledIncr();
}
var lastCount = counter;
@@ -197,21 +249,21 @@ $(document).ready(function() {
}, 96);
});
- asyncTest("throttle does not trigger leading call when leading is set to false", 2, function() {
+ asyncTest('throttle does not trigger leading call when leading is set to false', 2, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 60, {leading: false});
throttledIncr(); throttledIncr();
- ok(counter === 0);
+ equal(counter, 0);
_.delay(function() {
- ok(counter == 1);
+ equal(counter, 1);
start();
}, 96);
});
- asyncTest("more throttle does not trigger leading call when leading is set to false", 3, function() {
+ asyncTest('more throttle does not trigger leading call when leading is set to false', 3, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100, {leading: false});
@@ -220,19 +272,19 @@ $(document).ready(function() {
_.delay(throttledIncr, 50);
_.delay(throttledIncr, 60);
_.delay(throttledIncr, 200);
- ok(counter === 0);
+ equal(counter, 0);
_.delay(function() {
- ok(counter == 1);
+ equal(counter, 1);
}, 250);
_.delay(function() {
- ok(counter == 2);
+ equal(counter, 2);
start();
}, 350);
});
- asyncTest("one more throttle with leading: false test", 2, function() {
+ asyncTest('one more throttle with leading: false test', 2, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100, {leading: false});
@@ -247,37 +299,80 @@ $(document).ready(function() {
}, 200);
});
- asyncTest("throttle does not trigger trailing call when trailing is set to false", 4, function() {
+ asyncTest('throttle does not trigger trailing call when trailing is set to false', 4, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 60, {trailing: false});
throttledIncr(); throttledIncr(); throttledIncr();
- ok(counter === 1);
+ equal(counter, 1);
_.delay(function() {
- ok(counter == 1);
+ equal(counter, 1);
throttledIncr(); throttledIncr();
- ok(counter == 2);
+ equal(counter, 2);
_.delay(function() {
- ok(counter == 2);
+ equal(counter, 2);
start();
}, 96);
}, 96);
});
- asyncTest("debounce", 1, function() {
+ asyncTest('throttle continues to function after system time is set backwards', 2, function() {
+ var counter = 0;
+ var incr = function(){ counter++; };
+ var throttledIncr = _.throttle(incr, 100);
+ var origNowFunc = _.now;
+
+ throttledIncr();
+ equal(counter, 1);
+ _.now = function () {
+ return new Date(2013, 0, 1, 1, 1, 1);
+ };
+
+ _.delay(function() {
+ throttledIncr();
+ equal(counter, 2);
+ start();
+ _.now = origNowFunc;
+ }, 200);
+ });
+
+ asyncTest('throttle re-entrant', 2, function() {
+ var sequence = [
+ ['b1', 'b2'],
+ ['c1', 'c2']
+ ];
+ var value = '';
+ var throttledAppend;
+ var append = function(arg){
+ value += this + arg;
+ var args = sequence.pop();
+ if (args) {
+ throttledAppend.call(args[0], args[1]);
+ }
+ };
+ throttledAppend = _.throttle(append, 32);
+ throttledAppend.call('a1', 'a2');
+ equal(value, 'a1a2');
+ _.delay(function(){
+ equal(value, 'a1a2c1c2b1b2', 'append was throttled successfully');
+ start();
+ }, 100);
+ });
+
+ asyncTest('debounce', 1, function() {
var counter = 0;
var incr = function(){ counter++; };
var debouncedIncr = _.debounce(incr, 32);
debouncedIncr(); debouncedIncr();
_.delay(debouncedIncr, 16);
- _.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 96);
+ _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 96);
});
- asyncTest("debounce asap", 4, function() {
+ asyncTest('debounce asap', 4, function() {
var a, b;
var counter = 0;
var incr = function(){ return ++counter; };
@@ -290,29 +385,75 @@ $(document).ready(function() {
_.delay(debouncedIncr, 16);
_.delay(debouncedIncr, 32);
_.delay(debouncedIncr, 48);
- _.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 128);
+ _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 128);
});
- asyncTest("debounce asap recursively", 2, function() {
+ asyncTest('debounce asap recursively', 2, function() {
var counter = 0;
var debouncedIncr = _.debounce(function(){
counter++;
if (counter < 10) debouncedIncr();
}, 32, true);
debouncedIncr();
- equal(counter, 1, "incr was called immediately");
- _.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 96);
+ equal(counter, 1, 'incr was called immediately');
+ _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 96);
});
- test("once", function() {
+ asyncTest('debounce after system time is set backwards', 2, function() {
+ var counter = 0;
+ var origNowFunc = _.now;
+ var debouncedIncr = _.debounce(function(){
+ counter++;
+ }, 100, true);
+
+ debouncedIncr();
+ equal(counter, 1, 'incr was called immediately');
+
+ _.now = function () {
+ return new Date(2013, 0, 1, 1, 1, 1);
+ };
+
+ _.delay(function() {
+ debouncedIncr();
+ equal(counter, 2, 'incr was debounced successfully');
+ start();
+ _.now = origNowFunc;
+ }, 200);
+ });
+
+ asyncTest('debounce re-entrant', 2, function() {
+ var sequence = [
+ ['b1', 'b2']
+ ];
+ var value = '';
+ var debouncedAppend;
+ var append = function(arg){
+ value += this + arg;
+ var args = sequence.pop();
+ if (args) {
+ debouncedAppend.call(args[0], args[1]);
+ }
+ };
+ debouncedAppend = _.debounce(append, 32);
+ debouncedAppend.call('a1', 'a2');
+ equal(value, '');
+ _.delay(function(){
+ equal(value, 'a1a2b1b2', 'append was debounced successfully');
+ start();
+ }, 100);
+ });
+
+ test('once', function() {
var num = 0;
- var increment = _.once(function(){ num++; });
+ var increment = _.once(function(){ return ++num; });
increment();
increment();
equal(num, 1);
+
+ equal(increment(), 1, 'stores a memo to the last value');
});
- test("Recursive onced function.", 1, function() {
+ test('Recursive onced function.', 1, function() {
var f = _.once(function(){
ok(true);
f();
@@ -320,33 +461,55 @@ $(document).ready(function() {
f();
});
- test("wrap", function() {
- var greet = function(name){ return "hi: " + name; };
+ test('wrap', function() {
+ var greet = function(name){ return 'hi: ' + name; };
var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); });
equal(backwards('moe'), 'hi: moe eom', 'wrapped the salutation function');
- var inner = function(){ return "Hello "; };
- var obj = {name : "Moe"};
+ var inner = function(){ return 'Hello '; };
+ var obj = {name : 'Moe'};
obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; });
- equal(obj.hi(), "Hello Moe");
+ equal(obj.hi(), 'Hello Moe');
var noop = function(){};
- var wrapped = _.wrap(noop, function(fn){ return Array.prototype.slice.call(arguments, 0); });
+ var wrapped = _.wrap(noop, function(){ return Array.prototype.slice.call(arguments, 0); });
var ret = wrapped(['whats', 'your'], 'vector', 'victor');
deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']);
});
- test("compose", function() {
- var greet = function(name){ return "hi: " + name; };
+ test('negate', function() {
+ var isOdd = function(n){ return n & 1; };
+ equal(_.negate(isOdd)(2), true, 'should return the complement of the given function');
+ equal(_.negate(isOdd)(3), false, 'should return the complement of the given function');
+ });
+
+ test('compose', function() {
+ var greet = function(name){ return 'hi: ' + name; };
var exclaim = function(sentence){ return sentence + '!'; };
var composed = _.compose(exclaim, greet);
equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another');
composed = _.compose(greet, exclaim);
equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative');
+
+ // f(g(h(x, y, z)))
+ function h(x, y, z) {
+ equal(arguments.length, 3, 'First function called with multiple args');
+ return z * y;
+ }
+ function g(x) {
+ equal(arguments.length, 1, 'Composed function is called with 1 argument');
+ return x;
+ }
+ function f(x) {
+ equal(arguments.length, 1, 'Composed function is called with 1 argument');
+ return x * 2;
+ }
+ composed = _.compose(f, g, h);
+ equal(composed(1, 2, 3), 12);
});
- test("after", function() {
+ test('after', function() {
var testAfter = function(afterAmount, timesCalled) {
var afterCalled = 0;
var after = _.after(afterAmount, function() {
@@ -356,10 +519,35 @@ $(document).ready(function() {
return afterCalled;
};
- equal(testAfter(5, 5), 1, "after(N) should fire after being called N times");
- equal(testAfter(5, 4), 0, "after(N) should not fire unless called N times");
- equal(testAfter(0, 0), 0, "after(0) should not fire immediately");
- equal(testAfter(0, 1), 1, "after(0) should fire when first invoked");
+ equal(testAfter(5, 5), 1, 'after(N) should fire after being called N times');
+ equal(testAfter(5, 4), 0, 'after(N) should not fire unless called N times');
+ equal(testAfter(0, 0), 0, 'after(0) should not fire immediately');
+ equal(testAfter(0, 1), 1, 'after(0) should fire when first invoked');
+ });
+
+ test('before', function() {
+ var testBefore = function(beforeAmount, timesCalled) {
+ var beforeCalled = 0;
+ var before = _.before(beforeAmount, function() { beforeCalled++; });
+ while (timesCalled--) before();
+ return beforeCalled;
+ };
+
+ equal(testBefore(5, 5), 4, 'before(N) should not fire after being called N times');
+ equal(testBefore(5, 4), 4, 'before(N) should fire before being called N times');
+ equal(testBefore(0, 0), 0, 'before(0) should not fire immediately');
+ equal(testBefore(0, 1), 0, 'before(0) should not fire when first invoked');
+
+ var context = {num: 0};
+ var increment = _.before(3, function(){ return ++this.num; });
+ _.times(10, increment, context);
+ equal(increment(), 2, 'stores a memo to the last value');
+ equal(context.num, 2, 'provides context');
+ });
+
+ test('iteratee', function() {
+ var identity = _.iteratee();
+ equal(identity, _.identity, '_.iteratee is exposed as an external function.');
});
-});
+}());
diff --git a/vendor/underscore/test/objects.js b/vendor/underscore/test/objects.js
index 492171e..76e5598 100644
--- a/vendor/underscore/test/objects.js
+++ b/vendor/underscore/test/objects.js
@@ -1,98 +1,151 @@
-$(document).ready(function() {
+(function() {
- module("Objects");
+ module('Objects');
+ /* global iObject, iElement, iArguments, iFunction, iArray, iString, iNumber, iBoolean, iDate, iRegExp, iNaN, iNull, iUndefined, ActiveXObject */
- test("keys", function() {
- equal(_.keys({one : 1, two : 2}).join(', '), 'one, two', 'can extract the keys from an object');
+ test('keys', function() {
+ deepEqual(_.keys({one : 1, two : 2}), ['one', 'two'], 'can extract the keys from an object');
// the test above is not safe because it relies on for-in enumeration order
var a = []; a[1] = 0;
- equal(_.keys(a).join(', '), '1', 'is not fooled by sparse arrays; see issue #95');
- raises(function() { _.keys(null); }, TypeError, 'throws an error for `null` values');
- raises(function() { _.keys(void 0); }, TypeError, 'throws an error for `undefined` values');
- raises(function() { _.keys(1); }, TypeError, 'throws an error for number primitives');
- raises(function() { _.keys('a'); }, TypeError, 'throws an error for string primitives');
- raises(function() { _.keys(true); }, TypeError, 'throws an error for boolean primitives');
+ deepEqual(_.keys(a), ['1'], 'is not fooled by sparse arrays; see issue #95');
+ deepEqual(_.keys(null), []);
+ deepEqual(_.keys(void 0), []);
+ deepEqual(_.keys(1), []);
+ deepEqual(_.keys('a'), []);
+ deepEqual(_.keys(true), []);
});
- test("values", function() {
- equal(_.values({one: 1, two: 2}).join(', '), '1, 2', 'can extract the values from an object');
- equal(_.values({one: 1, two: 2, length: 3}).join(', '), '1, 2, 3', '... even when one of them is "length"');
+ test('values', function() {
+ deepEqual(_.values({one: 1, two: 2}), [1, 2], 'can extract the values from an object');
+ deepEqual(_.values({one: 1, two: 2, length: 3}), [1, 2, 3], '... even when one of them is "length"');
});
- test("pairs", function() {
+ test('pairs', function() {
deepEqual(_.pairs({one: 1, two: 2}), [['one', 1], ['two', 2]], 'can convert an object into pairs');
deepEqual(_.pairs({one: 1, two: 2, length: 3}), [['one', 1], ['two', 2], ['length', 3]], '... even when one of them is "length"');
});
- test("invert", function() {
+ test('invert', function() {
var obj = {first: 'Moe', second: 'Larry', third: 'Curly'};
- equal(_.keys(_.invert(obj)).join(' '), 'Moe Larry Curly', 'can invert an object');
- ok(_.isEqual(_.invert(_.invert(obj)), obj), 'two inverts gets you back where you started');
+ deepEqual(_.keys(_.invert(obj)), ['Moe', 'Larry', 'Curly'], 'can invert an object');
+ deepEqual(_.invert(_.invert(obj)), obj, 'two inverts gets you back where you started');
- var obj = {length: 3};
- ok(_.invert(obj)['3'] == 'length', 'can invert an object with "length"')
+ obj = {length: 3};
+ equal(_.invert(obj)['3'], 'length', 'can invert an object with "length"');
});
- test("functions", function() {
- var obj = {a : 'dash', b : _.map, c : (/yo/), d : _.reduce};
- ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object');
+ test('functions', function() {
+ var obj = {a : 'dash', b : _.map, c : /yo/, d : _.reduce};
+ deepEqual(['b', 'd'], _.functions(obj), 'can grab the function names of any passed-in object');
var Animal = function(){};
Animal.prototype.run = function(){};
- equal(_.functions(new Animal).join(''), 'run', 'also looks up functions on the prototype');
+ deepEqual(_.functions(new Animal), ['run'], 'also looks up functions on the prototype');
});
- test("extend", function() {
+ test('methods', function() {
+ strictEqual(_.functions, _.methods, 'alias for functions');
+ });
+
+ test('extend', function() {
var result;
- equal(_.extend({}, {a:'b'}).a, 'b', 'can extend an object with the attributes of another');
- equal(_.extend({a:'x'}, {a:'b'}).a, 'b', 'properties in source override destination');
- equal(_.extend({x:'x'}, {a:'b'}).x, 'x', "properties not in source don't get overriden");
- result = _.extend({x:'x'}, {a:'a'}, {b:'b'});
- ok(_.isEqual(result, {x:'x', a:'a', b:'b'}), 'can extend from multiple source objects');
- result = _.extend({x:'x'}, {a:'a', x:2}, {a:'b'});
- ok(_.isEqual(result, {x:2, a:'b'}), 'extending from multiple source objects last property trumps');
+ equal(_.extend({}, {a: 'b'}).a, 'b', 'can extend an object with the attributes of another');
+ equal(_.extend({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination');
+ equal(_.extend({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden");
+ result = _.extend({x: 'x'}, {a: 'a'}, {b: 'b'});
+ deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can extend from multiple source objects');
+ result = _.extend({x: 'x'}, {a: 'a', x: 2}, {a: 'b'});
+ deepEqual(result, {x: 2, a: 'b'}, 'extending from multiple source objects last property trumps');
result = _.extend({}, {a: void 0, b: null});
- equal(_.keys(result).join(''), 'ab', 'extend copies undefined values');
+ deepEqual(_.keys(result), ['a', 'b'], 'extend copies undefined values');
+
+ var F = function() {};
+ F.prototype = {a: 'b'};
+ var subObj = new F();
+ subObj.c = 'd';
+ deepEqual(_.extend({}, subObj), {c: 'd'}, 'extend ignores any properties but own from source');
try {
result = {};
- _.extend(result, null, undefined, {a:1});
+ _.extend(result, null, undefined, {a: 1});
} catch(ex) {}
equal(result.a, 1, 'should not error on `null` or `undefined` sources');
+
+ strictEqual(_.extend(null, {a: 1}), null, 'extending null results in null');
+ strictEqual(_.extend(undefined, {a: 1}), undefined, 'extending undefined results in undefined');
});
- test("pick", function() {
+ test('pick', function() {
var result;
- result = _.pick({a:1, b:2, c:3}, 'a', 'c');
- ok(_.isEqual(result, {a:1, c:3}), 'can restrict properties to those named');
- result = _.pick({a:1, b:2, c:3}, ['b', 'c']);
- ok(_.isEqual(result, {b:2, c:3}), 'can restrict properties to those named in an array');
- result = _.pick({a:1, b:2, c:3}, ['a'], 'b');
- ok(_.isEqual(result, {a:1, b:2}), 'can restrict properties to those named in mixed args');
+ result = _.pick({a: 1, b: 2, c: 3}, 'a', 'c');
+ deepEqual(result, {a: 1, c: 3}, 'can restrict properties to those named');
+ result = _.pick({a: 1, b: 2, c: 3}, ['b', 'c']);
+ deepEqual(result, {b: 2, c: 3}, 'can restrict properties to those named in an array');
+ result = _.pick({a: 1, b: 2, c: 3}, ['a'], 'b');
+ deepEqual(result, {a: 1, b: 2}, 'can restrict properties to those named in mixed args');
+ result = _.pick(['a', 'b'], 1);
+ deepEqual(result, {1: 'b'}, 'can pick numeric properties');
+
+ deepEqual(_.pick(null, 'a', 'b'), {}, 'non objects return empty object');
+ deepEqual(_.pick(undefined, 'toString'), {}, 'null/undefined return empty object');
+ deepEqual(_.pick(5, 'toString', 'b'), {toString: Number.prototype.toString}, 'can iterate primitives');
+
+ var data = {a: 1, b: 2, c: 3};
+ var callback = function(value, key, object) {
+ strictEqual(key, {1: 'a', 2: 'b', 3: 'c'}[value]);
+ strictEqual(object, data);
+ return value !== this.value;
+ };
+ result = _.pick(data, callback, {value: 2});
+ deepEqual(result, {a: 1, c: 3}, 'can accept a predicate and context');
var Obj = function(){};
Obj.prototype = {a: 1, b: 2, c: 3};
- ok(_.isEqual(_.pick(new Obj, 'a', 'c'), {a:1, c: 3}), 'include prototype props');
+ var instance = new Obj();
+ deepEqual(_.pick(instance, 'a', 'c'), {a: 1, c: 3}, 'include prototype props');
+
+ deepEqual(_.pick(data, function(val, key) {
+ return this[key] === 3 && this === instance;
+ }, instance), {c: 3}, 'function is given context');
});
- test("omit", function() {
+ test('omit', function() {
var result;
- result = _.omit({a:1, b:2, c:3}, 'b');
- ok(_.isEqual(result, {a:1, c:3}), 'can omit a single named property');
- result = _.omit({a:1, b:2, c:3}, 'a', 'c');
- ok(_.isEqual(result, {b:2}), 'can omit several named properties');
- result = _.omit({a:1, b:2, c:3}, ['b', 'c']);
- ok(_.isEqual(result, {a:1}), 'can omit properties named in an array');
+ result = _.omit({a: 1, b: 2, c: 3}, 'b');
+ deepEqual(result, {a: 1, c: 3}, 'can omit a single named property');
+ result = _.omit({a: 1, b: 2, c: 3}, 'a', 'c');
+ deepEqual(result, {b: 2}, 'can omit several named properties');
+ result = _.omit({a: 1, b: 2, c: 3}, ['b', 'c']);
+ deepEqual(result, {a: 1}, 'can omit properties named in an array');
+ result = _.omit(['a', 'b'], 0);
+ deepEqual(result, {1: 'b'}, 'can omit numeric properties');
+
+ deepEqual(_.omit(null, 'a', 'b'), {}, 'non objects return empty object');
+ deepEqual(_.omit(undefined, 'toString'), {}, 'null/undefined return empty object');
+ deepEqual(_.omit(5, 'toString', 'b'), {}, 'returns empty object for primitives');
+
+ var data = {a: 1, b: 2, c: 3};
+ var callback = function(value, key, object) {
+ strictEqual(key, {1: 'a', 2: 'b', 3: 'c'}[value]);
+ strictEqual(object, data);
+ return value !== this.value;
+ };
+ result = _.omit(data, callback, {value: 2});
+ deepEqual(result, {b: 2}, 'can accept a predicate');
var Obj = function(){};
Obj.prototype = {a: 1, b: 2, c: 3};
- ok(_.isEqual(_.omit(new Obj, 'b'), {a:1, c: 3}), 'include prototype props');
+ var instance = new Obj();
+ deepEqual(_.omit(instance, 'b'), {a: 1, c: 3}, 'include prototype props');
+
+ deepEqual(_.omit(data, function(val, key) {
+ return this[key] === 3 && this === instance;
+ }, instance), {a: 1, b: 2}, 'function is given context');
});
- test("defaults", function() {
- var result;
- var options = {zero: 0, one: 1, empty: "", nan: NaN, nothing: null};
+ test('defaults', function() {
+ var options = {zero: 0, one: 1, empty: '', nan: NaN, nothing: null};
_.defaults(options, {zero: 1, one: 10, twenty: 20, nothing: 'str'});
equal(options.zero, 0, 'value exists');
@@ -100,26 +153,29 @@ $(document).ready(function() {
equal(options.twenty, 20, 'default applied');
equal(options.nothing, null, "null isn't overridden");
- _.defaults(options, {empty: "full"}, {nan: "nan"}, {word: "word"}, {word: "dog"});
- equal(options.empty, "", 'value exists');
+ _.defaults(options, {empty: 'full'}, {nan: 'nan'}, {word: 'word'}, {word: 'dog'});
+ equal(options.empty, '', 'value exists');
ok(_.isNaN(options.nan), "NaN isn't overridden");
- equal(options.word, "word", 'new value is added, first one wins');
+ equal(options.word, 'word', 'new value is added, first one wins');
try {
options = {};
- _.defaults(options, null, undefined, {a:1});
+ _.defaults(options, null, undefined, {a: 1});
} catch(ex) {}
equal(options.a, 1, 'should not error on `null` or `undefined` sources');
+
+ strictEqual(_.defaults(null, {a: 1}), null, 'result is null if destination is null');
+ strictEqual(_.defaults(undefined, {a: 1}), undefined, 'result is undefined if destination is undefined');
});
- test("clone", function() {
+ test('clone', function() {
var moe = {name : 'moe', lucky : [13, 27, 34]};
var clone = _.clone(moe);
equal(clone.name, 'moe', 'the clone as the attributes of the original');
clone.name = 'curly';
- ok(clone.name == 'curly' && moe.name == 'moe', 'clones can change shallow attributes without affecting the original');
+ ok(clone.name === 'curly' && moe.name === 'moe', 'clones can change shallow attributes without affecting the original');
clone.lucky.push(101);
equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original');
@@ -129,7 +185,7 @@ $(document).ready(function() {
equal(_.clone(null), null, 'non objects should not be changed by clone');
});
- test("isEqual", function() {
+ test('isEqual', function() {
function First() {
this.value = 1;
}
@@ -140,133 +196,139 @@ $(document).ready(function() {
Second.prototype.value = 2;
// Basic equality and identity comparisons.
- ok(_.isEqual(null, null), "`null` is equal to `null`");
- ok(_.isEqual(), "`undefined` is equal to `undefined`");
+ ok(_.isEqual(null, null), '`null` is equal to `null`');
+ ok(_.isEqual(), '`undefined` is equal to `undefined`');
- ok(!_.isEqual(0, -0), "`0` is not equal to `-0`");
- ok(!_.isEqual(-0, 0), "Commutative equality is implemented for `0` and `-0`");
- ok(!_.isEqual(null, undefined), "`null` is not equal to `undefined`");
- ok(!_.isEqual(undefined, null), "Commutative equality is implemented for `null` and `undefined`");
+ ok(!_.isEqual(0, -0), '`0` is not equal to `-0`');
+ ok(!_.isEqual(-0, 0), 'Commutative equality is implemented for `0` and `-0`');
+ ok(!_.isEqual(null, undefined), '`null` is not equal to `undefined`');
+ ok(!_.isEqual(undefined, null), 'Commutative equality is implemented for `null` and `undefined`');
// String object and primitive comparisons.
- ok(_.isEqual("Curly", "Curly"), "Identical string primitives are equal");
- ok(_.isEqual(new String("Curly"), new String("Curly")), "String objects with identical primitive values are equal");
- ok(_.isEqual(new String("Curly"), "Curly"), "String primitives and their corresponding object wrappers are equal");
- ok(_.isEqual("Curly", new String("Curly")), "Commutative equality is implemented for string objects and primitives");
+ ok(_.isEqual('Curly', 'Curly'), 'Identical string primitives are equal');
+ ok(_.isEqual(new String('Curly'), new String('Curly')), 'String objects with identical primitive values are equal');
+ ok(_.isEqual(new String('Curly'), 'Curly'), 'String primitives and their corresponding object wrappers are equal');
+ ok(_.isEqual('Curly', new String('Curly')), 'Commutative equality is implemented for string objects and primitives');
- ok(!_.isEqual("Curly", "Larry"), "String primitives with different values are not equal");
- ok(!_.isEqual(new String("Curly"), new String("Larry")), "String objects with different primitive values are not equal");
- ok(!_.isEqual(new String("Curly"), {toString: function(){ return "Curly"; }}), "String objects and objects with a custom `toString` method are not equal");
+ ok(!_.isEqual('Curly', 'Larry'), 'String primitives with different values are not equal');
+ ok(!_.isEqual(new String('Curly'), new String('Larry')), 'String objects with different primitive values are not equal');
+ ok(!_.isEqual(new String('Curly'), {toString: function(){ return 'Curly'; }}), 'String objects and objects with a custom `toString` method are not equal');
// Number object and primitive comparisons.
- ok(_.isEqual(75, 75), "Identical number primitives are equal");
- ok(_.isEqual(new Number(75), new Number(75)), "Number objects with identical primitive values are equal");
- ok(_.isEqual(75, new Number(75)), "Number primitives and their corresponding object wrappers are equal");
- ok(_.isEqual(new Number(75), 75), "Commutative equality is implemented for number objects and primitives");
- ok(!_.isEqual(new Number(0), -0), "`new Number(0)` and `-0` are not equal");
- ok(!_.isEqual(0, new Number(-0)), "Commutative equality is implemented for `new Number(0)` and `-0`");
+ ok(_.isEqual(75, 75), 'Identical number primitives are equal');
+ ok(_.isEqual(new Number(75), new Number(75)), 'Number objects with identical primitive values are equal');
+ ok(_.isEqual(75, new Number(75)), 'Number primitives and their corresponding object wrappers are equal');
+ ok(_.isEqual(new Number(75), 75), 'Commutative equality is implemented for number objects and primitives');
+ ok(!_.isEqual(new Number(0), -0), '`new Number(0)` and `-0` are not equal');
+ ok(!_.isEqual(0, new Number(-0)), 'Commutative equality is implemented for `new Number(0)` and `-0`');
- ok(!_.isEqual(new Number(75), new Number(63)), "Number objects with different primitive values are not equal");
- ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), "Number objects and objects with a `valueOf` method are not equal");
+ ok(!_.isEqual(new Number(75), new Number(63)), 'Number objects with different primitive values are not equal');
+ ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), 'Number objects and objects with a `valueOf` method are not equal');
// Comparisons involving `NaN`.
- ok(_.isEqual(NaN, NaN), "`NaN` is equal to `NaN`");
- ok(!_.isEqual(61, NaN), "A number primitive is not equal to `NaN`");
- ok(!_.isEqual(new Number(79), NaN), "A number object is not equal to `NaN`");
- ok(!_.isEqual(Infinity, NaN), "`Infinity` is not equal to `NaN`");
+ ok(_.isEqual(NaN, NaN), '`NaN` is equal to `NaN`');
+ ok(_.isEqual(new Object(NaN), NaN), 'Object(`NaN`) is equal to `NaN`');
+ ok(!_.isEqual(61, NaN), 'A number primitive is not equal to `NaN`');
+ ok(!_.isEqual(new Number(79), NaN), 'A number object is not equal to `NaN`');
+ ok(!_.isEqual(Infinity, NaN), '`Infinity` is not equal to `NaN`');
// Boolean object and primitive comparisons.
- ok(_.isEqual(true, true), "Identical boolean primitives are equal");
- ok(_.isEqual(new Boolean, new Boolean), "Boolean objects with identical primitive values are equal");
- ok(_.isEqual(true, new Boolean(true)), "Boolean primitives and their corresponding object wrappers are equal");
- ok(_.isEqual(new Boolean(true), true), "Commutative equality is implemented for booleans");
- ok(!_.isEqual(new Boolean(true), new Boolean), "Boolean objects with different primitive values are not equal");
+ ok(_.isEqual(true, true), 'Identical boolean primitives are equal');
+ ok(_.isEqual(new Boolean, new Boolean), 'Boolean objects with identical primitive values are equal');
+ ok(_.isEqual(true, new Boolean(true)), 'Boolean primitives and their corresponding object wrappers are equal');
+ ok(_.isEqual(new Boolean(true), true), 'Commutative equality is implemented for booleans');
+ ok(!_.isEqual(new Boolean(true), new Boolean), 'Boolean objects with different primitive values are not equal');
// Common type coercions.
- ok(!_.isEqual(true, new Boolean(false)), "Boolean objects are not equal to the boolean primitive `true`");
- ok(!_.isEqual("75", 75), "String and number primitives with like values are not equal");
- ok(!_.isEqual(new Number(63), new String(63)), "String and number objects with like values are not equal");
- ok(!_.isEqual(75, "75"), "Commutative equality is implemented for like string and number values");
- ok(!_.isEqual(0, ""), "Number and string primitives with like values are not equal");
- ok(!_.isEqual(1, true), "Number and boolean primitives with like values are not equal");
- ok(!_.isEqual(new Boolean(false), new Number(0)), "Boolean and number objects with like values are not equal");
- ok(!_.isEqual(false, new String("")), "Boolean primitives and string objects with like values are not equal");
- ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), "Dates and their corresponding numeric primitive values are not equal");
+ ok(!_.isEqual(new Boolean(false), true), '`new Boolean(false)` is not equal to `true`');
+ ok(!_.isEqual('75', 75), 'String and number primitives with like values are not equal');
+ ok(!_.isEqual(new Number(63), new String(63)), 'String and number objects with like values are not equal');
+ ok(!_.isEqual(75, '75'), 'Commutative equality is implemented for like string and number values');
+ ok(!_.isEqual(0, ''), 'Number and string primitives with like values are not equal');
+ ok(!_.isEqual(1, true), 'Number and boolean primitives with like values are not equal');
+ ok(!_.isEqual(new Boolean(false), new Number(0)), 'Boolean and number objects with like values are not equal');
+ ok(!_.isEqual(false, new String('')), 'Boolean primitives and string objects with like values are not equal');
+ ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), 'Dates and their corresponding numeric primitive values are not equal');
// Dates.
- ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), "Date objects referencing identical times are equal");
- ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), "Date objects referencing different times are not equal");
+ ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), 'Date objects referencing identical times are equal');
+ ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), 'Date objects referencing different times are not equal');
ok(!_.isEqual(new Date(2009, 11, 13), {
getTime: function(){
return 12606876e5;
}
- }), "Date objects and objects with a `getTime` method are not equal");
- ok(!_.isEqual(new Date("Curly"), new Date("Curly")), "Invalid dates are not equal");
+ }), 'Date objects and objects with a `getTime` method are not equal');
+ ok(!_.isEqual(new Date('Curly'), new Date('Curly')), 'Invalid dates are not equal');
// Functions.
- ok(!_.isEqual(First, Second), "Different functions with identical bodies and source code representations are not equal");
+ ok(!_.isEqual(First, Second), 'Different functions with identical bodies and source code representations are not equal');
// RegExps.
- ok(_.isEqual(/(?:)/gim, /(?:)/gim), "RegExps with equivalent patterns and flags are equal");
- ok(!_.isEqual(/(?:)/g, /(?:)/gi), "RegExps with equivalent patterns and different flags are not equal");
- ok(!_.isEqual(/Moe/gim, /Curly/gim), "RegExps with different patterns and equivalent flags are not equal");
- ok(!_.isEqual(/(?:)/gi, /(?:)/g), "Commutative equality is implemented for RegExps");
- ok(!_.isEqual(/Curly/g, {source: "Larry", global: true, ignoreCase: false, multiline: false}), "RegExps and RegExp-like objects are not equal");
+ ok(_.isEqual(/(?:)/gim, /(?:)/gim), 'RegExps with equivalent patterns and flags are equal');
+ ok(_.isEqual(/(?:)/gi, /(?:)/ig), 'Flag order is not significant');
+ ok(!_.isEqual(/(?:)/g, /(?:)/gi), 'RegExps with equivalent patterns and different flags are not equal');
+ ok(!_.isEqual(/Moe/gim, /Curly/gim), 'RegExps with different patterns and equivalent flags are not equal');
+ ok(!_.isEqual(/(?:)/gi, /(?:)/g), 'Commutative equality is implemented for RegExps');
+ ok(!_.isEqual(/Curly/g, {source: 'Larry', global: true, ignoreCase: false, multiline: false}), 'RegExps and RegExp-like objects are not equal');
// Empty arrays, array-like objects, and object literals.
- ok(_.isEqual({}, {}), "Empty object literals are equal");
- ok(_.isEqual([], []), "Empty array literals are equal");
- ok(_.isEqual([{}], [{}]), "Empty nested arrays and objects are equal");
- ok(!_.isEqual({length: 0}, []), "Array-like objects and arrays are not equal.");
- ok(!_.isEqual([], {length: 0}), "Commutative equality is implemented for array-like objects");
+ ok(_.isEqual({}, {}), 'Empty object literals are equal');
+ ok(_.isEqual([], []), 'Empty array literals are equal');
+ ok(_.isEqual([{}], [{}]), 'Empty nested arrays and objects are equal');
+ ok(!_.isEqual({length: 0}, []), 'Array-like objects and arrays are not equal.');
+ ok(!_.isEqual([], {length: 0}), 'Commutative equality is implemented for array-like objects');
- ok(!_.isEqual({}, []), "Object literals and array literals are not equal");
- ok(!_.isEqual([], {}), "Commutative equality is implemented for objects and arrays");
+ ok(!_.isEqual({}, []), 'Object literals and array literals are not equal');
+ ok(!_.isEqual([], {}), 'Commutative equality is implemented for objects and arrays');
// Arrays with primitive and object values.
- ok(_.isEqual([1, "Larry", true], [1, "Larry", true]), "Arrays containing identical primitives are equal");
- ok(_.isEqual([(/Moe/g), new Date(2009, 9, 25)], [(/Moe/g), new Date(2009, 9, 25)]), "Arrays containing equivalent elements are equal");
+ ok(_.isEqual([1, 'Larry', true], [1, 'Larry', true]), 'Arrays containing identical primitives are equal');
+ ok(_.isEqual([/Moe/g, new Date(2009, 9, 25)], [/Moe/g, new Date(2009, 9, 25)]), 'Arrays containing equivalent elements are equal');
// Multi-dimensional arrays.
- var a = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
- var b = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
- ok(_.isEqual(a, b), "Arrays containing nested arrays and objects are recursively compared");
+ var a = [new Number(47), false, 'Larry', /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
+ var b = [new Number(47), false, 'Larry', /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
+ ok(_.isEqual(a, b), 'Arrays containing nested arrays and objects are recursively compared');
// Overwrite the methods defined in ES 5.1 section 15.4.4.
a.forEach = a.map = a.filter = a.every = a.indexOf = a.lastIndexOf = a.some = a.reduce = a.reduceRight = null;
b.join = b.pop = b.reverse = b.shift = b.slice = b.splice = b.concat = b.sort = b.unshift = null;
// Array elements and properties.
- ok(_.isEqual(a, b), "Arrays containing equivalent elements and different non-numeric properties are equal");
- a.push("White Rocks");
- ok(!_.isEqual(a, b), "Arrays of different lengths are not equal");
- a.push("East Boulder");
- b.push("Gunbarrel Ranch", "Teller Farm");
- ok(!_.isEqual(a, b), "Arrays of identical lengths containing different elements are not equal");
+ ok(_.isEqual(a, b), 'Arrays containing equivalent elements and different non-numeric properties are equal');
+ a.push('White Rocks');
+ ok(!_.isEqual(a, b), 'Arrays of different lengths are not equal');
+ a.push('East Boulder');
+ b.push('Gunbarrel Ranch', 'Teller Farm');
+ ok(!_.isEqual(a, b), 'Arrays of identical lengths containing different elements are not equal');
// Sparse arrays.
- ok(_.isEqual(Array(3), Array(3)), "Sparse arrays of identical lengths are equal");
- ok(!_.isEqual(Array(3), Array(6)), "Sparse arrays of different lengths are not equal when both are empty");
+ ok(_.isEqual(Array(3), Array(3)), 'Sparse arrays of identical lengths are equal');
+ ok(!_.isEqual(Array(3), Array(6)), 'Sparse arrays of different lengths are not equal when both are empty');
+
+ var sparse = [];
+ sparse[1] = 5;
+ ok(_.isEqual(sparse, [undefined, 5]), 'Handles sparse arrays as dense');
// Simple objects.
- ok(_.isEqual({a: "Curly", b: 1, c: true}, {a: "Curly", b: 1, c: true}), "Objects containing identical primitives are equal");
- ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), "Objects containing equivalent members are equal");
- ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), "Objects of identical sizes with different values are not equal");
- ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), "Objects of identical sizes with different property names are not equal");
- ok(!_.isEqual({a: 1, b: 2}, {a: 1}), "Objects of different sizes are not equal");
- ok(!_.isEqual({a: 1}, {a: 1, b: 2}), "Commutative equality is implemented for objects");
- ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), "Objects with identical keys and different values are not equivalent");
+ ok(_.isEqual({a: 'Curly', b: 1, c: true}, {a: 'Curly', b: 1, c: true}), 'Objects containing identical primitives are equal');
+ ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), 'Objects containing equivalent members are equal');
+ ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), 'Objects of identical sizes with different values are not equal');
+ ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), 'Objects of identical sizes with different property names are not equal');
+ ok(!_.isEqual({a: 1, b: 2}, {a: 1}), 'Objects of different sizes are not equal');
+ ok(!_.isEqual({a: 1}, {a: 1, b: 2}), 'Commutative equality is implemented for objects');
+ ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), 'Objects with identical keys and different values are not equivalent');
// `A` contains nested objects and arrays.
a = {
- name: new String("Moe Howard"),
+ name: new String('Moe Howard'),
age: new Number(77),
stooge: true,
- hobbies: ["acting"],
+ hobbies: ['acting'],
film: {
- name: "Sing a Song of Six Pants",
+ name: 'Sing a Song of Six Pants',
release: new Date(1947, 9, 30),
- stars: [new String("Larry Fine"), "Shemp Howard"],
+ stars: [new String('Larry Fine'), 'Shemp Howard'],
minutes: new Number(16),
seconds: 54
}
@@ -274,81 +336,81 @@ $(document).ready(function() {
// `B` contains equivalent nested objects and arrays.
b = {
- name: new String("Moe Howard"),
+ name: new String('Moe Howard'),
age: new Number(77),
stooge: true,
- hobbies: ["acting"],
+ hobbies: ['acting'],
film: {
- name: "Sing a Song of Six Pants",
+ name: 'Sing a Song of Six Pants',
release: new Date(1947, 9, 30),
- stars: [new String("Larry Fine"), "Shemp Howard"],
+ stars: [new String('Larry Fine'), 'Shemp Howard'],
minutes: new Number(16),
seconds: 54
}
};
- ok(_.isEqual(a, b), "Objects with nested equivalent members are recursively compared");
+ ok(_.isEqual(a, b), 'Objects with nested equivalent members are recursively compared');
// Instances.
- ok(_.isEqual(new First, new First), "Object instances are equal");
- ok(!_.isEqual(new First, new Second), "Objects with different constructors and identical own properties are not equal");
- ok(!_.isEqual({value: 1}, new First), "Object instances and objects sharing equivalent properties are not equal");
- ok(!_.isEqual({value: 2}, new Second), "The prototype chain of objects should not be examined");
+ ok(_.isEqual(new First, new First), 'Object instances are equal');
+ ok(!_.isEqual(new First, new Second), 'Objects with different constructors and identical own properties are not equal');
+ ok(!_.isEqual({value: 1}, new First), 'Object instances and objects sharing equivalent properties are not equal');
+ ok(!_.isEqual({value: 2}, new Second), 'The prototype chain of objects should not be examined');
// Circular Arrays.
(a = []).push(a);
(b = []).push(b);
- ok(_.isEqual(a, b), "Arrays containing circular references are equal");
- a.push(new String("Larry"));
- b.push(new String("Larry"));
- ok(_.isEqual(a, b), "Arrays containing circular references and equivalent properties are equal");
- a.push("Shemp");
- b.push("Curly");
- ok(!_.isEqual(a, b), "Arrays containing circular references and different properties are not equal");
+ ok(_.isEqual(a, b), 'Arrays containing circular references are equal');
+ a.push(new String('Larry'));
+ b.push(new String('Larry'));
+ ok(_.isEqual(a, b), 'Arrays containing circular references and equivalent properties are equal');
+ a.push('Shemp');
+ b.push('Curly');
+ ok(!_.isEqual(a, b), 'Arrays containing circular references and different properties are not equal');
// More circular arrays #767.
- a = ["everything is checked but", "this", "is not"];
+ a = ['everything is checked but', 'this', 'is not'];
a[1] = a;
- b = ["everything is checked but", ["this", "array"], "is not"];
- ok(!_.isEqual(a, b), "Comparison of circular references with non-circular references are not equal");
+ b = ['everything is checked but', ['this', 'array'], 'is not'];
+ ok(!_.isEqual(a, b), 'Comparison of circular references with non-circular references are not equal');
// Circular Objects.
a = {abc: null};
b = {abc: null};
a.abc = a;
b.abc = b;
- ok(_.isEqual(a, b), "Objects containing circular references are equal");
+ ok(_.isEqual(a, b), 'Objects containing circular references are equal');
a.def = 75;
b.def = 75;
- ok(_.isEqual(a, b), "Objects containing circular references and equivalent properties are equal");
+ ok(_.isEqual(a, b), 'Objects containing circular references and equivalent properties are equal');
a.def = new Number(75);
b.def = new Number(63);
- ok(!_.isEqual(a, b), "Objects containing circular references and different properties are not equal");
+ ok(!_.isEqual(a, b), 'Objects containing circular references and different properties are not equal');
// More circular objects #767.
- a = {everything: "is checked", but: "this", is: "not"};
+ a = {everything: 'is checked', but: 'this', is: 'not'};
a.but = a;
- b = {everything: "is checked", but: {that:"object"}, is: "not"};
- ok(!_.isEqual(a, b), "Comparison of circular references with non-circular object references are not equal");
+ b = {everything: 'is checked', but: {that: 'object'}, is: 'not'};
+ ok(!_.isEqual(a, b), 'Comparison of circular references with non-circular object references are not equal');
// Cyclic Structures.
a = [{abc: null}];
b = [{abc: null}];
(a[0].abc = a).push(a);
(b[0].abc = b).push(b);
- ok(_.isEqual(a, b), "Cyclic structures are equal");
- a[0].def = "Larry";
- b[0].def = "Larry";
- ok(_.isEqual(a, b), "Cyclic structures containing equivalent properties are equal");
- a[0].def = new String("Larry");
- b[0].def = new String("Curly");
- ok(!_.isEqual(a, b), "Cyclic structures containing different properties are not equal");
+ ok(_.isEqual(a, b), 'Cyclic structures are equal');
+ a[0].def = 'Larry';
+ b[0].def = 'Larry';
+ ok(_.isEqual(a, b), 'Cyclic structures containing equivalent properties are equal');
+ a[0].def = new String('Larry');
+ b[0].def = new String('Curly');
+ ok(!_.isEqual(a, b), 'Cyclic structures containing different properties are not equal');
// Complex Circular References.
a = {foo: {b: {foo: {c: {foo: null}}}}};
b = {foo: {b: {foo: {c: {foo: null}}}}};
a.foo.b.foo.c.foo = a;
b.foo.b.foo.c.foo = b;
- ok(_.isEqual(a, b), "Cyclic structures with nested and identically-named properties are equal");
+ ok(_.isEqual(a, b), 'Cyclic structures with nested and identically-named properties are equal');
// Chaining.
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal');
@@ -359,9 +421,22 @@ $(document).ready(function() {
// Objects from another frame.
ok(_.isEqual({}, iObject));
+
+ // Objects without a `constructor` property
+ if (Object.create) {
+ a = Object.create(null, {x: {value: 1, enumerable: true}});
+ b = {x: 1};
+ ok(_.isEqual(a, b), 'Handles objects without a constructor (e.g. from Object.create');
+ }
+
+ function Foo() { this.a = 1; }
+ Foo.prototype.constructor = null;
+
+ var other = {a: 1};
+ strictEqual(_.isEqual(new Foo, other), false, 'Objects from different constructors are not equal');
});
- test("isEmpty", function() {
+ test('isEmpty', function() {
ok(!_([1]).isEmpty(), '[1] is not empty');
ok(_.isEmpty([]), '[] is empty');
ok(!_.isEmpty({one : 1}), '{one : 1} is not empty');
@@ -375,51 +450,56 @@ $(document).ready(function() {
var obj = {one : 1};
delete obj.one;
ok(_.isEmpty(obj), 'deleting all the keys from an object empties it');
+
+ var args = function(){ return arguments; };
+ ok(_.isEmpty(args()), 'empty arguments object is empty');
+ ok(!_.isEmpty(args('')), 'non-empty arguments object is not empty');
});
// Setup remote variables for iFrame tests.
var iframe = document.createElement('iframe');
- jQuery(iframe).appendTo(document.body);
- var iDoc = iframe.contentDocument || iframe.contentWindow.document;
+ iframe.frameBorder = iframe.height = iframe.width = 0;
+ document.body.appendChild(iframe);
+ var iDoc = (iDoc = iframe.contentDocument || iframe.contentWindow).document || iDoc;
iDoc.write(
- "<script>\
- parent.iElement = document.createElement('div');\
- parent.iArguments = (function(){ return arguments; })(1, 2, 3);\
- parent.iArray = [1, 2, 3];\
- parent.iString = new String('hello');\
- parent.iNumber = new Number(100);\
- parent.iFunction = (function(){});\
- parent.iDate = new Date();\
- parent.iRegExp = /hi/;\
- parent.iNaN = NaN;\
- parent.iNull = null;\
- parent.iBoolean = new Boolean(false);\
- parent.iUndefined = undefined;\
- parent.iObject = {};\
- </script>"
+ '<script>' +
+ ' parent.iElement = document.createElement("div");' +
+ ' parent.iArguments = (function(){ return arguments; })(1, 2, 3);' +
+ ' parent.iArray = [1, 2, 3];' +
+ ' parent.iString = new String("hello");' +
+ ' parent.iNumber = new Number(100);' +
+ ' parent.iFunction = (function(){});' +
+ ' parent.iDate = new Date();' +
+ ' parent.iRegExp = /hi/;' +
+ ' parent.iNaN = NaN;' +
+ ' parent.iNull = null;' +
+ ' parent.iBoolean = new Boolean(false);' +
+ ' parent.iUndefined = undefined;' +
+ ' parent.iObject = {};' +
+ '</script>'
);
iDoc.close();
- test("isElement", function() {
+ test('isElement', function() {
ok(!_.isElement('div'), 'strings are not dom elements');
- ok(_.isElement($('html')[0]), 'the html tag is a DOM element');
+ ok(_.isElement(document.body), 'the body tag is a DOM element');
ok(_.isElement(iElement), 'even from another frame');
});
- test("isArguments", function() {
- var args = (function(){ return arguments; })(1, 2, 3);
+ test('isArguments', function() {
+ var args = (function(){ return arguments; }(1, 2, 3));
ok(!_.isArguments('string'), 'a string is not an arguments object');
ok(!_.isArguments(_.isArguments), 'a function is not an arguments object');
ok(_.isArguments(args), 'but the arguments object is an arguments object');
ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array');
- ok(!_.isArguments([1,2,3]), 'and not vanilla arrays.');
+ ok(!_.isArguments([1, 2, 3]), 'and not vanilla arrays.');
ok(_.isArguments(iArguments), 'even from another frame');
});
- test("isObject", function() {
+ test('isObject', function() {
ok(_.isObject(arguments), 'the arguments object is object');
ok(_.isObject([1, 2, 3]), 'and arrays');
- ok(_.isObject($('html')[0]), 'and DOM element');
+ ok(_.isObject(document.body), 'and DOM element');
ok(_.isObject(iElement), 'even from another frame');
ok(_.isObject(function () {}), 'and functions');
ok(_.isObject(iFunction), 'even from another frame');
@@ -431,23 +511,23 @@ $(document).ready(function() {
ok(_.isObject(new String('string')), 'but new String()');
});
- test("isArray", function() {
+ test('isArray', function() {
ok(!_.isArray(undefined), 'undefined vars are not arrays');
ok(!_.isArray(arguments), 'the arguments object is not an array');
ok(_.isArray([1, 2, 3]), 'but arrays are');
ok(_.isArray(iArray), 'even from another frame');
});
- test("isString", function() {
- var obj = new String("I am a string object");
+ test('isString', function() {
+ var obj = new String('I am a string object');
ok(!_.isString(document.body), 'the document body is not a string');
ok(_.isString([1, 2, 3].join(', ')), 'but strings are');
ok(_.isString(iString), 'even from another frame');
- ok(_.isString("I am a string literal"), 'string literals are');
+ ok(_.isString('I am a string literal'), 'string literals are');
ok(_.isString(obj), 'so are String objects');
});
- test("isNumber", function() {
+ test('isNumber', function() {
ok(!_.isNumber('string'), 'a string is not a number');
ok(!_.isNumber(arguments), 'the arguments object is not a number');
ok(!_.isNumber(undefined), 'undefined is not a number');
@@ -458,11 +538,11 @@ $(document).ready(function() {
ok(!_.isNumber('1'), 'numeric strings are not numbers');
});
- test("isBoolean", function() {
+ test('isBoolean', function() {
ok(!_.isBoolean(2), 'a number is not a boolean');
- ok(!_.isBoolean("string"), 'a string is not a boolean');
- ok(!_.isBoolean("false"), 'the string "false" is not a boolean');
- ok(!_.isBoolean("true"), 'the string "true" is not a boolean');
+ ok(!_.isBoolean('string'), 'a string is not a boolean');
+ ok(!_.isBoolean('false'), 'the string "false" is not a boolean');
+ ok(!_.isBoolean('true'), 'the string "true" is not a boolean');
ok(!_.isBoolean(arguments), 'the arguments object is not a boolean');
ok(!_.isBoolean(undefined), 'undefined is not a boolean');
ok(!_.isBoolean(NaN), 'NaN is not a boolean');
@@ -472,7 +552,7 @@ $(document).ready(function() {
ok(_.isBoolean(iBoolean), 'even from another frame');
});
- test("isFunction", function() {
+ test('isFunction', function() {
ok(!_.isFunction(undefined), 'undefined vars are not functions');
ok(!_.isFunction([1, 2, 3]), 'arrays are not functions');
ok(!_.isFunction('moe'), 'strings are not functions');
@@ -481,36 +561,36 @@ $(document).ready(function() {
ok(_.isFunction(function(){}), 'even anonymous ones');
});
- test("isDate", function() {
+ test('isDate', function() {
ok(!_.isDate(100), 'numbers are not dates');
ok(!_.isDate({}), 'objects are not dates');
ok(_.isDate(new Date()), 'but dates are');
ok(_.isDate(iDate), 'even from another frame');
});
- test("isRegExp", function() {
+ test('isRegExp', function() {
ok(!_.isRegExp(_.identity), 'functions are not RegExps');
ok(_.isRegExp(/identity/), 'but RegExps are');
ok(_.isRegExp(iRegExp), 'even from another frame');
});
- test("isFinite", function() {
- ok(!_.isFinite(undefined), 'undefined is not Finite');
- ok(!_.isFinite(null), 'null is not Finite');
- ok(!_.isFinite(NaN), 'NaN is not Finite');
- ok(!_.isFinite(Infinity), 'Infinity is not Finite');
- ok(!_.isFinite(-Infinity), '-Infinity is not Finite');
+ test('isFinite', function() {
+ ok(!_.isFinite(undefined), 'undefined is not finite');
+ ok(!_.isFinite(null), 'null is not finite');
+ ok(!_.isFinite(NaN), 'NaN is not finite');
+ ok(!_.isFinite(Infinity), 'Infinity is not finite');
+ ok(!_.isFinite(-Infinity), '-Infinity is not finite');
ok(_.isFinite('12'), 'Numeric strings are numbers');
ok(!_.isFinite('1a'), 'Non numeric strings are not numbers');
ok(!_.isFinite(''), 'Empty strings are not numbers');
var obj = new Number(5);
ok(_.isFinite(obj), 'Number instances can be finite');
- ok(_.isFinite(0), '0 is Finite');
- ok(_.isFinite(123), 'Ints are Finite');
- ok(_.isFinite(-12.44), 'Floats are Finite');
+ ok(_.isFinite(0), '0 is finite');
+ ok(_.isFinite(123), 'Ints are finite');
+ ok(_.isFinite(-12.44), 'Floats are finite');
});
- test("isNaN", function() {
+ test('isNaN', function() {
ok(!_.isNaN(undefined), 'undefined is not NaN');
ok(!_.isNaN(null), 'null is not NaN');
ok(!_.isNaN(0), '0 is not NaN');
@@ -519,14 +599,14 @@ $(document).ready(function() {
ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN');
});
- test("isNull", function() {
+ test('isNull', function() {
ok(!_.isNull(undefined), 'undefined is not null');
ok(!_.isNull(NaN), 'NaN is not null');
ok(_.isNull(null), 'but null is');
ok(_.isNull(iNull), 'even from another frame');
});
- test("isUndefined", function() {
+ test('isUndefined', function() {
ok(!_.isUndefined(1), 'numbers are defined');
ok(!_.isUndefined(null), 'null is defined');
ok(!_.isUndefined(false), 'false is defined');
@@ -537,8 +617,8 @@ $(document).ready(function() {
});
if (window.ActiveXObject) {
- test("IE host objects", function() {
- var xml = new ActiveXObject("Msxml2.DOMDocument.3.0");
+ test('IE host objects', function() {
+ var xml = new ActiveXObject('Msxml2.DOMDocument.3.0');
ok(!_.isNumber(xml));
ok(!_.isBoolean(xml));
ok(!_.isNaN(xml));
@@ -548,30 +628,91 @@ $(document).ready(function() {
});
}
- test("tap", function() {
+ test('tap', function() {
var intercepted = null;
var interceptor = function(obj) { intercepted = obj; };
var returned = _.tap(1, interceptor);
- equal(intercepted, 1, "passes tapped object to interceptor");
- equal(returned, 1, "returns tapped object");
+ equal(intercepted, 1, 'passes tapped object to interceptor');
+ equal(returned, 1, 'returns tapped object');
- returned = _([1,2,3]).chain().
+ returned = _([1, 2, 3]).chain().
map(function(n){ return n * 2; }).
max().
tap(interceptor).
value();
- ok(returned == 6 && intercepted == 6, 'can use tapped objects in a chain');
+ equal(returned, 6, 'can use tapped objects in a chain');
+ equal(intercepted, returned, 'can use tapped objects in a chain');
+ });
+
+ test('has', function () {
+ var obj = {foo: 'bar', func: function(){}};
+ ok(_.has(obj, 'foo'), 'has() checks that the object has a property.');
+ ok(!_.has(obj, 'baz'), "has() returns false if the object doesn't have the property.");
+ ok(_.has(obj, 'func'), 'has() works for functions too.');
+ obj.hasOwnProperty = null;
+ ok(_.has(obj, 'foo'), 'has() works even when the hasOwnProperty method is deleted.');
+ var child = {};
+ child.prototype = obj;
+ ok(!_.has(child, 'foo'), 'has() does not check the prototype chain for a property.');
+ strictEqual(_.has(null, 'foo'), false, 'has() returns false for null');
+ strictEqual(_.has(undefined, 'foo'), false, 'has() returns false for undefined');
});
- test("has", function () {
- var obj = {foo: "bar", func: function () {} };
- ok (_.has(obj, "foo"), "has() checks that the object has a property.");
- ok (_.has(obj, "baz") == false, "has() returns false if the object doesn't have the property.");
- ok (_.has(obj, "func"), "has() works for functions too.");
- obj.hasOwnProperty = null;
- ok (_.has(obj, "foo"), "has() works even when the hasOwnProperty method is deleted.");
- var child = {};
- child.prototype = obj;
- ok (_.has(child, "foo") == false, "has() does not check the prototype chain for a property.")
+ test('matches', function() {
+ var moe = {name: 'Moe Howard', hair: true};
+ var curly = {name: 'Curly Howard', hair: false};
+ var stooges = [moe, curly];
+
+ equal(_.matches({hair: true})(moe), true, 'Returns a boolean');
+ equal(_.matches({hair: true})(curly), false, 'Returns a boolean');
+
+ equal(_.matches({__x__: undefined})(5), false, 'can match undefined props on primitives');
+ equal(_.matches({__x__: undefined})({__x__: undefined}), true, 'can match undefined props');
+
+ equal(_.matches({})(null), true, 'Empty spec called with null object returns true');
+ equal(_.matches({a: 1})(null), false, 'Non-empty spec called with null object returns false');
+
+ ok(_.find(stooges, _.matches({hair: false})) === curly, 'returns a predicate that can be used by finding functions.');
+ ok(_.find(stooges, _.matches(moe)) === moe, 'can be used to locate an object exists in a collection.');
+ deepEqual(_.where([null, undefined], {a: 1}), [], 'Do not throw on null values.');
+
+ deepEqual(_.where([null, undefined], null), [null, undefined], 'null matches null');
+ deepEqual(_.where([null, undefined], {}), [null, undefined], 'null matches {}');
+ deepEqual(_.where([{b: 1}], {a: undefined}), [], 'handles undefined values (1683)');
+
+ _.each([true, 5, NaN, null, undefined], function(item) {
+ deepEqual(_.where([{a: 1}], item), [{a: 1}], 'treats primitives as empty');
+ });
+
+ function Prototest() {}
+ Prototest.prototype.x = 1;
+ var specObj = new Prototest;
+ var protospec = _.matches(specObj);
+ equal(protospec({x: 2}), true, 'spec is restricted to own properties');
+
+ specObj.y = 5;
+ protospec = _.matches(specObj);
+ equal(protospec({x: 1, y: 5}), true);
+ equal(protospec({x: 1, y: 4}), false);
+
+ ok(_.matches({x: 1, y: 5})(specObj), 'inherited and own properties are checked on the test object');
+
+ Prototest.x = 5;
+ ok(_.matches(Prototest)({x: 5, y: 1}), 'spec can be a function');
+
+ // #1729
+ var o = {'b': 1};
+ var m = _.matches(o);
+
+ equal(m({'b': 1}), true);
+ o.b = 2;
+ o.a = 1;
+ equal(m({'b': 1}), true, 'changing spec object doesnt change matches result');
+
+
+ //null edge cases
+ var oCon = _.matches({'constructor': Object});
+ deepEqual(_.map([null, undefined, 5, {}], oCon), [false, false, false, true], 'doesnt fasley match constructor on undefined/null');
});
-});
+
+}());
diff --git a/vendor/underscore/test/utility.js b/vendor/underscore/test/utility.js
index 52c5495..9c54ea0 100644
--- a/vendor/underscore/test/utility.js
+++ b/vendor/underscore/test/utility.js
@@ -1,8 +1,8 @@
-$(document).ready(function() {
+(function() {
var templateSettings;
- module("Utility", {
+ module('Utility', {
setup: function() {
templateSettings = _.clone(_.templateSettings);
@@ -14,54 +14,73 @@ $(document).ready(function() {
});
- test("#750 - Return _ instance.", 2, function() {
+ test('#750 - Return _ instance.', 2, function() {
var instance = _([]);
ok(_(instance) === instance);
ok(new _(instance) === instance);
});
- test("identity", function() {
+ test('identity', function() {
var moe = {name : 'moe'};
equal(_.identity(moe), moe, 'moe is the same as his identity');
});
- test("random", function() {
+ test('constant', function() {
+ var moe = {name : 'moe'};
+ equal(_.constant(moe)(), moe, 'should create a function that returns moe');
+ });
+
+ test('noop', function() {
+ strictEqual(_.noop('curly', 'larry', 'moe'), undefined, 'should always return undefined');
+ });
+
+ test('property', function() {
+ var moe = {name : 'moe'};
+ equal(_.property('name')(moe), 'moe', 'should return the property with the given name');
+ });
+
+ test('random', function() {
var array = _.range(1000);
var min = Math.pow(2, 31);
var max = Math.pow(2, 62);
ok(_.every(array, function() {
return _.random(min, max) >= min;
- }), "should produce a random number greater than or equal to the minimum number");
+ }), 'should produce a random number greater than or equal to the minimum number');
ok(_.some(array, function() {
return _.random(Number.MAX_VALUE) > 0;
- }), "should produce a random number when passed `Number.MAX_VALUE`");
+ }), 'should produce a random number when passed `Number.MAX_VALUE`');
+ });
+
+ test('now', function() {
+ var diff = _.now() - new Date().getTime();
+ ok(diff <= 0 && diff > -5, 'Produces the correct time in milliseconds');//within 5ms
});
- test("uniqueId", function() {
+ test('uniqueId', function() {
var ids = [], i = 0;
- while(i++ < 100) ids.push(_.uniqueId());
+ while (i++ < 100) ids.push(_.uniqueId());
equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids');
});
- test("times", function() {
+ test('times', function() {
var vals = [];
_.times(3, function (i) { vals.push(i); });
- ok(_.isEqual(vals, [0,1,2]), "is 0 indexed");
+ deepEqual(vals, [0, 1, 2], 'is 0 indexed');
//
vals = [];
_(3).times(function(i) { vals.push(i); });
- ok(_.isEqual(vals, [0,1,2]), "works as a wrapper");
+ deepEqual(vals, [0, 1, 2], 'works as a wrapper');
// collects return values
- ok(_.isEqual([0, 1, 2], _.times(3, function(i) { return i; })), "collects return values");
+ deepEqual([0, 1, 2], _.times(3, function(i) { return i; }), 'collects return values');
deepEqual(_.times(0, _.identity), []);
deepEqual(_.times(-1, _.identity), []);
deepEqual(_.times(parseFloat('-Infinity'), _.identity), []);
});
- test("mixin", function() {
+ test('mixin', function() {
_.mixin({
myReverse: function(string) {
return string.split('').reverse().join('');
@@ -71,126 +90,159 @@ $(document).ready(function() {
equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper');
});
- test("_.escape", function() {
- equal(_.escape("Curly & Moe"), "Curly & Moe");
- equal(_.escape('<a href="http://moe.com">Curly & Moe\'s</a>'), '<a href="http://moe.com">Curly & Moe's</a>');
- equal(_.escape("Curly & Moe"), "Curly & Moe");
+ test('_.escape', function() {
equal(_.escape(null), '');
});
- test("_.unescape", function() {
- var string = "Curly & Moe";
- equal(_.unescape("Curly & Moe"), string);
- equal(_.unescape('<a href="http://moe.com">Curly & Moe's</a>'), '<a href="http://moe.com">Curly & Moe\'s</a>');
- equal(_.unescape("Curly & Moe"), "Curly & Moe");
+ test('_.unescape', function() {
+ var string = 'Curly & Moe';
equal(_.unescape(null), '');
equal(_.unescape(_.escape(string)), string);
+ equal(_.unescape(string), string, 'don\'t unescape unnecessarily');
});
- test("template", function() {
+ // Don't care what they escape them to just that they're escaped and can be unescaped
+ test('_.escape & unescape', function() {
+ // test & (&) seperately obviously
+ var escapeCharacters = ['<', '>', '"', '\'', '`'];
+
+ _.each(escapeCharacters, function(escapeChar) {
+ var str = 'a ' + escapeChar + ' string escaped';
+ var escaped = _.escape(str);
+ notEqual(str, escaped, escapeChar + ' is escaped');
+ equal(str, _.unescape(escaped), escapeChar + ' can be unescaped');
+
+ str = 'a ' + escapeChar + escapeChar + escapeChar + 'some more string' + escapeChar;
+ escaped = _.escape(str);
+
+ equal(escaped.indexOf(escapeChar), -1, 'can escape multiple occurances of ' + escapeChar);
+ equal(_.unescape(escaped), str, 'multiple occurrences of ' + escapeChar + ' can be unescaped');
+ });
+
+ // handles multiple escape characters at once
+ var joiner = ' other stuff ';
+ var allEscaped = escapeCharacters.join(joiner);
+ allEscaped += allEscaped;
+ ok(_.every(escapeCharacters, function(escapeChar) {
+ return allEscaped.indexOf(escapeChar) !== -1;
+ }), 'handles multiple characters');
+ ok(allEscaped.indexOf(joiner) >= 0, 'can escape multiple escape characters at the same time');
+
+ // test & -> &
+ var str = 'some string & another string & yet another';
+ var escaped = _.escape(str);
+
+ ok(escaped.indexOf('&') !== -1, 'handles & aka &');
+ equal(_.unescape(str), str, 'can unescape &');
+ });
+
+ test('template', function() {
var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");
var result = basicTemplate({thing : 'This'});
equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation');
- var sansSemicolonTemplate = _.template("A <% this %> B");
- equal(sansSemicolonTemplate(), "A B");
+ var sansSemicolonTemplate = _.template('A <% this %> B');
+ equal(sansSemicolonTemplate(), 'A B');
- var backslashTemplate = _.template("<%= thing %> is \\ridanculous");
- equal(backslashTemplate({thing: 'This'}), "This is \\ridanculous");
+ var backslashTemplate = _.template('<%= thing %> is \\ridanculous');
+ equal(backslashTemplate({thing: 'This'}), 'This is \\ridanculous');
var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>');
equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.');
- var fancyTemplate = _.template("<ul><% \
- for (var key in people) { \
- %><li><%= people[key] %></li><% } %></ul>");
- result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
- equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
+ var fancyTemplate = _.template('<ul><% ' +
+ ' for (var key in people) { ' +
+ '%><li><%= people[key] %></li><% } %></ul>');
+ result = fancyTemplate({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
+ equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates');
- var escapedCharsInJavascriptTemplate = _.template("<ul><% _.each(numbers.split('\\n'), function(item) { %><li><%= item %></li><% }) %></ul>");
- result = escapedCharsInJavascriptTemplate({numbers: "one\ntwo\nthree\nfour"});
- equal(result, "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>", 'Can use escaped characters (e.g. \\n) in Javascript');
+ var escapedCharsInJavascriptTemplate = _.template('<ul><% _.each(numbers.split("\\n"), function(item) { %><li><%= item %></li><% }) %></ul>');
+ result = escapedCharsInJavascriptTemplate({numbers: 'one\ntwo\nthree\nfour'});
+ equal(result, '<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>', 'Can use escaped characters (e.g. \\n) in JavaScript');
- var namespaceCollisionTemplate = _.template("<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><div class=\"thumbnail\" rel=\"<%= p %>\"></div><% }); %>");
+ var namespaceCollisionTemplate = _.template('<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><div class="thumbnail" rel="<%= p %>"></div><% }); %>');
result = namespaceCollisionTemplate({
pageCount: 3,
thumbnails: {
- 1: "p1-thumbnail.gif",
- 2: "p2-thumbnail.gif",
- 3: "p3-thumbnail.gif"
+ 1: 'p1-thumbnail.gif',
+ 2: 'p2-thumbnail.gif',
+ 3: 'p3-thumbnail.gif'
}
});
- equal(result, "3 p3-thumbnail.gif <div class=\"thumbnail\" rel=\"p1-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p2-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p3-thumbnail.gif\"></div>");
+ equal(result, '3 p3-thumbnail.gif <div class="thumbnail" rel="p1-thumbnail.gif"></div><div class="thumbnail" rel="p2-thumbnail.gif"></div><div class="thumbnail" rel="p3-thumbnail.gif"></div>');
- var noInterpolateTemplate = _.template("<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
+ var noInterpolateTemplate = _.template('<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>');
result = noInterpolateTemplate();
- equal(result, "<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
+ equal(result, '<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>');
var quoteTemplate = _.template("It's its, not it's");
equal(quoteTemplate({}), "It's its, not it's");
- var quoteInStatementAndBody = _.template("<%\
- if(foo == 'bar'){ \
- %>Statement quotes and 'quotes'.<% } %>");
- equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
+ var quoteInStatementAndBody = _.template('<% ' +
+ " if(foo == 'bar'){ " +
+ "%>Statement quotes and 'quotes'.<% } %>");
+ equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'.");
var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.');
equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.');
- var template = _.template("<i><%- value %></i>");
- var result = template({value: "<script>"});
+ var template = _.template('<i><%- value %></i>');
+ result = template({value: '<script>'});
equal(result, '<i><script></i>');
var stooge = {
- name: "Moe",
+ name: 'Moe',
template: _.template("I'm <%= this.name %>")
};
equal(stooge.template(), "I'm Moe");
- if (!$.browser.msie) {
- var fromHTML = _.template($('#template').html());
- equal(fromHTML({data : 12345}).replace(/\s/g, ''), '<li>24690</li>');
- }
+ template = _.template('\n ' +
+ ' <%\n ' +
+ ' // a comment\n ' +
+ ' if (data) { data += 12345; }; %>\n ' +
+ ' <li><%= data %></li>\n '
+ );
+ equal(template({data : 12345}).replace(/\s/g, ''), '<li>24690</li>');
_.templateSettings = {
evaluate : /\{\{([\s\S]+?)\}\}/g,
interpolate : /\{\{=([\s\S]+?)\}\}/g
};
- var custom = _.template("<ul>{{ for (var key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>");
- result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
- equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
+ var custom = _.template('<ul>{{ for (var key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>');
+ result = custom({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
+ equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates');
var customQuote = _.template("It's its, not it's");
equal(customQuote({}), "It's its, not it's");
- var quoteInStatementAndBody = _.template("{{ if(foo == 'bar'){ }}Statement quotes and 'quotes'.{{ } }}");
- equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
+ quoteInStatementAndBody = _.template("{{ if(foo == 'bar'){ }}Statement quotes and 'quotes'.{{ } }}");
+ equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'.");
_.templateSettings = {
evaluate : /<\?([\s\S]+?)\?>/g,
interpolate : /<\?=([\s\S]+?)\?>/g
};
- var customWithSpecialChars = _.template("<ul><? for (var key in people) { ?><li><?= people[key] ?></li><? } ?></ul>");
- result = customWithSpecialChars({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
- equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
+ var customWithSpecialChars = _.template('<ul><? for (var key in people) { ?><li><?= people[key] ?></li><? } ?></ul>');
+ result = customWithSpecialChars({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
+ equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates');
var customWithSpecialCharsQuote = _.template("It's its, not it's");
equal(customWithSpecialCharsQuote({}), "It's its, not it's");
- var quoteInStatementAndBody = _.template("<? if(foo == 'bar'){ ?>Statement quotes and 'quotes'.<? } ?>");
- equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
+ quoteInStatementAndBody = _.template("<? if(foo == 'bar'){ ?>Statement quotes and 'quotes'.<? } ?>");
+ equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'.");
_.templateSettings = {
interpolate : /\{\{(.+?)\}\}/g
};
- var mustache = _.template("Hello {{planet}}!");
- equal(mustache({planet : "World"}), "Hello World!", "can mimic mustache.js");
+ var mustache = _.template('Hello {{planet}}!');
+ equal(mustache({planet : 'World'}), 'Hello World!', 'can mimic mustache.js');
- var templateWithNull = _.template("a null undefined {{planet}}");
- equal(templateWithNull({planet : "world"}), "a null undefined world", "can handle missing escape and evaluate settings");
+ var templateWithNull = _.template('a null undefined {{planet}}');
+ equal(templateWithNull({planet : 'world'}), 'a null undefined world', 'can handle missing escape and evaluate settings');
});
test('_.template provides the generated function source, when a SyntaxError occurs', function() {
@@ -219,7 +271,8 @@ $(document).ready(function() {
test('_.templateSettings.variable', function() {
var s = '<%=data.x%>';
var data = {x: 'x'};
- strictEqual(_.template(s, data, {variable: 'data'}), 'x');
+ var tmp = _.template(s, {variable: 'data'});
+ strictEqual(tmp(data), 'x');
_.templateSettings.variable = 'data';
strictEqual(_.template(s)(data), 'x');
});
@@ -240,22 +293,22 @@ $(document).ready(function() {
strictEqual(templateEscaped({x: undefined}), '');
var templateWithProperty = _.template('<%=x.foo%>');
- strictEqual(templateWithProperty({x: {} }), '');
- strictEqual(templateWithProperty({x: {} }), '');
+ strictEqual(templateWithProperty({x: {}}), '');
+ strictEqual(templateWithProperty({x: {}}), '');
var templateWithPropertyEscaped = _.template('<%-x.foo%>');
- strictEqual(templateWithPropertyEscaped({x: {} }), '');
- strictEqual(templateWithPropertyEscaped({x: {} }), '');
+ strictEqual(templateWithPropertyEscaped({x: {}}), '');
+ strictEqual(templateWithPropertyEscaped({x: {}}), '');
});
test('interpolate evaluates code only once.', 2, function() {
var count = 0;
var template = _.template('<%= f() %>');
- template({f: function(){ ok(!(count++)); }});
+ template({f: function(){ ok(!count++); }});
var countEscaped = 0;
var templateEscaped = _.template('<%- f() %>');
- templateEscaped({f: function(){ ok(!(countEscaped++)); }});
+ templateEscaped({f: function(){ ok(!countEscaped++); }});
});
test('#746 - _.template settings are not modified.', 1, function() {
@@ -269,4 +322,4 @@ $(document).ready(function() {
strictEqual(template(), '<<\nx\n>>');
});
-});
+}());
diff --git a/vendor/underscore/underscore-min.js b/vendor/underscore/underscore-min.js
index d22f881..11f1d96 100644
--- a/vendor/underscore/underscore-min.js
+++ b/vendor/underscore/underscore-min.js
@@ -1,6 +1,6 @@
-// Underscore.js 1.5.2
+// Underscore.js 1.7.0
// http://underscorejs.org
-// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license.
-(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,g=e.filter,d=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,w=Object.keys,_=i.bind,j=function(n){return n instanceof j?n:this instanceof j?(this._wrapped=n,void 0):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exp [...]
+(function(){var n=this,t=n._,r=Array.prototype,e=Object.prototype,u=Function.prototype,i=r.push,a=r.slice,o=r.concat,l=e.toString,c=e.hasOwnProperty,f=Array.isArray,s=Object.keys,p=u.bind,h=function(n){return n instanceof h?n:this instanceof h?void(this._wrapped=n):new h(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=h),exports._=h):n._=h,h.VERSION="1.7.0";var g=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return [...]
//# sourceMappingURL=underscore-min.map
\ No newline at end of file
diff --git a/vendor/underscore/underscore.js b/vendor/underscore/underscore.js
index b50115d..b4f49a0 100644
--- a/vendor/underscore/underscore.js
+++ b/vendor/underscore/underscore.js
@@ -1,6 +1,6 @@
-// Underscore.js 1.5.2
+// Underscore.js 1.7.0
// http://underscorejs.org
-// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license.
(function() {
@@ -14,9 +14,6 @@
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
- // Establish the object that gets returned to break out of a loop iteration.
- var breaker = {};
-
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
@@ -31,15 +28,6 @@
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
var
- nativeForEach = ArrayProto.forEach,
- nativeMap = ArrayProto.map,
- nativeReduce = ArrayProto.reduce,
- nativeReduceRight = ArrayProto.reduceRight,
- nativeFilter = ArrayProto.filter,
- nativeEvery = ArrayProto.every,
- nativeSome = ArrayProto.some,
- nativeIndexOf = ArrayProto.indexOf,
- nativeLastIndexOf = ArrayProto.lastIndexOf,
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind;
@@ -53,8 +41,7 @@
// Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in
- // the browser, add `_` as a global object via a string identifier,
- // for Closure Compiler "advanced" mode.
+ // the browser, add `_` as a global object.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
@@ -65,97 +52,125 @@
}
// Current version.
- _.VERSION = '1.5.2';
+ _.VERSION = '1.7.0';
+
+ // Internal function that returns an efficient (for current engines) version
+ // of the passed-in callback, to be repeatedly applied in other Underscore
+ // functions.
+ var createCallback = function(func, context, argCount) {
+ if (context === void 0) return func;
+ switch (argCount == null ? 3 : argCount) {
+ case 1: return function(value) {
+ return func.call(context, value);
+ };
+ case 2: return function(value, other) {
+ return func.call(context, value, other);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(context, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(context, accumulator, value, index, collection);
+ };
+ }
+ return function() {
+ return func.apply(context, arguments);
+ };
+ };
+
+ // A mostly-internal function to generate callbacks that can be applied
+ // to each element in a collection, returning the desired result — either
+ // identity, an arbitrary callback, a property matcher, or a property accessor.
+ _.iteratee = function(value, context, argCount) {
+ if (value == null) return _.identity;
+ if (_.isFunction(value)) return createCallback(value, context, argCount);
+ if (_.isObject(value)) return _.matches(value);
+ return _.property(value);
+ };
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
- // Handles objects with the built-in `forEach`, arrays, and raw objects.
- // Delegates to **ECMAScript 5**'s native `forEach` if available.
- var each = _.each = _.forEach = function(obj, iterator, context) {
- if (obj == null) return;
- if (nativeForEach && obj.forEach === nativeForEach) {
- obj.forEach(iterator, context);
- } else if (obj.length === +obj.length) {
- for (var i = 0, length = obj.length; i < length; i++) {
- if (iterator.call(context, obj[i], i, obj) === breaker) return;
+ // Handles raw objects in addition to array-likes. Treats all
+ // sparse array-likes as if they were dense.
+ _.each = _.forEach = function(obj, iteratee, context) {
+ if (obj == null) return obj;
+ iteratee = createCallback(iteratee, context);
+ var i, length = obj.length;
+ if (length === +length) {
+ for (i = 0; i < length; i++) {
+ iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
- for (var i = 0, length = keys.length; i < length; i++) {
- if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
+ for (i = 0, length = keys.length; i < length; i++) {
+ iteratee(obj[keys[i]], keys[i], obj);
}
}
+ return obj;
};
- // Return the results of applying the iterator to each element.
- // Delegates to **ECMAScript 5**'s native `map` if available.
- _.map = _.collect = function(obj, iterator, context) {
- var results = [];
- if (obj == null) return results;
- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
- each(obj, function(value, index, list) {
- results.push(iterator.call(context, value, index, list));
- });
+ // Return the results of applying the iteratee to each element.
+ _.map = _.collect = function(obj, iteratee, context) {
+ if (obj == null) return [];
+ iteratee = _.iteratee(iteratee, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ results = Array(length),
+ currentKey;
+ for (var index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ results[index] = iteratee(obj[currentKey], currentKey, obj);
+ }
return results;
};
var reduceError = 'Reduce of empty array with no initial value';
// **Reduce** builds up a single result from a list of values, aka `inject`,
- // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
+ // or `foldl`.
+ _.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
if (obj == null) obj = [];
- if (nativeReduce && obj.reduce === nativeReduce) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
+ iteratee = createCallback(iteratee, context, 4);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ index = 0, currentKey;
+ if (arguments.length < 3) {
+ if (!length) throw new TypeError(reduceError);
+ memo = obj[keys ? keys[index++] : index++];
+ }
+ for (; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
- each(obj, function(value, index, list) {
- if (!initial) {
- memo = value;
- initial = true;
- } else {
- memo = iterator.call(context, memo, value, index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
return memo;
};
// The right-associative version of reduce, also known as `foldr`.
- // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
+ _.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
if (obj == null) obj = [];
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+ iteratee = createCallback(iteratee, context, 4);
+ var keys = obj.length !== + obj.length && _.keys(obj),
+ index = (keys || obj).length,
+ currentKey;
+ if (arguments.length < 3) {
+ if (!index) throw new TypeError(reduceError);
+ memo = obj[keys ? keys[--index] : --index];
}
- var length = obj.length;
- if (length !== +length) {
- var keys = _.keys(obj);
- length = keys.length;
+ while (index--) {
+ currentKey = keys ? keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
- each(obj, function(value, index, list) {
- index = keys ? keys[--length] : --length;
- if (!initial) {
- memo = obj[index];
- initial = true;
- } else {
- memo = iterator.call(context, memo, obj[index], index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
return memo;
};
// Return the first value which passes a truth test. Aliased as `detect`.
- _.find = _.detect = function(obj, iterator, context) {
+ _.find = _.detect = function(obj, predicate, context) {
var result;
- any(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) {
+ predicate = _.iteratee(predicate, context);
+ _.some(obj, function(value, index, list) {
+ if (predicate(value, index, list)) {
result = value;
return true;
}
@@ -164,61 +179,58 @@
};
// Return all the elements that pass a truth test.
- // Delegates to **ECMAScript 5**'s native `filter` if available.
// Aliased as `select`.
- _.filter = _.select = function(obj, iterator, context) {
+ _.filter = _.select = function(obj, predicate, context) {
var results = [];
if (obj == null) return results;
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
- each(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) results.push(value);
+ predicate = _.iteratee(predicate, context);
+ _.each(obj, function(value, index, list) {
+ if (predicate(value, index, list)) results.push(value);
});
return results;
};
// Return all the elements for which a truth test fails.
- _.reject = function(obj, iterator, context) {
- return _.filter(obj, function(value, index, list) {
- return !iterator.call(context, value, index, list);
- }, context);
+ _.reject = function(obj, predicate, context) {
+ return _.filter(obj, _.negate(_.iteratee(predicate)), context);
};
// Determine whether all of the elements match a truth test.
- // Delegates to **ECMAScript 5**'s native `every` if available.
// Aliased as `all`.
- _.every = _.all = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = true;
- if (obj == null) return result;
- if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
- each(obj, function(value, index, list) {
- if (!(result = result && iterator.call(context, value, index, list))) return breaker;
- });
- return !!result;
+ _.every = _.all = function(obj, predicate, context) {
+ if (obj == null) return true;
+ predicate = _.iteratee(predicate, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ index, currentKey;
+ for (index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
+ }
+ return true;
};
// Determine if at least one element in the object matches a truth test.
- // Delegates to **ECMAScript 5**'s native `some` if available.
// Aliased as `any`.
- var any = _.some = _.any = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = false;
- if (obj == null) return result;
- if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
- each(obj, function(value, index, list) {
- if (result || (result = iterator.call(context, value, index, list))) return breaker;
- });
- return !!result;
+ _.some = _.any = function(obj, predicate, context) {
+ if (obj == null) return false;
+ predicate = _.iteratee(predicate, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ index, currentKey;
+ for (index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ if (predicate(obj[currentKey], currentKey, obj)) return true;
+ }
+ return false;
};
// Determine if the array or object contains a given value (using `===`).
// Aliased as `include`.
_.contains = _.include = function(obj, target) {
if (obj == null) return false;
- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
- return any(obj, function(value) {
- return value === target;
- });
+ if (obj.length !== +obj.length) obj = _.values(obj);
+ return _.indexOf(obj, target) >= 0;
};
// Invoke a method (with arguments) on every item in a collection.
@@ -232,94 +244,104 @@
// Convenience version of a common use case of `map`: fetching a property.
_.pluck = function(obj, key) {
- return _.map(obj, function(value){ return value[key]; });
+ return _.map(obj, _.property(key));
};
// Convenience version of a common use case of `filter`: selecting only objects
// containing specific `key:value` pairs.
- _.where = function(obj, attrs, first) {
- if (_.isEmpty(attrs)) return first ? void 0 : [];
- return _[first ? 'find' : 'filter'](obj, function(value) {
- for (var key in attrs) {
- if (attrs[key] !== value[key]) return false;
- }
- return true;
- });
+ _.where = function(obj, attrs) {
+ return _.filter(obj, _.matches(attrs));
};
// Convenience version of a common use case of `find`: getting the first object
// containing specific `key:value` pairs.
_.findWhere = function(obj, attrs) {
- return _.where(obj, attrs, true);
+ return _.find(obj, _.matches(attrs));
};
- // Return the maximum element or (element-based computation).
- // Can't optimize arrays of integers longer than 65,535 elements.
- // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
- _.max = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.max.apply(Math, obj);
+ // Return the maximum element (or element-based computation).
+ _.max = function(obj, iteratee, context) {
+ var result = -Infinity, lastComputed = -Infinity,
+ value, computed;
+ if (iteratee == null && obj != null) {
+ obj = obj.length === +obj.length ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value > result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index, list) {
+ computed = iteratee(value, index, list);
+ if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+ result = value;
+ lastComputed = computed;
+ }
+ });
}
- if (!iterator && _.isEmpty(obj)) return -Infinity;
- var result = {computed : -Infinity, value: -Infinity};
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- computed > result.computed && (result = {value : value, computed : computed});
- });
- return result.value;
+ return result;
};
// Return the minimum element (or element-based computation).
- _.min = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.min.apply(Math, obj);
+ _.min = function(obj, iteratee, context) {
+ var result = Infinity, lastComputed = Infinity,
+ value, computed;
+ if (iteratee == null && obj != null) {
+ obj = obj.length === +obj.length ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value < result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index, list) {
+ computed = iteratee(value, index, list);
+ if (computed < lastComputed || computed === Infinity && result === Infinity) {
+ result = value;
+ lastComputed = computed;
+ }
+ });
}
- if (!iterator && _.isEmpty(obj)) return Infinity;
- var result = {computed : Infinity, value: Infinity};
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- computed < result.computed && (result = {value : value, computed : computed});
- });
- return result.value;
+ return result;
};
- // Shuffle an array, using the modern version of the
+ // Shuffle a collection, using the modern version of the
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
_.shuffle = function(obj) {
- var rand;
- var index = 0;
- var shuffled = [];
- each(obj, function(value) {
- rand = _.random(index++);
- shuffled[index - 1] = shuffled[rand];
- shuffled[rand] = value;
- });
+ var set = obj && obj.length === +obj.length ? obj : _.values(obj);
+ var length = set.length;
+ var shuffled = Array(length);
+ for (var index = 0, rand; index < length; index++) {
+ rand = _.random(0, index);
+ if (rand !== index) shuffled[index] = shuffled[rand];
+ shuffled[rand] = set[index];
+ }
return shuffled;
};
- // Sample **n** random values from an array.
- // If **n** is not specified, returns a single random element from the array.
+ // Sample **n** random values from a collection.
+ // If **n** is not specified, returns a single random element.
// The internal `guard` argument allows it to work with `map`.
_.sample = function(obj, n, guard) {
- if (arguments.length < 2 || guard) {
+ if (n == null || guard) {
+ if (obj.length !== +obj.length) obj = _.values(obj);
return obj[_.random(obj.length - 1)];
}
return _.shuffle(obj).slice(0, Math.max(0, n));
};
- // An internal function to generate lookup iterators.
- var lookupIterator = function(value) {
- return _.isFunction(value) ? value : function(obj){ return obj[value]; };
- };
-
- // Sort the object's values by a criterion produced by an iterator.
- _.sortBy = function(obj, value, context) {
- var iterator = lookupIterator(value);
+ // Sort the object's values by a criterion produced by an iteratee.
+ _.sortBy = function(obj, iteratee, context) {
+ iteratee = _.iteratee(iteratee, context);
return _.pluck(_.map(obj, function(value, index, list) {
return {
value: value,
index: index,
- criteria: iterator.call(context, value, index, list)
+ criteria: iteratee(value, index, list)
};
}).sort(function(left, right) {
var a = left.criteria;
@@ -334,12 +356,12 @@
// An internal function used for aggregate "group by" operations.
var group = function(behavior) {
- return function(obj, value, context) {
+ return function(obj, iteratee, context) {
var result = {};
- var iterator = value == null ? _.identity : lookupIterator(value);
- each(obj, function(value, index) {
- var key = iterator.call(context, value, index, obj);
- behavior(result, key, value);
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index) {
+ var key = iteratee(value, index, obj);
+ behavior(result, value, key);
});
return result;
};
@@ -347,32 +369,32 @@
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
- _.groupBy = group(function(result, key, value) {
- (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
+ _.groupBy = group(function(result, value, key) {
+ if (_.has(result, key)) result[key].push(value); else result[key] = [value];
});
// Indexes the object's values by a criterion, similar to `groupBy`, but for
// when you know that your index values will be unique.
- _.indexBy = group(function(result, key, value) {
+ _.indexBy = group(function(result, value, key) {
result[key] = value;
});
// Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the
// criterion.
- _.countBy = group(function(result, key) {
- _.has(result, key) ? result[key]++ : result[key] = 1;
+ _.countBy = group(function(result, value, key) {
+ if (_.has(result, key)) result[key]++; else result[key] = 1;
});
// Use a comparator function to figure out the smallest index at which
// an object should be inserted so as to maintain order. Uses binary search.
- _.sortedIndex = function(array, obj, iterator, context) {
- iterator = iterator == null ? _.identity : lookupIterator(iterator);
- var value = iterator.call(context, obj);
+ _.sortedIndex = function(array, obj, iteratee, context) {
+ iteratee = _.iteratee(iteratee, context, 1);
+ var value = iteratee(obj);
var low = 0, high = array.length;
while (low < high) {
- var mid = (low + high) >>> 1;
- iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
+ var mid = low + high >>> 1;
+ if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
};
@@ -388,7 +410,18 @@
// Return the number of elements in an object.
_.size = function(obj) {
if (obj == null) return 0;
- return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
+ return obj.length === +obj.length ? obj.length : _.keys(obj).length;
+ };
+
+ // Split a collection into two arrays: one whose elements all satisfy the given
+ // predicate, and one whose elements all do not satisfy the predicate.
+ _.partition = function(obj, predicate, context) {
+ predicate = _.iteratee(predicate, context);
+ var pass = [], fail = [];
+ _.each(obj, function(value, key, obj) {
+ (predicate(value, key, obj) ? pass : fail).push(value);
+ });
+ return [pass, fail];
};
// Array Functions
@@ -399,7 +432,9 @@
// allows it to work with `_.map`.
_.first = _.head = _.take = function(array, n, guard) {
if (array == null) return void 0;
- return (n == null) || guard ? array[0] : slice.call(array, 0, n);
+ if (n == null || guard) return array[0];
+ if (n < 0) return [];
+ return slice.call(array, 0, n);
};
// Returns everything but the last entry of the array. Especially useful on
@@ -407,18 +442,15 @@
// the array, excluding the last N. The **guard** check allows it to work with
// `_.map`.
_.initial = function(array, n, guard) {
- return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
+ return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
};
// Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`.
_.last = function(array, n, guard) {
if (array == null) return void 0;
- if ((n == null) || guard) {
- return array[array.length - 1];
- } else {
- return slice.call(array, Math.max(array.length - n, 0));
- }
+ if (n == null || guard) return array[array.length - 1];
+ return slice.call(array, Math.max(array.length - n, 0));
};
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
@@ -426,7 +458,7 @@
// the rest N values in the array. The **guard**
// check allows it to work with `_.map`.
_.rest = _.tail = _.drop = function(array, n, guard) {
- return slice.call(array, (n == null) || guard ? 1 : n);
+ return slice.call(array, n == null || guard ? 1 : n);
};
// Trim out all falsy values from an array.
@@ -435,23 +467,26 @@
};
// Internal implementation of a recursive `flatten` function.
- var flatten = function(input, shallow, output) {
+ var flatten = function(input, shallow, strict, output) {
if (shallow && _.every(input, _.isArray)) {
return concat.apply(output, input);
}
- each(input, function(value) {
- if (_.isArray(value) || _.isArguments(value)) {
- shallow ? push.apply(output, value) : flatten(value, shallow, output);
+ for (var i = 0, length = input.length; i < length; i++) {
+ var value = input[i];
+ if (!_.isArray(value) && !_.isArguments(value)) {
+ if (!strict) output.push(value);
+ } else if (shallow) {
+ push.apply(output, value);
} else {
- output.push(value);
+ flatten(value, shallow, strict, output);
}
- });
+ }
return output;
};
// Flatten out an array, either recursively (by default), or just one level.
_.flatten = function(array, shallow) {
- return flatten(array, shallow, []);
+ return flatten(array, shallow, false, []);
};
// Return a version of the array that does not contain the specified value(s).
@@ -462,55 +497,74 @@
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
- _.uniq = _.unique = function(array, isSorted, iterator, context) {
- if (_.isFunction(isSorted)) {
- context = iterator;
- iterator = isSorted;
+ _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+ if (array == null) return [];
+ if (!_.isBoolean(isSorted)) {
+ context = iteratee;
+ iteratee = isSorted;
isSorted = false;
}
- var initial = iterator ? _.map(array, iterator, context) : array;
- var results = [];
+ if (iteratee != null) iteratee = _.iteratee(iteratee, context);
+ var result = [];
var seen = [];
- each(initial, function(value, index) {
- if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
- seen.push(value);
- results.push(array[index]);
+ for (var i = 0, length = array.length; i < length; i++) {
+ var value = array[i];
+ if (isSorted) {
+ if (!i || seen !== value) result.push(value);
+ seen = value;
+ } else if (iteratee) {
+ var computed = iteratee(value, i, array);
+ if (_.indexOf(seen, computed) < 0) {
+ seen.push(computed);
+ result.push(value);
+ }
+ } else if (_.indexOf(result, value) < 0) {
+ result.push(value);
}
- });
- return results;
+ }
+ return result;
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
- return _.uniq(_.flatten(arguments, true));
+ return _.uniq(flatten(arguments, true, true, []));
};
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
- var rest = slice.call(arguments, 1);
- return _.filter(_.uniq(array), function(item) {
- return _.every(rest, function(other) {
- return _.indexOf(other, item) >= 0;
- });
- });
+ if (array == null) return [];
+ var result = [];
+ var argsLength = arguments.length;
+ for (var i = 0, length = array.length; i < length; i++) {
+ var item = array[i];
+ if (_.contains(result, item)) continue;
+ for (var j = 1; j < argsLength; j++) {
+ if (!_.contains(arguments[j], item)) break;
+ }
+ if (j === argsLength) result.push(item);
+ }
+ return result;
};
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
- var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
- return _.filter(array, function(value){ return !_.contains(rest, value); });
+ var rest = flatten(slice.call(arguments, 1), true, true, []);
+ return _.filter(array, function(value){
+ return !_.contains(rest, value);
+ });
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
- _.zip = function() {
- var length = _.max(_.pluck(arguments, "length").concat(0));
- var results = new Array(length);
+ _.zip = function(array) {
+ if (array == null) return [];
+ var length = _.max(arguments, 'length').length;
+ var results = Array(length);
for (var i = 0; i < length; i++) {
- results[i] = _.pluck(arguments, '' + i);
+ results[i] = _.pluck(arguments, i);
}
return results;
};
@@ -531,10 +585,8 @@
return result;
};
- // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
- // we need this function. Return the position of the first occurrence of an
- // item in an array, or -1 if the item is not included in the array.
- // Delegates to **ECMAScript 5**'s native `indexOf` if available.
+ // Return the position of the first occurrence of an item in an array,
+ // or -1 if the item is not included in the array.
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) {
@@ -542,26 +594,23 @@
var i = 0, length = array.length;
if (isSorted) {
if (typeof isSorted == 'number') {
- i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
+ i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
} else {
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
}
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
for (; i < length; i++) if (array[i] === item) return i;
return -1;
};
- // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
_.lastIndexOf = function(array, item, from) {
if (array == null) return -1;
- var hasIndex = from != null;
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
- return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
+ var idx = array.length;
+ if (typeof from == 'number') {
+ idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
}
- var i = (hasIndex ? from : array.length);
- while (i--) if (array[i] === item) return i;
+ while (--idx >= 0) if (array[idx] === item) return idx;
return -1;
};
@@ -573,15 +622,13 @@
stop = start || 0;
start = 0;
}
- step = arguments[2] || 1;
+ step = step || 1;
var length = Math.max(Math.ceil((stop - start) / step), 0);
- var idx = 0;
- var range = new Array(length);
+ var range = Array(length);
- while(idx < length) {
- range[idx++] = start;
- start += step;
+ for (var idx = 0; idx < length; idx++, start += step) {
+ range[idx] = start;
}
return range;
@@ -591,7 +638,7 @@
// ------------------
// Reusable constructor function for prototype setting.
- var ctor = function(){};
+ var Ctor = function(){};
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
@@ -599,52 +646,68 @@
_.bind = function(func, context) {
var args, bound;
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
- if (!_.isFunction(func)) throw new TypeError;
+ if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
args = slice.call(arguments, 2);
- return bound = function() {
+ bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
- ctor.prototype = func.prototype;
- var self = new ctor;
- ctor.prototype = null;
+ Ctor.prototype = func.prototype;
+ var self = new Ctor;
+ Ctor.prototype = null;
var result = func.apply(self, args.concat(slice.call(arguments)));
- if (Object(result) === result) return result;
+ if (_.isObject(result)) return result;
return self;
};
+ return bound;
};
// Partially apply a function by creating a version that has had some of its
- // arguments pre-filled, without changing its dynamic `this` context.
+ // arguments pre-filled, without changing its dynamic `this` context. _ acts
+ // as a placeholder, allowing any combination of arguments to be pre-filled.
_.partial = function(func) {
- var args = slice.call(arguments, 1);
+ var boundArgs = slice.call(arguments, 1);
return function() {
- return func.apply(this, args.concat(slice.call(arguments)));
+ var position = 0;
+ var args = boundArgs.slice();
+ for (var i = 0, length = args.length; i < length; i++) {
+ if (args[i] === _) args[i] = arguments[position++];
+ }
+ while (position < arguments.length) args.push(arguments[position++]);
+ return func.apply(this, args);
};
};
- // Bind all of an object's methods to that object. Useful for ensuring that
- // all callbacks defined on an object belong to it.
+ // Bind a number of an object's methods to that object. Remaining arguments
+ // are the method names to be bound. Useful for ensuring that all callbacks
+ // defined on an object belong to it.
_.bindAll = function(obj) {
- var funcs = slice.call(arguments, 1);
- if (funcs.length === 0) throw new Error("bindAll must be passed function names");
- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
+ var i, length = arguments.length, key;
+ if (length <= 1) throw new Error('bindAll must be passed function names');
+ for (i = 1; i < length; i++) {
+ key = arguments[i];
+ obj[key] = _.bind(obj[key], obj);
+ }
return obj;
};
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
- var memo = {};
- hasher || (hasher = _.identity);
- return function() {
- var key = hasher.apply(this, arguments);
- return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+ var memoize = function(key) {
+ var cache = memoize.cache;
+ var address = hasher ? hasher.apply(this, arguments) : key;
+ if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
+ return cache[address];
};
+ memoize.cache = {};
+ return memoize;
};
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
- return setTimeout(function(){ return func.apply(null, args); }, wait);
+ return setTimeout(function(){
+ return func.apply(null, args);
+ }, wait);
};
// Defers a function, scheduling it to run after the current call stack has
@@ -662,23 +725,25 @@
var context, args, result;
var timeout = null;
var previous = 0;
- options || (options = {});
+ if (!options) options = {};
var later = function() {
- previous = options.leading === false ? 0 : new Date;
+ previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
+ if (!timeout) context = args = null;
};
return function() {
- var now = new Date;
+ var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
- if (remaining <= 0) {
+ if (remaining <= 0 || remaining > wait) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
+ if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
@@ -692,38 +757,33 @@
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;
+
+ var later = function() {
+ var last = _.now() - timestamp;
+
+ if (last < wait && last > 0) {
+ timeout = setTimeout(later, wait - last);
+ } else {
+ timeout = null;
+ if (!immediate) {
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ }
+ }
+ };
+
return function() {
context = this;
args = arguments;
- timestamp = new Date();
- var later = function() {
- var last = (new Date()) - timestamp;
- if (last < wait) {
- timeout = setTimeout(later, wait - last);
- } else {
- timeout = null;
- if (!immediate) result = func.apply(context, args);
- }
- };
+ timestamp = _.now();
var callNow = immediate && !timeout;
- if (!timeout) {
- timeout = setTimeout(later, wait);
+ if (!timeout) timeout = setTimeout(later, wait);
+ if (callNow) {
+ result = func.apply(context, args);
+ context = args = null;
}
- if (callNow) result = func.apply(context, args);
- return result;
- };
- };
- // Returns a function that will be executed at most one time, no matter how
- // often you call it. Useful for lazy initialization.
- _.once = function(func) {
- var ran = false, memo;
- return function() {
- if (ran) return memo;
- ran = true;
- memo = func.apply(this, arguments);
- func = null;
- return memo;
+ return result;
};
};
@@ -731,23 +791,26 @@
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
_.wrap = function(func, wrapper) {
+ return _.partial(wrapper, func);
+ };
+
+ // Returns a negated version of the passed-in predicate.
+ _.negate = function(predicate) {
return function() {
- var args = [func];
- push.apply(args, arguments);
- return wrapper.apply(this, args);
+ return !predicate.apply(this, arguments);
};
};
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
_.compose = function() {
- var funcs = arguments;
+ var args = arguments;
+ var start = args.length - 1;
return function() {
- var args = arguments;
- for (var i = funcs.length - 1; i >= 0; i--) {
- args = [funcs[i].apply(this, args)];
- }
- return args[0];
+ var i = start;
+ var result = args[start].apply(this, arguments);
+ while (i--) result = args[i].call(this, result);
+ return result;
};
};
@@ -760,13 +823,31 @@
};
};
+ // Returns a function that will only be executed before being called N times.
+ _.before = function(times, func) {
+ var memo;
+ return function() {
+ if (--times > 0) {
+ memo = func.apply(this, arguments);
+ } else {
+ func = null;
+ }
+ return memo;
+ };
+ };
+
+ // Returns a function that will be executed at most one time, no matter how
+ // often you call it. Useful for lazy initialization.
+ _.once = _.partial(_.before, 2);
+
// Object Functions
// ----------------
// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
- _.keys = nativeKeys || function(obj) {
- if (obj !== Object(obj)) throw new TypeError('Invalid object');
+ _.keys = function(obj) {
+ if (!_.isObject(obj)) return [];
+ if (nativeKeys) return nativeKeys(obj);
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
return keys;
@@ -776,7 +857,7 @@
_.values = function(obj) {
var keys = _.keys(obj);
var length = keys.length;
- var values = new Array(length);
+ var values = Array(length);
for (var i = 0; i < length; i++) {
values[i] = obj[keys[i]];
}
@@ -787,7 +868,7 @@
_.pairs = function(obj) {
var keys = _.keys(obj);
var length = keys.length;
- var pairs = new Array(length);
+ var pairs = Array(length);
for (var i = 0; i < length; i++) {
pairs[i] = [keys[i], obj[keys[i]]];
}
@@ -816,45 +897,62 @@
// Extend a given object with all the properties in passed-in object(s).
_.extend = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- obj[prop] = source[prop];
+ if (!_.isObject(obj)) return obj;
+ var source, prop;
+ for (var i = 1, length = arguments.length; i < length; i++) {
+ source = arguments[i];
+ for (prop in source) {
+ if (hasOwnProperty.call(source, prop)) {
+ obj[prop] = source[prop];
}
}
- });
+ }
return obj;
};
// Return a copy of the object only containing the whitelisted properties.
- _.pick = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- each(keys, function(key) {
- if (key in obj) copy[key] = obj[key];
- });
- return copy;
+ _.pick = function(obj, iteratee, context) {
+ var result = {}, key;
+ if (obj == null) return result;
+ if (_.isFunction(iteratee)) {
+ iteratee = createCallback(iteratee, context);
+ for (key in obj) {
+ var value = obj[key];
+ if (iteratee(value, key, obj)) result[key] = value;
+ }
+ } else {
+ var keys = concat.apply([], slice.call(arguments, 1));
+ obj = new Object(obj);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ key = keys[i];
+ if (key in obj) result[key] = obj[key];
+ }
+ }
+ return result;
};
// Return a copy of the object without the blacklisted properties.
- _.omit = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- for (var key in obj) {
- if (!_.contains(keys, key)) copy[key] = obj[key];
+ _.omit = function(obj, iteratee, context) {
+ if (_.isFunction(iteratee)) {
+ iteratee = _.negate(iteratee);
+ } else {
+ var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
+ iteratee = function(value, key) {
+ return !_.contains(keys, key);
+ };
}
- return copy;
+ return _.pick(obj, iteratee, context);
};
// Fill in a given object with default properties.
_.defaults = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- if (obj[prop] === void 0) obj[prop] = source[prop];
- }
+ if (!_.isObject(obj)) return obj;
+ for (var i = 1, length = arguments.length; i < length; i++) {
+ var source = arguments[i];
+ for (var prop in source) {
+ if (obj[prop] === void 0) obj[prop] = source[prop];
}
- });
+ }
return obj;
};
@@ -876,7 +974,7 @@
var eq = function(a, b, aStack, bStack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
- if (a === b) return a !== 0 || 1 / a == 1 / b;
+ if (a === b) return a !== 0 || 1 / a === 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
@@ -884,29 +982,27 @@
if (b instanceof _) b = b._wrapped;
// Compare `[[Class]]` names.
var className = toString.call(a);
- if (className != toString.call(b)) return false;
+ if (className !== toString.call(b)) return false;
switch (className) {
- // Strings, numbers, dates, and booleans are compared by value.
+ // Strings, numbers, regular expressions, dates, and booleans are compared by value.
+ case '[object RegExp]':
+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
case '[object String]':
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
- return a == String(b);
+ return '' + a === '' + b;
case '[object Number]':
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
- // other numeric values.
- return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
+ // `NaN`s are equivalent, but non-reflexive.
+ // Object(NaN) is equivalent to NaN
+ if (+a !== +a) return +b !== +b;
+ // An `egal` comparison is performed for other numeric values.
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
case '[object Date]':
case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
- return +a == +b;
- // RegExps are compared by their source patterns and flags.
- case '[object RegExp]':
- return a.source == b.source &&
- a.global == b.global &&
- a.multiline == b.multiline &&
- a.ignoreCase == b.ignoreCase;
+ return +a === +b;
}
if (typeof a != 'object' || typeof b != 'object') return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
@@ -915,24 +1011,29 @@
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
- if (aStack[length] == a) return bStack[length] == b;
+ if (aStack[length] === a) return bStack[length] === b;
}
// Objects with different constructors are not equivalent, but `Object`s
// from different frames are.
var aCtor = a.constructor, bCtor = b.constructor;
- if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
- _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
+ if (
+ aCtor !== bCtor &&
+ // Handle Object.create(x) cases
+ 'constructor' in a && 'constructor' in b &&
+ !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
+ _.isFunction(bCtor) && bCtor instanceof bCtor)
+ ) {
return false;
}
// Add the first object to the stack of traversed objects.
aStack.push(a);
bStack.push(b);
- var size = 0, result = true;
+ var size, result;
// Recursively compare objects and arrays.
- if (className == '[object Array]') {
+ if (className === '[object Array]') {
// Compare array lengths to determine if a deep comparison is necessary.
size = a.length;
- result = size == b.length;
+ result = size === b.length;
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
@@ -941,20 +1042,16 @@
}
} else {
// Deep compare objects.
- for (var key in a) {
- if (_.has(a, key)) {
- // Count the expected number of properties.
- size++;
- // Deep compare each member.
- if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
- }
- }
- // Ensure that both objects contain the same number of properties.
+ var keys = _.keys(a), key;
+ size = keys.length;
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
+ result = _.keys(b).length === size;
if (result) {
- for (key in b) {
- if (_.has(b, key) && !(size--)) break;
+ while (size--) {
+ // Deep compare each member
+ key = keys[size];
+ if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
}
- result = !size;
}
}
// Remove the first object from the stack of traversed objects.
@@ -972,7 +1069,7 @@
// An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) {
if (obj == null) return true;
- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
+ if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
for (var key in obj) if (_.has(obj, key)) return false;
return true;
};
@@ -985,18 +1082,19 @@
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
- return toString.call(obj) == '[object Array]';
+ return toString.call(obj) === '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
- return obj === Object(obj);
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
};
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
- each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
+ _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
_['is' + name] = function(obj) {
- return toString.call(obj) == '[object ' + name + ']';
+ return toString.call(obj) === '[object ' + name + ']';
};
});
@@ -1004,14 +1102,14 @@
// there isn't any inspectable "Arguments" type.
if (!_.isArguments(arguments)) {
_.isArguments = function(obj) {
- return !!(obj && _.has(obj, 'callee'));
+ return _.has(obj, 'callee');
};
}
- // Optimize `isFunction` if appropriate.
- if (typeof (/./) !== 'function') {
+ // Optimize `isFunction` if appropriate. Work around an IE 11 bug.
+ if (typeof /./ !== 'function') {
_.isFunction = function(obj) {
- return typeof obj === 'function';
+ return typeof obj == 'function' || false;
};
}
@@ -1022,12 +1120,12 @@
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
_.isNaN = function(obj) {
- return _.isNumber(obj) && obj != +obj;
+ return _.isNumber(obj) && obj !== +obj;
};
// Is a given value a boolean?
_.isBoolean = function(obj) {
- return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
};
// Is a given value equal to null?
@@ -1043,7 +1141,7 @@
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
- return hasOwnProperty.call(obj, key);
+ return obj != null && hasOwnProperty.call(obj, key);
};
// Utility Functions
@@ -1056,15 +1154,44 @@
return this;
};
- // Keep the identity function around for default iterators.
+ // Keep the identity function around for default iteratees.
_.identity = function(value) {
return value;
};
+ _.constant = function(value) {
+ return function() {
+ return value;
+ };
+ };
+
+ _.noop = function(){};
+
+ _.property = function(key) {
+ return function(obj) {
+ return obj[key];
+ };
+ };
+
+ // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
+ _.matches = function(attrs) {
+ var pairs = _.pairs(attrs), length = pairs.length;
+ return function(obj) {
+ if (obj == null) return !length;
+ obj = new Object(obj);
+ for (var i = 0; i < length; i++) {
+ var pair = pairs[i], key = pair[0];
+ if (pair[1] !== obj[key] || !(key in obj)) return false;
+ }
+ return true;
+ };
+ };
+
// Run a function **n** times.
- _.times = function(n, iterator, context) {
+ _.times = function(n, iteratee, context) {
var accum = Array(Math.max(0, n));
- for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
+ iteratee = createCallback(iteratee, context, 1);
+ for (var i = 0; i < n; i++) accum[i] = iteratee(i);
return accum;
};
@@ -1077,52 +1204,45 @@
return min + Math.floor(Math.random() * (max - min + 1));
};
- // List of HTML entities for escaping.
- var entityMap = {
- escape: {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": '''
- }
+ // A (possibly faster) way to get the current timestamp as an integer.
+ _.now = Date.now || function() {
+ return new Date().getTime();
};
- entityMap.unescape = _.invert(entityMap.escape);
- // Regexes containing the keys and values listed immediately above.
- var entityRegexes = {
- escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
- unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
+ // List of HTML entities for escaping.
+ var escapeMap = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
};
+ var unescapeMap = _.invert(escapeMap);
// Functions for escaping and unescaping strings to/from HTML interpolation.
- _.each(['escape', 'unescape'], function(method) {
- _[method] = function(string) {
- if (string == null) return '';
- return ('' + string).replace(entityRegexes[method], function(match) {
- return entityMap[method][match];
- });
+ var createEscaper = function(map) {
+ var escaper = function(match) {
+ return map[match];
};
- });
+ // Regexes for identifying a key that needs to be escaped
+ var source = '(?:' + _.keys(map).join('|') + ')';
+ var testRegexp = RegExp(source);
+ var replaceRegexp = RegExp(source, 'g');
+ return function(string) {
+ string = string == null ? '' : '' + string;
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+ };
+ };
+ _.escape = createEscaper(escapeMap);
+ _.unescape = createEscaper(unescapeMap);
// If the value of the named `property` is a function then invoke it with the
// `object` as context; otherwise, return it.
_.result = function(object, property) {
if (object == null) return void 0;
var value = object[property];
- return _.isFunction(value) ? value.call(object) : value;
- };
-
- // Add your own custom functions to the Underscore object.
- _.mixin = function(obj) {
- each(_.functions(obj), function(name) {
- var func = _[name] = obj[name];
- _.prototype[name] = function() {
- var args = [this._wrapped];
- push.apply(args, arguments);
- return result.call(this, func.apply(_, args));
- };
- });
+ return _.isFunction(value) ? object[property]() : value;
};
// Generate a unique integer id (unique within the entire client session).
@@ -1153,22 +1273,26 @@
'\\': '\\',
'\r': 'r',
'\n': 'n',
- '\t': 't',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
- var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
+ var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
+
+ var escapeChar = function(match) {
+ return '\\' + escapes[match];
+ };
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
- _.template = function(text, data, settings) {
- var render;
+ // NB: `oldSettings` only exists for backwards compatibility.
+ _.template = function(text, settings, oldSettings) {
+ if (!settings && oldSettings) settings = oldSettings;
settings = _.defaults({}, settings, _.templateSettings);
// Combine delimiters into one regular expression via alternation.
- var matcher = new RegExp([
+ var matcher = RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
@@ -1178,19 +1302,18 @@
var index = 0;
var source = "__p+='";
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
- source += text.slice(index, offset)
- .replace(escaper, function(match) { return '\\' + escapes[match]; });
+ source += text.slice(index, offset).replace(escaper, escapeChar);
+ index = offset + match.length;
if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
- }
- if (interpolate) {
+ } else if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
- }
- if (evaluate) {
+ } else if (evaluate) {
source += "';\n" + evaluate + "\n__p+='";
}
- index = offset + match.length;
+
+ // Adobe VMs need the match returned to produce the correct offest.
return match;
});
source += "';\n";
@@ -1200,29 +1323,31 @@
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
- source + "return __p;\n";
+ source + 'return __p;\n';
try {
- render = new Function(settings.variable || 'obj', '_', source);
+ var render = new Function(settings.variable || 'obj', '_', source);
} catch (e) {
e.source = source;
throw e;
}
- if (data) return render(data, _);
var template = function(data) {
return render.call(this, data, _);
};
- // Provide the compiled function source as a convenience for precompilation.
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
+ // Provide the compiled source as a convenience for precompilation.
+ var argument = settings.variable || 'obj';
+ template.source = 'function(' + argument + '){\n' + source + '}';
return template;
};
- // Add a "chain" function, which will delegate to the wrapper.
+ // Add a "chain" function. Start chaining a wrapped Underscore object.
_.chain = function(obj) {
- return _(obj).chain();
+ var instance = _(obj);
+ instance._chain = true;
+ return instance;
};
// OOP
@@ -1236,41 +1361,55 @@
return this._chain ? _(obj).chain() : obj;
};
+ // Add your own custom functions to the Underscore object.
+ _.mixin = function(obj) {
+ _.each(_.functions(obj), function(name) {
+ var func = _[name] = obj[name];
+ _.prototype[name] = function() {
+ var args = [this._wrapped];
+ push.apply(args, arguments);
+ return result.call(this, func.apply(_, args));
+ };
+ });
+ };
+
// Add all of the Underscore functions to the wrapper object.
_.mixin(_);
// Add all mutator Array functions to the wrapper.
- each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
var obj = this._wrapped;
method.apply(obj, arguments);
- if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
+ if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
return result.call(this, obj);
};
});
// Add all accessor Array functions to the wrapper.
- each(['concat', 'join', 'slice'], function(name) {
+ _.each(['concat', 'join', 'slice'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
return result.call(this, method.apply(this._wrapped, arguments));
};
});
- _.extend(_.prototype, {
-
- // Start chaining a wrapped Underscore object.
- chain: function() {
- this._chain = true;
- return this;
- },
-
- // Extracts the result from a wrapped and chained object.
- value: function() {
- return this._wrapped;
- }
-
- });
-
-}).call(this);
+ // Extracts the result from a wrapped and chained object.
+ _.prototype.value = function() {
+ return this._wrapped;
+ };
+
+ // AMD registration happens at the end for compatibility with AMD loaders
+ // that may not enforce next-turn semantics on modules. Even though general
+ // practice for AMD registration is to be anonymous, underscore registers
+ // as a named module because, like jQuery, it is a base library that is
+ // popular enough to be bundled in a third party lib, but not be part of
+ // an AMD load request. Those cases could generate an error when an
+ // anonymous define() is called outside of a loader request.
+ if (typeof define === 'function' && define.amd) {
+ define('underscore', [], function() {
+ return _;
+ });
+ }
+}.call(this));
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-lodash.git
More information about the Pkg-javascript-commits
mailing list