Compare commits

..

2 Commits

Author SHA1 Message Date
jdalton
f2d87df120 Bump to v3.10.0. 2015-06-30 09:40:56 -07:00
jdalton
7351c0b0b9 Rebuild lodash and docs. 2015-06-29 23:19:08 -07:00
91 changed files with 39933 additions and 78949 deletions

View File

@@ -4,9 +4,15 @@
root = true root = true
[*] [*]
charset = utf-8
end_of_line = lf end_of_line = lf
indent_size = 2 charset = utf-8
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
[**.{js,json,md}]
indent_style = space
indent_size = 2
insert_final_newline = true
[**.html]
indent_style = tab
insert_final_newline = false

View File

@@ -1,78 +0,0 @@
# Contributing to Lodash
Contributions are always welcome. Before contributing please read the
[code of conduct](https://js.foundation/community/code-of-conduct) &
[search the issue tracker](https://github.com/lodash/lodash/issues); your issue
may have already been discussed or fixed in `master`. To contribute,
[fork](https://help.github.com/articles/fork-a-repo/) Lodash, commit your changes,
& [send a pull request](https://help.github.com/articles/using-pull-requests/).
## Feature Requests
Feature requests should be submitted in the
[issue tracker](https://github.com/lodash/lodash/issues), with a description of
the expected behavior & use case, where theyll remain closed until sufficient interest,
[e.g. :+1: reactions](https://help.github.com/articles/about-discussions-in-issues-and-pull-requests/),
has been [shown by the community](https://github.com/lodash/lodash/issues?q=label%3A%22votes+needed%22+sort%3Areactions-%2B1-desc).
Before submitting a request, please search for similar ones in the
[closed issues](https://github.com/lodash/lodash/issues?q=is%3Aissue+is%3Aclosed+label%3Aenhancement).
## Pull Requests
For additions or bug fixes you should only need to modify `lodash.js`. Include
updated unit tests in the `test` directory as part of your pull request. Dont
worry about regenerating the `dist/` or `doc/` files.
Before running the unit tests youll need to install, `npm i`,
[development dependencies](https://docs.npmjs.com/files/package.json#devdependencies).
Run unit tests from the command-line via `npm test`, or open `test/index.html` &
`test/fp.html` in a web browser. The [Backbone](http://backbonejs.org/) &
[Underscore](http://underscorejs.org/) test suites are included as well.
## Contributor License Agreement
Lodash is a member of the [Open JS Foundation](https://openjsf.org/).
As such, we request that all contributors sign our
[contributor license agreement (CLA)](https://js.foundation/CLA/).
For more information about CLAs, please check out Alex Russells excellent post,
[“Why Do I Need to Sign This?”](https://infrequently.org/2008/06/why-do-i-need-to-sign-this/).
## Coding Guidelines
In addition to the following guidelines, please follow the conventions already
established in the code.
- **Spacing**:<br>
Use two spaces for indentation. No tabs.
- **Naming**:<br>
Keep variable & method names concise & descriptive.<br>
Variable names `index`, `array`, & `iteratee` 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, &
[JSDoc-style](http://www.2ality.com/2011/08/jsdoc-intro.html) comments for
functions.
Guidelines are enforced using [JSCS](https://www.npmjs.com/package/jscs):
```bash
$ npm run style
```
## Tips
You can opt-in to a pre-push git hook by adding an `.opt-in` file to the root of
the project containing:
```txt
pre-push
```
With that, when you `git push`, the pre-push git hook will trigger and execute
`npm run validate`.

4
.gitignore vendored
View File

@@ -1,4 +1,6 @@
.DS_Store .DS_Store
*.custom.*
*.log *.log
doc/*.html *.map
lodash.compat.min.js
node_modules node_modules

97
.jscsrc
View File

@@ -1,97 +0,0 @@
{
"maxErrors": "2000",
"maximumLineLength": {
"value": 180,
"allExcept": ["comments", "functionSignature", "regex"]
},
"requireCurlyBraces": [
"if",
"else",
"for",
"while",
"do",
"try",
"catch"
],
"requireOperatorBeforeLineBreak": [
"=",
"+",
"-",
"/",
"*",
"==",
"===",
"!=",
"!==",
">",
">=",
"<",
"<="
],
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"return",
"try",
"catch"
],
"requireSpaceBeforeBinaryOperators": [
"=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=",
"&=", "|=", "^=",
"+", "-", "*", "/", "%", "<<", ">>", ">>>", "&",
"|", "^", "&&", "||", "===", "==", ">=",
"<=", "<", ">", "!=", "!=="
],
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"requireCamelCaseOrUpperCaseIdentifiers": true,
"requireDotNotation": { "allExcept": ["keywords"] },
"requireEarlyReturn": true,
"requireLineFeedAtFileEnd": true,
"requireSemicolons": true,
"requireSpaceAfterBinaryOperators": true,
"requireSpacesInConditionalExpression": true,
"requireSpaceBeforeObjectValues": true,
"requireSpaceBeforeBlockStatements": true,
"requireSpacesInForStatement": true,
"validateIndentation": 2,
"validateParameterSeparator": ", ",
"validateQuoteMarks": { "mark": "'", "escape": true },
"disallowSpacesInAnonymousFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInFunctionDeclaration": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowKeywords": ["with"],
"disallowMixedSpacesAndTabs": true,
"disallowMultipleLineBreaks": true,
"disallowNewlineBeforeBlockStatements": true,
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceAfterPrefixUnaryOperators": true,
"disallowSpacesInCallExpression": true,
"disallowSpacesInsideArrayBrackets": true,
"disallowSpacesInsideParentheses": true,
"disallowTrailingWhitespace": true,
"disallowUnusedVariables": true,
"jsDoc": {
"checkRedundantAccess": true,
"checkTypes": true,
"requireNewlineAfterDescription": true,
"requireParamDescription": true,
"requireParamTypes": true,
"requireReturnTypes": true
}
}

View File

@@ -1,11 +0,0 @@
'use strict';
delete global['__core-js_shared__'];
const _ = require('./lodash.js');
const globals = require('lodash-doc-globals');
module.exports = {
'babel': false,
'globals': _.assign({ '_': _ }, globals)
};

View File

@@ -1,135 +1,76 @@
language: node_js language: node_js
sudo: false
node_js: node_js:
- 7 - "0.12"
addons:
jwt:
secure: OYhRpW+8A0Iik+9GmHwa45ZwXeBXw/6zh6I+1w2H9g/LqPRp+Nhq3f4FSpvrrfno8lO8W4h+7s6+JOzF8C8NxNda5UUygKjF9pUphgiQdqls3YZMJlC9zXVl7gQXAHi3nG1s8vWSpwpzYD9fqczE1FX9n0+R63qX3eB6C/LbPeI=
cache:
directories:
- ~/.npm
- ~/.yarn-cache
- travis_phantomjs
env: env:
global: global:
- BIN=node ISTANBUL=false OPTION="" - PATTERN1="s|\s*else\s*\{\s*iteratee\(index\);\s*\}||"
- SAUCE_LABS=false SAUCE_USERNAME=lodash - BIN="node" BUILD="compat" ISTANBUL=false OPTION=""
- NPM_VERSION="^2.0.0" SAUCE_LABS=false SAUCE_USERNAME="lodash"
- secure: "tg1JFsIFnxzLaTboFPOnm+aJCuMm5+JdhLlESlqg9x3fwro++7KCnwHKLNovhchaPe4otC43ZMB/nfWhDnDm11dKbm/V6HlTkED+dadTsaLxVDg6J+7yK41QhokBPJOxLV78iDaNaAQVYEirAgZ0yn8kFubxmNKV+bpCGQNc9yU="
matrix: matrix:
- - BUILD="compat"
- BIN=phantomjs - BUILD="modern"
- ISTANBUL=true - BUILD="modern"
- SAUCE_LABS=true - BUILD="modern" ISTANBUL=true
- BIN="phantomjs"
- BIN="rhino" OPTION="-opt -1"
- BIN="rhino" OPTION="-opt -1 -require"
- BIN="ringo" OPTION="-o -1"
matrix: matrix:
include: include:
- node_js: 6 - node_js: "iojs"
env: env:
- node_js: "iojs"
env: BUILD="modern"
- node_js: "0.8"
env: NPM_VERSION="~1.4.0"
- node_js: "0.8"
env: BUILD="modern" NPM_VERSION="~1.4.0"
- node_js: "0.10"
env:
- node_js: "0.10"
env: BUILD="modern"
- node_js: "0.12"
env: SAUCE_LABS=true
- node_js: "0.12"
env: SAUCE_LABS=true BUILD="modern"
git: git:
depth: 10 depth: 10
branches: branches:
only: only:
- master - master
- 4.17
notifications: notifications:
webhooks: webhooks:
urls: urls:
- https://webhooks.gitter.im/e/4aab6358b0e9aed0b628 - https://webhooks.gitter.im/e/4aab6358b0e9aed0b628
on_success: change on_success: change
on_failure: always on_failure: always
before_install: before_install:
# Upgrade PhantomJS. - "nvm use $TRAVIS_NODE_VERSION"
- | - "npm config set loglevel error"
export PHANTOMJS_VERSION=2.1.1 - "npm i -g npm@\"$NPM_VERSION\""
export PATH=$PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64/bin:$PATH - "[ $SAUCE_LABS == false ] || npm i chalk@\"^1.0.0\" ecstatic@\"0.8.0\" request@\"^2.0.0\" sauce-tunnel@\"2.2.3\""
if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then - "[ $ISTANBUL == false ] || (npm i -g coveralls@\"^2.0.0\" && npm i istanbul@\"0.3.17\")"
rm -rf $PWD/travis_phantomjs - "[ $BIN != 'rhino' ] || (sudo mkdir /opt/rhino-1.7.6 && sudo wget --no-check-certificate -O $_/js.jar https://lodash.com/_travis/rhino-1.7.6.jar)"
mkdir -p $PWD/travis_phantomjs - "[ $BIN != 'rhino' ] || (echo -e '#!/bin/sh\\njava -jar /opt/rhino-1.7.6/js.jar $@' | sudo tee /usr/local/bin/rhino && sudo chmod +x /usr/local/bin/rhino)"
wget https://github.com/Medium/phantomjs/releases/download/v$PHANTOMJS_VERSION/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 - "[ $BIN != 'ringo' ] || (wget --no-check-certificate https://lodash.com/_travis/ringojs-0.11.zip && sudo unzip ringojs-0.11 -d /opt && rm ringojs-0.11.zip)"
tar -xvf phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs - "[ $BIN != 'ringo' ] || (sudo ln -s /opt/ringojs-0.11/bin/ringo /usr/local/bin/ringo && sudo chmod +x $_)"
fi - "perl -pi -e 's|\"lodash\"|\"lodash-compat\"|' ./package.json"
phantomjs -v - "git clone --depth=10 --branch=master git://github.com/lodash/lodash-cli ./node_modules/lodash-cli && mkdir $_/node_modules && cd $_ && ln -s ../../../ ./lodash-compat && cd ../ && npm i && cd ../../"
- "node ./node_modules/lodash-cli/bin/lodash $BUILD -o ./lodash.$BUILD.js"
# Use exact Node version.
- nvm use $TRAVIS_NODE_VERSION
# Setup package managers.
- npm set loglevel error
- npm set progress false
- npm i -g yarn@0.16.1
- yarn -V
# Remove code skipped on the coverage run.
- |
PATTERN[0]="|\s*while\s*\([^)]+\)\s*\{\s*iteratee\(index\);\s*\}|"
PATTERN[1]="|\bindex,\s*iterable\)\s*===\s*false\)[^}]+?(break;)|"
PATTERN[2]="|\bcase\s+(?:dataView|promise|set|map|weakMap)CtorString:.+|g"
PATTERN[3]="|\s*if\s*\(cache\.size\b[\s\S]+?\}|"
PATTERN[4]="|\s*if\s*\(\!lodashFunc\)\s*\{\s*return;\s*\}|"
PATTERN[5]="|\s*define\([\s\S]+?\);|"
PATTERN[6]="|\s*root\._\s*=\s*_;|"
if [ $ISTANBUL = true ]; then
set -e
for PTRN in ${PATTERN[@]}; do
node ./test/remove.js $PTRN ./lodash.js
done
fi
install:
# Install packages.
- yarn
# Use lodash-cli from GitHub. Temporarily use a fork.
- git clone --depth=10 --branch=master git://github.com/bnjmnt4n/lodash-cli ./node_modules/lodash-cli
- cd ./node_modules/lodash-cli/; npm i --production; cd ../../
- mkdir -p ./node_modules/lodash-cli/node_modules/lodash; cd $_; cp ../../../../lodash.js ./lodash.js; cp ../../../../package.json ./package.json; cd ../../../../
script: script:
# Detect code coverage. - "[ $ISTANBUL == false ] || cp ./lodash.$BUILD.js ./lodash.js"
- | - "[ $ISTANBUL == false ] || perl -0pi -e \"$PATTERN\" ./lodash.js"
if [ $ISTANBUL = true ]; then - "[ $ISTANBUL == false ] || node ./node_modules/istanbul/lib/cli.js cover -x \"**/vendor/**\" --report lcovonly ./test/test.js -- ./lodash.js"
istanbul cover -x "**/vendor/**" --report lcovonly ./test/test.js -- ./lodash.js - "[ $ISTANBUL == false ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || (cat ./coverage/lcov.info | coveralls) || true"
if [ $TRAVIS_SECURE_ENV_VARS = true ]; then - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || cd ./test"
cat ./coverage/lcov.info | coveralls - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || $BIN $OPTION ./test.js ../lodash.$BUILD.js"
cat ./coverage/coverage.json | codecov - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || $BIN $OPTION ./test.js ../lodash.$BUILD.min.js"
fi - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.js&noglobals=true\" tags=\"$BUILD,development\""
fi - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.min.js&noglobals=true\" tags=\"$BUILD,production\""
- "[ $SAUCE_LABS == false ] || [ $BUILD != 'compat' ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,ie-compat\" compatMode=7"
# Test in Node.js and PhantomJS. - "[ $SAUCE_LABS == false ] || [ $BUILD != 'compat' ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,ie-compat\" compatMode=7"
- | - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,backbone\""
if [ $ISTANBUL = false ]; then - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,backbone\""
node ./node_modules/lodash-cli/bin/lodash -o ./dist/lodash.js - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,underscore\""
node ./node_modules/lodash-cli/bin/lodash modularize exports=node -o ./ - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,underscore\""
node ./node_modules/lodash-cli/bin/lodash -d -o ./lodash.js
if [ $SAUCE_LABS = false ]; then
cd ./test
$BIN $OPTION ./test.js ../lodash.js
if [ $TRAVIS_SECURE_ENV_VARS = true ]; then
$BIN $OPTION ./test.js ../dist/lodash.min.js
fi
fi
fi
# Test in Sauce Labs.
- |
if [ $SAUCE_LABS = true ]; then
node ./node_modules/lodash-cli/bin/lodash core -o ./dist/lodash.core.js
npm run build
$BIN ./test/saucelabs.js name="lodash tests" runner="test/index.html?build=../dist/lodash.js&noglobals=true" tags=development
$BIN ./test/saucelabs.js name="lodash tests" runner="test/index.html?build=../dist/lodash.min.js&noglobals=true" tags=production
$BIN ./test/saucelabs.js name="lodash-fp tests" runner="test/fp.html?noglobals=true" tags=development
$BIN ./test/saucelabs.js name="underscore tests" runner="test/underscore.html?build=../dist/lodash.js" tags=development,underscore
$BIN ./test/saucelabs.js name="underscore tests" runner="test/underscore.html?build=../dist/lodash.min.js" tags=production,underscore
$BIN ./test/saucelabs.js name="backbone tests" runner="test/backbone.html?build=../dist/lodash.js" tags=development,backbone
$BIN ./test/saucelabs.js name="backbone tests" runner="test/backbone.html?build=../dist/lodash.min.js" tags=production,backbone
$BIN ./test/saucelabs.js name="backbone tests" runner="test/backbone.html?build=../dist/lodash.core.js" tags=development,backbone
$BIN ./test/saucelabs.js name="backbone tests" runner="test/backbone.html?build=../dist/lodash.core.min.js" tags=production,backbone
fi

View File

@@ -1 +0,0 @@
https://github.com/lodash/lodash/wiki/Changelog

39
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,39 @@
# Contributing to lodash
If youd like to contribute a feature or bug fix, you can [fork](https://help.github.com/articles/fork-a-repo/) lodash, 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.
Dont worry about regenerating the documentation, lodash.js, or lodash.min.js.
Before running the unit tests youll need to install, `npm i`, [development dependencies](https://docs.npmjs.com/files/package.json#devdependencies).
Run unit 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/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
lodash is a member of the [Dojo Foundation](http://dojofoundation.org/).
As such, we request that all contributors sign the Dojo Foundation [contributor license agreement](http://dojofoundation.org/about/claForm).
For more information about CLAs, please check out Alex Russells excellent post, [“Why Do I Need to Sign This?”](http://infrequently.org/2008/06/why-do-i-need-to-sign-this/).
## Coding Guidelines
In addition to the following guidelines, please follow the conventions already established in the code.
- **Spacing**:<br>
Use two spaces for indentation. No tabs.
- **Naming**:<br>
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, & [JSDoc-style](http://www.2ality.com/2011/08/jsdoc-intro.html) comments for new methods.

29
LICENSE
View File

@@ -1,17 +1,7 @@
Copyright OpenJS Foundation and other contributors <https://openjsf.org/> Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
Based on Underscore.js, copyright 2009-2015 Jeremy Ashkenas,
Based on Underscore.js, copyright Jeremy Ashkenas,
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/> DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/lodash/lodash
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including "Software"), to deal in the Software without restriction, including
@@ -30,18 +20,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code displayed within the prose of the
documentation.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
Files located in the node_modules and vendor directories are externally
maintained libraries used by this software which have their own
licenses; we recommend you read them, as their terms may differ from the
terms above.

View File

@@ -1,80 +1,29 @@
# lodash v4.17.20 # lodash v3.10.0
[Site](https://lodash.com/) | The [modern build](https://github.com/lodash/lodash/wiki/Build-Differences) of [lodash](https://lodash.com/) with packages for [Bower](http://bower.io/), [Component](http://component.github.io/), & [Volo](http://volojs.org/).
[Docs](https://lodash.com/docs) |
[FP Guide](https://github.com/lodash/lodash/wiki/FP-Guide) |
[Contributing](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md) |
[Wiki](https://github.com/lodash/lodash/wiki "Changelog, Roadmap, etc.") |
[Code of Conduct](https://js.foundation/conduct/) |
[Twitter](https://twitter.com/bestiejs) |
[Chat](https://gitter.im/lodash/lodash)
The [Lodash](https://lodash.com/) library exported as a [UMD](https://github.com/umdjs/umd) module.
Generated using [lodash-cli](https://www.npmjs.com/package/lodash-cli): Generated using [lodash-cli](https://www.npmjs.com/package/lodash-cli):
```shell ```bash
$ npm run build $ lodash modern -o ./lodash.js
$ lodash -o ./dist/lodash.js
$ lodash core -o ./dist/lodash.core.js
``` ```
## Download ## Community
* [Core build](https://raw.githubusercontent.com/lodash/lodash/4.17.20/dist/lodash.core.js) ([~4 kB gzipped](https://raw.githubusercontent.com/lodash/lodash/4.17.20/dist/lodash.core.min.js)) [![Join the chat at https://gitter.im/lodash/lodash](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/lodash/lodash)
* [Full build](https://raw.githubusercontent.com/lodash/lodash/4.17.20/dist/lodash.js) ([~24 kB gzipped](https://raw.githubusercontent.com/lodash/lodash/4.17.20/dist/lodash.min.js))
* [CDN copies](https://www.jsdelivr.com/projects/lodash)
Lodash is released under the [MIT license](https://raw.githubusercontent.com/lodash/lodash/4.17.20/LICENSE) & supports modern environments.<br> ## Module formats
Review the [build differences](https://github.com/lodash/lodash/wiki/build-differences) & pick one thats right for you.
## Installation lodash is also available in a variety of other builds & module formats.
In a browser: * 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
```html * AMD modules for [modern](https://github.com/lodash/lodash/tree/3.10.0-amd) & [compatibility](https://github.com/lodash/lodash-compat/tree/3.10.0-amd) builds
<script src="lodash.js"></script> * ES modules for the [modern](https://github.com/lodash/lodash/tree/3.10.0-es) build
```
Using npm: ## Further Reading
```shell
$ npm i -g npm
$ npm i --save lodash
```
In Node.js: * [API Documentation](https://lodash.com/docs)
```js * [Build Differences](https://github.com/lodash/lodash/wiki/Build-Differences)
// Load the full build. * [Changelog](https://github.com/lodash/lodash/wiki/Changelog)
var _ = require('lodash'); * [Release Notes](https://github.com/lodash/lodash/releases)
// Load the core build. * [Roadmap](https://github.com/lodash/lodash/wiki/Roadmap)
var _ = require('lodash/core'); * [More Resources](https://github.com/lodash/lodash/wiki/Resources)
// Load the FP build for immutable auto-curried iteratee-first data-last methods.
var fp = require('lodash/fp');
// Load method categories.
var array = require('lodash/array');
var object = require('lodash/fp/object');
// Cherry-pick methods for smaller browserify/rollup/webpack bundles.
var at = require('lodash/at');
var curryN = require('lodash/fp/curryN');
```
**Note:**<br>
Install [n_](https://www.npmjs.com/package/n_) for Lodash use in the Node.js < 6 REPL.
## Why Lodash?
Lodash makes JavaScript easier by taking the hassle out of working with arrays,<br>
numbers, objects, strings, etc. Lodashs modular methods are great for:
* Iterating arrays, objects, & strings
* Manipulating & testing values
* Creating composite functions
## Module Formats
Lodash is available in a [variety of builds](https://lodash.com/custom-builds) & module formats.
* [lodash](https://www.npmjs.com/package/lodash) & [per method packages](https://www.npmjs.com/browse/keyword/lodash-modularized)
* [lodash-es](https://www.npmjs.com/package/lodash-es), [babel-plugin-lodash](https://www.npmjs.com/package/babel-plugin-lodash), & [lodash-webpack-plugin](https://www.npmjs.com/package/lodash-webpack-plugin)
* [lodash/fp](https://github.com/lodash/lodash/tree/npm/fp)
* [lodash-amd](https://www.npmjs.com/package/lodash-amd)

19
bower.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "lodash",
"main": "lodash.js",
"ignore": [
".*",
"*.custom.*",
"*.log",
"*.map",
"*.md",
"lodash.src.js",
"component.json",
"package.json",
"doc",
"node_modules",
"perf",
"test",
"vendor"
]
}

10
component.json Normal file
View File

@@ -0,0 +1,10 @@
{
"name": "lodash",
"repo": "lodash/lodash",
"version": "3.10.0",
"description": "The modern build of lodash.",
"license": "MIT",
"main": "lodash.js",
"keywords": ["stdlib", "util"],
"scripts": ["lodash.js"]
}

3877
dist/lodash.core.js vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +0,0 @@
/**
* @license
* Lodash (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
* Build: `lodash core -o ./dist/lodash.core.js`
*/
;(function(){function n(n,t){return n.push.apply(n,t),n}function t(n,t,r,e){for(var u=n.length,o=r+(e?1:-1);e?o--:++o<u;)if(t(n[o],o,n))return o;return-1}function r(n){return function(t){return null==t?nt:t[n]}}function e(n){return function(t){return null==n?nt:n[t]}}function u(n,t,r,e,u){return u(n,function(n,u,o){r=e?(e=false,n):t(r,n,u,o)}),r}function o(n,t){return E(t,function(t){return n[t]})}function i(n,t){return function(r){return n(t(r))}}function c(n){return n instanceof f?n:new f(n)}function f(n,t){
this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t}function a(n,t,r){var e=n[t];Rt.call(n,t)&&wn(e,r)&&(r!==nt||t in n)||l(n,t,r)}function l(n,t,r){n[t]=r}function p(n,t,r){if(typeof n!="function")throw new TypeError(rt);return setTimeout(function(){n.apply(nt,r)},t)}function s(n,t){var r=true;return Ut(n,function(n,e,u){return r=!!t(n,e,u)}),r}function h(n,t,r){for(var e=-1,u=n.length;++e<u;){var o=n[e],i=t(o);if(null!=i&&(c===nt?i===i&&true:r(i,c)))var c=i,f=o}return f}function v(n,t){var r=[];
return Ut(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function y(t,r,e,u,o){var i=-1,c=t.length;for(e||(e=H),o||(o=[]);++i<c;){var f=t[i];r>0&&e(f)?r>1?y(f,r-1,e,u,o):n(o,f):u||(o[o.length]=f)}return o}function g(n,t){return n&&Vt(n,t,cr)}function _(n,t){return v(t,function(t){return Tn(n[t])})}function b(n){return W(n)}function j(n,t){return n>t}function d(n){return In(n)&&b(n)==ht}function m(n,t,r,e,u){return n===t||(null==n||null==t||!In(n)&&!In(t)?n!==n&&t!==t:O(n,t,r,e,m,u))}function O(n,t,r,e,u,o){
var i=Zt(n),c=Zt(t),f=i?lt:b(n),a=c?lt:b(t);f=f==at?bt:f,a=a==at?bt:a;var l=f==bt,p=a==bt,s=f==a;o||(o=[]);var h=Lt(o,function(t){return t[0]==n}),v=Lt(o,function(n){return n[0]==t});if(h&&v)return h[1]==t;if(o.push([n,t]),o.push([t,n]),s&&!l){var y=i?J(n,t,r,e,u,o):M(n,t,f,r,e,u,o);return o.pop(),y}if(!(r&et)){var g=l&&Rt.call(n,"__wrapped__"),_=p&&Rt.call(t,"__wrapped__");if(g||_){var j=g?n.value():n,d=_?t.value():t,y=u(j,d,r,e,o);return o.pop(),y}}if(!s)return false;var y=U(n,t,r,e,u,o);return o.pop(),
y}function x(n){return In(n)&&b(n)==dt}function w(n){return typeof n=="function"?n:null==n?Hn:(typeof n=="object"?N:r)(n)}function A(n,t){return n<t}function E(n,t){var r=-1,e=An(n)?Array(n.length):[];return Ut(n,function(n,u,o){e[++r]=t(n,u,o)}),e}function N(n){var t=Gt(n);return function(r){var e=t.length;if(null==r)return!e;for(r=Object(r);e--;){var u=t[e];if(!(u in r&&m(n[u],r[u],et|ut)))return false}return true}}function k(n,t){return n=Object(n),gn(t,function(t,r){return r in n&&(t[r]=n[r]),t},{})}
function F(n,t){return Kt(X(n,t,Hn),n+"")}function T(n,t,r){var e=-1,u=n.length;t<0&&(t=-t>u?0:u+t),r=r>u?u:r,r<0&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0;for(var o=Array(u);++e<u;)o[e]=n[e+t];return o}function S(n){return T(n,0,n.length)}function B(n,t){var r;return Ut(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}function I(t,r){var e=t;return gn(r,function(t,r){return r.func.apply(r.thisArg,n([t],r.args))},e)}function R(n,t){if(n!==t){var r=n!==nt,e=null===n,u=n===n,o=false,i=t!==nt,c=null===t,f=t===t,a=false;if(!c&&!a&&!o&&n>t||o&&i&&f&&!c&&!a||e&&i&&f||!r&&f||!u)return 1;
if(!e&&!o&&!a&&n<t||a&&r&&u&&!e&&!o||c&&r&&u||!i&&u||!f)return-1}return 0}function $(n,t,r,e){var u=!r;r||(r={});for(var o=-1,i=t.length;++o<i;){var c=t[o],f=e?e(r[c],n[c],c,r,n):nt;f===nt&&(f=n[c]),u?l(r,c,f):a(r,c,f)}return r}function q(n){return F(function(t,r){var e=-1,u=r.length,o=u>1?r[u-1]:nt;for(o=n.length>3&&typeof o=="function"?(u--,o):nt,t=Object(t);++e<u;){var i=r[e];i&&n(t,i,e,o)}return t})}function D(n,t){return function(r,e){if(null==r)return r;if(!An(r))return n(r,e);for(var u=r.length,o=t?u:-1,i=Object(r);(t?o--:++o<u)&&e(i[o],o,i)!==false;);
return r}}function P(n){return function(t,r,e){for(var u=-1,o=Object(t),i=e(t),c=i.length;c--;){var f=i[n?c:++u];if(r(o[f],f,o)===false)break}return t}}function z(n){return function(){var t=arguments,r=Mt(n.prototype),e=n.apply(r,t);return Bn(e)?e:r}}function C(n){return function(t,r,e){var u=Object(t);if(!An(t)){var o=w(r,3);t=cr(t),r=function(n){return o(u[n],n,u)}}var i=n(t,r,e);return i>-1?u[o?t[i]:i]:nt}}function G(n,t,r,e){function u(){for(var t=-1,c=arguments.length,f=-1,a=e.length,l=Array(a+c),p=this&&this!==kt&&this instanceof u?i:n;++f<a;)l[f]=e[f];
for(;c--;)l[f++]=arguments[++t];return p.apply(o?r:this,l)}if(typeof n!="function")throw new TypeError(rt);var o=t&ot,i=z(n);return u}function J(n,t,r,e,u,o){var i=r&et,c=n.length,f=t.length;if(c!=f&&!(i&&f>c))return false;var a=o.get(n),l=o.get(t);if(a&&l)return a==t&&l==n;for(var p=-1,s=true,h=r&ut?[]:nt;++p<c;){var v,y=n[p],g=t[p];if(v!==nt){if(v)continue;s=false;break}if(h){if(!B(t,function(n,t){if(!un(h,t)&&(y===n||u(y,n,r,e,o)))return h.push(t)})){s=false;break}}else if(y!==g&&!u(y,g,r,e,o)){s=false;break;
}}return s}function M(n,t,r,e,u,o,i){switch(r){case st:case ht:case _t:return wn(+n,+t);case vt:return n.name==t.name&&n.message==t.message;case dt:case mt:return n==t+""}return false}function U(n,t,r,e,u,o){var i=r&et,c=cr(n),f=c.length;if(f!=cr(t).length&&!i)return false;for(var a=f;a--;){var l=c[a];if(!(i?l in t:Rt.call(t,l)))return false}var p=o.get(n),s=o.get(t);if(p&&s)return p==t&&s==n;for(var h=true,v=i;++a<f;){l=c[a];var y,g=n[l],_=t[l];if(!(y===nt?g===_||u(g,_,r,e,o):y)){h=false;break}v||(v="constructor"==l);
}if(h&&!v){var b=n.constructor,j=t.constructor;b!=j&&"constructor"in n&&"constructor"in t&&!(typeof b=="function"&&b instanceof b&&typeof j=="function"&&j instanceof j)&&(h=false)}return h}function V(n){return Kt(X(n,nt,tn),n+"")}function H(n){return Zt(n)||Yt(n)}function K(n,t){var r=typeof n;return t=null==t?ft:t,!!t&&("number"==r||"symbol"!=r&&wt.test(n))&&n>-1&&n%1==0&&n<t}function L(n,t,r){if(!Bn(r))return false;var e=typeof t;return!!("number"==e?An(r)&&K(t,r.length):"string"==e&&t in r)&&wn(r[t],n);
}function Q(n){var t=[];if(null!=n)for(var r in Object(n))t.push(r);return t}function W(n){return qt.call(n)}function X(n,t,r){return t=Jt(t===nt?n.length-1:t,0),function(){for(var e=arguments,u=-1,o=Jt(e.length-t,0),i=Array(o);++u<o;)i[u]=e[t+u];u=-1;for(var c=Array(t+1);++u<t;)c[u]=e[u];return c[t]=r(i),n.apply(this,c)}}function Y(n){return v(n,Boolean)}function Z(){var t=arguments.length;if(!t)return[];for(var r=Array(t-1),e=arguments[0],u=t;u--;)r[u-1]=arguments[u];return n(Zt(e)?S(e):[e],y(r,1));
}function nn(n,r,e){var u=null==n?0:n.length;if(!u)return-1;var o=null==e?0:rr(e);return o<0&&(o=Jt(u+o,0)),t(n,w(r,3),o)}function tn(n){return(null==n?0:n.length)?y(n,1):[]}function rn(n){return(null==n?0:n.length)?y(n,ct):[]}function en(n){return n&&n.length?n[0]:nt}function un(n,t,r){var e=null==n?0:n.length;r=typeof r=="number"?r<0?Jt(e+r,0):r:0;for(var u=(r||0)-1,o=t===t;++u<e;){var i=n[u];if(o?i===t:i!==i)return u}return-1}function on(n){var t=null==n?0:n.length;return t?n[t-1]:nt}function cn(n,t,r){
var e=null==n?0:n.length;return t=null==t?0:+t,r=r===nt?e:+r,e?T(n,t,r):[]}function fn(n){var t=c(n);return t.__chain__=true,t}function an(n,t){return t(n),n}function ln(n,t){return t(n)}function pn(){return I(this.__wrapped__,this.__actions__)}function sn(n,t,r){return t=r?nt:t,s(n,w(t))}function hn(n,t){return v(n,w(t))}function vn(n,t){return Ut(n,w(t))}function yn(n,t){return E(n,w(t))}function gn(n,t,r){return u(n,w(t),r,arguments.length<3,Ut)}function _n(n){return null==n?0:(n=An(n)?n:Gt(n),n.length);
}function bn(n,t,r){return t=r?nt:t,B(n,w(t))}function jn(n,t){var e=0;return t=w(t),E(E(n,function(n,r,u){return{value:n,index:e++,criteria:t(n,r,u)}}).sort(function(n,t){return R(n.criteria,t.criteria)||n.index-t.index}),r("value"))}function dn(n,t){var r;if(typeof t!="function")throw new TypeError(rt);return n=rr(n),function(){return--n>0&&(r=t.apply(this,arguments)),n<=1&&(t=nt),r}}function mn(n){if(typeof n!="function")throw new TypeError(rt);return function(){return!n.apply(this,arguments)};
}function On(n){return dn(2,n)}function xn(n){return Bn(n)?Zt(n)?S(n):$(n,Gt(n)):n}function wn(n,t){return n===t||n!==n&&t!==t}function An(n){return null!=n&&Sn(n.length)&&!Tn(n)}function En(n){return n===true||n===false||In(n)&&b(n)==st}function Nn(n){return An(n)&&(Zt(n)||Dn(n)||Tn(n.splice)||Yt(n))?!n.length:!Gt(n).length}function kn(n,t){return m(n,t)}function Fn(n){return typeof n=="number"&&Ct(n)}function Tn(n){if(!Bn(n))return false;var t=b(n);return t==yt||t==gt||t==pt||t==jt}function Sn(n){return typeof n=="number"&&n>-1&&n%1==0&&n<=ft;
}function Bn(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function In(n){return null!=n&&typeof n=="object"}function Rn(n){return qn(n)&&n!=+n}function $n(n){return null===n}function qn(n){return typeof n=="number"||In(n)&&b(n)==_t}function Dn(n){return typeof n=="string"||!Zt(n)&&In(n)&&b(n)==mt}function Pn(n){return n===nt}function zn(n){return An(n)?n.length?S(n):[]:Un(n)}function Cn(n){return typeof n=="string"?n:null==n?"":n+""}function Gn(n,t){var r=Mt(n);return null==t?r:ur(r,t);
}function Jn(n,t){return null!=n&&Rt.call(n,t)}function Mn(n,t,r){var e=null==n?nt:n[t];return e===nt&&(e=r),Tn(e)?e.call(n):e}function Un(n){return null==n?[]:o(n,cr(n))}function Vn(n){return n=Cn(n),n&&xt.test(n)?n.replace(Ot,St):n}function Hn(n){return n}function Kn(n){return N(ur({},n))}function Ln(t,r,e){var u=cr(r),o=_(r,u);null!=e||Bn(r)&&(o.length||!u.length)||(e=r,r=t,t=this,o=_(r,cr(r)));var i=!(Bn(e)&&"chain"in e&&!e.chain),c=Tn(t);return Ut(o,function(e){var u=r[e];t[e]=u,c&&(t.prototype[e]=function(){
var r=this.__chain__;if(i||r){var e=t(this.__wrapped__);return(e.__actions__=S(this.__actions__)).push({func:u,args:arguments,thisArg:t}),e.__chain__=r,e}return u.apply(t,n([this.value()],arguments))})}),t}function Qn(){return kt._===this&&(kt._=Dt),this}function Wn(){}function Xn(n){var t=++$t;return Cn(n)+t}function Yn(n){return n&&n.length?h(n,Hn,j):nt}function Zn(n){return n&&n.length?h(n,Hn,A):nt}var nt,tt="4.17.20",rt="Expected a function",et=1,ut=2,ot=1,it=32,ct=1/0,ft=9007199254740991,at="[object Arguments]",lt="[object Array]",pt="[object AsyncFunction]",st="[object Boolean]",ht="[object Date]",vt="[object Error]",yt="[object Function]",gt="[object GeneratorFunction]",_t="[object Number]",bt="[object Object]",jt="[object Proxy]",dt="[object RegExp]",mt="[object String]",Ot=/[&<>"']/g,xt=RegExp(Ot.source),wt=/^(?:0|[1-9]\d*)$/,At={
"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},Et=typeof global=="object"&&global&&global.Object===Object&&global,Nt=typeof self=="object"&&self&&self.Object===Object&&self,kt=Et||Nt||Function("return this")(),Ft=typeof exports=="object"&&exports&&!exports.nodeType&&exports,Tt=Ft&&typeof module=="object"&&module&&!module.nodeType&&module,St=e(At),Bt=Array.prototype,It=Object.prototype,Rt=It.hasOwnProperty,$t=0,qt=It.toString,Dt=kt._,Pt=Object.create,zt=It.propertyIsEnumerable,Ct=kt.isFinite,Gt=i(Object.keys,Object),Jt=Math.max,Mt=function(){
function n(){}return function(t){if(!Bn(t))return{};if(Pt)return Pt(t);n.prototype=t;var r=new n;return n.prototype=nt,r}}();f.prototype=Mt(c.prototype),f.prototype.constructor=f;var Ut=D(g),Vt=P(),Ht=Wn,Kt=Hn,Lt=C(nn),Qt=F(function(n,t,r){return G(n,ot|it,t,r)}),Wt=F(function(n,t){return p(n,1,t)}),Xt=F(function(n,t,r){return p(n,er(t)||0,r)}),Yt=Ht(function(){return arguments}())?Ht:function(n){return In(n)&&Rt.call(n,"callee")&&!zt.call(n,"callee")},Zt=Array.isArray,nr=d,tr=x,rr=Number,er=Number,ur=q(function(n,t){
$(t,Gt(t),n)}),or=q(function(n,t){$(t,Q(t),n)}),ir=F(function(n,t){n=Object(n);var r=-1,e=t.length,u=e>2?t[2]:nt;for(u&&L(t[0],t[1],u)&&(e=1);++r<e;)for(var o=t[r],i=fr(o),c=-1,f=i.length;++c<f;){var a=i[c],l=n[a];(l===nt||wn(l,It[a])&&!Rt.call(n,a))&&(n[a]=o[a])}return n}),cr=Gt,fr=Q,ar=V(function(n,t){return null==n?{}:k(n,t)}),lr=w;c.assignIn=or,c.before=dn,c.bind=Qt,c.chain=fn,c.compact=Y,c.concat=Z,c.create=Gn,c.defaults=ir,c.defer=Wt,c.delay=Xt,c.filter=hn,c.flatten=tn,c.flattenDeep=rn,c.iteratee=lr,
c.keys=cr,c.map=yn,c.matches=Kn,c.mixin=Ln,c.negate=mn,c.once=On,c.pick=ar,c.slice=cn,c.sortBy=jn,c.tap=an,c.thru=ln,c.toArray=zn,c.values=Un,c.extend=or,Ln(c,c),c.clone=xn,c.escape=Vn,c.every=sn,c.find=Lt,c.forEach=vn,c.has=Jn,c.head=en,c.identity=Hn,c.indexOf=un,c.isArguments=Yt,c.isArray=Zt,c.isBoolean=En,c.isDate=nr,c.isEmpty=Nn,c.isEqual=kn,c.isFinite=Fn,c.isFunction=Tn,c.isNaN=Rn,c.isNull=$n,c.isNumber=qn,c.isObject=Bn,c.isRegExp=tr,c.isString=Dn,c.isUndefined=Pn,c.last=on,c.max=Yn,c.min=Zn,
c.noConflict=Qn,c.noop=Wn,c.reduce=gn,c.result=Mn,c.size=_n,c.some=bn,c.uniqueId=Xn,c.each=vn,c.first=en,Ln(c,function(){var n={};return g(c,function(t,r){Rt.call(c.prototype,r)||(n[r]=t)}),n}(),{chain:false}),c.VERSION=tt,Ut(["pop","join","replace","reverse","split","push","shift","sort","splice","unshift"],function(n){var t=(/^(?:replace|split)$/.test(n)?String.prototype:Bt)[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|join|replace|shift)$/.test(n);c.prototype[n]=function(){var n=arguments;
if(e&&!this.__chain__){var u=this.value();return t.apply(Zt(u)?u:[],n)}return this[r](function(r){return t.apply(Zt(r)?r:[],n)})}}),c.prototype.toJSON=c.prototype.valueOf=c.prototype.value=pn,typeof define=="function"&&typeof define.amd=="object"&&define.amd?(kt._=c, define(function(){return c})):Tt?((Tt.exports=c)._=c,Ft._=c):kt._=c}).call(this);

1031
dist/lodash.fp.js vendored

File diff suppressed because it is too large Load Diff

21
dist/lodash.fp.min.js vendored
View File

@@ -1,21 +0,0 @@
(function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.fp=e():t.fp=e()})(this,function(){return function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return t[n].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){function n(t,e){return i(t,t,e)}var i=r(1);"function"==typeof _&&"function"==typeof _.runInContext&&(_=n(_.runInContext())),
t.exports=n},function(t,e,r){function n(t,e){return 2==e?function(e,r){return t.apply(void 0,arguments)}:function(e){return t.apply(void 0,arguments)}}function i(t,e){return 2==e?function(e,r){return t(e,r)}:function(e){return t(e)}}function a(t){for(var e=t?t.length:0,r=Array(e);e--;)r[e]=t[e];return r}function o(t){return function(e){return t({},e)}}function s(t,e){return function(){for(var r=arguments.length,n=r-1,i=Array(r);r--;)i[r]=arguments[r];var a=i[e],o=i.slice(0,e);return a&&d.apply(o,a),
e!=n&&d.apply(o,i.slice(e+1)),t.apply(this,o)}}function l(t,e){return function(){var r=arguments.length;if(r){for(var n=Array(r);r--;)n[r]=arguments[r];var i=n[0]=e.apply(void 0,n);return t.apply(void 0,n),i}}}function u(t,e,r,d){function c(t,e){if(b.cap){var r=p.iterateeRearg[t];if(r)return x(e,r);var n=!O&&p.iterateeAry[t];if(n)return W(e,n)}return e}function h(t,e,r){return E||b.curry&&r>1?D(e,r):e}function g(t,e,r){if(b.fixed&&(F||!p.skipFixed[t])){var n=p.methodSpread[t],i=n&&n.start;return void 0===i?L(e,r):s(e,i);
}return e}function y(t,e,r){return b.rearg&&r>1&&(M||!p.skipRearg[t])?N(e,p.methodRearg[t]||p.aryRearg[r]):e}function m(t,e){e=U(e);for(var r=-1,n=e.length,i=n-1,a=w(Object(t)),o=a;null!=o&&++r<n;){var s=e[r],l=o[s];null==l||T(l)||P(l)||K(l)||(o[s]=w(r==i?l:Object(l))),o=o[s]}return a}function v(t){return J.runInContext.convert(t)(void 0)}function A(t,e){var r=p.aliasToReal[t]||t,n=p.remap[r]||r,i=d;return function(t){return u(O?j:C,r,O?j[n]:e,S(S({},i),t))}}function W(t,e){return I(t,function(t){
return"function"==typeof t?i(t,e):t})}function x(t,e){return I(t,function(t){var r=e.length;return n(N(i(t,r),e),r)})}function I(t,e){return function(){var r=arguments.length;if(!r)return t();for(var n=Array(r);r--;)n[r]=arguments[r];var i=b.rearg?0:r-1;return n[i]=e(n[i]),t.apply(void 0,n)}}function R(t,e,r){var n,i=p.aliasToReal[t]||t,s=e,u=H[i];return u?s=u(e):b.immutable&&(p.mutate.array[i]?s=l(e,a):p.mutate.object[i]?s=l(e,o(e)):p.mutate.set[i]&&(s=l(e,m))),z(G,function(t){return z(p.aryMethod[t],function(e){
if(i==e){var r=p.methodSpread[i];return n=r&&r.afterRearg?g(i,y(i,s,t),t):y(i,g(i,s,t),t),n=c(i,n),n=h(i,n,t),!1}}),!n}),n||(n=s),n==e&&(n=E?D(n,1):function(){return e.apply(this,arguments)}),n.convert=A(i,e),n.placeholder=e.placeholder=r,n}var O="function"==typeof e,k=e===Object(e);if(k&&(d=r,r=e,e=void 0),null==r)throw new TypeError;d||(d={});var b={cap:!("cap"in d)||d.cap,curry:!("curry"in d)||d.curry,fixed:!("fixed"in d)||d.fixed,immutable:!("immutable"in d)||d.immutable,rearg:!("rearg"in d)||d.rearg
},B=O?r:f,E="curry"in d&&d.curry,F="fixed"in d&&d.fixed,M="rearg"in d&&d.rearg,j=O?r.runInContext():void 0,C=O?r:{ary:t.ary,assign:t.assign,clone:t.clone,curry:t.curry,forEach:t.forEach,isArray:t.isArray,isError:t.isError,isFunction:t.isFunction,isWeakMap:t.isWeakMap,iteratee:t.iteratee,keys:t.keys,rearg:t.rearg,toInteger:t.toInteger,toPath:t.toPath},L=C.ary,S=C.assign,w=C.clone,D=C.curry,z=C.forEach,q=C.isArray,P=C.isError,T=C.isFunction,K=C.isWeakMap,_=C.keys,N=C.rearg,V=C.toInteger,U=C.toPath,G=_(p.aryMethod),H={
castArray:function(t){return function(){var e=arguments[0];return q(e)?t(a(e)):t.apply(void 0,arguments)}},iteratee:function(t){return function(){var e=arguments[0],r=arguments[1],n=t(e,r),a=n.length;return b.cap&&"number"==typeof r?(r=r>2?r-2:1,a&&a<=r?n:i(n,r)):n}},mixin:function(t){return function(e){var r=this;if(!T(r))return t(r,Object(e));var n=[];return z(_(e),function(t){T(e[t])&&n.push([t,r.prototype[t]])}),t(r,Object(e)),z(n,function(t){var e=t[1];T(e)?r.prototype[t[0]]=e:delete r.prototype[t[0]];
}),r}},nthArg:function(t){return function(e){var r=e<0?1:V(e)+1;return D(t(e),r)}},rearg:function(t){return function(e,r){var n=r?r.length:0;return D(t(e,r),n)}},runInContext:function(e){return function(r){return u(t,e(r),d)}}};if(!k)return R(e,r,B);var J=r,Q=[];return z(G,function(t){z(p.aryMethod[t],function(t){var e=J[p.remap[t]||t];e&&Q.push([t,R(t,e,J)])})}),z(_(J),function(t){var e=J[t];if("function"==typeof e){for(var r=Q.length;r--;)if(Q[r][0]==t)return;e.convert=A(t,e),Q.push([t,e])}}),z(Q,function(t){
J[t[0]]=t[1]}),J.convert=v,J.placeholder=J,z(_(J),function(t){z(p.realToAlias[t]||[],function(e){J[e]=J[t]})}),J}var p=r(2),f=r(3),d=Array.prototype.push;t.exports=u},function(t,e){e.aliasToReal={each:"forEach",eachRight:"forEachRight",entries:"toPairs",entriesIn:"toPairsIn",extend:"assignIn",extendAll:"assignInAll",extendAllWith:"assignInAllWith",extendWith:"assignInWith",first:"head",conforms:"conformsTo",matches:"isMatch",property:"get",__:"placeholder",F:"stubFalse",T:"stubTrue",all:"every",allPass:"overEvery",
always:"constant",any:"some",anyPass:"overSome",apply:"spread",assoc:"set",assocPath:"set",complement:"negate",compose:"flowRight",contains:"includes",dissoc:"unset",dissocPath:"unset",dropLast:"dropRight",dropLastWhile:"dropRightWhile",equals:"isEqual",identical:"eq",indexBy:"keyBy",init:"initial",invertObj:"invert",juxt:"over",omitAll:"omit",nAry:"ary",path:"get",pathEq:"matchesProperty",pathOr:"getOr",paths:"at",pickAll:"pick",pipe:"flow",pluck:"map",prop:"get",propEq:"matchesProperty",propOr:"getOr",
props:"at",symmetricDifference:"xor",symmetricDifferenceBy:"xorBy",symmetricDifferenceWith:"xorWith",takeLast:"takeRight",takeLastWhile:"takeRightWhile",unapply:"rest",unnest:"flatten",useWith:"overArgs",where:"conformsTo",whereEq:"isMatch",zipObj:"zipObject"},e.aryMethod={1:["assignAll","assignInAll","attempt","castArray","ceil","create","curry","curryRight","defaultsAll","defaultsDeepAll","floor","flow","flowRight","fromPairs","invert","iteratee","memoize","method","mergeAll","methodOf","mixin","nthArg","over","overEvery","overSome","rest","reverse","round","runInContext","spread","template","trim","trimEnd","trimStart","uniqueId","words","zipAll"],
2:["add","after","ary","assign","assignAllWith","assignIn","assignInAllWith","at","before","bind","bindAll","bindKey","chunk","cloneDeepWith","cloneWith","concat","conformsTo","countBy","curryN","curryRightN","debounce","defaults","defaultsDeep","defaultTo","delay","difference","divide","drop","dropRight","dropRightWhile","dropWhile","endsWith","eq","every","filter","find","findIndex","findKey","findLast","findLastIndex","findLastKey","flatMap","flatMapDeep","flattenDepth","forEach","forEachRight","forIn","forInRight","forOwn","forOwnRight","get","groupBy","gt","gte","has","hasIn","includes","indexOf","intersection","invertBy","invoke","invokeMap","isEqual","isMatch","join","keyBy","lastIndexOf","lt","lte","map","mapKeys","mapValues","matchesProperty","maxBy","meanBy","merge","mergeAllWith","minBy","multiply","nth","omit","omitBy","overArgs","pad","padEnd","padStart","parseInt","partial","partialRight","partition","pick","pickBy","propertyOf","pull","pullAll","pullAt","random","range","rangeRight","rearg","reject","remove","repeat","restFrom","result","sampleSize","some","sortBy","sortedIndex","sortedIndexOf","sortedLastIndex","sortedLastIndexOf","sortedUniqBy","split","spreadFrom","startsWith","subtract","sumBy","take","takeRight","takeRightWhile","takeWhile","tap","throttle","thru","times","trimChars","trimCharsEnd","trimCharsStart","truncate","union","uniqBy","uniqWith","unset","unzipWith","without","wrap","xor","zip","zipObject","zipObjectDeep"],
3:["assignInWith","assignWith","clamp","differenceBy","differenceWith","findFrom","findIndexFrom","findLastFrom","findLastIndexFrom","getOr","includesFrom","indexOfFrom","inRange","intersectionBy","intersectionWith","invokeArgs","invokeArgsMap","isEqualWith","isMatchWith","flatMapDepth","lastIndexOfFrom","mergeWith","orderBy","padChars","padCharsEnd","padCharsStart","pullAllBy","pullAllWith","rangeStep","rangeStepRight","reduce","reduceRight","replace","set","slice","sortedIndexBy","sortedLastIndexBy","transform","unionBy","unionWith","update","xorBy","xorWith","zipWith"],
4:["fill","setWith","updateWith"]},e.aryRearg={2:[1,0],3:[2,0,1],4:[3,2,0,1]},e.iterateeAry={dropRightWhile:1,dropWhile:1,every:1,filter:1,find:1,findFrom:1,findIndex:1,findIndexFrom:1,findKey:1,findLast:1,findLastFrom:1,findLastIndex:1,findLastIndexFrom:1,findLastKey:1,flatMap:1,flatMapDeep:1,flatMapDepth:1,forEach:1,forEachRight:1,forIn:1,forInRight:1,forOwn:1,forOwnRight:1,map:1,mapKeys:1,mapValues:1,partition:1,reduce:2,reduceRight:2,reject:1,remove:1,some:1,takeRightWhile:1,takeWhile:1,times:1,
transform:2},e.iterateeRearg={mapKeys:[1],reduceRight:[1,0]},e.methodRearg={assignInAllWith:[1,0],assignInWith:[1,2,0],assignAllWith:[1,0],assignWith:[1,2,0],differenceBy:[1,2,0],differenceWith:[1,2,0],getOr:[2,1,0],intersectionBy:[1,2,0],intersectionWith:[1,2,0],isEqualWith:[1,2,0],isMatchWith:[2,1,0],mergeAllWith:[1,0],mergeWith:[1,2,0],padChars:[2,1,0],padCharsEnd:[2,1,0],padCharsStart:[2,1,0],pullAllBy:[2,1,0],pullAllWith:[2,1,0],rangeStep:[1,2,0],rangeStepRight:[1,2,0],setWith:[3,1,2,0],sortedIndexBy:[2,1,0],
sortedLastIndexBy:[2,1,0],unionBy:[1,2,0],unionWith:[1,2,0],updateWith:[3,1,2,0],xorBy:[1,2,0],xorWith:[1,2,0],zipWith:[1,2,0]},e.methodSpread={assignAll:{start:0},assignAllWith:{start:0},assignInAll:{start:0},assignInAllWith:{start:0},defaultsAll:{start:0},defaultsDeepAll:{start:0},invokeArgs:{start:2},invokeArgsMap:{start:2},mergeAll:{start:0},mergeAllWith:{start:0},partial:{start:1},partialRight:{start:1},without:{start:1},zipAll:{start:0}},e.mutate={array:{fill:!0,pull:!0,pullAll:!0,pullAllBy:!0,
pullAllWith:!0,pullAt:!0,remove:!0,reverse:!0},object:{assign:!0,assignAll:!0,assignAllWith:!0,assignIn:!0,assignInAll:!0,assignInAllWith:!0,assignInWith:!0,assignWith:!0,defaults:!0,defaultsAll:!0,defaultsDeep:!0,defaultsDeepAll:!0,merge:!0,mergeAll:!0,mergeAllWith:!0,mergeWith:!0},set:{set:!0,setWith:!0,unset:!0,update:!0,updateWith:!0}},e.realToAlias=function(){var t=Object.prototype.hasOwnProperty,r=e.aliasToReal,n={};for(var i in r){var a=r[i];t.call(n,a)?n[a].push(i):n[a]=[i]}return n}(),e.remap={
assignAll:"assign",assignAllWith:"assignWith",assignInAll:"assignIn",assignInAllWith:"assignInWith",curryN:"curry",curryRightN:"curryRight",defaultsAll:"defaults",defaultsDeepAll:"defaultsDeep",findFrom:"find",findIndexFrom:"findIndex",findLastFrom:"findLast",findLastIndexFrom:"findLastIndex",getOr:"get",includesFrom:"includes",indexOfFrom:"indexOf",invokeArgs:"invoke",invokeArgsMap:"invokeMap",lastIndexOfFrom:"lastIndexOf",mergeAll:"merge",mergeAllWith:"mergeWith",padChars:"pad",padCharsEnd:"padEnd",
padCharsStart:"padStart",propertyOf:"get",rangeStep:"range",rangeStepRight:"rangeRight",restFrom:"rest",spreadFrom:"spread",trimChars:"trim",trimCharsEnd:"trimEnd",trimCharsStart:"trimStart",zipAll:"zip"},e.skipFixed={castArray:!0,flow:!0,flowRight:!0,iteratee:!0,mixin:!0,rearg:!0,runInContext:!0},e.skipRearg={add:!0,assign:!0,assignIn:!0,bind:!0,bindKey:!0,concat:!0,difference:!0,divide:!0,eq:!0,gt:!0,gte:!0,isEqual:!0,lt:!0,lte:!0,matchesProperty:!0,merge:!0,multiply:!0,overArgs:!0,partial:!0,partialRight:!0,
propertyOf:!0,random:!0,range:!0,rangeRight:!0,subtract:!0,zip:!0,zipObject:!0,zipObjectDeep:!0}},function(t,e){t.exports={}}])});

17161
dist/lodash.js vendored

File diff suppressed because it is too large Load Diff

139
dist/lodash.min.js vendored
View File

@@ -1,139 +0,0 @@
/**
* @license
* Lodash <https://lodash.com/>
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
(function(){function n(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function t(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u<i;){var o=n[u];t(e,o,r(o),n)}return e}function r(n,t){for(var r=-1,e=null==n?0:n.length;++r<e&&t(n[r],r,n)!==!1;);return n}function e(n,t){for(var r=null==n?0:n.length;r--&&t(n[r],r,n)!==!1;);return n}function u(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(!t(n[r],r,n))return!1;
return!0}function i(n,t){for(var r=-1,e=null==n?0:n.length,u=0,i=[];++r<e;){var o=n[r];t(o,r,n)&&(i[u++]=o)}return i}function o(n,t){return!!(null==n?0:n.length)&&y(n,t,0)>-1}function f(n,t,r){for(var e=-1,u=null==n?0:n.length;++e<u;)if(r(t,n[e]))return!0;return!1}function c(n,t){for(var r=-1,e=null==n?0:n.length,u=Array(e);++r<e;)u[r]=t(n[r],r,n);return u}function a(n,t){for(var r=-1,e=t.length,u=n.length;++r<e;)n[u+r]=t[r];return n}function l(n,t,r,e){var u=-1,i=null==n?0:n.length;for(e&&i&&(r=n[++u]);++u<i;)r=t(r,n[u],u,n);
return r}function s(n,t,r,e){var u=null==n?0:n.length;for(e&&u&&(r=n[--u]);u--;)r=t(r,n[u],u,n);return r}function h(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(t(n[r],r,n))return!0;return!1}function p(n){return n.split("")}function _(n){return n.match(Bt)||[]}function v(n,t,r){var e;return r(n,function(n,r,u){if(t(n,r,u))return e=r,!1}),e}function g(n,t,r,e){for(var u=n.length,i=r+(e?1:-1);e?i--:++i<u;)if(t(n[i],i,n))return i;return-1}function y(n,t,r){return t===t?q(n,t,r):g(n,b,r)}function d(n,t,r,e){
for(var u=r-1,i=n.length;++u<i;)if(e(n[u],t))return u;return-1}function b(n){return n!==n}function w(n,t){var r=null==n?0:n.length;return r?k(n,t)/r:Sn}function m(n){return function(t){return null==t?Y:t[n]}}function x(n){return function(t){return null==n?Y:n[t]}}function j(n,t,r,e,u){return u(n,function(n,u,i){r=e?(e=!1,n):t(r,n,u,i)}),r}function A(n,t){var r=n.length;for(n.sort(t);r--;)n[r]=n[r].value;return n}function k(n,t){for(var r,e=-1,u=n.length;++e<u;){var i=t(n[e]);i!==Y&&(r=r===Y?i:r+i);
}return r}function O(n,t){for(var r=-1,e=Array(n);++r<n;)e[r]=t(r);return e}function I(n,t){return c(t,function(t){return[t,n[t]]})}function R(n){return function(t){return n(t)}}function z(n,t){return c(t,function(t){return n[t]})}function E(n,t){return n.has(t)}function S(n,t){for(var r=-1,e=n.length;++r<e&&y(t,n[r],0)>-1;);return r}function W(n,t){for(var r=n.length;r--&&y(t,n[r],0)>-1;);return r}function L(n,t){for(var r=n.length,e=0;r--;)n[r]===t&&++e;return e}function C(n){return"\\"+Gr[n]}function U(n,t){
return null==n?Y:n[t]}function B(n){return Dr.test(n)}function T(n){return Mr.test(n)}function $(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}function D(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n]}),r}function M(n,t){return function(r){return n(t(r))}}function F(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){var o=n[r];o!==t&&o!==un||(n[r]=un,i[u++]=r)}return i}function N(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=n}),r}function P(n){
var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=[n,n]}),r}function q(n,t,r){for(var e=r-1,u=n.length;++e<u;)if(n[e]===t)return e;return-1}function Z(n,t,r){for(var e=r+1;e--;)if(n[e]===t)return e;return e}function K(n){return B(n)?G(n):se(n)}function V(n){return B(n)?H(n):p(n)}function G(n){for(var t=Tr.lastIndex=0;Tr.test(n);)++t;return t}function H(n){return n.match(Tr)||[]}function J(n){return n.match($r)||[]}var Y,Q="4.17.20",X=200,nn="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",tn="Expected a function",rn="__lodash_hash_undefined__",en=500,un="__lodash_placeholder__",on=1,fn=2,cn=4,an=1,ln=2,sn=1,hn=2,pn=4,_n=8,vn=16,gn=32,yn=64,dn=128,bn=256,wn=512,mn=30,xn="...",jn=800,An=16,kn=1,On=2,In=3,Rn=1/0,zn=9007199254740991,En=1.7976931348623157e308,Sn=NaN,Wn=4294967295,Ln=Wn-1,Cn=Wn>>>1,Un=[["ary",dn],["bind",sn],["bindKey",hn],["curry",_n],["curryRight",vn],["flip",wn],["partial",gn],["partialRight",yn],["rearg",bn]],Bn="[object Arguments]",Tn="[object Array]",$n="[object AsyncFunction]",Dn="[object Boolean]",Mn="[object Date]",Fn="[object DOMException]",Nn="[object Error]",Pn="[object Function]",qn="[object GeneratorFunction]",Zn="[object Map]",Kn="[object Number]",Vn="[object Null]",Gn="[object Object]",Hn="[object Promise]",Jn="[object Proxy]",Yn="[object RegExp]",Qn="[object Set]",Xn="[object String]",nt="[object Symbol]",tt="[object Undefined]",rt="[object WeakMap]",et="[object WeakSet]",ut="[object ArrayBuffer]",it="[object DataView]",ot="[object Float32Array]",ft="[object Float64Array]",ct="[object Int8Array]",at="[object Int16Array]",lt="[object Int32Array]",st="[object Uint8Array]",ht="[object Uint8ClampedArray]",pt="[object Uint16Array]",_t="[object Uint32Array]",vt=/\b__p \+= '';/g,gt=/\b(__p \+=) '' \+/g,yt=/(__e\(.*?\)|\b__t\)) \+\n'';/g,dt=/&(?:amp|lt|gt|quot|#39);/g,bt=/[&<>"']/g,wt=RegExp(dt.source),mt=RegExp(bt.source),xt=/<%-([\s\S]+?)%>/g,jt=/<%([\s\S]+?)%>/g,At=/<%=([\s\S]+?)%>/g,kt=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Ot=/^\w*$/,It=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Rt=/[\\^$.*+?()[\]{}|]/g,zt=RegExp(Rt.source),Et=/^\s+|\s+$/g,St=/^\s+/,Wt=/\s+$/,Lt=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Ct=/\{\n\/\* \[wrapped with (.+)\] \*/,Ut=/,? & /,Bt=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,Tt=/\\(\\)?/g,$t=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,Dt=/\w*$/,Mt=/^[-+]0x[0-9a-f]+$/i,Ft=/^0b[01]+$/i,Nt=/^\[object .+?Constructor\]$/,Pt=/^0o[0-7]+$/i,qt=/^(?:0|[1-9]\d*)$/,Zt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,Kt=/($^)/,Vt=/['\n\r\u2028\u2029\\]/g,Gt="\\ud800-\\udfff",Ht="\\u0300-\\u036f",Jt="\\ufe20-\\ufe2f",Yt="\\u20d0-\\u20ff",Qt=Ht+Jt+Yt,Xt="\\u2700-\\u27bf",nr="a-z\\xdf-\\xf6\\xf8-\\xff",tr="\\xac\\xb1\\xd7\\xf7",rr="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",er="\\u2000-\\u206f",ur=" \\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",ir="A-Z\\xc0-\\xd6\\xd8-\\xde",or="\\ufe0e\\ufe0f",fr=tr+rr+er+ur,cr="['\u2019]",ar="["+Gt+"]",lr="["+fr+"]",sr="["+Qt+"]",hr="\\d+",pr="["+Xt+"]",_r="["+nr+"]",vr="[^"+Gt+fr+hr+Xt+nr+ir+"]",gr="\\ud83c[\\udffb-\\udfff]",yr="(?:"+sr+"|"+gr+")",dr="[^"+Gt+"]",br="(?:\\ud83c[\\udde6-\\uddff]){2}",wr="[\\ud800-\\udbff][\\udc00-\\udfff]",mr="["+ir+"]",xr="\\u200d",jr="(?:"+_r+"|"+vr+")",Ar="(?:"+mr+"|"+vr+")",kr="(?:"+cr+"(?:d|ll|m|re|s|t|ve))?",Or="(?:"+cr+"(?:D|LL|M|RE|S|T|VE))?",Ir=yr+"?",Rr="["+or+"]?",zr="(?:"+xr+"(?:"+[dr,br,wr].join("|")+")"+Rr+Ir+")*",Er="\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Sr="\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])",Wr=Rr+Ir+zr,Lr="(?:"+[pr,br,wr].join("|")+")"+Wr,Cr="(?:"+[dr+sr+"?",sr,br,wr,ar].join("|")+")",Ur=RegExp(cr,"g"),Br=RegExp(sr,"g"),Tr=RegExp(gr+"(?="+gr+")|"+Cr+Wr,"g"),$r=RegExp([mr+"?"+_r+"+"+kr+"(?="+[lr,mr,"$"].join("|")+")",Ar+"+"+Or+"(?="+[lr,mr+jr,"$"].join("|")+")",mr+"?"+jr+"+"+kr,mr+"+"+Or,Sr,Er,hr,Lr].join("|"),"g"),Dr=RegExp("["+xr+Gt+Qt+or+"]"),Mr=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Fr=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Nr=-1,Pr={};
Pr[ot]=Pr[ft]=Pr[ct]=Pr[at]=Pr[lt]=Pr[st]=Pr[ht]=Pr[pt]=Pr[_t]=!0,Pr[Bn]=Pr[Tn]=Pr[ut]=Pr[Dn]=Pr[it]=Pr[Mn]=Pr[Nn]=Pr[Pn]=Pr[Zn]=Pr[Kn]=Pr[Gn]=Pr[Yn]=Pr[Qn]=Pr[Xn]=Pr[rt]=!1;var qr={};qr[Bn]=qr[Tn]=qr[ut]=qr[it]=qr[Dn]=qr[Mn]=qr[ot]=qr[ft]=qr[ct]=qr[at]=qr[lt]=qr[Zn]=qr[Kn]=qr[Gn]=qr[Yn]=qr[Qn]=qr[Xn]=qr[nt]=qr[st]=qr[ht]=qr[pt]=qr[_t]=!0,qr[Nn]=qr[Pn]=qr[rt]=!1;var Zr={"\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","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g",
"\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O",
"\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w",
"\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"},Kr={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},Vr={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'"},Gr={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Hr=parseFloat,Jr=parseInt,Yr="object"==typeof global&&global&&global.Object===Object&&global,Qr="object"==typeof self&&self&&self.Object===Object&&self,Xr=Yr||Qr||Function("return this")(),ne="object"==typeof exports&&exports&&!exports.nodeType&&exports,te=ne&&"object"==typeof module&&module&&!module.nodeType&&module,re=te&&te.exports===ne,ee=re&&Yr.process,ue=function(){
try{var n=te&&te.require&&te.require("util").types;return n?n:ee&&ee.binding&&ee.binding("util")}catch(n){}}(),ie=ue&&ue.isArrayBuffer,oe=ue&&ue.isDate,fe=ue&&ue.isMap,ce=ue&&ue.isRegExp,ae=ue&&ue.isSet,le=ue&&ue.isTypedArray,se=m("length"),he=x(Zr),pe=x(Kr),_e=x(Vr),ve=function p(x){function q(n){if(oc(n)&&!yh(n)&&!(n instanceof Bt)){if(n instanceof H)return n;if(yl.call(n,"__wrapped__"))return to(n)}return new H(n)}function G(){}function H(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,
this.__index__=0,this.__values__=Y}function Bt(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=Wn,this.__views__=[]}function Gt(){var n=new Bt(this.__wrapped__);return n.__actions__=Uu(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Uu(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Uu(this.__views__),n}function Ht(){if(this.__filtered__){var n=new Bt(this);n.__dir__=-1,
n.__filtered__=!0}else n=this.clone(),n.__dir__*=-1;return n}function Jt(){var n=this.__wrapped__.value(),t=this.__dir__,r=yh(n),e=t<0,u=r?n.length:0,i=Ai(0,u,this.__views__),o=i.start,f=i.end,c=f-o,a=e?f:o-1,l=this.__iteratees__,s=l.length,h=0,p=Vl(c,this.__takeCount__);if(!r||!e&&u==c&&p==c)return du(n,this.__actions__);var _=[];n:for(;c--&&h<p;){a+=t;for(var v=-1,g=n[a];++v<s;){var y=l[v],d=y.iteratee,b=y.type,w=d(g);if(b==On)g=w;else if(!w){if(b==kn)continue n;break n}}_[h++]=g}return _}function Yt(n){
var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Qt(){this.__data__=es?es(null):{},this.size=0}function Xt(n){var t=this.has(n)&&delete this.__data__[n];return this.size-=t?1:0,t}function nr(n){var t=this.__data__;if(es){var r=t[n];return r===rn?Y:r}return yl.call(t,n)?t[n]:Y}function tr(n){var t=this.__data__;return es?t[n]!==Y:yl.call(t,n)}function rr(n,t){var r=this.__data__;return this.size+=this.has(n)?0:1,r[n]=es&&t===Y?rn:t,this}function er(n){
var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function ur(){this.__data__=[],this.size=0}function ir(n){var t=this.__data__,r=Er(t,n);return!(r<0)&&(r==t.length-1?t.pop():Sl.call(t,r,1),--this.size,!0)}function or(n){var t=this.__data__,r=Er(t,n);return r<0?Y:t[r][1]}function fr(n){return Er(this.__data__,n)>-1}function cr(n,t){var r=this.__data__,e=Er(r,n);return e<0?(++this.size,r.push([n,t])):r[e][1]=t,this}function ar(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){
var e=n[t];this.set(e[0],e[1])}}function lr(){this.size=0,this.__data__={hash:new Yt,map:new(Xl||er),string:new Yt}}function sr(n){var t=wi(this,n).delete(n);return this.size-=t?1:0,t}function hr(n){return wi(this,n).get(n)}function pr(n){return wi(this,n).has(n)}function _r(n,t){var r=wi(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this}function vr(n){var t=-1,r=null==n?0:n.length;for(this.__data__=new ar;++t<r;)this.add(n[t])}function gr(n){return this.__data__.set(n,rn),this}function yr(n){
return this.__data__.has(n)}function dr(n){this.size=(this.__data__=new er(n)).size}function br(){this.__data__=new er,this.size=0}function wr(n){var t=this.__data__,r=t.delete(n);return this.size=t.size,r}function mr(n){return this.__data__.get(n)}function xr(n){return this.__data__.has(n)}function jr(n,t){var r=this.__data__;if(r instanceof er){var e=r.__data__;if(!Xl||e.length<X-1)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new ar(e)}return r.set(n,t),this.size=r.size,this}function Ar(n,t){
var r=yh(n),e=!r&&gh(n),u=!r&&!e&&bh(n),i=!r&&!e&&!u&&Ah(n),o=r||e||u||i,f=o?O(n.length,ll):[],c=f.length;for(var a in n)!t&&!yl.call(n,a)||o&&("length"==a||u&&("offset"==a||"parent"==a)||i&&("buffer"==a||"byteLength"==a||"byteOffset"==a)||Wi(a,c))||f.push(a);return f}function kr(n){var t=n.length;return t?n[Xe(0,t-1)]:Y}function Or(n,t){return Yi(Uu(n),$r(t,0,n.length))}function Ir(n){return Yi(Uu(n))}function Rr(n,t,r){(r===Y||Kf(n[t],r))&&(r!==Y||t in n)||Cr(n,t,r)}function zr(n,t,r){var e=n[t];
yl.call(n,t)&&Kf(e,r)&&(r!==Y||t in n)||Cr(n,t,r)}function Er(n,t){for(var r=n.length;r--;)if(Kf(n[r][0],t))return r;return-1}function Sr(n,t,r,e){return vs(n,function(n,u,i){t(e,n,r(n),i)}),e}function Wr(n,t){return n&&Bu(t,Fc(t),n)}function Lr(n,t){return n&&Bu(t,Nc(t),n)}function Cr(n,t,r){"__proto__"==t&&Ul?Ul(n,t,{configurable:!0,enumerable:!0,value:r,writable:!0}):n[t]=r}function Tr(n,t){for(var r=-1,e=t.length,u=el(e),i=null==n;++r<e;)u[r]=i?Y:$c(n,t[r]);return u}function $r(n,t,r){return n===n&&(r!==Y&&(n=n<=r?n:r),
t!==Y&&(n=n>=t?n:t)),n}function Dr(n,t,e,u,i,o){var f,c=t&on,a=t&fn,l=t&cn;if(e&&(f=i?e(n,u,i,o):e(n)),f!==Y)return f;if(!ic(n))return n;var s=yh(n);if(s){if(f=Ii(n),!c)return Uu(n,f)}else{var h=Is(n),p=h==Pn||h==qn;if(bh(n))return ku(n,c);if(h==Gn||h==Bn||p&&!i){if(f=a||p?{}:Ri(n),!c)return a?$u(n,Lr(f,n)):Tu(n,Wr(f,n))}else{if(!qr[h])return i?n:{};f=zi(n,h,c)}}o||(o=new dr);var _=o.get(n);if(_)return _;o.set(n,f),jh(n)?n.forEach(function(r){f.add(Dr(r,t,e,r,n,o))}):mh(n)&&n.forEach(function(r,u){
f.set(u,Dr(r,t,e,u,n,o))});var v=l?a?gi:vi:a?Nc:Fc,g=s?Y:v(n);return r(g||n,function(r,u){g&&(u=r,r=n[u]),zr(f,u,Dr(r,t,e,u,n,o))}),f}function Mr(n){var t=Fc(n);return function(r){return Zr(r,n,t)}}function Zr(n,t,r){var e=r.length;if(null==n)return!e;for(n=cl(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===Y&&!(u in n)||!i(o))return!1}return!0}function Kr(n,t,r){if("function"!=typeof n)throw new sl(tn);return Es(function(){n.apply(Y,r)},t)}function Vr(n,t,r,e){var u=-1,i=o,a=!0,l=n.length,s=[],h=t.length;
if(!l)return s;r&&(t=c(t,R(r))),e?(i=f,a=!1):t.length>=X&&(i=E,a=!1,t=new vr(t));n:for(;++u<l;){var p=n[u],_=null==r?p:r(p);if(p=e||0!==p?p:0,a&&_===_){for(var v=h;v--;)if(t[v]===_)continue n;s.push(p)}else i(t,_,e)||s.push(p)}return s}function Gr(n,t){var r=!0;return vs(n,function(n,e,u){return r=!!t(n,e,u)}),r}function Yr(n,t,r){for(var e=-1,u=n.length;++e<u;){var i=n[e],o=t(i);if(null!=o&&(f===Y?o===o&&!yc(o):r(o,f)))var f=o,c=i}return c}function Qr(n,t,r,e){var u=n.length;for(r=jc(r),r<0&&(r=-r>u?0:u+r),
e=e===Y||e>u?u:jc(e),e<0&&(e+=u),e=r>e?0:Ac(e);r<e;)n[r++]=t;return n}function ne(n,t){var r=[];return vs(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function te(n,t,r,e,u){var i=-1,o=n.length;for(r||(r=Si),u||(u=[]);++i<o;){var f=n[i];t>0&&r(f)?t>1?te(f,t-1,r,e,u):a(u,f):e||(u[u.length]=f)}return u}function ee(n,t){return n&&ys(n,t,Fc)}function ue(n,t){return n&&ds(n,t,Fc)}function se(n,t){return i(t,function(t){return rc(n[t])})}function ve(n,t){t=ju(t,n);for(var r=0,e=t.length;null!=n&&r<e;)n=n[Qi(t[r++])];
return r&&r==e?n:Y}function ye(n,t,r){var e=t(n);return yh(n)?e:a(e,r(n))}function de(n){return null==n?n===Y?tt:Vn:Cl&&Cl in cl(n)?ji(n):qi(n)}function be(n,t){return n>t}function we(n,t){return null!=n&&yl.call(n,t)}function me(n,t){return null!=n&&t in cl(n)}function xe(n,t,r){return n>=Vl(t,r)&&n<Kl(t,r)}function je(n,t,r){for(var e=r?f:o,u=n[0].length,i=n.length,a=i,l=el(i),s=1/0,h=[];a--;){var p=n[a];a&&t&&(p=c(p,R(t))),s=Vl(p.length,s),l[a]=!r&&(t||u>=120&&p.length>=120)?new vr(a&&p):Y}p=n[0];
var _=-1,v=l[0];n:for(;++_<u&&h.length<s;){var g=p[_],y=t?t(g):g;if(g=r||0!==g?g:0,!(v?E(v,y):e(h,y,r))){for(a=i;--a;){var d=l[a];if(!(d?E(d,y):e(n[a],y,r)))continue n}v&&v.push(y),h.push(g)}}return h}function Ae(n,t,r,e){return ee(n,function(n,u,i){t(e,r(n),u,i)}),e}function ke(t,r,e){r=ju(r,t),t=Ki(t,r);var u=null==t?t:t[Qi(mo(r))];return null==u?Y:n(u,t,e)}function Oe(n){return oc(n)&&de(n)==Bn}function Ie(n){return oc(n)&&de(n)==ut}function Re(n){return oc(n)&&de(n)==Mn}function ze(n,t,r,e,u){
return n===t||(null==n||null==t||!oc(n)&&!oc(t)?n!==n&&t!==t:Ee(n,t,r,e,ze,u))}function Ee(n,t,r,e,u,i){var o=yh(n),f=yh(t),c=o?Tn:Is(n),a=f?Tn:Is(t);c=c==Bn?Gn:c,a=a==Bn?Gn:a;var l=c==Gn,s=a==Gn,h=c==a;if(h&&bh(n)){if(!bh(t))return!1;o=!0,l=!1}if(h&&!l)return i||(i=new dr),o||Ah(n)?si(n,t,r,e,u,i):hi(n,t,c,r,e,u,i);if(!(r&an)){var p=l&&yl.call(n,"__wrapped__"),_=s&&yl.call(t,"__wrapped__");if(p||_){var v=p?n.value():n,g=_?t.value():t;return i||(i=new dr),u(v,g,r,e,i)}}return!!h&&(i||(i=new dr),pi(n,t,r,e,u,i));
}function Se(n){return oc(n)&&Is(n)==Zn}function We(n,t,r,e){var u=r.length,i=u,o=!e;if(null==n)return!i;for(n=cl(n);u--;){var f=r[u];if(o&&f[2]?f[1]!==n[f[0]]:!(f[0]in n))return!1}for(;++u<i;){f=r[u];var c=f[0],a=n[c],l=f[1];if(o&&f[2]){if(a===Y&&!(c in n))return!1}else{var s=new dr;if(e)var h=e(a,l,c,n,t,s);if(!(h===Y?ze(l,a,an|ln,e,s):h))return!1}}return!0}function Le(n){return!(!ic(n)||Ti(n))&&(rc(n)?jl:Nt).test(Xi(n))}function Ce(n){return oc(n)&&de(n)==Yn}function Ue(n){return oc(n)&&Is(n)==Qn;
}function Be(n){return oc(n)&&uc(n.length)&&!!Pr[de(n)]}function Te(n){return"function"==typeof n?n:null==n?Sa:"object"==typeof n?yh(n)?Pe(n[0],n[1]):Ne(n):Da(n)}function $e(n){if(!$i(n))return Zl(n);var t=[];for(var r in cl(n))yl.call(n,r)&&"constructor"!=r&&t.push(r);return t}function De(n){if(!ic(n))return Pi(n);var t=$i(n),r=[];for(var e in n)("constructor"!=e||!t&&yl.call(n,e))&&r.push(e);return r}function Me(n,t){return n<t}function Fe(n,t){var r=-1,e=Vf(n)?el(n.length):[];return vs(n,function(n,u,i){
e[++r]=t(n,u,i)}),e}function Ne(n){var t=mi(n);return 1==t.length&&t[0][2]?Mi(t[0][0],t[0][1]):function(r){return r===n||We(r,n,t)}}function Pe(n,t){return Ci(n)&&Di(t)?Mi(Qi(n),t):function(r){var e=$c(r,n);return e===Y&&e===t?Mc(r,n):ze(t,e,an|ln)}}function qe(n,t,r,e,u){n!==t&&ys(t,function(i,o){if(u||(u=new dr),ic(i))Ze(n,t,o,r,qe,e,u);else{var f=e?e(Gi(n,o),i,o+"",n,t,u):Y;f===Y&&(f=i),Rr(n,o,f)}},Nc)}function Ze(n,t,r,e,u,i,o){var f=Gi(n,r),c=Gi(t,r),a=o.get(c);if(a)return Rr(n,r,a),Y;var l=i?i(f,c,r+"",n,t,o):Y,s=l===Y;
if(s){var h=yh(c),p=!h&&bh(c),_=!h&&!p&&Ah(c);l=c,h||p||_?yh(f)?l=f:Gf(f)?l=Uu(f):p?(s=!1,l=ku(c,!0)):_?(s=!1,l=Eu(c,!0)):l=[]:_c(c)||gh(c)?(l=f,gh(f)?l=Oc(f):ic(f)&&!rc(f)||(l=Ri(c))):s=!1}s&&(o.set(c,l),u(l,c,e,i,o),o.delete(c)),Rr(n,r,l)}function Ke(n,t){var r=n.length;if(r)return t+=t<0?r:0,Wi(t,r)?n[t]:Y}function Ve(n,t,r){t=t.length?c(t,function(n){return yh(n)?function(t){return ve(t,1===n.length?n[0]:n)}:n}):[Sa];var e=-1;return t=c(t,R(bi())),A(Fe(n,function(n,r,u){return{criteria:c(t,function(t){
return t(n)}),index:++e,value:n}}),function(n,t){return Wu(n,t,r)})}function Ge(n,t){return He(n,t,function(t,r){return Mc(n,r)})}function He(n,t,r){for(var e=-1,u=t.length,i={};++e<u;){var o=t[e],f=ve(n,o);r(f,o)&&iu(i,ju(o,n),f)}return i}function Je(n){return function(t){return ve(t,n)}}function Ye(n,t,r,e){var u=e?d:y,i=-1,o=t.length,f=n;for(n===t&&(t=Uu(t)),r&&(f=c(n,R(r)));++i<o;)for(var a=0,l=t[i],s=r?r(l):l;(a=u(f,s,a,e))>-1;)f!==n&&Sl.call(f,a,1),Sl.call(n,a,1);return n}function Qe(n,t){for(var r=n?t.length:0,e=r-1;r--;){
var u=t[r];if(r==e||u!==i){var i=u;Wi(u)?Sl.call(n,u,1):vu(n,u)}}return n}function Xe(n,t){return n+Ml(Jl()*(t-n+1))}function nu(n,t,r,e){for(var u=-1,i=Kl(Dl((t-n)/(r||1)),0),o=el(i);i--;)o[e?i:++u]=n,n+=r;return o}function tu(n,t){var r="";if(!n||t<1||t>zn)return r;do t%2&&(r+=n),t=Ml(t/2),t&&(n+=n);while(t);return r}function ru(n,t){return Ss(Zi(n,t,Sa),n+"")}function eu(n){return kr(na(n))}function uu(n,t){var r=na(n);return Yi(r,$r(t,0,r.length))}function iu(n,t,r,e){if(!ic(n))return n;t=ju(t,n);
for(var u=-1,i=t.length,o=i-1,f=n;null!=f&&++u<i;){var c=Qi(t[u]),a=r;if("__proto__"===c||"constructor"===c||"prototype"===c)return n;if(u!=o){var l=f[c];a=e?e(l,c,f):Y,a===Y&&(a=ic(l)?l:Wi(t[u+1])?[]:{})}zr(f,c,a),f=f[c]}return n}function ou(n){return Yi(na(n))}function fu(n,t,r){var e=-1,u=n.length;t<0&&(t=-t>u?0:u+t),r=r>u?u:r,r<0&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0;for(var i=el(u);++e<u;)i[e]=n[e+t];return i}function cu(n,t){var r;return vs(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}function au(n,t,r){
var e=0,u=null==n?e:n.length;if("number"==typeof t&&t===t&&u<=Cn){for(;e<u;){var i=e+u>>>1,o=n[i];null!==o&&!yc(o)&&(r?o<=t:o<t)?e=i+1:u=i}return u}return lu(n,t,Sa,r)}function lu(n,t,r,e){var u=0,i=null==n?0:n.length;if(0===i)return 0;t=r(t);for(var o=t!==t,f=null===t,c=yc(t),a=t===Y;u<i;){var l=Ml((u+i)/2),s=r(n[l]),h=s!==Y,p=null===s,_=s===s,v=yc(s);if(o)var g=e||_;else g=a?_&&(e||h):f?_&&h&&(e||!p):c?_&&h&&!p&&(e||!v):!p&&!v&&(e?s<=t:s<t);g?u=l+1:i=l}return Vl(i,Ln)}function su(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){
var o=n[r],f=t?t(o):o;if(!r||!Kf(f,c)){var c=f;i[u++]=0===o?0:o}}return i}function hu(n){return"number"==typeof n?n:yc(n)?Sn:+n}function pu(n){if("string"==typeof n)return n;if(yh(n))return c(n,pu)+"";if(yc(n))return ps?ps.call(n):"";var t=n+"";return"0"==t&&1/n==-Rn?"-0":t}function _u(n,t,r){var e=-1,u=o,i=n.length,c=!0,a=[],l=a;if(r)c=!1,u=f;else if(i>=X){var s=t?null:js(n);if(s)return N(s);c=!1,u=E,l=new vr}else l=t?[]:a;n:for(;++e<i;){var h=n[e],p=t?t(h):h;if(h=r||0!==h?h:0,c&&p===p){for(var _=l.length;_--;)if(l[_]===p)continue n;
t&&l.push(p),a.push(h)}else u(l,p,r)||(l!==a&&l.push(p),a.push(h))}return a}function vu(n,t){return t=ju(t,n),n=Ki(n,t),null==n||delete n[Qi(mo(t))]}function gu(n,t,r,e){return iu(n,t,r(ve(n,t)),e)}function yu(n,t,r,e){for(var u=n.length,i=e?u:-1;(e?i--:++i<u)&&t(n[i],i,n););return r?fu(n,e?0:i,e?i+1:u):fu(n,e?i+1:0,e?u:i)}function du(n,t){var r=n;return r instanceof Bt&&(r=r.value()),l(t,function(n,t){return t.func.apply(t.thisArg,a([n],t.args))},r)}function bu(n,t,r){var e=n.length;if(e<2)return e?_u(n[0]):[];
for(var u=-1,i=el(e);++u<e;)for(var o=n[u],f=-1;++f<e;)f!=u&&(i[u]=Vr(i[u]||o,n[f],t,r));return _u(te(i,1),t,r)}function wu(n,t,r){for(var e=-1,u=n.length,i=t.length,o={};++e<u;){r(o,n[e],e<i?t[e]:Y)}return o}function mu(n){return Gf(n)?n:[]}function xu(n){return"function"==typeof n?n:Sa}function ju(n,t){return yh(n)?n:Ci(n,t)?[n]:Ws(Rc(n))}function Au(n,t,r){var e=n.length;return r=r===Y?e:r,!t&&r>=e?n:fu(n,t,r)}function ku(n,t){if(t)return n.slice();var r=n.length,e=Il?Il(r):new n.constructor(r);
return n.copy(e),e}function Ou(n){var t=new n.constructor(n.byteLength);return new Ol(t).set(new Ol(n)),t}function Iu(n,t){return new n.constructor(t?Ou(n.buffer):n.buffer,n.byteOffset,n.byteLength)}function Ru(n){var t=new n.constructor(n.source,Dt.exec(n));return t.lastIndex=n.lastIndex,t}function zu(n){return hs?cl(hs.call(n)):{}}function Eu(n,t){return new n.constructor(t?Ou(n.buffer):n.buffer,n.byteOffset,n.length)}function Su(n,t){if(n!==t){var r=n!==Y,e=null===n,u=n===n,i=yc(n),o=t!==Y,f=null===t,c=t===t,a=yc(t);
if(!f&&!a&&!i&&n>t||i&&o&&c&&!f&&!a||e&&o&&c||!r&&c||!u)return 1;if(!e&&!i&&!a&&n<t||a&&r&&u&&!e&&!i||f&&r&&u||!o&&u||!c)return-1}return 0}function Wu(n,t,r){for(var e=-1,u=n.criteria,i=t.criteria,o=u.length,f=r.length;++e<o;){var c=Su(u[e],i[e]);if(c){if(e>=f)return c;return c*("desc"==r[e]?-1:1)}}return n.index-t.index}function Lu(n,t,r,e){for(var u=-1,i=n.length,o=r.length,f=-1,c=t.length,a=Kl(i-o,0),l=el(c+a),s=!e;++f<c;)l[f]=t[f];for(;++u<o;)(s||u<i)&&(l[r[u]]=n[u]);for(;a--;)l[f++]=n[u++];return l;
}function Cu(n,t,r,e){for(var u=-1,i=n.length,o=-1,f=r.length,c=-1,a=t.length,l=Kl(i-f,0),s=el(l+a),h=!e;++u<l;)s[u]=n[u];for(var p=u;++c<a;)s[p+c]=t[c];for(;++o<f;)(h||u<i)&&(s[p+r[o]]=n[u++]);return s}function Uu(n,t){var r=-1,e=n.length;for(t||(t=el(e));++r<e;)t[r]=n[r];return t}function Bu(n,t,r,e){var u=!r;r||(r={});for(var i=-1,o=t.length;++i<o;){var f=t[i],c=e?e(r[f],n[f],f,r,n):Y;c===Y&&(c=n[f]),u?Cr(r,f,c):zr(r,f,c)}return r}function Tu(n,t){return Bu(n,ks(n),t)}function $u(n,t){return Bu(n,Os(n),t);
}function Du(n,r){return function(e,u){var i=yh(e)?t:Sr,o=r?r():{};return i(e,n,bi(u,2),o)}}function Mu(n){return ru(function(t,r){var e=-1,u=r.length,i=u>1?r[u-1]:Y,o=u>2?r[2]:Y;for(i=n.length>3&&"function"==typeof i?(u--,i):Y,o&&Li(r[0],r[1],o)&&(i=u<3?Y:i,u=1),t=cl(t);++e<u;){var f=r[e];f&&n(t,f,e,i)}return t})}function Fu(n,t){return function(r,e){if(null==r)return r;if(!Vf(r))return n(r,e);for(var u=r.length,i=t?u:-1,o=cl(r);(t?i--:++i<u)&&e(o[i],i,o)!==!1;);return r}}function Nu(n){return function(t,r,e){
for(var u=-1,i=cl(t),o=e(t),f=o.length;f--;){var c=o[n?f:++u];if(r(i[c],c,i)===!1)break}return t}}function Pu(n,t,r){function e(){return(this&&this!==Xr&&this instanceof e?i:n).apply(u?r:this,arguments)}var u=t&sn,i=Ku(n);return e}function qu(n){return function(t){t=Rc(t);var r=B(t)?V(t):Y,e=r?r[0]:t.charAt(0),u=r?Au(r,1).join(""):t.slice(1);return e[n]()+u}}function Zu(n){return function(t){return l(Oa(oa(t).replace(Ur,"")),n,"")}}function Ku(n){return function(){var t=arguments;switch(t.length){
case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=_s(n.prototype),e=n.apply(r,t);return ic(e)?e:r}}function Vu(t,r,e){function u(){for(var o=arguments.length,f=el(o),c=o,a=di(u);c--;)f[c]=arguments[c];var l=o<3&&f[0]!==a&&f[o-1]!==a?[]:F(f,a);
return o-=l.length,o<e?ui(t,r,Ju,u.placeholder,Y,f,l,Y,Y,e-o):n(this&&this!==Xr&&this instanceof u?i:t,this,f)}var i=Ku(t);return u}function Gu(n){return function(t,r,e){var u=cl(t);if(!Vf(t)){var i=bi(r,3);t=Fc(t),r=function(n){return i(u[n],n,u)}}var o=n(t,r,e);return o>-1?u[i?t[o]:o]:Y}}function Hu(n){return _i(function(t){var r=t.length,e=r,u=H.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if("function"!=typeof i)throw new sl(tn);if(u&&!o&&"wrapper"==yi(i))var o=new H([],!0)}for(e=o?e:r;++e<r;){
i=t[e];var f=yi(i),c="wrapper"==f?As(i):Y;o=c&&Bi(c[0])&&c[1]==(dn|_n|gn|bn)&&!c[4].length&&1==c[9]?o[yi(c[0])].apply(o,c[3]):1==i.length&&Bi(i)?o[f]():o.thru(i)}return function(){var n=arguments,e=n[0];if(o&&1==n.length&&yh(e))return o.plant(e).value();for(var u=0,i=r?t[u].apply(this,n):e;++u<r;)i=t[u].call(this,i);return i}})}function Ju(n,t,r,e,u,i,o,f,c,a){function l(){for(var y=arguments.length,d=el(y),b=y;b--;)d[b]=arguments[b];if(_)var w=di(l),m=L(d,w);if(e&&(d=Lu(d,e,u,_)),i&&(d=Cu(d,i,o,_)),
y-=m,_&&y<a){return ui(n,t,Ju,l.placeholder,r,d,F(d,w),f,c,a-y)}var x=h?r:this,j=p?x[n]:n;return y=d.length,f?d=Vi(d,f):v&&y>1&&d.reverse(),s&&c<y&&(d.length=c),this&&this!==Xr&&this instanceof l&&(j=g||Ku(j)),j.apply(x,d)}var s=t&dn,h=t&sn,p=t&hn,_=t&(_n|vn),v=t&wn,g=p?Y:Ku(n);return l}function Yu(n,t){return function(r,e){return Ae(r,n,t(e),{})}}function Qu(n,t){return function(r,e){var u;if(r===Y&&e===Y)return t;if(r!==Y&&(u=r),e!==Y){if(u===Y)return e;"string"==typeof r||"string"==typeof e?(r=pu(r),
e=pu(e)):(r=hu(r),e=hu(e)),u=n(r,e)}return u}}function Xu(t){return _i(function(r){return r=c(r,R(bi())),ru(function(e){var u=this;return t(r,function(t){return n(t,u,e)})})})}function ni(n,t){t=t===Y?" ":pu(t);var r=t.length;if(r<2)return r?tu(t,n):t;var e=tu(t,Dl(n/K(t)));return B(t)?Au(V(e),0,n).join(""):e.slice(0,n)}function ti(t,r,e,u){function i(){for(var r=-1,c=arguments.length,a=-1,l=u.length,s=el(l+c),h=this&&this!==Xr&&this instanceof i?f:t;++a<l;)s[a]=u[a];for(;c--;)s[a++]=arguments[++r];
return n(h,o?e:this,s)}var o=r&sn,f=Ku(t);return i}function ri(n){return function(t,r,e){return e&&"number"!=typeof e&&Li(t,r,e)&&(r=e=Y),t=xc(t),r===Y?(r=t,t=0):r=xc(r),e=e===Y?t<r?1:-1:xc(e),nu(t,r,e,n)}}function ei(n){return function(t,r){return"string"==typeof t&&"string"==typeof r||(t=kc(t),r=kc(r)),n(t,r)}}function ui(n,t,r,e,u,i,o,f,c,a){var l=t&_n,s=l?o:Y,h=l?Y:o,p=l?i:Y,_=l?Y:i;t|=l?gn:yn,t&=~(l?yn:gn),t&pn||(t&=~(sn|hn));var v=[n,t,u,p,s,_,h,f,c,a],g=r.apply(Y,v);return Bi(n)&&zs(g,v),g.placeholder=e,
Hi(g,n,t)}function ii(n){var t=fl[n];return function(n,r){if(n=kc(n),r=null==r?0:Vl(jc(r),292),r&&Pl(n)){var e=(Rc(n)+"e").split("e");return e=(Rc(t(e[0]+"e"+(+e[1]+r)))+"e").split("e"),+(e[0]+"e"+(+e[1]-r))}return t(n)}}function oi(n){return function(t){var r=Is(t);return r==Zn?D(t):r==Qn?P(t):I(t,n(t))}}function fi(n,t,r,e,u,i,o,f){var c=t&hn;if(!c&&"function"!=typeof n)throw new sl(tn);var a=e?e.length:0;if(a||(t&=~(gn|yn),e=u=Y),o=o===Y?o:Kl(jc(o),0),f=f===Y?f:jc(f),a-=u?u.length:0,t&yn){var l=e,s=u;
e=u=Y}var h=c?Y:As(n),p=[n,t,r,e,u,l,s,i,o,f];if(h&&Ni(p,h),n=p[0],t=p[1],r=p[2],e=p[3],u=p[4],f=p[9]=p[9]===Y?c?0:n.length:Kl(p[9]-a,0),!f&&t&(_n|vn)&&(t&=~(_n|vn)),t&&t!=sn)_=t==_n||t==vn?Vu(n,t,f):t!=gn&&t!=(sn|gn)||u.length?Ju.apply(Y,p):ti(n,t,r,e);else var _=Pu(n,t,r);return Hi((h?bs:zs)(_,p),n,t)}function ci(n,t,r,e){return n===Y||Kf(n,_l[r])&&!yl.call(e,r)?t:n}function ai(n,t,r,e,u,i){return ic(n)&&ic(t)&&(i.set(t,n),qe(n,t,Y,ai,i),i.delete(t)),n}function li(n){return _c(n)?Y:n}function si(n,t,r,e,u,i){
var o=r&an,f=n.length,c=t.length;if(f!=c&&!(o&&c>f))return!1;var a=i.get(n),l=i.get(t);if(a&&l)return a==t&&l==n;var s=-1,p=!0,_=r&ln?new vr:Y;for(i.set(n,t),i.set(t,n);++s<f;){var v=n[s],g=t[s];if(e)var y=o?e(g,v,s,t,n,i):e(v,g,s,n,t,i);if(y!==Y){if(y)continue;p=!1;break}if(_){if(!h(t,function(n,t){if(!E(_,t)&&(v===n||u(v,n,r,e,i)))return _.push(t)})){p=!1;break}}else if(v!==g&&!u(v,g,r,e,i)){p=!1;break}}return i.delete(n),i.delete(t),p}function hi(n,t,r,e,u,i,o){switch(r){case it:if(n.byteLength!=t.byteLength||n.byteOffset!=t.byteOffset)return!1;
n=n.buffer,t=t.buffer;case ut:return!(n.byteLength!=t.byteLength||!i(new Ol(n),new Ol(t)));case Dn:case Mn:case Kn:return Kf(+n,+t);case Nn:return n.name==t.name&&n.message==t.message;case Yn:case Xn:return n==t+"";case Zn:var f=D;case Qn:var c=e&an;if(f||(f=N),n.size!=t.size&&!c)return!1;var a=o.get(n);if(a)return a==t;e|=ln,o.set(n,t);var l=si(f(n),f(t),e,u,i,o);return o.delete(n),l;case nt:if(hs)return hs.call(n)==hs.call(t)}return!1}function pi(n,t,r,e,u,i){var o=r&an,f=vi(n),c=f.length;if(c!=vi(t).length&&!o)return!1;
for(var a=c;a--;){var l=f[a];if(!(o?l in t:yl.call(t,l)))return!1}var s=i.get(n),h=i.get(t);if(s&&h)return s==t&&h==n;var p=!0;i.set(n,t),i.set(t,n);for(var _=o;++a<c;){l=f[a];var v=n[l],g=t[l];if(e)var y=o?e(g,v,l,t,n,i):e(v,g,l,n,t,i);if(!(y===Y?v===g||u(v,g,r,e,i):y)){p=!1;break}_||(_="constructor"==l)}if(p&&!_){var d=n.constructor,b=t.constructor;d!=b&&"constructor"in n&&"constructor"in t&&!("function"==typeof d&&d instanceof d&&"function"==typeof b&&b instanceof b)&&(p=!1)}return i.delete(n),
i.delete(t),p}function _i(n){return Ss(Zi(n,Y,ho),n+"")}function vi(n){return ye(n,Fc,ks)}function gi(n){return ye(n,Nc,Os)}function yi(n){for(var t=n.name+"",r=is[t],e=yl.call(is,t)?r.length:0;e--;){var u=r[e],i=u.func;if(null==i||i==n)return u.name}return t}function di(n){return(yl.call(q,"placeholder")?q:n).placeholder}function bi(){var n=q.iteratee||Wa;return n=n===Wa?Te:n,arguments.length?n(arguments[0],arguments[1]):n}function wi(n,t){var r=n.__data__;return Ui(t)?r["string"==typeof t?"string":"hash"]:r.map;
}function mi(n){for(var t=Fc(n),r=t.length;r--;){var e=t[r],u=n[e];t[r]=[e,u,Di(u)]}return t}function xi(n,t){var r=U(n,t);return Le(r)?r:Y}function ji(n){var t=yl.call(n,Cl),r=n[Cl];try{n[Cl]=Y;var e=!0}catch(n){}var u=wl.call(n);return e&&(t?n[Cl]=r:delete n[Cl]),u}function Ai(n,t,r){for(var e=-1,u=r.length;++e<u;){var i=r[e],o=i.size;switch(i.type){case"drop":n+=o;break;case"dropRight":t-=o;break;case"take":t=Vl(t,n+o);break;case"takeRight":n=Kl(n,t-o)}}return{start:n,end:t}}function ki(n){var t=n.match(Ct);
return t?t[1].split(Ut):[]}function Oi(n,t,r){t=ju(t,n);for(var e=-1,u=t.length,i=!1;++e<u;){var o=Qi(t[e]);if(!(i=null!=n&&r(n,o)))break;n=n[o]}return i||++e!=u?i:(u=null==n?0:n.length,!!u&&uc(u)&&Wi(o,u)&&(yh(n)||gh(n)))}function Ii(n){var t=n.length,r=new n.constructor(t);return t&&"string"==typeof n[0]&&yl.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function Ri(n){return"function"!=typeof n.constructor||$i(n)?{}:_s(Rl(n))}function zi(n,t,r){var e=n.constructor;switch(t){case ut:return Ou(n);
case Dn:case Mn:return new e(+n);case it:return Iu(n,r);case ot:case ft:case ct:case at:case lt:case st:case ht:case pt:case _t:return Eu(n,r);case Zn:return new e;case Kn:case Xn:return new e(n);case Yn:return Ru(n);case Qn:return new e;case nt:return zu(n)}}function Ei(n,t){var r=t.length;if(!r)return n;var e=r-1;return t[e]=(r>1?"& ":"")+t[e],t=t.join(r>2?", ":" "),n.replace(Lt,"{\n/* [wrapped with "+t+"] */\n")}function Si(n){return yh(n)||gh(n)||!!(Wl&&n&&n[Wl])}function Wi(n,t){var r=typeof n;
return t=null==t?zn:t,!!t&&("number"==r||"symbol"!=r&&qt.test(n))&&n>-1&&n%1==0&&n<t}function Li(n,t,r){if(!ic(r))return!1;var e=typeof t;return!!("number"==e?Vf(r)&&Wi(t,r.length):"string"==e&&t in r)&&Kf(r[t],n)}function Ci(n,t){if(yh(n))return!1;var r=typeof n;return!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=n&&!yc(n))||(Ot.test(n)||!kt.test(n)||null!=t&&n in cl(t))}function Ui(n){var t=typeof n;return"string"==t||"number"==t||"symbol"==t||"boolean"==t?"__proto__"!==n:null===n}function Bi(n){
var t=yi(n),r=q[t];if("function"!=typeof r||!(t in Bt.prototype))return!1;if(n===r)return!0;var e=As(r);return!!e&&n===e[0]}function Ti(n){return!!bl&&bl in n}function $i(n){var t=n&&n.constructor;return n===("function"==typeof t&&t.prototype||_l)}function Di(n){return n===n&&!ic(n)}function Mi(n,t){return function(r){return null!=r&&(r[n]===t&&(t!==Y||n in cl(r)))}}function Fi(n){var t=Wf(n,function(n){return r.size===en&&r.clear(),n}),r=t.cache;return t}function Ni(n,t){var r=n[1],e=t[1],u=r|e,i=u<(sn|hn|dn),o=e==dn&&r==_n||e==dn&&r==bn&&n[7].length<=t[8]||e==(dn|bn)&&t[7].length<=t[8]&&r==_n;
if(!i&&!o)return n;e&sn&&(n[2]=t[2],u|=r&sn?0:pn);var f=t[3];if(f){var c=n[3];n[3]=c?Lu(c,f,t[4]):f,n[4]=c?F(n[3],un):t[4]}return f=t[5],f&&(c=n[5],n[5]=c?Cu(c,f,t[6]):f,n[6]=c?F(n[5],un):t[6]),f=t[7],f&&(n[7]=f),e&dn&&(n[8]=null==n[8]?t[8]:Vl(n[8],t[8])),null==n[9]&&(n[9]=t[9]),n[0]=t[0],n[1]=u,n}function Pi(n){var t=[];if(null!=n)for(var r in cl(n))t.push(r);return t}function qi(n){return wl.call(n)}function Zi(t,r,e){return r=Kl(r===Y?t.length-1:r,0),function(){for(var u=arguments,i=-1,o=Kl(u.length-r,0),f=el(o);++i<o;)f[i]=u[r+i];
i=-1;for(var c=el(r+1);++i<r;)c[i]=u[i];return c[r]=e(f),n(t,this,c)}}function Ki(n,t){return t.length<2?n:ve(n,fu(t,0,-1))}function Vi(n,t){for(var r=n.length,e=Vl(t.length,r),u=Uu(n);e--;){var i=t[e];n[e]=Wi(i,r)?u[i]:Y}return n}function Gi(n,t){if(("constructor"!==t||"function"!=typeof n[t])&&"__proto__"!=t)return n[t]}function Hi(n,t,r){var e=t+"";return Ss(n,Ei(e,no(ki(e),r)))}function Ji(n){var t=0,r=0;return function(){var e=Gl(),u=An-(e-r);if(r=e,u>0){if(++t>=jn)return arguments[0]}else t=0;
return n.apply(Y,arguments)}}function Yi(n,t){var r=-1,e=n.length,u=e-1;for(t=t===Y?e:t;++r<t;){var i=Xe(r,u),o=n[i];n[i]=n[r],n[r]=o}return n.length=t,n}function Qi(n){if("string"==typeof n||yc(n))return n;var t=n+"";return"0"==t&&1/n==-Rn?"-0":t}function Xi(n){if(null!=n){try{return gl.call(n)}catch(n){}try{return n+""}catch(n){}}return""}function no(n,t){return r(Un,function(r){var e="_."+r[0];t&r[1]&&!o(n,e)&&n.push(e)}),n.sort()}function to(n){if(n instanceof Bt)return n.clone();var t=new H(n.__wrapped__,n.__chain__);
return t.__actions__=Uu(n.__actions__),t.__index__=n.__index__,t.__values__=n.__values__,t}function ro(n,t,r){t=(r?Li(n,t,r):t===Y)?1:Kl(jc(t),0);var e=null==n?0:n.length;if(!e||t<1)return[];for(var u=0,i=0,o=el(Dl(e/t));u<e;)o[i++]=fu(n,u,u+=t);return o}function eo(n){for(var t=-1,r=null==n?0:n.length,e=0,u=[];++t<r;){var i=n[t];i&&(u[e++]=i)}return u}function uo(){var n=arguments.length;if(!n)return[];for(var t=el(n-1),r=arguments[0],e=n;e--;)t[e-1]=arguments[e];return a(yh(r)?Uu(r):[r],te(t,1));
}function io(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===Y?1:jc(t),fu(n,t<0?0:t,e)):[]}function oo(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===Y?1:jc(t),t=e-t,fu(n,0,t<0?0:t)):[]}function fo(n,t){return n&&n.length?yu(n,bi(t,3),!0,!0):[]}function co(n,t){return n&&n.length?yu(n,bi(t,3),!0):[]}function ao(n,t,r,e){var u=null==n?0:n.length;return u?(r&&"number"!=typeof r&&Li(n,t,r)&&(r=0,e=u),Qr(n,t,r,e)):[]}function lo(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=null==r?0:jc(r);
return u<0&&(u=Kl(e+u,0)),g(n,bi(t,3),u)}function so(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e-1;return r!==Y&&(u=jc(r),u=r<0?Kl(e+u,0):Vl(u,e-1)),g(n,bi(t,3),u,!0)}function ho(n){return(null==n?0:n.length)?te(n,1):[]}function po(n){return(null==n?0:n.length)?te(n,Rn):[]}function _o(n,t){return(null==n?0:n.length)?(t=t===Y?1:jc(t),te(n,t)):[]}function vo(n){for(var t=-1,r=null==n?0:n.length,e={};++t<r;){var u=n[t];e[u[0]]=u[1]}return e}function go(n){return n&&n.length?n[0]:Y}function yo(n,t,r){
var e=null==n?0:n.length;if(!e)return-1;var u=null==r?0:jc(r);return u<0&&(u=Kl(e+u,0)),y(n,t,u)}function bo(n){return(null==n?0:n.length)?fu(n,0,-1):[]}function wo(n,t){return null==n?"":ql.call(n,t)}function mo(n){var t=null==n?0:n.length;return t?n[t-1]:Y}function xo(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e;return r!==Y&&(u=jc(r),u=u<0?Kl(e+u,0):Vl(u,e-1)),t===t?Z(n,t,u):g(n,b,u,!0)}function jo(n,t){return n&&n.length?Ke(n,jc(t)):Y}function Ao(n,t){return n&&n.length&&t&&t.length?Ye(n,t):n;
}function ko(n,t,r){return n&&n.length&&t&&t.length?Ye(n,t,bi(r,2)):n}function Oo(n,t,r){return n&&n.length&&t&&t.length?Ye(n,t,Y,r):n}function Io(n,t){var r=[];if(!n||!n.length)return r;var e=-1,u=[],i=n.length;for(t=bi(t,3);++e<i;){var o=n[e];t(o,e,n)&&(r.push(o),u.push(e))}return Qe(n,u),r}function Ro(n){return null==n?n:Yl.call(n)}function zo(n,t,r){var e=null==n?0:n.length;return e?(r&&"number"!=typeof r&&Li(n,t,r)?(t=0,r=e):(t=null==t?0:jc(t),r=r===Y?e:jc(r)),fu(n,t,r)):[]}function Eo(n,t){
return au(n,t)}function So(n,t,r){return lu(n,t,bi(r,2))}function Wo(n,t){var r=null==n?0:n.length;if(r){var e=au(n,t);if(e<r&&Kf(n[e],t))return e}return-1}function Lo(n,t){return au(n,t,!0)}function Co(n,t,r){return lu(n,t,bi(r,2),!0)}function Uo(n,t){if(null==n?0:n.length){var r=au(n,t,!0)-1;if(Kf(n[r],t))return r}return-1}function Bo(n){return n&&n.length?su(n):[]}function To(n,t){return n&&n.length?su(n,bi(t,2)):[]}function $o(n){var t=null==n?0:n.length;return t?fu(n,1,t):[]}function Do(n,t,r){
return n&&n.length?(t=r||t===Y?1:jc(t),fu(n,0,t<0?0:t)):[]}function Mo(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===Y?1:jc(t),t=e-t,fu(n,t<0?0:t,e)):[]}function Fo(n,t){return n&&n.length?yu(n,bi(t,3),!1,!0):[]}function No(n,t){return n&&n.length?yu(n,bi(t,3)):[]}function Po(n){return n&&n.length?_u(n):[]}function qo(n,t){return n&&n.length?_u(n,bi(t,2)):[]}function Zo(n,t){return t="function"==typeof t?t:Y,n&&n.length?_u(n,Y,t):[]}function Ko(n){if(!n||!n.length)return[];var t=0;return n=i(n,function(n){
if(Gf(n))return t=Kl(n.length,t),!0}),O(t,function(t){return c(n,m(t))})}function Vo(t,r){if(!t||!t.length)return[];var e=Ko(t);return null==r?e:c(e,function(t){return n(r,Y,t)})}function Go(n,t){return wu(n||[],t||[],zr)}function Ho(n,t){return wu(n||[],t||[],iu)}function Jo(n){var t=q(n);return t.__chain__=!0,t}function Yo(n,t){return t(n),n}function Qo(n,t){return t(n)}function Xo(){return Jo(this)}function nf(){return new H(this.value(),this.__chain__)}function tf(){this.__values__===Y&&(this.__values__=mc(this.value()));
var n=this.__index__>=this.__values__.length;return{done:n,value:n?Y:this.__values__[this.__index__++]}}function rf(){return this}function ef(n){for(var t,r=this;r instanceof G;){var e=to(r);e.__index__=0,e.__values__=Y,t?u.__wrapped__=e:t=e;var u=e;r=r.__wrapped__}return u.__wrapped__=n,t}function uf(){var n=this.__wrapped__;if(n instanceof Bt){var t=n;return this.__actions__.length&&(t=new Bt(this)),t=t.reverse(),t.__actions__.push({func:Qo,args:[Ro],thisArg:Y}),new H(t,this.__chain__)}return this.thru(Ro);
}function of(){return du(this.__wrapped__,this.__actions__)}function ff(n,t,r){var e=yh(n)?u:Gr;return r&&Li(n,t,r)&&(t=Y),e(n,bi(t,3))}function cf(n,t){return(yh(n)?i:ne)(n,bi(t,3))}function af(n,t){return te(vf(n,t),1)}function lf(n,t){return te(vf(n,t),Rn)}function sf(n,t,r){return r=r===Y?1:jc(r),te(vf(n,t),r)}function hf(n,t){return(yh(n)?r:vs)(n,bi(t,3))}function pf(n,t){return(yh(n)?e:gs)(n,bi(t,3))}function _f(n,t,r,e){n=Vf(n)?n:na(n),r=r&&!e?jc(r):0;var u=n.length;return r<0&&(r=Kl(u+r,0)),
gc(n)?r<=u&&n.indexOf(t,r)>-1:!!u&&y(n,t,r)>-1}function vf(n,t){return(yh(n)?c:Fe)(n,bi(t,3))}function gf(n,t,r,e){return null==n?[]:(yh(t)||(t=null==t?[]:[t]),r=e?Y:r,yh(r)||(r=null==r?[]:[r]),Ve(n,t,r))}function yf(n,t,r){var e=yh(n)?l:j,u=arguments.length<3;return e(n,bi(t,4),r,u,vs)}function df(n,t,r){var e=yh(n)?s:j,u=arguments.length<3;return e(n,bi(t,4),r,u,gs)}function bf(n,t){return(yh(n)?i:ne)(n,Lf(bi(t,3)))}function wf(n){return(yh(n)?kr:eu)(n)}function mf(n,t,r){return t=(r?Li(n,t,r):t===Y)?1:jc(t),
(yh(n)?Or:uu)(n,t)}function xf(n){return(yh(n)?Ir:ou)(n)}function jf(n){if(null==n)return 0;if(Vf(n))return gc(n)?K(n):n.length;var t=Is(n);return t==Zn||t==Qn?n.size:$e(n).length}function Af(n,t,r){var e=yh(n)?h:cu;return r&&Li(n,t,r)&&(t=Y),e(n,bi(t,3))}function kf(n,t){if("function"!=typeof t)throw new sl(tn);return n=jc(n),function(){if(--n<1)return t.apply(this,arguments)}}function Of(n,t,r){return t=r?Y:t,t=n&&null==t?n.length:t,fi(n,dn,Y,Y,Y,Y,t)}function If(n,t){var r;if("function"!=typeof t)throw new sl(tn);
return n=jc(n),function(){return--n>0&&(r=t.apply(this,arguments)),n<=1&&(t=Y),r}}function Rf(n,t,r){t=r?Y:t;var e=fi(n,_n,Y,Y,Y,Y,Y,t);return e.placeholder=Rf.placeholder,e}function zf(n,t,r){t=r?Y:t;var e=fi(n,vn,Y,Y,Y,Y,Y,t);return e.placeholder=zf.placeholder,e}function Ef(n,t,r){function e(t){var r=h,e=p;return h=p=Y,d=t,v=n.apply(e,r)}function u(n){return d=n,g=Es(f,t),b?e(n):v}function i(n){var r=n-y,e=n-d,u=t-r;return w?Vl(u,_-e):u}function o(n){var r=n-y,e=n-d;return y===Y||r>=t||r<0||w&&e>=_;
}function f(){var n=ih();return o(n)?c(n):(g=Es(f,i(n)),Y)}function c(n){return g=Y,m&&h?e(n):(h=p=Y,v)}function a(){g!==Y&&xs(g),d=0,h=y=p=g=Y}function l(){return g===Y?v:c(ih())}function s(){var n=ih(),r=o(n);if(h=arguments,p=this,y=n,r){if(g===Y)return u(y);if(w)return xs(g),g=Es(f,t),e(y)}return g===Y&&(g=Es(f,t)),v}var h,p,_,v,g,y,d=0,b=!1,w=!1,m=!0;if("function"!=typeof n)throw new sl(tn);return t=kc(t)||0,ic(r)&&(b=!!r.leading,w="maxWait"in r,_=w?Kl(kc(r.maxWait)||0,t):_,m="trailing"in r?!!r.trailing:m),
s.cancel=a,s.flush=l,s}function Sf(n){return fi(n,wn)}function Wf(n,t){if("function"!=typeof n||null!=t&&"function"!=typeof t)throw new sl(tn);var r=function(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;if(i.has(u))return i.get(u);var o=n.apply(this,e);return r.cache=i.set(u,o)||i,o};return r.cache=new(Wf.Cache||ar),r}function Lf(n){if("function"!=typeof n)throw new sl(tn);return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:
return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function Cf(n){return If(2,n)}function Uf(n,t){if("function"!=typeof n)throw new sl(tn);return t=t===Y?t:jc(t),ru(n,t)}function Bf(t,r){if("function"!=typeof t)throw new sl(tn);return r=null==r?0:Kl(jc(r),0),ru(function(e){var u=e[r],i=Au(e,0,r);return u&&a(i,u),n(t,this,i)})}function Tf(n,t,r){var e=!0,u=!0;if("function"!=typeof n)throw new sl(tn);return ic(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),
Ef(n,t,{leading:e,maxWait:t,trailing:u})}function $f(n){return Of(n,1)}function Df(n,t){return sh(xu(t),n)}function Mf(){if(!arguments.length)return[];var n=arguments[0];return yh(n)?n:[n]}function Ff(n){return Dr(n,cn)}function Nf(n,t){return t="function"==typeof t?t:Y,Dr(n,cn,t)}function Pf(n){return Dr(n,on|cn)}function qf(n,t){return t="function"==typeof t?t:Y,Dr(n,on|cn,t)}function Zf(n,t){return null==t||Zr(n,t,Fc(t))}function Kf(n,t){return n===t||n!==n&&t!==t}function Vf(n){return null!=n&&uc(n.length)&&!rc(n);
}function Gf(n){return oc(n)&&Vf(n)}function Hf(n){return n===!0||n===!1||oc(n)&&de(n)==Dn}function Jf(n){return oc(n)&&1===n.nodeType&&!_c(n)}function Yf(n){if(null==n)return!0;if(Vf(n)&&(yh(n)||"string"==typeof n||"function"==typeof n.splice||bh(n)||Ah(n)||gh(n)))return!n.length;var t=Is(n);if(t==Zn||t==Qn)return!n.size;if($i(n))return!$e(n).length;for(var r in n)if(yl.call(n,r))return!1;return!0}function Qf(n,t){return ze(n,t)}function Xf(n,t,r){r="function"==typeof r?r:Y;var e=r?r(n,t):Y;return e===Y?ze(n,t,Y,r):!!e;
}function nc(n){if(!oc(n))return!1;var t=de(n);return t==Nn||t==Fn||"string"==typeof n.message&&"string"==typeof n.name&&!_c(n)}function tc(n){return"number"==typeof n&&Pl(n)}function rc(n){if(!ic(n))return!1;var t=de(n);return t==Pn||t==qn||t==$n||t==Jn}function ec(n){return"number"==typeof n&&n==jc(n)}function uc(n){return"number"==typeof n&&n>-1&&n%1==0&&n<=zn}function ic(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function oc(n){return null!=n&&"object"==typeof n}function fc(n,t){
return n===t||We(n,t,mi(t))}function cc(n,t,r){return r="function"==typeof r?r:Y,We(n,t,mi(t),r)}function ac(n){return pc(n)&&n!=+n}function lc(n){if(Rs(n))throw new il(nn);return Le(n)}function sc(n){return null===n}function hc(n){return null==n}function pc(n){return"number"==typeof n||oc(n)&&de(n)==Kn}function _c(n){if(!oc(n)||de(n)!=Gn)return!1;var t=Rl(n);if(null===t)return!0;var r=yl.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&gl.call(r)==ml}function vc(n){
return ec(n)&&n>=-zn&&n<=zn}function gc(n){return"string"==typeof n||!yh(n)&&oc(n)&&de(n)==Xn}function yc(n){return"symbol"==typeof n||oc(n)&&de(n)==nt}function dc(n){return n===Y}function bc(n){return oc(n)&&Is(n)==rt}function wc(n){return oc(n)&&de(n)==et}function mc(n){if(!n)return[];if(Vf(n))return gc(n)?V(n):Uu(n);if(Ll&&n[Ll])return $(n[Ll]());var t=Is(n);return(t==Zn?D:t==Qn?N:na)(n)}function xc(n){if(!n)return 0===n?n:0;if(n=kc(n),n===Rn||n===-Rn){return(n<0?-1:1)*En}return n===n?n:0}function jc(n){
var t=xc(n),r=t%1;return t===t?r?t-r:t:0}function Ac(n){return n?$r(jc(n),0,Wn):0}function kc(n){if("number"==typeof n)return n;if(yc(n))return Sn;if(ic(n)){var t="function"==typeof n.valueOf?n.valueOf():n;n=ic(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(Et,"");var r=Ft.test(n);return r||Pt.test(n)?Jr(n.slice(2),r?2:8):Mt.test(n)?Sn:+n}function Oc(n){return Bu(n,Nc(n))}function Ic(n){return n?$r(jc(n),-zn,zn):0===n?n:0}function Rc(n){return null==n?"":pu(n)}function zc(n,t){var r=_s(n);
return null==t?r:Wr(r,t)}function Ec(n,t){return v(n,bi(t,3),ee)}function Sc(n,t){return v(n,bi(t,3),ue)}function Wc(n,t){return null==n?n:ys(n,bi(t,3),Nc)}function Lc(n,t){return null==n?n:ds(n,bi(t,3),Nc)}function Cc(n,t){return n&&ee(n,bi(t,3))}function Uc(n,t){return n&&ue(n,bi(t,3))}function Bc(n){return null==n?[]:se(n,Fc(n))}function Tc(n){return null==n?[]:se(n,Nc(n))}function $c(n,t,r){var e=null==n?Y:ve(n,t);return e===Y?r:e}function Dc(n,t){return null!=n&&Oi(n,t,we)}function Mc(n,t){return null!=n&&Oi(n,t,me);
}function Fc(n){return Vf(n)?Ar(n):$e(n)}function Nc(n){return Vf(n)?Ar(n,!0):De(n)}function Pc(n,t){var r={};return t=bi(t,3),ee(n,function(n,e,u){Cr(r,t(n,e,u),n)}),r}function qc(n,t){var r={};return t=bi(t,3),ee(n,function(n,e,u){Cr(r,e,t(n,e,u))}),r}function Zc(n,t){return Kc(n,Lf(bi(t)))}function Kc(n,t){if(null==n)return{};var r=c(gi(n),function(n){return[n]});return t=bi(t),He(n,r,function(n,r){return t(n,r[0])})}function Vc(n,t,r){t=ju(t,n);var e=-1,u=t.length;for(u||(u=1,n=Y);++e<u;){var i=null==n?Y:n[Qi(t[e])];
i===Y&&(e=u,i=r),n=rc(i)?i.call(n):i}return n}function Gc(n,t,r){return null==n?n:iu(n,t,r)}function Hc(n,t,r,e){return e="function"==typeof e?e:Y,null==n?n:iu(n,t,r,e)}function Jc(n,t,e){var u=yh(n),i=u||bh(n)||Ah(n);if(t=bi(t,4),null==e){var o=n&&n.constructor;e=i?u?new o:[]:ic(n)&&rc(o)?_s(Rl(n)):{}}return(i?r:ee)(n,function(n,r,u){return t(e,n,r,u)}),e}function Yc(n,t){return null==n||vu(n,t)}function Qc(n,t,r){return null==n?n:gu(n,t,xu(r))}function Xc(n,t,r,e){return e="function"==typeof e?e:Y,
null==n?n:gu(n,t,xu(r),e)}function na(n){return null==n?[]:z(n,Fc(n))}function ta(n){return null==n?[]:z(n,Nc(n))}function ra(n,t,r){return r===Y&&(r=t,t=Y),r!==Y&&(r=kc(r),r=r===r?r:0),t!==Y&&(t=kc(t),t=t===t?t:0),$r(kc(n),t,r)}function ea(n,t,r){return t=xc(t),r===Y?(r=t,t=0):r=xc(r),n=kc(n),xe(n,t,r)}function ua(n,t,r){if(r&&"boolean"!=typeof r&&Li(n,t,r)&&(t=r=Y),r===Y&&("boolean"==typeof t?(r=t,t=Y):"boolean"==typeof n&&(r=n,n=Y)),n===Y&&t===Y?(n=0,t=1):(n=xc(n),t===Y?(t=n,n=0):t=xc(t)),n>t){
var e=n;n=t,t=e}if(r||n%1||t%1){var u=Jl();return Vl(n+u*(t-n+Hr("1e-"+((u+"").length-1))),t)}return Xe(n,t)}function ia(n){return Jh(Rc(n).toLowerCase())}function oa(n){return n=Rc(n),n&&n.replace(Zt,he).replace(Br,"")}function fa(n,t,r){n=Rc(n),t=pu(t);var e=n.length;r=r===Y?e:$r(jc(r),0,e);var u=r;return r-=t.length,r>=0&&n.slice(r,u)==t}function ca(n){return n=Rc(n),n&&mt.test(n)?n.replace(bt,pe):n}function aa(n){return n=Rc(n),n&&zt.test(n)?n.replace(Rt,"\\$&"):n}function la(n,t,r){n=Rc(n),t=jc(t);
var e=t?K(n):0;if(!t||e>=t)return n;var u=(t-e)/2;return ni(Ml(u),r)+n+ni(Dl(u),r)}function sa(n,t,r){n=Rc(n),t=jc(t);var e=t?K(n):0;return t&&e<t?n+ni(t-e,r):n}function ha(n,t,r){n=Rc(n),t=jc(t);var e=t?K(n):0;return t&&e<t?ni(t-e,r)+n:n}function pa(n,t,r){return r||null==t?t=0:t&&(t=+t),Hl(Rc(n).replace(St,""),t||0)}function _a(n,t,r){return t=(r?Li(n,t,r):t===Y)?1:jc(t),tu(Rc(n),t)}function va(){var n=arguments,t=Rc(n[0]);return n.length<3?t:t.replace(n[1],n[2])}function ga(n,t,r){return r&&"number"!=typeof r&&Li(n,t,r)&&(t=r=Y),
(r=r===Y?Wn:r>>>0)?(n=Rc(n),n&&("string"==typeof t||null!=t&&!xh(t))&&(t=pu(t),!t&&B(n))?Au(V(n),0,r):n.split(t,r)):[]}function ya(n,t,r){return n=Rc(n),r=null==r?0:$r(jc(r),0,n.length),t=pu(t),n.slice(r,r+t.length)==t}function da(n,t,r){var e=q.templateSettings;r&&Li(n,t,r)&&(t=Y),n=Rc(n),t=zh({},t,e,ci);var u,i,o=zh({},t.imports,e.imports,ci),f=Fc(o),c=z(o,f),a=0,l=t.interpolate||Kt,s="__p += '",h=al((t.escape||Kt).source+"|"+l.source+"|"+(l===At?$t:Kt).source+"|"+(t.evaluate||Kt).source+"|$","g"),p="//# sourceURL="+(yl.call(t,"sourceURL")?(t.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++Nr+"]")+"\n";
n.replace(h,function(t,r,e,o,f,c){return e||(e=o),s+=n.slice(a,c).replace(Vt,C),r&&(u=!0,s+="' +\n__e("+r+") +\n'"),f&&(i=!0,s+="';\n"+f+";\n__p += '"),e&&(s+="' +\n((__t = ("+e+")) == null ? '' : __t) +\n'"),a=c+t.length,t}),s+="';\n";var _=yl.call(t,"variable")&&t.variable;_||(s="with (obj) {\n"+s+"\n}\n"),s=(i?s.replace(vt,""):s).replace(gt,"$1").replace(yt,"$1;"),s="function("+(_||"obj")+") {\n"+(_?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(u?", __e = _.escape":"")+(i?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+s+"return __p\n}";
var v=Yh(function(){return ol(f,p+"return "+s).apply(Y,c)});if(v.source=s,nc(v))throw v;return v}function ba(n){return Rc(n).toLowerCase()}function wa(n){return Rc(n).toUpperCase()}function ma(n,t,r){if(n=Rc(n),n&&(r||t===Y))return n.replace(Et,"");if(!n||!(t=pu(t)))return n;var e=V(n),u=V(t);return Au(e,S(e,u),W(e,u)+1).join("")}function xa(n,t,r){if(n=Rc(n),n&&(r||t===Y))return n.replace(Wt,"");if(!n||!(t=pu(t)))return n;var e=V(n);return Au(e,0,W(e,V(t))+1).join("")}function ja(n,t,r){if(n=Rc(n),
n&&(r||t===Y))return n.replace(St,"");if(!n||!(t=pu(t)))return n;var e=V(n);return Au(e,S(e,V(t))).join("")}function Aa(n,t){var r=mn,e=xn;if(ic(t)){var u="separator"in t?t.separator:u;r="length"in t?jc(t.length):r,e="omission"in t?pu(t.omission):e}n=Rc(n);var i=n.length;if(B(n)){var o=V(n);i=o.length}if(r>=i)return n;var f=r-K(e);if(f<1)return e;var c=o?Au(o,0,f).join(""):n.slice(0,f);if(u===Y)return c+e;if(o&&(f+=c.length-f),xh(u)){if(n.slice(f).search(u)){var a,l=c;for(u.global||(u=al(u.source,Rc(Dt.exec(u))+"g")),
u.lastIndex=0;a=u.exec(l);)var s=a.index;c=c.slice(0,s===Y?f:s)}}else if(n.indexOf(pu(u),f)!=f){var h=c.lastIndexOf(u);h>-1&&(c=c.slice(0,h))}return c+e}function ka(n){return n=Rc(n),n&&wt.test(n)?n.replace(dt,_e):n}function Oa(n,t,r){return n=Rc(n),t=r?Y:t,t===Y?T(n)?J(n):_(n):n.match(t)||[]}function Ia(t){var r=null==t?0:t.length,e=bi();return t=r?c(t,function(n){if("function"!=typeof n[1])throw new sl(tn);return[e(n[0]),n[1]]}):[],ru(function(e){for(var u=-1;++u<r;){var i=t[u];if(n(i[0],this,e))return n(i[1],this,e);
}})}function Ra(n){return Mr(Dr(n,on))}function za(n){return function(){return n}}function Ea(n,t){return null==n||n!==n?t:n}function Sa(n){return n}function Wa(n){return Te("function"==typeof n?n:Dr(n,on))}function La(n){return Ne(Dr(n,on))}function Ca(n,t){return Pe(n,Dr(t,on))}function Ua(n,t,e){var u=Fc(t),i=se(t,u);null!=e||ic(t)&&(i.length||!u.length)||(e=t,t=n,n=this,i=se(t,Fc(t)));var o=!(ic(e)&&"chain"in e&&!e.chain),f=rc(n);return r(i,function(r){var e=t[r];n[r]=e,f&&(n.prototype[r]=function(){
var t=this.__chain__;if(o||t){var r=n(this.__wrapped__);return(r.__actions__=Uu(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,a([this.value()],arguments))})}),n}function Ba(){return Xr._===this&&(Xr._=xl),this}function Ta(){}function $a(n){return n=jc(n),ru(function(t){return Ke(t,n)})}function Da(n){return Ci(n)?m(Qi(n)):Je(n)}function Ma(n){return function(t){return null==n?Y:ve(n,t)}}function Fa(){return[]}function Na(){return!1}function Pa(){return{};
}function qa(){return""}function Za(){return!0}function Ka(n,t){if(n=jc(n),n<1||n>zn)return[];var r=Wn,e=Vl(n,Wn);t=bi(t),n-=Wn;for(var u=O(e,t);++r<n;)t(r);return u}function Va(n){return yh(n)?c(n,Qi):yc(n)?[n]:Uu(Ws(Rc(n)))}function Ga(n){var t=++dl;return Rc(n)+t}function Ha(n){return n&&n.length?Yr(n,Sa,be):Y}function Ja(n,t){return n&&n.length?Yr(n,bi(t,2),be):Y}function Ya(n){return w(n,Sa)}function Qa(n,t){return w(n,bi(t,2))}function Xa(n){return n&&n.length?Yr(n,Sa,Me):Y}function nl(n,t){
return n&&n.length?Yr(n,bi(t,2),Me):Y}function tl(n){return n&&n.length?k(n,Sa):0}function rl(n,t){return n&&n.length?k(n,bi(t,2)):0}x=null==x?Xr:ge.defaults(Xr.Object(),x,ge.pick(Xr,Fr));var el=x.Array,ul=x.Date,il=x.Error,ol=x.Function,fl=x.Math,cl=x.Object,al=x.RegExp,ll=x.String,sl=x.TypeError,hl=el.prototype,pl=ol.prototype,_l=cl.prototype,vl=x["__core-js_shared__"],gl=pl.toString,yl=_l.hasOwnProperty,dl=0,bl=function(){var n=/[^.]+$/.exec(vl&&vl.keys&&vl.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:"";
}(),wl=_l.toString,ml=gl.call(cl),xl=Xr._,jl=al("^"+gl.call(yl).replace(Rt,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Al=re?x.Buffer:Y,kl=x.Symbol,Ol=x.Uint8Array,Il=Al?Al.allocUnsafe:Y,Rl=M(cl.getPrototypeOf,cl),zl=cl.create,El=_l.propertyIsEnumerable,Sl=hl.splice,Wl=kl?kl.isConcatSpreadable:Y,Ll=kl?kl.iterator:Y,Cl=kl?kl.toStringTag:Y,Ul=function(){try{var n=xi(cl,"defineProperty");return n({},"",{}),n}catch(n){}}(),Bl=x.clearTimeout!==Xr.clearTimeout&&x.clearTimeout,Tl=ul&&ul.now!==Xr.Date.now&&ul.now,$l=x.setTimeout!==Xr.setTimeout&&x.setTimeout,Dl=fl.ceil,Ml=fl.floor,Fl=cl.getOwnPropertySymbols,Nl=Al?Al.isBuffer:Y,Pl=x.isFinite,ql=hl.join,Zl=M(cl.keys,cl),Kl=fl.max,Vl=fl.min,Gl=ul.now,Hl=x.parseInt,Jl=fl.random,Yl=hl.reverse,Ql=xi(x,"DataView"),Xl=xi(x,"Map"),ns=xi(x,"Promise"),ts=xi(x,"Set"),rs=xi(x,"WeakMap"),es=xi(cl,"create"),us=rs&&new rs,is={},os=Xi(Ql),fs=Xi(Xl),cs=Xi(ns),as=Xi(ts),ls=Xi(rs),ss=kl?kl.prototype:Y,hs=ss?ss.valueOf:Y,ps=ss?ss.toString:Y,_s=function(){
function n(){}return function(t){if(!ic(t))return{};if(zl)return zl(t);n.prototype=t;var r=new n;return n.prototype=Y,r}}();q.templateSettings={escape:xt,evaluate:jt,interpolate:At,variable:"",imports:{_:q}},q.prototype=G.prototype,q.prototype.constructor=q,H.prototype=_s(G.prototype),H.prototype.constructor=H,Bt.prototype=_s(G.prototype),Bt.prototype.constructor=Bt,Yt.prototype.clear=Qt,Yt.prototype.delete=Xt,Yt.prototype.get=nr,Yt.prototype.has=tr,Yt.prototype.set=rr,er.prototype.clear=ur,er.prototype.delete=ir,
er.prototype.get=or,er.prototype.has=fr,er.prototype.set=cr,ar.prototype.clear=lr,ar.prototype.delete=sr,ar.prototype.get=hr,ar.prototype.has=pr,ar.prototype.set=_r,vr.prototype.add=vr.prototype.push=gr,vr.prototype.has=yr,dr.prototype.clear=br,dr.prototype.delete=wr,dr.prototype.get=mr,dr.prototype.has=xr,dr.prototype.set=jr;var vs=Fu(ee),gs=Fu(ue,!0),ys=Nu(),ds=Nu(!0),bs=us?function(n,t){return us.set(n,t),n}:Sa,ws=Ul?function(n,t){return Ul(n,"toString",{configurable:!0,enumerable:!1,value:za(t),
writable:!0})}:Sa,ms=ru,xs=Bl||function(n){return Xr.clearTimeout(n)},js=ts&&1/N(new ts([,-0]))[1]==Rn?function(n){return new ts(n)}:Ta,As=us?function(n){return us.get(n)}:Ta,ks=Fl?function(n){return null==n?[]:(n=cl(n),i(Fl(n),function(t){return El.call(n,t)}))}:Fa,Os=Fl?function(n){for(var t=[];n;)a(t,ks(n)),n=Rl(n);return t}:Fa,Is=de;(Ql&&Is(new Ql(new ArrayBuffer(1)))!=it||Xl&&Is(new Xl)!=Zn||ns&&Is(ns.resolve())!=Hn||ts&&Is(new ts)!=Qn||rs&&Is(new rs)!=rt)&&(Is=function(n){var t=de(n),r=t==Gn?n.constructor:Y,e=r?Xi(r):"";
if(e)switch(e){case os:return it;case fs:return Zn;case cs:return Hn;case as:return Qn;case ls:return rt}return t});var Rs=vl?rc:Na,zs=Ji(bs),Es=$l||function(n,t){return Xr.setTimeout(n,t)},Ss=Ji(ws),Ws=Fi(function(n){var t=[];return 46===n.charCodeAt(0)&&t.push(""),n.replace(It,function(n,r,e,u){t.push(e?u.replace(Tt,"$1"):r||n)}),t}),Ls=ru(function(n,t){return Gf(n)?Vr(n,te(t,1,Gf,!0)):[]}),Cs=ru(function(n,t){var r=mo(t);return Gf(r)&&(r=Y),Gf(n)?Vr(n,te(t,1,Gf,!0),bi(r,2)):[]}),Us=ru(function(n,t){
var r=mo(t);return Gf(r)&&(r=Y),Gf(n)?Vr(n,te(t,1,Gf,!0),Y,r):[]}),Bs=ru(function(n){var t=c(n,mu);return t.length&&t[0]===n[0]?je(t):[]}),Ts=ru(function(n){var t=mo(n),r=c(n,mu);return t===mo(r)?t=Y:r.pop(),r.length&&r[0]===n[0]?je(r,bi(t,2)):[]}),$s=ru(function(n){var t=mo(n),r=c(n,mu);return t="function"==typeof t?t:Y,t&&r.pop(),r.length&&r[0]===n[0]?je(r,Y,t):[]}),Ds=ru(Ao),Ms=_i(function(n,t){var r=null==n?0:n.length,e=Tr(n,t);return Qe(n,c(t,function(n){return Wi(n,r)?+n:n}).sort(Su)),e}),Fs=ru(function(n){
return _u(te(n,1,Gf,!0))}),Ns=ru(function(n){var t=mo(n);return Gf(t)&&(t=Y),_u(te(n,1,Gf,!0),bi(t,2))}),Ps=ru(function(n){var t=mo(n);return t="function"==typeof t?t:Y,_u(te(n,1,Gf,!0),Y,t)}),qs=ru(function(n,t){return Gf(n)?Vr(n,t):[]}),Zs=ru(function(n){return bu(i(n,Gf))}),Ks=ru(function(n){var t=mo(n);return Gf(t)&&(t=Y),bu(i(n,Gf),bi(t,2))}),Vs=ru(function(n){var t=mo(n);return t="function"==typeof t?t:Y,bu(i(n,Gf),Y,t)}),Gs=ru(Ko),Hs=ru(function(n){var t=n.length,r=t>1?n[t-1]:Y;return r="function"==typeof r?(n.pop(),
r):Y,Vo(n,r)}),Js=_i(function(n){var t=n.length,r=t?n[0]:0,e=this.__wrapped__,u=function(t){return Tr(t,n)};return!(t>1||this.__actions__.length)&&e instanceof Bt&&Wi(r)?(e=e.slice(r,+r+(t?1:0)),e.__actions__.push({func:Qo,args:[u],thisArg:Y}),new H(e,this.__chain__).thru(function(n){return t&&!n.length&&n.push(Y),n})):this.thru(u)}),Ys=Du(function(n,t,r){yl.call(n,r)?++n[r]:Cr(n,r,1)}),Qs=Gu(lo),Xs=Gu(so),nh=Du(function(n,t,r){yl.call(n,r)?n[r].push(t):Cr(n,r,[t])}),th=ru(function(t,r,e){var u=-1,i="function"==typeof r,o=Vf(t)?el(t.length):[];
return vs(t,function(t){o[++u]=i?n(r,t,e):ke(t,r,e)}),o}),rh=Du(function(n,t,r){Cr(n,r,t)}),eh=Du(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),uh=ru(function(n,t){if(null==n)return[];var r=t.length;return r>1&&Li(n,t[0],t[1])?t=[]:r>2&&Li(t[0],t[1],t[2])&&(t=[t[0]]),Ve(n,te(t,1),[])}),ih=Tl||function(){return Xr.Date.now()},oh=ru(function(n,t,r){var e=sn;if(r.length){var u=F(r,di(oh));e|=gn}return fi(n,e,t,r,u)}),fh=ru(function(n,t,r){var e=sn|hn;if(r.length){var u=F(r,di(fh));e|=gn;
}return fi(t,e,n,r,u)}),ch=ru(function(n,t){return Kr(n,1,t)}),ah=ru(function(n,t,r){return Kr(n,kc(t)||0,r)});Wf.Cache=ar;var lh=ms(function(t,r){r=1==r.length&&yh(r[0])?c(r[0],R(bi())):c(te(r,1),R(bi()));var e=r.length;return ru(function(u){for(var i=-1,o=Vl(u.length,e);++i<o;)u[i]=r[i].call(this,u[i]);return n(t,this,u)})}),sh=ru(function(n,t){return fi(n,gn,Y,t,F(t,di(sh)))}),hh=ru(function(n,t){return fi(n,yn,Y,t,F(t,di(hh)))}),ph=_i(function(n,t){return fi(n,bn,Y,Y,Y,t)}),_h=ei(be),vh=ei(function(n,t){
return n>=t}),gh=Oe(function(){return arguments}())?Oe:function(n){return oc(n)&&yl.call(n,"callee")&&!El.call(n,"callee")},yh=el.isArray,dh=ie?R(ie):Ie,bh=Nl||Na,wh=oe?R(oe):Re,mh=fe?R(fe):Se,xh=ce?R(ce):Ce,jh=ae?R(ae):Ue,Ah=le?R(le):Be,kh=ei(Me),Oh=ei(function(n,t){return n<=t}),Ih=Mu(function(n,t){if($i(t)||Vf(t))return Bu(t,Fc(t),n),Y;for(var r in t)yl.call(t,r)&&zr(n,r,t[r])}),Rh=Mu(function(n,t){Bu(t,Nc(t),n)}),zh=Mu(function(n,t,r,e){Bu(t,Nc(t),n,e)}),Eh=Mu(function(n,t,r,e){Bu(t,Fc(t),n,e);
}),Sh=_i(Tr),Wh=ru(function(n,t){n=cl(n);var r=-1,e=t.length,u=e>2?t[2]:Y;for(u&&Li(t[0],t[1],u)&&(e=1);++r<e;)for(var i=t[r],o=Nc(i),f=-1,c=o.length;++f<c;){var a=o[f],l=n[a];(l===Y||Kf(l,_l[a])&&!yl.call(n,a))&&(n[a]=i[a])}return n}),Lh=ru(function(t){return t.push(Y,ai),n($h,Y,t)}),Ch=Yu(function(n,t,r){null!=t&&"function"!=typeof t.toString&&(t=wl.call(t)),n[t]=r},za(Sa)),Uh=Yu(function(n,t,r){null!=t&&"function"!=typeof t.toString&&(t=wl.call(t)),yl.call(n,t)?n[t].push(r):n[t]=[r]},bi),Bh=ru(ke),Th=Mu(function(n,t,r){
qe(n,t,r)}),$h=Mu(function(n,t,r,e){qe(n,t,r,e)}),Dh=_i(function(n,t){var r={};if(null==n)return r;var e=!1;t=c(t,function(t){return t=ju(t,n),e||(e=t.length>1),t}),Bu(n,gi(n),r),e&&(r=Dr(r,on|fn|cn,li));for(var u=t.length;u--;)vu(r,t[u]);return r}),Mh=_i(function(n,t){return null==n?{}:Ge(n,t)}),Fh=oi(Fc),Nh=oi(Nc),Ph=Zu(function(n,t,r){return t=t.toLowerCase(),n+(r?ia(t):t)}),qh=Zu(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Zh=Zu(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),Kh=qu("toLowerCase"),Vh=Zu(function(n,t,r){
return n+(r?"_":"")+t.toLowerCase()}),Gh=Zu(function(n,t,r){return n+(r?" ":"")+Jh(t)}),Hh=Zu(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),Jh=qu("toUpperCase"),Yh=ru(function(t,r){try{return n(t,Y,r)}catch(n){return nc(n)?n:new il(n)}}),Qh=_i(function(n,t){return r(t,function(t){t=Qi(t),Cr(n,t,oh(n[t],n))}),n}),Xh=Hu(),np=Hu(!0),tp=ru(function(n,t){return function(r){return ke(r,n,t)}}),rp=ru(function(n,t){return function(r){return ke(n,r,t)}}),ep=Xu(c),up=Xu(u),ip=Xu(h),op=ri(),fp=ri(!0),cp=Qu(function(n,t){
return n+t},0),ap=ii("ceil"),lp=Qu(function(n,t){return n/t},1),sp=ii("floor"),hp=Qu(function(n,t){return n*t},1),pp=ii("round"),_p=Qu(function(n,t){return n-t},0);return q.after=kf,q.ary=Of,q.assign=Ih,q.assignIn=Rh,q.assignInWith=zh,q.assignWith=Eh,q.at=Sh,q.before=If,q.bind=oh,q.bindAll=Qh,q.bindKey=fh,q.castArray=Mf,q.chain=Jo,q.chunk=ro,q.compact=eo,q.concat=uo,q.cond=Ia,q.conforms=Ra,q.constant=za,q.countBy=Ys,q.create=zc,q.curry=Rf,q.curryRight=zf,q.debounce=Ef,q.defaults=Wh,q.defaultsDeep=Lh,
q.defer=ch,q.delay=ah,q.difference=Ls,q.differenceBy=Cs,q.differenceWith=Us,q.drop=io,q.dropRight=oo,q.dropRightWhile=fo,q.dropWhile=co,q.fill=ao,q.filter=cf,q.flatMap=af,q.flatMapDeep=lf,q.flatMapDepth=sf,q.flatten=ho,q.flattenDeep=po,q.flattenDepth=_o,q.flip=Sf,q.flow=Xh,q.flowRight=np,q.fromPairs=vo,q.functions=Bc,q.functionsIn=Tc,q.groupBy=nh,q.initial=bo,q.intersection=Bs,q.intersectionBy=Ts,q.intersectionWith=$s,q.invert=Ch,q.invertBy=Uh,q.invokeMap=th,q.iteratee=Wa,q.keyBy=rh,q.keys=Fc,q.keysIn=Nc,
q.map=vf,q.mapKeys=Pc,q.mapValues=qc,q.matches=La,q.matchesProperty=Ca,q.memoize=Wf,q.merge=Th,q.mergeWith=$h,q.method=tp,q.methodOf=rp,q.mixin=Ua,q.negate=Lf,q.nthArg=$a,q.omit=Dh,q.omitBy=Zc,q.once=Cf,q.orderBy=gf,q.over=ep,q.overArgs=lh,q.overEvery=up,q.overSome=ip,q.partial=sh,q.partialRight=hh,q.partition=eh,q.pick=Mh,q.pickBy=Kc,q.property=Da,q.propertyOf=Ma,q.pull=Ds,q.pullAll=Ao,q.pullAllBy=ko,q.pullAllWith=Oo,q.pullAt=Ms,q.range=op,q.rangeRight=fp,q.rearg=ph,q.reject=bf,q.remove=Io,q.rest=Uf,
q.reverse=Ro,q.sampleSize=mf,q.set=Gc,q.setWith=Hc,q.shuffle=xf,q.slice=zo,q.sortBy=uh,q.sortedUniq=Bo,q.sortedUniqBy=To,q.split=ga,q.spread=Bf,q.tail=$o,q.take=Do,q.takeRight=Mo,q.takeRightWhile=Fo,q.takeWhile=No,q.tap=Yo,q.throttle=Tf,q.thru=Qo,q.toArray=mc,q.toPairs=Fh,q.toPairsIn=Nh,q.toPath=Va,q.toPlainObject=Oc,q.transform=Jc,q.unary=$f,q.union=Fs,q.unionBy=Ns,q.unionWith=Ps,q.uniq=Po,q.uniqBy=qo,q.uniqWith=Zo,q.unset=Yc,q.unzip=Ko,q.unzipWith=Vo,q.update=Qc,q.updateWith=Xc,q.values=na,q.valuesIn=ta,
q.without=qs,q.words=Oa,q.wrap=Df,q.xor=Zs,q.xorBy=Ks,q.xorWith=Vs,q.zip=Gs,q.zipObject=Go,q.zipObjectDeep=Ho,q.zipWith=Hs,q.entries=Fh,q.entriesIn=Nh,q.extend=Rh,q.extendWith=zh,Ua(q,q),q.add=cp,q.attempt=Yh,q.camelCase=Ph,q.capitalize=ia,q.ceil=ap,q.clamp=ra,q.clone=Ff,q.cloneDeep=Pf,q.cloneDeepWith=qf,q.cloneWith=Nf,q.conformsTo=Zf,q.deburr=oa,q.defaultTo=Ea,q.divide=lp,q.endsWith=fa,q.eq=Kf,q.escape=ca,q.escapeRegExp=aa,q.every=ff,q.find=Qs,q.findIndex=lo,q.findKey=Ec,q.findLast=Xs,q.findLastIndex=so,
q.findLastKey=Sc,q.floor=sp,q.forEach=hf,q.forEachRight=pf,q.forIn=Wc,q.forInRight=Lc,q.forOwn=Cc,q.forOwnRight=Uc,q.get=$c,q.gt=_h,q.gte=vh,q.has=Dc,q.hasIn=Mc,q.head=go,q.identity=Sa,q.includes=_f,q.indexOf=yo,q.inRange=ea,q.invoke=Bh,q.isArguments=gh,q.isArray=yh,q.isArrayBuffer=dh,q.isArrayLike=Vf,q.isArrayLikeObject=Gf,q.isBoolean=Hf,q.isBuffer=bh,q.isDate=wh,q.isElement=Jf,q.isEmpty=Yf,q.isEqual=Qf,q.isEqualWith=Xf,q.isError=nc,q.isFinite=tc,q.isFunction=rc,q.isInteger=ec,q.isLength=uc,q.isMap=mh,
q.isMatch=fc,q.isMatchWith=cc,q.isNaN=ac,q.isNative=lc,q.isNil=hc,q.isNull=sc,q.isNumber=pc,q.isObject=ic,q.isObjectLike=oc,q.isPlainObject=_c,q.isRegExp=xh,q.isSafeInteger=vc,q.isSet=jh,q.isString=gc,q.isSymbol=yc,q.isTypedArray=Ah,q.isUndefined=dc,q.isWeakMap=bc,q.isWeakSet=wc,q.join=wo,q.kebabCase=qh,q.last=mo,q.lastIndexOf=xo,q.lowerCase=Zh,q.lowerFirst=Kh,q.lt=kh,q.lte=Oh,q.max=Ha,q.maxBy=Ja,q.mean=Ya,q.meanBy=Qa,q.min=Xa,q.minBy=nl,q.stubArray=Fa,q.stubFalse=Na,q.stubObject=Pa,q.stubString=qa,
q.stubTrue=Za,q.multiply=hp,q.nth=jo,q.noConflict=Ba,q.noop=Ta,q.now=ih,q.pad=la,q.padEnd=sa,q.padStart=ha,q.parseInt=pa,q.random=ua,q.reduce=yf,q.reduceRight=df,q.repeat=_a,q.replace=va,q.result=Vc,q.round=pp,q.runInContext=p,q.sample=wf,q.size=jf,q.snakeCase=Vh,q.some=Af,q.sortedIndex=Eo,q.sortedIndexBy=So,q.sortedIndexOf=Wo,q.sortedLastIndex=Lo,q.sortedLastIndexBy=Co,q.sortedLastIndexOf=Uo,q.startCase=Gh,q.startsWith=ya,q.subtract=_p,q.sum=tl,q.sumBy=rl,q.template=da,q.times=Ka,q.toFinite=xc,q.toInteger=jc,
q.toLength=Ac,q.toLower=ba,q.toNumber=kc,q.toSafeInteger=Ic,q.toString=Rc,q.toUpper=wa,q.trim=ma,q.trimEnd=xa,q.trimStart=ja,q.truncate=Aa,q.unescape=ka,q.uniqueId=Ga,q.upperCase=Hh,q.upperFirst=Jh,q.each=hf,q.eachRight=pf,q.first=go,Ua(q,function(){var n={};return ee(q,function(t,r){yl.call(q.prototype,r)||(n[r]=t)}),n}(),{chain:!1}),q.VERSION=Q,r(["bind","bindKey","curry","curryRight","partial","partialRight"],function(n){q[n].placeholder=q}),r(["drop","take"],function(n,t){Bt.prototype[n]=function(r){
r=r===Y?1:Kl(jc(r),0);var e=this.__filtered__&&!t?new Bt(this):this.clone();return e.__filtered__?e.__takeCount__=Vl(r,e.__takeCount__):e.__views__.push({size:Vl(r,Wn),type:n+(e.__dir__<0?"Right":"")}),e},Bt.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),r(["filter","map","takeWhile"],function(n,t){var r=t+1,e=r==kn||r==In;Bt.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:bi(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),r(["head","last"],function(n,t){
var r="take"+(t?"Right":"");Bt.prototype[n]=function(){return this[r](1).value()[0]}}),r(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");Bt.prototype[n]=function(){return this.__filtered__?new Bt(this):this[r](1)}}),Bt.prototype.compact=function(){return this.filter(Sa)},Bt.prototype.find=function(n){return this.filter(n).head()},Bt.prototype.findLast=function(n){return this.reverse().find(n)},Bt.prototype.invokeMap=ru(function(n,t){return"function"==typeof n?new Bt(this):this.map(function(r){
return ke(r,n,t)})}),Bt.prototype.reject=function(n){return this.filter(Lf(bi(n)))},Bt.prototype.slice=function(n,t){n=jc(n);var r=this;return r.__filtered__&&(n>0||t<0)?new Bt(r):(n<0?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==Y&&(t=jc(t),r=t<0?r.dropRight(-t):r.take(t-n)),r)},Bt.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Bt.prototype.toArray=function(){return this.take(Wn)},ee(Bt.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=q[e?"take"+("last"==t?"Right":""):t],i=e||/^find/.test(t);
u&&(q.prototype[t]=function(){var t=this.__wrapped__,o=e?[1]:arguments,f=t instanceof Bt,c=o[0],l=f||yh(t),s=function(n){var t=u.apply(q,a([n],o));return e&&h?t[0]:t};l&&r&&"function"==typeof c&&1!=c.length&&(f=l=!1);var h=this.__chain__,p=!!this.__actions__.length,_=i&&!h,v=f&&!p;if(!i&&l){t=v?t:new Bt(this);var g=n.apply(t,o);return g.__actions__.push({func:Qo,args:[s],thisArg:Y}),new H(g,h)}return _&&v?n.apply(this,o):(g=this.thru(s),_?e?g.value()[0]:g.value():g)})}),r(["pop","push","shift","sort","splice","unshift"],function(n){
var t=hl[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);q.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(yh(u)?u:[],n)}return this[r](function(r){return t.apply(yh(r)?r:[],n)})}}),ee(Bt.prototype,function(n,t){var r=q[t];if(r){var e=r.name+"";yl.call(is,e)||(is[e]=[]),is[e].push({name:t,func:r})}}),is[Ju(Y,hn).name]=[{name:"wrapper",func:Y}],Bt.prototype.clone=Gt,Bt.prototype.reverse=Ht,Bt.prototype.value=Jt,q.prototype.at=Js,
q.prototype.chain=Xo,q.prototype.commit=nf,q.prototype.next=tf,q.prototype.plant=ef,q.prototype.reverse=uf,q.prototype.toJSON=q.prototype.valueOf=q.prototype.value=of,q.prototype.first=q.prototype.head,Ll&&(q.prototype[Ll]=rf),q},ge=ve();"function"==typeof define&&"object"==typeof define.amd&&define.amd?(Xr._=ge,define(function(){return ge})):te?((te.exports=ge)._=ge,ne._=ge):Xr._=ge}).call(this);

420
dist/mapping.fp.js vendored
View File

@@ -1,420 +0,0 @@
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["mapping"] = factory();
else
root["mapping"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
/** Used to map aliases to their real names. */
exports.aliasToReal = {
// Lodash aliases.
'each': 'forEach',
'eachRight': 'forEachRight',
'entries': 'toPairs',
'entriesIn': 'toPairsIn',
'extend': 'assignIn',
'extendAll': 'assignInAll',
'extendAllWith': 'assignInAllWith',
'extendWith': 'assignInWith',
'first': 'head',
// Methods that are curried variants of others.
'conforms': 'conformsTo',
'matches': 'isMatch',
'property': 'get',
// Ramda aliases.
'__': 'placeholder',
'F': 'stubFalse',
'T': 'stubTrue',
'all': 'every',
'allPass': 'overEvery',
'always': 'constant',
'any': 'some',
'anyPass': 'overSome',
'apply': 'spread',
'assoc': 'set',
'assocPath': 'set',
'complement': 'negate',
'compose': 'flowRight',
'contains': 'includes',
'dissoc': 'unset',
'dissocPath': 'unset',
'dropLast': 'dropRight',
'dropLastWhile': 'dropRightWhile',
'equals': 'isEqual',
'identical': 'eq',
'indexBy': 'keyBy',
'init': 'initial',
'invertObj': 'invert',
'juxt': 'over',
'omitAll': 'omit',
'nAry': 'ary',
'path': 'get',
'pathEq': 'matchesProperty',
'pathOr': 'getOr',
'paths': 'at',
'pickAll': 'pick',
'pipe': 'flow',
'pluck': 'map',
'prop': 'get',
'propEq': 'matchesProperty',
'propOr': 'getOr',
'props': 'at',
'symmetricDifference': 'xor',
'symmetricDifferenceBy': 'xorBy',
'symmetricDifferenceWith': 'xorWith',
'takeLast': 'takeRight',
'takeLastWhile': 'takeRightWhile',
'unapply': 'rest',
'unnest': 'flatten',
'useWith': 'overArgs',
'where': 'conformsTo',
'whereEq': 'isMatch',
'zipObj': 'zipObject'
};
/** Used to map ary to method names. */
exports.aryMethod = {
'1': [
'assignAll', 'assignInAll', 'attempt', 'castArray', 'ceil', 'create',
'curry', 'curryRight', 'defaultsAll', 'defaultsDeepAll', 'floor', 'flow',
'flowRight', 'fromPairs', 'invert', 'iteratee', 'memoize', 'method', 'mergeAll',
'methodOf', 'mixin', 'nthArg', 'over', 'overEvery', 'overSome','rest', 'reverse',
'round', 'runInContext', 'spread', 'template', 'trim', 'trimEnd', 'trimStart',
'uniqueId', 'words', 'zipAll'
],
'2': [
'add', 'after', 'ary', 'assign', 'assignAllWith', 'assignIn', 'assignInAllWith',
'at', 'before', 'bind', 'bindAll', 'bindKey', 'chunk', 'cloneDeepWith',
'cloneWith', 'concat', 'conformsTo', 'countBy', 'curryN', 'curryRightN',
'debounce', 'defaults', 'defaultsDeep', 'defaultTo', 'delay', 'difference',
'divide', 'drop', 'dropRight', 'dropRightWhile', 'dropWhile', 'endsWith', 'eq',
'every', 'filter', 'find', 'findIndex', 'findKey', 'findLast', 'findLastIndex',
'findLastKey', 'flatMap', 'flatMapDeep', 'flattenDepth', 'forEach',
'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'get',
'groupBy', 'gt', 'gte', 'has', 'hasIn', 'includes', 'indexOf', 'intersection',
'invertBy', 'invoke', 'invokeMap', 'isEqual', 'isMatch', 'join', 'keyBy',
'lastIndexOf', 'lt', 'lte', 'map', 'mapKeys', 'mapValues', 'matchesProperty',
'maxBy', 'meanBy', 'merge', 'mergeAllWith', 'minBy', 'multiply', 'nth', 'omit',
'omitBy', 'overArgs', 'pad', 'padEnd', 'padStart', 'parseInt', 'partial',
'partialRight', 'partition', 'pick', 'pickBy', 'propertyOf', 'pull', 'pullAll',
'pullAt', 'random', 'range', 'rangeRight', 'rearg', 'reject', 'remove',
'repeat', 'restFrom', 'result', 'sampleSize', 'some', 'sortBy', 'sortedIndex',
'sortedIndexOf', 'sortedLastIndex', 'sortedLastIndexOf', 'sortedUniqBy',
'split', 'spreadFrom', 'startsWith', 'subtract', 'sumBy', 'take', 'takeRight',
'takeRightWhile', 'takeWhile', 'tap', 'throttle', 'thru', 'times', 'trimChars',
'trimCharsEnd', 'trimCharsStart', 'truncate', 'union', 'uniqBy', 'uniqWith',
'unset', 'unzipWith', 'without', 'wrap', 'xor', 'zip', 'zipObject',
'zipObjectDeep'
],
'3': [
'assignInWith', 'assignWith', 'clamp', 'differenceBy', 'differenceWith',
'findFrom', 'findIndexFrom', 'findLastFrom', 'findLastIndexFrom', 'getOr',
'includesFrom', 'indexOfFrom', 'inRange', 'intersectionBy', 'intersectionWith',
'invokeArgs', 'invokeArgsMap', 'isEqualWith', 'isMatchWith', 'flatMapDepth',
'lastIndexOfFrom', 'mergeWith', 'orderBy', 'padChars', 'padCharsEnd',
'padCharsStart', 'pullAllBy', 'pullAllWith', 'rangeStep', 'rangeStepRight',
'reduce', 'reduceRight', 'replace', 'set', 'slice', 'sortedIndexBy',
'sortedLastIndexBy', 'transform', 'unionBy', 'unionWith', 'update', 'xorBy',
'xorWith', 'zipWith'
],
'4': [
'fill', 'setWith', 'updateWith'
]
};
/** Used to map ary to rearg configs. */
exports.aryRearg = {
'2': [1, 0],
'3': [2, 0, 1],
'4': [3, 2, 0, 1]
};
/** Used to map method names to their iteratee ary. */
exports.iterateeAry = {
'dropRightWhile': 1,
'dropWhile': 1,
'every': 1,
'filter': 1,
'find': 1,
'findFrom': 1,
'findIndex': 1,
'findIndexFrom': 1,
'findKey': 1,
'findLast': 1,
'findLastFrom': 1,
'findLastIndex': 1,
'findLastIndexFrom': 1,
'findLastKey': 1,
'flatMap': 1,
'flatMapDeep': 1,
'flatMapDepth': 1,
'forEach': 1,
'forEachRight': 1,
'forIn': 1,
'forInRight': 1,
'forOwn': 1,
'forOwnRight': 1,
'map': 1,
'mapKeys': 1,
'mapValues': 1,
'partition': 1,
'reduce': 2,
'reduceRight': 2,
'reject': 1,
'remove': 1,
'some': 1,
'takeRightWhile': 1,
'takeWhile': 1,
'times': 1,
'transform': 2
};
/** Used to map method names to iteratee rearg configs. */
exports.iterateeRearg = {
'mapKeys': [1],
'reduceRight': [1, 0]
};
/** Used to map method names to rearg configs. */
exports.methodRearg = {
'assignInAllWith': [1, 0],
'assignInWith': [1, 2, 0],
'assignAllWith': [1, 0],
'assignWith': [1, 2, 0],
'differenceBy': [1, 2, 0],
'differenceWith': [1, 2, 0],
'getOr': [2, 1, 0],
'intersectionBy': [1, 2, 0],
'intersectionWith': [1, 2, 0],
'isEqualWith': [1, 2, 0],
'isMatchWith': [2, 1, 0],
'mergeAllWith': [1, 0],
'mergeWith': [1, 2, 0],
'padChars': [2, 1, 0],
'padCharsEnd': [2, 1, 0],
'padCharsStart': [2, 1, 0],
'pullAllBy': [2, 1, 0],
'pullAllWith': [2, 1, 0],
'rangeStep': [1, 2, 0],
'rangeStepRight': [1, 2, 0],
'setWith': [3, 1, 2, 0],
'sortedIndexBy': [2, 1, 0],
'sortedLastIndexBy': [2, 1, 0],
'unionBy': [1, 2, 0],
'unionWith': [1, 2, 0],
'updateWith': [3, 1, 2, 0],
'xorBy': [1, 2, 0],
'xorWith': [1, 2, 0],
'zipWith': [1, 2, 0]
};
/** Used to map method names to spread configs. */
exports.methodSpread = {
'assignAll': { 'start': 0 },
'assignAllWith': { 'start': 0 },
'assignInAll': { 'start': 0 },
'assignInAllWith': { 'start': 0 },
'defaultsAll': { 'start': 0 },
'defaultsDeepAll': { 'start': 0 },
'invokeArgs': { 'start': 2 },
'invokeArgsMap': { 'start': 2 },
'mergeAll': { 'start': 0 },
'mergeAllWith': { 'start': 0 },
'partial': { 'start': 1 },
'partialRight': { 'start': 1 },
'without': { 'start': 1 },
'zipAll': { 'start': 0 }
};
/** Used to identify methods which mutate arrays or objects. */
exports.mutate = {
'array': {
'fill': true,
'pull': true,
'pullAll': true,
'pullAllBy': true,
'pullAllWith': true,
'pullAt': true,
'remove': true,
'reverse': true
},
'object': {
'assign': true,
'assignAll': true,
'assignAllWith': true,
'assignIn': true,
'assignInAll': true,
'assignInAllWith': true,
'assignInWith': true,
'assignWith': true,
'defaults': true,
'defaultsAll': true,
'defaultsDeep': true,
'defaultsDeepAll': true,
'merge': true,
'mergeAll': true,
'mergeAllWith': true,
'mergeWith': true,
},
'set': {
'set': true,
'setWith': true,
'unset': true,
'update': true,
'updateWith': true
}
};
/** Used to map real names to their aliases. */
exports.realToAlias = (function() {
var hasOwnProperty = Object.prototype.hasOwnProperty,
object = exports.aliasToReal,
result = {};
for (var key in object) {
var value = object[key];
if (hasOwnProperty.call(result, value)) {
result[value].push(key);
} else {
result[value] = [key];
}
}
return result;
}());
/** Used to map method names to other names. */
exports.remap = {
'assignAll': 'assign',
'assignAllWith': 'assignWith',
'assignInAll': 'assignIn',
'assignInAllWith': 'assignInWith',
'curryN': 'curry',
'curryRightN': 'curryRight',
'defaultsAll': 'defaults',
'defaultsDeepAll': 'defaultsDeep',
'findFrom': 'find',
'findIndexFrom': 'findIndex',
'findLastFrom': 'findLast',
'findLastIndexFrom': 'findLastIndex',
'getOr': 'get',
'includesFrom': 'includes',
'indexOfFrom': 'indexOf',
'invokeArgs': 'invoke',
'invokeArgsMap': 'invokeMap',
'lastIndexOfFrom': 'lastIndexOf',
'mergeAll': 'merge',
'mergeAllWith': 'mergeWith',
'padChars': 'pad',
'padCharsEnd': 'padEnd',
'padCharsStart': 'padStart',
'propertyOf': 'get',
'rangeStep': 'range',
'rangeStepRight': 'rangeRight',
'restFrom': 'rest',
'spreadFrom': 'spread',
'trimChars': 'trim',
'trimCharsEnd': 'trimEnd',
'trimCharsStart': 'trimStart',
'zipAll': 'zip'
};
/** Used to track methods that skip fixing their arity. */
exports.skipFixed = {
'castArray': true,
'flow': true,
'flowRight': true,
'iteratee': true,
'mixin': true,
'rearg': true,
'runInContext': true
};
/** Used to track methods that skip rearranging arguments. */
exports.skipRearg = {
'add': true,
'assign': true,
'assignIn': true,
'bind': true,
'bindKey': true,
'concat': true,
'difference': true,
'divide': true,
'eq': true,
'gt': true,
'gte': true,
'isEqual': true,
'lt': true,
'lte': true,
'matchesProperty': true,
'merge': true,
'multiply': true,
'overArgs': true,
'partial': true,
'partialRight': true,
'propertyOf': true,
'random': true,
'range': true,
'rangeRight': true,
'subtract': true,
'zip': true,
'zipObject': true,
'zipObjectDeep': true
};
/***/ })
/******/ ])
});
;

File diff suppressed because it is too large Load Diff

View File

@@ -1,569 +0,0 @@
var mapping = require('./_mapping'),
fallbackHolder = require('./placeholder');
/** Built-in value reference. */
var push = Array.prototype.push;
/**
* Creates a function, with an arity of `n`, that invokes `func` with the
* arguments it receives.
*
* @private
* @param {Function} func The function to wrap.
* @param {number} n The arity of the new function.
* @returns {Function} Returns the new function.
*/
function baseArity(func, n) {
return n == 2
? function(a, b) { return func.apply(undefined, arguments); }
: function(a) { return func.apply(undefined, arguments); };
}
/**
* Creates a function that invokes `func`, with up to `n` arguments, ignoring
* any additional arguments.
*
* @private
* @param {Function} func The function to cap arguments for.
* @param {number} n The arity cap.
* @returns {Function} Returns the new function.
*/
function baseAry(func, n) {
return n == 2
? function(a, b) { return func(a, b); }
: function(a) { return func(a); };
}
/**
* Creates a clone of `array`.
*
* @private
* @param {Array} array The array to clone.
* @returns {Array} Returns the cloned array.
*/
function cloneArray(array) {
var length = array ? array.length : 0,
result = Array(length);
while (length--) {
result[length] = array[length];
}
return result;
}
/**
* Creates a function that clones a given object using the assignment `func`.
*
* @private
* @param {Function} func The assignment function.
* @returns {Function} Returns the new cloner function.
*/
function createCloner(func) {
return function(object) {
return func({}, object);
};
}
/**
* A specialized version of `_.spread` which flattens the spread array into
* the arguments of the invoked `func`.
*
* @private
* @param {Function} func The function to spread arguments over.
* @param {number} start The start position of the spread.
* @returns {Function} Returns the new function.
*/
function flatSpread(func, start) {
return function() {
var length = arguments.length,
lastIndex = length - 1,
args = Array(length);
while (length--) {
args[length] = arguments[length];
}
var array = args[start],
otherArgs = args.slice(0, start);
if (array) {
push.apply(otherArgs, array);
}
if (start != lastIndex) {
push.apply(otherArgs, args.slice(start + 1));
}
return func.apply(this, otherArgs);
};
}
/**
* Creates a function that wraps `func` and uses `cloner` to clone the first
* argument it receives.
*
* @private
* @param {Function} func The function to wrap.
* @param {Function} cloner The function to clone arguments.
* @returns {Function} Returns the new immutable function.
*/
function wrapImmutable(func, cloner) {
return function() {
var length = arguments.length;
if (!length) {
return;
}
var args = Array(length);
while (length--) {
args[length] = arguments[length];
}
var result = args[0] = cloner.apply(undefined, args);
func.apply(undefined, args);
return result;
};
}
/**
* The base implementation of `convert` which accepts a `util` object of methods
* required to perform conversions.
*
* @param {Object} util The util object.
* @param {string} name The name of the function to convert.
* @param {Function} func The function to convert.
* @param {Object} [options] The options object.
* @param {boolean} [options.cap=true] Specify capping iteratee arguments.
* @param {boolean} [options.curry=true] Specify currying.
* @param {boolean} [options.fixed=true] Specify fixed arity.
* @param {boolean} [options.immutable=true] Specify immutable operations.
* @param {boolean} [options.rearg=true] Specify rearranging arguments.
* @returns {Function|Object} Returns the converted function or object.
*/
function baseConvert(util, name, func, options) {
var isLib = typeof name == 'function',
isObj = name === Object(name);
if (isObj) {
options = func;
func = name;
name = undefined;
}
if (func == null) {
throw new TypeError;
}
options || (options = {});
var config = {
'cap': 'cap' in options ? options.cap : true,
'curry': 'curry' in options ? options.curry : true,
'fixed': 'fixed' in options ? options.fixed : true,
'immutable': 'immutable' in options ? options.immutable : true,
'rearg': 'rearg' in options ? options.rearg : true
};
var defaultHolder = isLib ? func : fallbackHolder,
forceCurry = ('curry' in options) && options.curry,
forceFixed = ('fixed' in options) && options.fixed,
forceRearg = ('rearg' in options) && options.rearg,
pristine = isLib ? func.runInContext() : undefined;
var helpers = isLib ? func : {
'ary': util.ary,
'assign': util.assign,
'clone': util.clone,
'curry': util.curry,
'forEach': util.forEach,
'isArray': util.isArray,
'isError': util.isError,
'isFunction': util.isFunction,
'isWeakMap': util.isWeakMap,
'iteratee': util.iteratee,
'keys': util.keys,
'rearg': util.rearg,
'toInteger': util.toInteger,
'toPath': util.toPath
};
var ary = helpers.ary,
assign = helpers.assign,
clone = helpers.clone,
curry = helpers.curry,
each = helpers.forEach,
isArray = helpers.isArray,
isError = helpers.isError,
isFunction = helpers.isFunction,
isWeakMap = helpers.isWeakMap,
keys = helpers.keys,
rearg = helpers.rearg,
toInteger = helpers.toInteger,
toPath = helpers.toPath;
var aryMethodKeys = keys(mapping.aryMethod);
var wrappers = {
'castArray': function(castArray) {
return function() {
var value = arguments[0];
return isArray(value)
? castArray(cloneArray(value))
: castArray.apply(undefined, arguments);
};
},
'iteratee': function(iteratee) {
return function() {
var func = arguments[0],
arity = arguments[1],
result = iteratee(func, arity),
length = result.length;
if (config.cap && typeof arity == 'number') {
arity = arity > 2 ? (arity - 2) : 1;
return (length && length <= arity) ? result : baseAry(result, arity);
}
return result;
};
},
'mixin': function(mixin) {
return function(source) {
var func = this;
if (!isFunction(func)) {
return mixin(func, Object(source));
}
var pairs = [];
each(keys(source), function(key) {
if (isFunction(source[key])) {
pairs.push([key, func.prototype[key]]);
}
});
mixin(func, Object(source));
each(pairs, function(pair) {
var value = pair[1];
if (isFunction(value)) {
func.prototype[pair[0]] = value;
} else {
delete func.prototype[pair[0]];
}
});
return func;
};
},
'nthArg': function(nthArg) {
return function(n) {
var arity = n < 0 ? 1 : (toInteger(n) + 1);
return curry(nthArg(n), arity);
};
},
'rearg': function(rearg) {
return function(func, indexes) {
var arity = indexes ? indexes.length : 0;
return curry(rearg(func, indexes), arity);
};
},
'runInContext': function(runInContext) {
return function(context) {
return baseConvert(util, runInContext(context), options);
};
}
};
/*--------------------------------------------------------------------------*/
/**
* Casts `func` to a function with an arity capped iteratee if needed.
*
* @private
* @param {string} name The name of the function to inspect.
* @param {Function} func The function to inspect.
* @returns {Function} Returns the cast function.
*/
function castCap(name, func) {
if (config.cap) {
var indexes = mapping.iterateeRearg[name];
if (indexes) {
return iterateeRearg(func, indexes);
}
var n = !isLib && mapping.iterateeAry[name];
if (n) {
return iterateeAry(func, n);
}
}
return func;
}
/**
* Casts `func` to a curried function if needed.
*
* @private
* @param {string} name The name of the function to inspect.
* @param {Function} func The function to inspect.
* @param {number} n The arity of `func`.
* @returns {Function} Returns the cast function.
*/
function castCurry(name, func, n) {
return (forceCurry || (config.curry && n > 1))
? curry(func, n)
: func;
}
/**
* Casts `func` to a fixed arity function if needed.
*
* @private
* @param {string} name The name of the function to inspect.
* @param {Function} func The function to inspect.
* @param {number} n The arity cap.
* @returns {Function} Returns the cast function.
*/
function castFixed(name, func, n) {
if (config.fixed && (forceFixed || !mapping.skipFixed[name])) {
var data = mapping.methodSpread[name],
start = data && data.start;
return start === undefined ? ary(func, n) : flatSpread(func, start);
}
return func;
}
/**
* Casts `func` to an rearged function if needed.
*
* @private
* @param {string} name The name of the function to inspect.
* @param {Function} func The function to inspect.
* @param {number} n The arity of `func`.
* @returns {Function} Returns the cast function.
*/
function castRearg(name, func, n) {
return (config.rearg && n > 1 && (forceRearg || !mapping.skipRearg[name]))
? rearg(func, mapping.methodRearg[name] || mapping.aryRearg[n])
: func;
}
/**
* Creates a clone of `object` by `path`.
*
* @private
* @param {Object} object The object to clone.
* @param {Array|string} path The path to clone by.
* @returns {Object} Returns the cloned object.
*/
function cloneByPath(object, path) {
path = toPath(path);
var index = -1,
length = path.length,
lastIndex = length - 1,
result = clone(Object(object)),
nested = result;
while (nested != null && ++index < length) {
var key = path[index],
value = nested[key];
if (value != null &&
!(isFunction(value) || isError(value) || isWeakMap(value))) {
nested[key] = clone(index == lastIndex ? value : Object(value));
}
nested = nested[key];
}
return result;
}
/**
* Converts `lodash` to an immutable auto-curried iteratee-first data-last
* version with conversion `options` applied.
*
* @param {Object} [options] The options object. See `baseConvert` for more details.
* @returns {Function} Returns the converted `lodash`.
*/
function convertLib(options) {
return _.runInContext.convert(options)(undefined);
}
/**
* Create a converter function for `func` of `name`.
*
* @param {string} name The name of the function to convert.
* @param {Function} func The function to convert.
* @returns {Function} Returns the new converter function.
*/
function createConverter(name, func) {
var realName = mapping.aliasToReal[name] || name,
methodName = mapping.remap[realName] || realName,
oldOptions = options;
return function(options) {
var newUtil = isLib ? pristine : helpers,
newFunc = isLib ? pristine[methodName] : func,
newOptions = assign(assign({}, oldOptions), options);
return baseConvert(newUtil, realName, newFunc, newOptions);
};
}
/**
* Creates a function that wraps `func` to invoke its iteratee, with up to `n`
* arguments, ignoring any additional arguments.
*
* @private
* @param {Function} func The function to cap iteratee arguments for.
* @param {number} n The arity cap.
* @returns {Function} Returns the new function.
*/
function iterateeAry(func, n) {
return overArg(func, function(func) {
return typeof func == 'function' ? baseAry(func, n) : func;
});
}
/**
* Creates a function that wraps `func` to invoke its iteratee 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.
*
* @private
* @param {Function} func The function to rearrange iteratee arguments for.
* @param {number[]} indexes The arranged argument indexes.
* @returns {Function} Returns the new function.
*/
function iterateeRearg(func, indexes) {
return overArg(func, function(func) {
var n = indexes.length;
return baseArity(rearg(baseAry(func, n), indexes), n);
});
}
/**
* Creates a function that invokes `func` with its first argument transformed.
*
* @private
* @param {Function} func The function to wrap.
* @param {Function} transform The argument transform.
* @returns {Function} Returns the new function.
*/
function overArg(func, transform) {
return function() {
var length = arguments.length;
if (!length) {
return func();
}
var args = Array(length);
while (length--) {
args[length] = arguments[length];
}
var index = config.rearg ? 0 : (length - 1);
args[index] = transform(args[index]);
return func.apply(undefined, args);
};
}
/**
* Creates a function that wraps `func` and applys the conversions
* rules by `name`.
*
* @private
* @param {string} name The name of the function to wrap.
* @param {Function} func The function to wrap.
* @returns {Function} Returns the converted function.
*/
function wrap(name, func, placeholder) {
var result,
realName = mapping.aliasToReal[name] || name,
wrapped = func,
wrapper = wrappers[realName];
if (wrapper) {
wrapped = wrapper(func);
}
else if (config.immutable) {
if (mapping.mutate.array[realName]) {
wrapped = wrapImmutable(func, cloneArray);
}
else if (mapping.mutate.object[realName]) {
wrapped = wrapImmutable(func, createCloner(func));
}
else if (mapping.mutate.set[realName]) {
wrapped = wrapImmutable(func, cloneByPath);
}
}
each(aryMethodKeys, function(aryKey) {
each(mapping.aryMethod[aryKey], function(otherName) {
if (realName == otherName) {
var data = mapping.methodSpread[realName],
afterRearg = data && data.afterRearg;
result = afterRearg
? castFixed(realName, castRearg(realName, wrapped, aryKey), aryKey)
: castRearg(realName, castFixed(realName, wrapped, aryKey), aryKey);
result = castCap(realName, result);
result = castCurry(realName, result, aryKey);
return false;
}
});
return !result;
});
result || (result = wrapped);
if (result == func) {
result = forceCurry ? curry(result, 1) : function() {
return func.apply(this, arguments);
};
}
result.convert = createConverter(realName, func);
result.placeholder = func.placeholder = placeholder;
return result;
}
/*--------------------------------------------------------------------------*/
if (!isObj) {
return wrap(name, func, defaultHolder);
}
var _ = func;
// Convert methods by ary cap.
var pairs = [];
each(aryMethodKeys, function(aryKey) {
each(mapping.aryMethod[aryKey], function(key) {
var func = _[mapping.remap[key] || key];
if (func) {
pairs.push([key, wrap(key, func, _)]);
}
});
});
// Convert remaining methods.
each(keys(_), function(key) {
var func = _[key];
if (typeof func == 'function') {
var length = pairs.length;
while (length--) {
if (pairs[length][0] == key) {
return;
}
}
func.convert = createConverter(key, func);
pairs.push([key, func]);
}
});
// Assign to `_` leaving `_.prototype` unchanged to allow chaining.
each(pairs, function(pair) {
_[pair[0]] = pair[1];
});
_.convert = convertLib;
_.placeholder = _;
// Assign aliases.
each(keys(_), function(key) {
each(mapping.realToAlias[key] || [], function(alias) {
_[alias] = _[key];
});
});
return _;
}
module.exports = baseConvert;

View File

@@ -1,18 +0,0 @@
var baseConvert = require('./_baseConvert');
/**
* Converts `lodash` to an immutable auto-curried iteratee-first data-last
* version with conversion `options` applied.
*
* @param {Function} lodash The lodash function to convert.
* @param {Object} [options] The options object. See `baseConvert` for more details.
* @returns {Function} Returns the converted `lodash`.
*/
function browserConvert(lodash, options) {
return baseConvert(lodash, lodash, options);
}
if (typeof _ == 'function' && typeof _.runInContext == 'function') {
_ = browserConvert(_.runInContext());
}
module.exports = browserConvert;

View File

@@ -1,358 +0,0 @@
/** Used to map aliases to their real names. */
exports.aliasToReal = {
// Lodash aliases.
'each': 'forEach',
'eachRight': 'forEachRight',
'entries': 'toPairs',
'entriesIn': 'toPairsIn',
'extend': 'assignIn',
'extendAll': 'assignInAll',
'extendAllWith': 'assignInAllWith',
'extendWith': 'assignInWith',
'first': 'head',
// Methods that are curried variants of others.
'conforms': 'conformsTo',
'matches': 'isMatch',
'property': 'get',
// Ramda aliases.
'__': 'placeholder',
'F': 'stubFalse',
'T': 'stubTrue',
'all': 'every',
'allPass': 'overEvery',
'always': 'constant',
'any': 'some',
'anyPass': 'overSome',
'apply': 'spread',
'assoc': 'set',
'assocPath': 'set',
'complement': 'negate',
'compose': 'flowRight',
'contains': 'includes',
'dissoc': 'unset',
'dissocPath': 'unset',
'dropLast': 'dropRight',
'dropLastWhile': 'dropRightWhile',
'equals': 'isEqual',
'identical': 'eq',
'indexBy': 'keyBy',
'init': 'initial',
'invertObj': 'invert',
'juxt': 'over',
'omitAll': 'omit',
'nAry': 'ary',
'path': 'get',
'pathEq': 'matchesProperty',
'pathOr': 'getOr',
'paths': 'at',
'pickAll': 'pick',
'pipe': 'flow',
'pluck': 'map',
'prop': 'get',
'propEq': 'matchesProperty',
'propOr': 'getOr',
'props': 'at',
'symmetricDifference': 'xor',
'symmetricDifferenceBy': 'xorBy',
'symmetricDifferenceWith': 'xorWith',
'takeLast': 'takeRight',
'takeLastWhile': 'takeRightWhile',
'unapply': 'rest',
'unnest': 'flatten',
'useWith': 'overArgs',
'where': 'conformsTo',
'whereEq': 'isMatch',
'zipObj': 'zipObject'
};
/** Used to map ary to method names. */
exports.aryMethod = {
'1': [
'assignAll', 'assignInAll', 'attempt', 'castArray', 'ceil', 'create',
'curry', 'curryRight', 'defaultsAll', 'defaultsDeepAll', 'floor', 'flow',
'flowRight', 'fromPairs', 'invert', 'iteratee', 'memoize', 'method', 'mergeAll',
'methodOf', 'mixin', 'nthArg', 'over', 'overEvery', 'overSome','rest', 'reverse',
'round', 'runInContext', 'spread', 'template', 'trim', 'trimEnd', 'trimStart',
'uniqueId', 'words', 'zipAll'
],
'2': [
'add', 'after', 'ary', 'assign', 'assignAllWith', 'assignIn', 'assignInAllWith',
'at', 'before', 'bind', 'bindAll', 'bindKey', 'chunk', 'cloneDeepWith',
'cloneWith', 'concat', 'conformsTo', 'countBy', 'curryN', 'curryRightN',
'debounce', 'defaults', 'defaultsDeep', 'defaultTo', 'delay', 'difference',
'divide', 'drop', 'dropRight', 'dropRightWhile', 'dropWhile', 'endsWith', 'eq',
'every', 'filter', 'find', 'findIndex', 'findKey', 'findLast', 'findLastIndex',
'findLastKey', 'flatMap', 'flatMapDeep', 'flattenDepth', 'forEach',
'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'get',
'groupBy', 'gt', 'gte', 'has', 'hasIn', 'includes', 'indexOf', 'intersection',
'invertBy', 'invoke', 'invokeMap', 'isEqual', 'isMatch', 'join', 'keyBy',
'lastIndexOf', 'lt', 'lte', 'map', 'mapKeys', 'mapValues', 'matchesProperty',
'maxBy', 'meanBy', 'merge', 'mergeAllWith', 'minBy', 'multiply', 'nth', 'omit',
'omitBy', 'overArgs', 'pad', 'padEnd', 'padStart', 'parseInt', 'partial',
'partialRight', 'partition', 'pick', 'pickBy', 'propertyOf', 'pull', 'pullAll',
'pullAt', 'random', 'range', 'rangeRight', 'rearg', 'reject', 'remove',
'repeat', 'restFrom', 'result', 'sampleSize', 'some', 'sortBy', 'sortedIndex',
'sortedIndexOf', 'sortedLastIndex', 'sortedLastIndexOf', 'sortedUniqBy',
'split', 'spreadFrom', 'startsWith', 'subtract', 'sumBy', 'take', 'takeRight',
'takeRightWhile', 'takeWhile', 'tap', 'throttle', 'thru', 'times', 'trimChars',
'trimCharsEnd', 'trimCharsStart', 'truncate', 'union', 'uniqBy', 'uniqWith',
'unset', 'unzipWith', 'without', 'wrap', 'xor', 'zip', 'zipObject',
'zipObjectDeep'
],
'3': [
'assignInWith', 'assignWith', 'clamp', 'differenceBy', 'differenceWith',
'findFrom', 'findIndexFrom', 'findLastFrom', 'findLastIndexFrom', 'getOr',
'includesFrom', 'indexOfFrom', 'inRange', 'intersectionBy', 'intersectionWith',
'invokeArgs', 'invokeArgsMap', 'isEqualWith', 'isMatchWith', 'flatMapDepth',
'lastIndexOfFrom', 'mergeWith', 'orderBy', 'padChars', 'padCharsEnd',
'padCharsStart', 'pullAllBy', 'pullAllWith', 'rangeStep', 'rangeStepRight',
'reduce', 'reduceRight', 'replace', 'set', 'slice', 'sortedIndexBy',
'sortedLastIndexBy', 'transform', 'unionBy', 'unionWith', 'update', 'xorBy',
'xorWith', 'zipWith'
],
'4': [
'fill', 'setWith', 'updateWith'
]
};
/** Used to map ary to rearg configs. */
exports.aryRearg = {
'2': [1, 0],
'3': [2, 0, 1],
'4': [3, 2, 0, 1]
};
/** Used to map method names to their iteratee ary. */
exports.iterateeAry = {
'dropRightWhile': 1,
'dropWhile': 1,
'every': 1,
'filter': 1,
'find': 1,
'findFrom': 1,
'findIndex': 1,
'findIndexFrom': 1,
'findKey': 1,
'findLast': 1,
'findLastFrom': 1,
'findLastIndex': 1,
'findLastIndexFrom': 1,
'findLastKey': 1,
'flatMap': 1,
'flatMapDeep': 1,
'flatMapDepth': 1,
'forEach': 1,
'forEachRight': 1,
'forIn': 1,
'forInRight': 1,
'forOwn': 1,
'forOwnRight': 1,
'map': 1,
'mapKeys': 1,
'mapValues': 1,
'partition': 1,
'reduce': 2,
'reduceRight': 2,
'reject': 1,
'remove': 1,
'some': 1,
'takeRightWhile': 1,
'takeWhile': 1,
'times': 1,
'transform': 2
};
/** Used to map method names to iteratee rearg configs. */
exports.iterateeRearg = {
'mapKeys': [1],
'reduceRight': [1, 0]
};
/** Used to map method names to rearg configs. */
exports.methodRearg = {
'assignInAllWith': [1, 0],
'assignInWith': [1, 2, 0],
'assignAllWith': [1, 0],
'assignWith': [1, 2, 0],
'differenceBy': [1, 2, 0],
'differenceWith': [1, 2, 0],
'getOr': [2, 1, 0],
'intersectionBy': [1, 2, 0],
'intersectionWith': [1, 2, 0],
'isEqualWith': [1, 2, 0],
'isMatchWith': [2, 1, 0],
'mergeAllWith': [1, 0],
'mergeWith': [1, 2, 0],
'padChars': [2, 1, 0],
'padCharsEnd': [2, 1, 0],
'padCharsStart': [2, 1, 0],
'pullAllBy': [2, 1, 0],
'pullAllWith': [2, 1, 0],
'rangeStep': [1, 2, 0],
'rangeStepRight': [1, 2, 0],
'setWith': [3, 1, 2, 0],
'sortedIndexBy': [2, 1, 0],
'sortedLastIndexBy': [2, 1, 0],
'unionBy': [1, 2, 0],
'unionWith': [1, 2, 0],
'updateWith': [3, 1, 2, 0],
'xorBy': [1, 2, 0],
'xorWith': [1, 2, 0],
'zipWith': [1, 2, 0]
};
/** Used to map method names to spread configs. */
exports.methodSpread = {
'assignAll': { 'start': 0 },
'assignAllWith': { 'start': 0 },
'assignInAll': { 'start': 0 },
'assignInAllWith': { 'start': 0 },
'defaultsAll': { 'start': 0 },
'defaultsDeepAll': { 'start': 0 },
'invokeArgs': { 'start': 2 },
'invokeArgsMap': { 'start': 2 },
'mergeAll': { 'start': 0 },
'mergeAllWith': { 'start': 0 },
'partial': { 'start': 1 },
'partialRight': { 'start': 1 },
'without': { 'start': 1 },
'zipAll': { 'start': 0 }
};
/** Used to identify methods which mutate arrays or objects. */
exports.mutate = {
'array': {
'fill': true,
'pull': true,
'pullAll': true,
'pullAllBy': true,
'pullAllWith': true,
'pullAt': true,
'remove': true,
'reverse': true
},
'object': {
'assign': true,
'assignAll': true,
'assignAllWith': true,
'assignIn': true,
'assignInAll': true,
'assignInAllWith': true,
'assignInWith': true,
'assignWith': true,
'defaults': true,
'defaultsAll': true,
'defaultsDeep': true,
'defaultsDeepAll': true,
'merge': true,
'mergeAll': true,
'mergeAllWith': true,
'mergeWith': true,
},
'set': {
'set': true,
'setWith': true,
'unset': true,
'update': true,
'updateWith': true
}
};
/** Used to map real names to their aliases. */
exports.realToAlias = (function() {
var hasOwnProperty = Object.prototype.hasOwnProperty,
object = exports.aliasToReal,
result = {};
for (var key in object) {
var value = object[key];
if (hasOwnProperty.call(result, value)) {
result[value].push(key);
} else {
result[value] = [key];
}
}
return result;
}());
/** Used to map method names to other names. */
exports.remap = {
'assignAll': 'assign',
'assignAllWith': 'assignWith',
'assignInAll': 'assignIn',
'assignInAllWith': 'assignInWith',
'curryN': 'curry',
'curryRightN': 'curryRight',
'defaultsAll': 'defaults',
'defaultsDeepAll': 'defaultsDeep',
'findFrom': 'find',
'findIndexFrom': 'findIndex',
'findLastFrom': 'findLast',
'findLastIndexFrom': 'findLastIndex',
'getOr': 'get',
'includesFrom': 'includes',
'indexOfFrom': 'indexOf',
'invokeArgs': 'invoke',
'invokeArgsMap': 'invokeMap',
'lastIndexOfFrom': 'lastIndexOf',
'mergeAll': 'merge',
'mergeAllWith': 'mergeWith',
'padChars': 'pad',
'padCharsEnd': 'padEnd',
'padCharsStart': 'padStart',
'propertyOf': 'get',
'rangeStep': 'range',
'rangeStepRight': 'rangeRight',
'restFrom': 'rest',
'spreadFrom': 'spread',
'trimChars': 'trim',
'trimCharsEnd': 'trimEnd',
'trimCharsStart': 'trimStart',
'zipAll': 'zip'
};
/** Used to track methods that skip fixing their arity. */
exports.skipFixed = {
'castArray': true,
'flow': true,
'flowRight': true,
'iteratee': true,
'mixin': true,
'rearg': true,
'runInContext': true
};
/** Used to track methods that skip rearranging arguments. */
exports.skipRearg = {
'add': true,
'assign': true,
'assignIn': true,
'bind': true,
'bindKey': true,
'concat': true,
'difference': true,
'divide': true,
'eq': true,
'gt': true,
'gte': true,
'isEqual': true,
'lt': true,
'lte': true,
'matchesProperty': true,
'merge': true,
'multiply': true,
'overArgs': true,
'partial': true,
'partialRight': true,
'propertyOf': true,
'random': true,
'range': true,
'rangeRight': true,
'subtract': true,
'zip': true,
'zipObject': true,
'zipObjectDeep': true
};

View File

@@ -1,6 +0,0 @@
/**
* The default argument placeholder value for methods.
*
* @type {Object}
*/
module.exports = {};

View File

@@ -1,71 +0,0 @@
'use strict';
const _ = require('lodash');
const fs = require('fs-extra');
const glob = require('glob');
const path = require('path');
const minify = require('../common/minify.js');
/*----------------------------------------------------------------------------*/
/**
* Creates a [fs.copy](https://github.com/jprichardson/node-fs-extra#copy)
* function with `srcPath` and `destPath` partially applied.
*
* @memberOf file
* @param {string} srcPath The path of the file to copy.
* @param {string} destPath The path to copy the file to.
* @returns {Function} Returns the partially applied function.
*/
function copy(srcPath, destPath) {
return _.partial(fs.copy, srcPath, destPath);
}
/**
* Creates an object of base name and compiled template pairs that match `pattern`.
*
* @memberOf file
* @param {string} pattern The glob pattern to be match.
* @returns {Object} Returns the object of compiled templates.
*/
function globTemplate(pattern) {
return _.transform(glob.sync(pattern), (result, filePath) => {
const key = path.basename(filePath, path.extname(filePath));
result[key] = _.template(fs.readFileSync(filePath, 'utf8'));
}, {});
}
/**
* Creates a `minify` function with `srcPath` and `destPath` partially applied.
*
* @memberOf file
* @param {string} srcPath The path of the file to minify.
* @param {string} destPath The path to write the file to.
* @returns {Function} Returns the partially applied function.
*/
function min(srcPath, destPath) {
return _.partial(minify, srcPath, destPath);
}
/**
* Creates a [fs.writeFile](https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback)
* function with `filePath` and `data` partially applied.
*
* @memberOf file
* @param {string} destPath The path to write the file to.
* @param {string} data The data to write to the file.
* @returns {Function} Returns the partially applied function.
*/
function write(destPath, data) {
return _.partial(fs.writeFile, destPath, data);
}
/*----------------------------------------------------------------------------*/
module.exports = {
copy,
globTemplate,
min,
write
};

View File

@@ -1,9 +0,0 @@
'use strict';
const _mapping = require('../../fp/_mapping');
const util = require('./util');
const Hash = util.Hash;
/*----------------------------------------------------------------------------*/
module.exports = new Hash(_mapping);

View File

@@ -1,39 +0,0 @@
'use strict';
const _ = require('lodash');
const fs = require('fs-extra');
const uglify = require('uglify-js');
const uglifyOptions = require('./uglify.options');
/*----------------------------------------------------------------------------*/
/**
* Asynchronously minifies the file at `srcPath`, writes it to `destPath`, and
* invokes `callback` upon completion. The callback is invoked with one argument:
* (error).
*
* If unspecified, `destPath` is `srcPath` with an extension of `.min.js`.
* (e.g. the `destPath` of `path/to/foo.js` would be `path/to/foo.min.js`)
*
* @param {string} srcPath The path of the file to minify.
* @param {string} [destPath] The path to write the file to.
* @param {Function} callback The function invoked upon completion.
* @param {Object} [option] The UglifyJS options object.
*/
function minify(srcPath, destPath, callback, options) {
if (_.isFunction(destPath)) {
if (_.isObject(callback)) {
options = callback;
}
callback = destPath;
destPath = undefined;
}
if (!destPath) {
destPath = srcPath.replace(/(?=\.js$)/, '.min');
}
const output = uglify.minify(srcPath, _.defaults(options || {}, uglifyOptions));
fs.writeFile(destPath, output.code, 'utf-8', callback);
}
module.exports = minify;

View File

@@ -1,22 +0,0 @@
'use strict';
/**
* The UglifyJS options object for
* [compress](https://github.com/mishoo/UglifyJS2#compressor-options),
* [mangle](https://github.com/mishoo/UglifyJS2#mangler-options), and
* [output](https://github.com/mishoo/UglifyJS2#beautifier-options) options.
*/
module.exports = {
'compress': {
'collapse_vars': true,
'negate_iife': false,
'pure_getters': true,
'unsafe': true,
'warnings': false
},
'output': {
'ascii_only': true,
'comments': /@license/,
'max_line_len': 500
}
};

View File

@@ -1,40 +0,0 @@
'use strict';
const _ = require('lodash');
/*----------------------------------------------------------------------------*/
/**
* Creates a hash object. If a `properties` object is provided, its own
* enumerable properties are assigned to the created hash.
*
* @memberOf util
* @param {Object} [properties] The properties to assign to the hash.
* @returns {Object} Returns the new hash object.
*/
function Hash(properties) {
return _.transform(properties, (result, value, key) => {
result[key] = (_.isPlainObject(value) && !(value instanceof Hash))
? new Hash(value)
: value;
}, this);
}
Hash.prototype = Object.create(null);
/**
* This method throws any error it receives.
*
* @memberOf util
* @param {Object} [error] The error object.
*/
function pitch(error) {
if (error != null) {
throw error;
}
}
module.exports = {
Hash,
pitch
};

View File

@@ -1,56 +0,0 @@
'use strict';
const _ = require('lodash');
const async = require('async');
const path = require('path');
const webpack = require('webpack');
const file = require('../common/file');
const util = require('../common/util');
const basePath = path.join(__dirname, '..', '..');
const distPath = path.join(basePath, 'dist');
const fpPath = path.join(basePath, 'fp');
const filename = 'lodash.fp.js';
const fpConfig = {
'entry': path.join(fpPath, '_convertBrowser.js'),
'output': {
'path': distPath,
'filename': filename,
'library': 'fp',
'libraryTarget': 'umd'
},
'plugins': [
new webpack.optimize.OccurenceOrderPlugin,
new webpack.optimize.DedupePlugin
]
};
const mappingConfig = {
'entry': path.join(fpPath, '_mapping.js'),
'output': {
'path': distPath,
'filename': 'mapping.fp.js',
'library': 'mapping',
'libraryTarget': 'umd'
}
};
/*----------------------------------------------------------------------------*/
/**
* Creates browser builds of the FP converter and mappings at the `target` path.
*
* @private
* @param {string} target The output directory path.
*/
function build() {
async.series([
_.partial(webpack, mappingConfig),
_.partial(webpack, fpConfig),
file.min(path.join(distPath, filename))
], util.pitch);
}
build();

View File

@@ -1,78 +0,0 @@
'use strict';
const _ = require('lodash');
const fs = require('fs-extra');
const path = require('path');
const file = require('../common/file');
const mapping = require('../common/mapping');
const util = require('../common/util');
const templatePath = path.join(__dirname, 'template/doc');
const template = file.globTemplate(path.join(templatePath, '*.jst'));
const argNames = ['a', 'b', 'c', 'd'];
const templateData = {
mapping,
toArgOrder,
toFuncList
};
/**
* Converts arranged argument `indexes` into a named argument string
* representation of their order.
*
* @private
* @param {number[]} indexes The arranged argument indexes.
* @returns {string} Returns the named argument string.
*/
function toArgOrder(indexes) {
const reordered = [];
_.each(indexes, (newIndex, index) => {
reordered[newIndex] = argNames[index];
});
return '`(' + reordered.join(', ') + ')`';
}
/**
* Converts `funcNames` into a chunked list string representation.
*
* @private
* @param {string[]} funcNames The function names.
* @returns {string} Returns the function list string.
*/
function toFuncList(funcNames) {
let chunks = _.chunk(funcNames.slice().sort(), 5);
let lastChunk = _.last(chunks);
const lastName = lastChunk ? lastChunk.pop() : undefined;
chunks = _.reject(chunks, _.isEmpty);
lastChunk = _.last(chunks);
let result = '`' + _.map(chunks, chunk => chunk.join('`, `') + '`').join(',\n`');
if (lastName == null) {
return result;
}
if (_.size(chunks) > 1 || _.size(lastChunk) > 1) {
result += ',';
}
result += ' &';
result += _.size(lastChunk) < 5 ? ' ' : '\n';
return result + '`' + lastName + '`';
}
/*----------------------------------------------------------------------------*/
/**
* Creates the FP-Guide wiki at the `target` path.
*
* @private
* @param {string} target The output file path.
*/
function build(target) {
target = path.resolve(target);
fs.writeFile(target, template.wiki(templateData), util.pitch);
}
build(_.last(process.argv));

View File

@@ -1,150 +0,0 @@
'use strict';
const _ = require('lodash');
const async = require('async');
const glob = require('glob');
const path = require('path');
const file = require('../common/file');
const mapping = require('../common/mapping');
const util = require('../common/util');
const templatePath = path.join(__dirname, 'template/modules');
const template = file.globTemplate(path.join(templatePath, '*.jst'));
const aryMethods = _.union(
mapping.aryMethod[1],
mapping.aryMethod[2],
mapping.aryMethod[3],
mapping.aryMethod[4]
);
const categories = [
'array',
'collection',
'date',
'function',
'lang',
'math',
'number',
'object',
'seq',
'string',
'util'
];
const ignored = [
'_*.js',
'core.js',
'core.min.js',
'fp.js',
'index.js',
'lodash.js',
'lodash.min.js'
];
/**
* Checks if `name` is a method alias.
*
* @private
* @param {string} name The name to check.
* @returns {boolean} Returns `true` if `name` is a method alias, else `false`.
*/
function isAlias(name) {
return _.has(mapping.aliasToReal, name);
}
/**
* Checks if `name` is a category name.
*
* @private
* @param {string} name The name to check.
* @returns {boolean} Returns `true` if `name` is a category name, else `false`.
*/
function isCategory(name) {
return _.includes(categories, name);
}
/**
* Checks if `name` belongs to a method that's passed thru and not wrapped.
*
* @private
* @param {string} name The name to check.
* @returns {boolean} Returns `true` if `name` is of a pass thru method,
* else `false`.
*/
function isThru(name) {
return !_.includes(aryMethods, name);
}
/**
* Gets metadata for `func`.
*
* @private
* @param {Function} func The function to query.
* @returns {*} Returns the metadata for `func`.
*/
function getTemplate(moduleName) {
const data = {
'name': _.get(mapping.aliasToReal, moduleName, moduleName),
'mapping': mapping
};
if (isAlias(moduleName)) {
return template.alias(data);
}
if (isCategory(moduleName)) {
return template.category(data);
}
if (isThru(moduleName)) {
return template.thru(data);
}
return template.module(data);
}
/*----------------------------------------------------------------------------*/
/**
* Creates FP modules at the `target` path.
*
* @private
* @param {string} target The output directory path.
*/
function build(target) {
target = path.resolve(target);
const fpPath = path.join(target, 'fp');
// Glob existing lodash module paths.
const modulePaths = glob.sync(path.join(target, '*.js'), {
'nodir': true,
'ignore': ignored.map(filename => {
return path.join(target, filename);
})
});
// Add FP alias and remapped module paths.
_.each([mapping.aliasToReal, mapping.remap], data => {
_.forOwn(data, (realName, alias) => {
const modulePath = path.join(target, alias + '.js');
if (!_.includes(modulePaths, modulePath)) {
modulePaths.push(modulePath);
}
});
});
const actions = modulePaths.map(modulePath => {
const moduleName = path.basename(modulePath, '.js');
return file.write(path.join(fpPath, moduleName + '.js'), getTemplate(moduleName));
});
actions.unshift(file.copy(path.join(__dirname, '../../fp'), fpPath));
actions.push(file.write(path.join(fpPath, '_falseOptions.js'), template._falseOptions()));
actions.push(file.write(path.join(fpPath, '_util.js'), template._util()));
actions.push(file.write(path.join(target, 'fp.js'), template.fp()));
actions.push(file.write(path.join(fpPath, 'convert.js'), template.convert()));
async.series(actions, util.pitch);
}
build(_.last(process.argv));

View File

@@ -1,228 +0,0 @@
## lodash/fp
The `lodash/fp` module promotes a more
[functional programming](https://en.wikipedia.org/wiki/Functional_programming)
(FP) friendly style by exporting an instance of `lodash` with its methods wrapped
to produce immutable auto-curried iteratee-first data-last methods.
## Installation
In a browser:
```html
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
<script>
// Loading `lodash.fp.js` converts `_` to its fp variant.
_.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
// ➜ { 'a': 1, 'b': 2 }
// Use `noConflict` to restore the pre-fp variant.
var fp = _.noConflict();
_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 });
// ➜ { 'a': 1, 'b': 2 }
fp.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
// ➜ { 'a': 1, 'b': 2 }
</script>
```
In Node.js:
```js
// Load the fp build.
var fp = require('lodash/fp');
// Load a method category.
var object = require('lodash/fp/object');
// Load a single method for smaller builds with browserify/rollup/webpack.
var extend = require('lodash/fp/extend');
```
## Mapping
Immutable auto-curried iteratee-first data-last methods sound great, but what
does that really mean for each method? Below is a breakdown of the mapping used
to convert each method.
#### Capped Iteratee Arguments
Iteratee arguments are capped to avoid gotchas with variadic iteratees.
```js
// The `lodash/map` iteratee receives three arguments:
// (value, index|key, collection)
_.map(['6', '8', '10'], parseInt);
// ➜ [6, NaN, 2]
// The `lodash/fp/map` iteratee is capped at one argument:
// (value)
fp.map(parseInt)(['6', '8', '10']);
// ➜ [6, 8, 10]
```
Methods that cap iteratees to one argument:<br>
<%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 1)))) %>
Methods that cap iteratees to two arguments:<br>
<%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 2)))) %>
The iteratee of `mapKeys` is capped to one argument: `(key)`
#### Fixed Arity
Methods have fixed arities to support auto-currying.
```js
// `lodash/padStart` accepts an optional `chars` param.
_.padStart('a', 3, '-')
// ➜ '--a'
// `lodash/fp/padStart` does not.
fp.padStart(3)('a');
// ➜ ' a'
fp.padCharsStart('-')(3)('a');
// ➜ '--a'
```
Methods with a fixed arity of one:<br>
<%= toFuncList(_.difference(mapping.aryMethod[1], _.keys(mapping.skipFixed))) %>
Methods with a fixed arity of two:<br>
<%= toFuncList(_.difference(mapping.aryMethod[2], _.keys(mapping.skipFixed))) %>
Methods with a fixed arity of three:<br>
<%= toFuncList(_.difference(mapping.aryMethod[3], _.keys(mapping.skipFixed))) %>
Methods with a fixed arity of four:<br>
<%= toFuncList(_.difference(mapping.aryMethod[4], _.keys(mapping.skipFixed))) %>
#### Rearranged Arguments
Method arguments are rearranged to make composition easier.
```js
// `lodash/filter` is data-first iteratee-last:
// (collection, iteratee)
var compact = _.partial(_.filter, _, Boolean);
compact(['a', null, 'c']);
// ➜ ['a', 'c']
// `lodash/fp/filter` is iteratee-first data-last:
// (iteratee, collection)
var compact = fp.filter(Boolean);
compact(['a', null, 'c']);
// ➜ ['a', 'c']
```
##### Most methods follow these rules
A fixed arity of two has an argument order of:<br>
<%= toArgOrder(mapping.aryRearg[2]) %>
A fixed arity of three has an argument order of:<br>
<%= toArgOrder(mapping.aryRearg[3]) %>
A fixed arity of four has an argument order of:<br>
<%= toArgOrder(mapping.aryRearg[4]) %>
##### Exceptions to the rules
Methods that accept an array as their last, second to last, or only argument:<br>
<%= toFuncList(_.keys(mapping.methodSpread)) %>
Methods with unchanged argument orders:<br>
<%= toFuncList(_.keys(mapping.skipRearg)) %>
Methods with custom argument orders:<br>
<%= _.map(_.keys(mapping.methodRearg), methodName => {
const orders = mapping.methodRearg[methodName];
return ' * `_.' + methodName + '` has an order of ' + toArgOrder(orders);
}).join('\n') %>
The iteratee of `reduceRight` has an argument order of: `(b, a)`
#### New Methods
Not all variadic methods have corresponding new method variants. Feel free to
[request](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md#feature-requests)
any additions.
Methods created to accommodate Lodashs variadic methods:<br>
<%= toFuncList(_.keys(mapping.remap)) %>
#### Aliases
There are <%= _.size(mapping.aliasToReal) %> method aliases:<br>
<%= _.map(_.keys(mapping.aliasToReal).sort(), alias => {
const realName = mapping.aliasToReal[alias];
return ' * `_.' + alias + '` is an alias of `_.' + realName + '`';
}).join('\n') %>
## Placeholders
The placeholder argument, which defaults to `_`, may be used to fill in method
arguments in a different order. Placeholders are filled by the first available
arguments of the curried returned function.
```js
// The equivalent of `2 > 5`.
_.gt(2)(5);
// ➜ false
// The equivalent of `_.gt(5, 2)` or `5 > 2`.
_.gt(_, 2)(5);
// ➜ true
```
## Chaining
The `lodash/fp` module **does not** convert chain sequence methods. See
[Izaak Schroeders article](https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba)
on using functional composition as an alternative to method chaining.
## Convert
Although `lodash/fp` & its method modules come pre-converted, there are times
when you may want to customize the conversion. Thats when the `convert` method
comes in handy.
```js
// Every option is `true` by default.
var _fp = fp.convert({
// Specify capping iteratee arguments.
'cap': true,
// Specify currying.
'curry': true,
// Specify fixed arity.
'fixed': true,
// Specify immutable operations.
'immutable': true,
// Specify rearranging arguments.
'rearg': true
});
// The `convert` method is available on each method too.
var mapValuesWithKey = fp.mapValues.convert({ 'cap': false });
// Heres an example of disabling iteratee argument caps to access the `key` param.
mapValuesWithKey(function(value, key) {
return key == 'a' ? -1 : value;
})({ 'a': 1, 'b': 1 });
// => { 'a': -1, 'b': 1 }
```
Manual conversions are also possible with the `convert` module.
```js
var convert = require('lodash/fp/convert');
// Convert by name.
var assign = convert('assign', require('lodash.assign'));
// Convert by object.
var fp = convert({
'assign': require('lodash.assign'),
'chunk': require('lodash.chunk')
});
// Convert by `lodash` instance.
var fp = convert(lodash.runInContext());
```
## Tooling
Use [eslint-plugin-lodash-fp](https://www.npmjs.com/package/eslint-plugin-lodash-fp)
to help use `lodash/fp` more efficiently.

View File

@@ -1,7 +0,0 @@
module.exports = {
'cap': false,
'curry': false,
'fixed': false,
'immutable': false,
'rearg': false
};

View File

@@ -1,16 +0,0 @@
module.exports = {
'ary': require('../ary'),
'assign': require('../_baseAssign'),
'clone': require('../clone'),
'curry': require('../curry'),
'forEach': require('../_arrayEach'),
'isArray': require('../isArray'),
'isError': require('../isError'),
'isFunction': require('../isFunction'),
'isWeakMap': require('../isWeakMap'),
'iteratee': require('../iteratee'),
'keys': require('../_baseKeys'),
'rearg': require('../rearg'),
'toInteger': require('../toInteger'),
'toPath': require('../toPath')
};

View File

@@ -1 +0,0 @@
module.exports = require('./<%= name %>');

View File

@@ -1,2 +0,0 @@
var convert = require('./convert');
module.exports = convert(require('../<%= name %>'));

View File

@@ -1,18 +0,0 @@
var baseConvert = require('./_baseConvert'),
util = require('./_util');
/**
* Converts `func` of `name` to an immutable auto-curried iteratee-first data-last
* version with conversion `options` applied. If `name` is an object its methods
* will be converted.
*
* @param {string} name The name of the function to wrap.
* @param {Function} [func] The function to wrap.
* @param {Object} [options] The options object. See `baseConvert` for more details.
* @returns {Function|Object} Returns the converted function or object.
*/
function convert(name, func, options) {
return baseConvert(util, name, func, options);
}
module.exports = convert;

View File

@@ -1,2 +0,0 @@
var _ = require('./lodash.min').runInContext();
module.exports = require('./fp/_baseConvert')(_, _);

View File

@@ -1,5 +0,0 @@
var convert = require('./convert'),
func = convert('<%= name %>', require('../<%= _.get(mapping.remap, name, name) %>'));
func.placeholder = require('./placeholder');
module.exports = func;

View File

@@ -1,5 +0,0 @@
var convert = require('./convert'),
func = convert('<%= name %>', require('../<%= _.get(mapping.remap, name, name) %>'), require('./_falseOptions'));
func.placeholder = require('./placeholder');
module.exports = func;

View File

@@ -1,31 +0,0 @@
'use strict';
const async = require('async');
const path = require('path');
const file = require('../common/file');
const util = require('../common/util');
const basePath = path.join(__dirname, '..', '..');
const distPath = path.join(basePath, 'dist');
const filename = 'lodash.js';
const baseLodash = path.join(basePath, filename);
const distLodash = path.join(distPath, filename);
/*----------------------------------------------------------------------------*/
/**
* Creates browser builds of Lodash at the `target` path.
*
* @private
* @param {string} target The output directory path.
*/
function build() {
async.series([
file.copy(baseLodash, distLodash),
file.min(distLodash)
], util.pitch);
}
build();

View File

@@ -1,83 +0,0 @@
'use strict';
const _ = require('lodash');
const docdown = require('docdown');
const fs = require('fs-extra');
const path = require('path');
const util = require('../common/util');
const basePath = path.join(__dirname, '..', '..');
const docPath = path.join(basePath, 'doc');
const readmePath = path.join(docPath, 'README.md');
const pkg = require('../../package.json');
const version = pkg.version;
const config = {
'base': {
'path': path.join(basePath, 'lodash.js'),
'title': `<a href="https://lodash.com/">lodash</a> <span>v${ version }</span>`,
'toc': 'categories',
'url': `https://github.com/lodash/lodash/blob/${ version }/lodash.js`
},
'github': {
'style': 'github',
'sublinks': [npmLink('&#x24C3;', 'See the npm package')]
},
'site': {
'entryLink': '<a href="${entryHref}" class="fa fa-link"></a>',
'sourceLink': '[source](${sourceHref})',
'tocHref': '',
'tocLink': '',
'sublinks': [npmLink('npm package')]
}
};
/**
* Composes a npm link from `text` and optional `title`.
*
* @private
* @param {string} text The link text.
* @param {string} [title] The link title.
* @returns {string} Returns the composed npm link.
*/
function npmLink(text, title) {
return (
'<% if (name == "templateSettings" || !/^(?:methods|properties|seq)$/i.test(category)) {' +
'print(' +
'"[' + text + '](https://www.npmjs.com/package/lodash." + name.toLowerCase() + ' +
'"' + (title == null ? '' : ' \\"' + title + '\\"') + ')"' +
');' +
'} %>'
);
}
/**
* Post-process `markdown` to make adjustments.
*
* @private
* @param {string} markdown The markdown to process.
* @returns {string} Returns the processed markdown.
*/
function postprocess(markdown) {
// Wrap symbol property identifiers in brackets.
return markdown.replace(/\.(Symbol\.(?:[a-z]+[A-Z]?)+)/g, '[$1]');
}
/*----------------------------------------------------------------------------*/
/**
* Creates the documentation markdown formatted for 'github' or 'site'.
*
* @private
* @param {string} type The format type.
*/
function build(type) {
const options = _.defaults({}, config.base, config[type]);
const markdown = docdown(options);
fs.writeFile(readmePath, postprocess(markdown), util.pitch);
}
build(_.last(process.argv));

View File

@@ -1,34 +0,0 @@
'use strict';
const _ = require('lodash');
const async = require('async');
const path = require('path');
const file = require('../common/file');
const util = require('../common/util');
const basePath = path.join(__dirname, '..', '..');
const distPath = path.join(basePath, 'dist');
const filePairs = [
[path.join(distPath, 'lodash.core.js'), 'core.js'],
[path.join(distPath, 'lodash.core.min.js'), 'core.min.js'],
[path.join(distPath, 'lodash.min.js'), 'lodash.min.js']
];
/*----------------------------------------------------------------------------*/
/**
* Creates supplementary Lodash modules at the `target` path.
*
* @private
* @param {string} target The output directory path.
*/
function build(target) {
const actions = _.map(filePairs, pair =>
file.copy(pair[0], path.join(target, pair[1])));
async.series(actions, util.pitch);
}
build(_.last(process.argv));

View File

@@ -1,224 +0,0 @@
'use strict';
const _ = require('lodash');
const cheerio = require('cheerio');
const fs = require('fs');
const marky = require('marky-markdown');
const path = require('path');
const util = require('../common/util');
const basePath = path.join(__dirname, '..', '..');
const docPath = path.join(basePath, 'doc');
const readmePath = path.join(docPath, 'README.md');
const highlights = {
'html': [
'string'
],
'js': [
'comment',
'console',
'delimiter',
'method',
'modifier',
'name',
'numeric',
'string',
'support',
'type'
]
};
const exts = _.keys(highlights);
/**
* Converts Lodash method references into documentation links.
*
* @private
* @param {Object} $ The Cheerio object.
*/
function autoLink($) {
$('.doc-container code').each(function() {
const $code = $(this);
const html = $code.html();
if (/^_\.\w+$/.test(html)) {
const id = html.split('.')[1];
$code.replaceWith(`<a href="#${ id }"><code>_.${ id }</code></a>`);
}
});
}
/**
* Removes horizontal rules from the document.
*
* @private
* @param {Object} $ The Cheerio object.
*/
function removeHorizontalRules($) {
$('hr').remove();
}
/**
* Removes marky-markdown specific ids and class names.
*
* @private
* @param {Object} $ The Cheerio object.
*/
function removeMarkyAttributes($) {
$('[id^="user-content-"]')
.attr('class', null)
.attr('id', null);
$(':header:not(h3) > a').each(function() {
const $a = $(this);
$a.replaceWith($a.html());
});
}
/**
* Renames "_" id and anchor references to "lodash".
*
* @private
* @param {Object} $ The Cheerio object.
*/
function renameLodashId($) {
$('#_').attr('id', 'lodash');
$('[href="#_"]').attr('href', '#lodash');
}
/**
* Repairs broken marky-markdown headers.
* See https://github.com/npm/marky-markdown/issues/217 for more details.
*
* @private
* @param {Object} $ The Cheerio object.
*/
function repairMarkyHeaders($) {
$('p:empty + h3').prev().remove();
$('h3 ~ p:empty').each(function() {
const $p = $(this);
let node = this.prev;
while ((node = node.prev) && node.name != 'h3' && node.name != 'p') {
$p.prepend(node.next);
}
});
$('h3 code em').parent().each(function() {
const $code = $(this);
$code.html($code.html().replace(/<\/?em>/g, '_'));
});
}
/**
* Cleans up highlights blocks by removing extraneous class names and elements.
*
* @private
* @param {Object} $ The Cheerio object.
*/
function tidyHighlights($) {
$('.highlight').each(function() {
let $spans;
const $parent = $(this);
const classes = $parent.find('.source,.text').first().attr('class').split(' ');
const ext = _(classes).intersection(exts).last();
$parent.addClass(ext);
// Remove line indicators for single line snippets.
$parent.children('pre').each(function() {
const $divs = $(this).children('div');
if ($divs.length == 1) {
$divs.replaceWith($divs.html());
}
});
// Remove extraneous class names.
$parent.find('[class]').each(function() {
const $element = $(this);
const classes = $element.attr('class').split(' ');
const attr = _(classes).intersection(highlights[ext]).join(' ');
$element.attr('class', attr || null);
});
// Collapse nested comment highlights.
$parent.find(`[class~="comment"]`).each(function() {
const $element = $(this);
$element.text($element.text().trim());
});
// Collapse nested string highlights.
$parent.find(`[class~="string"]`).each(function() {
const $element = $(this);
$element.text($element.text());
});
// Collapse nested spans.
while (($spans = $parent.find('span:not([class])')).length) {
$spans.each(function() {
let $span = $(this);
while ($span[0] && $span[0].name == 'span' && !$span.attr('class')) {
const $parent = $span.parent();
$span.replaceWith($span.html());
$span = $parent;
}
});
}
});
}
/*----------------------------------------------------------------------------*/
/**
* Creates the documentation HTML.
*
* @private
*/
function build() {
const markdown = fs
// Load markdown.
.readFileSync(readmePath, 'utf8')
// Uncomment docdown HTML hints.
.replace(/(<)!--\s*|\s*--(>)/g, '$1$2')
// Convert source and npm package links to anchors.
.replace(/\[source\]\(([^)]+)\) \[npm package\]\(([^)]+)\)/g, (match, href1, href2) =>
`<p><a href="${ href1 }">source</a> <a href="${ href2 }">npm package</a></p>`
);
const $ = cheerio.load(marky(markdown, {
'enableHeadingLinkIcons': false,
'sanitize': false
}));
const $header = $('h1').first().remove();
const version = $header.find('span').first().text().trim().slice(1);
// Auto-link Lodash method references.
autoLink($);
// Rename "_" id references to "lodash".
renameLodashId($);
// Remove docdown horizontal rules.
removeHorizontalRules($);
// Remove marky-markdown attribute additions.
removeMarkyAttributes($);
// Repair marky-markdown wrapping around headers.
repairMarkyHeaders($);
// Cleanup highlights.
tidyHighlights($);
const html = [
// Append YAML front matter.
'---',
'id: docs',
'layout: docs',
'title: Lodash Documentation',
'version: ' + (version || null),
'---',
'',
// Wrap in raw tags to avoid Liquid template tag processing.
'{% raw %}',
$.html().trim(),
'{% endraw %}',
''
].join('\n');
fs.writeFile(path.join(docPath, version + '.html'), html, util.pitch);
}
build();

15858
lodash.js

File diff suppressed because it is too large Load Diff

99
lodash.min.js vendored Normal file
View File

@@ -0,0 +1,99 @@
/**
* @license
* lodash 3.10.0 (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
* Build: `lodash modern -o ./lodash.js`
*/
;(function(){function n(n,t){if(n!==t){var r=null===n,e=n===w,u=n===n,o=null===t,i=t===w,f=t===t;if(n>t&&!o||!u||r&&!i&&f||e&&f)return 1;if(n<t&&!r||!f||o&&!e&&u||i&&u)return-1}return 0}function t(n,t,r){for(var e=n.length,u=r?e:-1;r?u--:++u<e;)if(t(n[u],u,n))return u;return-1}function r(n,t,r){if(t!==t)return p(n,r);r-=1;for(var e=n.length;++r<e;)if(n[r]===t)return r;return-1}function e(n){return typeof n=="function"||false}function u(n){return null==n?"":n+""}function o(n,t){for(var r=-1,e=n.length;++r<e&&-1<t.indexOf(n.charAt(r)););
return r}function i(n,t){for(var r=n.length;r--&&-1<t.indexOf(n.charAt(r)););return r}function f(t,r){return n(t.a,r.a)||t.b-r.b}function a(n){return Nn[n]}function c(n){return Tn[n]}function l(n,t,r){return t?n=Bn[n]:r&&(n=Dn[n]),"\\"+n}function s(n){return"\\"+Dn[n]}function p(n,t,r){var e=n.length;for(t+=r?0:-1;r?t--:++t<e;){var u=n[t];if(u!==u)return t}return-1}function h(n){return!!n&&typeof n=="object"}function _(n){return 160>=n&&9<=n&&13>=n||32==n||160==n||5760==n||6158==n||8192<=n&&(8202>=n||8232==n||8233==n||8239==n||8287==n||12288==n||65279==n);
}function v(n,t){for(var r=-1,e=n.length,u=-1,o=[];++r<e;)n[r]===t&&(n[r]=z,o[++u]=r);return o}function g(n){for(var t=-1,r=n.length;++t<r&&_(n.charCodeAt(t)););return t}function y(n){for(var t=n.length;t--&&_(n.charCodeAt(t)););return t}function d(n){return Ln[n]}function m(_){function Nn(n){if(h(n)&&!(Oo(n)||n instanceof zn)){if(n instanceof Ln)return n;if(nu.call(n,"__chain__")&&nu.call(n,"__wrapped__"))return Mr(n)}return new Ln(n)}function Tn(){}function Ln(n,t,r){this.__wrapped__=n,this.__actions__=r||[],
this.__chain__=!!t}function zn(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=false,this.__iteratees__=[],this.__takeCount__=Ru,this.__views__=[]}function Bn(){this.__data__={}}function Dn(n){var t=n?n.length:0;for(this.data={hash:gu(null),set:new lu};t--;)this.push(n[t])}function Mn(n,t){var r=n.data;return(typeof t=="string"||ge(t)?r.set.has(t):r.hash[t])?0:-1}function qn(n,t){var r=-1,e=n.length;for(t||(t=Be(e));++r<e;)t[r]=n[r];return t}function Pn(n,t){for(var r=-1,e=n.length;++r<e&&false!==t(n[r],r,n););
return n}function Kn(n,t){for(var r=-1,e=n.length;++r<e;)if(!t(n[r],r,n))return false;return true}function Vn(n,t){for(var r=-1,e=n.length,u=-1,o=[];++r<e;){var i=n[r];t(i,r,n)&&(o[++u]=i)}return o}function Gn(n,t){for(var r=-1,e=n.length,u=Be(e);++r<e;)u[r]=t(n[r],r,n);return u}function Jn(n,t){for(var r=-1,e=t.length,u=n.length;++r<e;)n[u+r]=t[r];return n}function Xn(n,t,r,e){var u=-1,o=n.length;for(e&&o&&(r=n[++u]);++u<o;)r=t(r,n[u],u,n);return r}function Hn(n,t){for(var r=-1,e=n.length;++r<e;)if(t(n[r],r,n))return true;
return false}function Qn(n,t,r,e){return n!==w&&nu.call(e,r)?n:t}function nt(n,t,r){for(var e=-1,u=zo(t),o=u.length;++e<o;){var i=u[e],f=n[i],a=r(f,t[i],i,n,t);(a===a?a===f:f!==f)&&(f!==w||i in n)||(n[i]=a)}return n}function tt(n,t){return null==t?n:et(t,zo(t),n)}function rt(n,t){for(var r=-1,e=null==n,u=!e&&Er(n),o=u?n.length:0,i=t.length,f=Be(i);++r<i;){var a=t[r];f[r]=u?Cr(a,o)?n[a]:w:e?w:n[a]}return f}function et(n,t,r){r||(r={});for(var e=-1,u=t.length;++e<u;){var o=t[e];r[o]=n[o]}return r}function ut(n,t,r){
var e=typeof n;return"function"==e?t===w?n:Bt(n,t,r):null==n?Fe:"object"==e?bt(n):t===w?ze(n):xt(n,t)}function ot(n,t,r,e,u,o,i){var f;if(r&&(f=u?r(n,e,u):r(n)),f!==w)return f;if(!ge(n))return n;if(e=Oo(n)){if(f=kr(n),!t)return qn(n,f)}else{var a=ru.call(n),c=a==K;if(a!=Z&&a!=B&&(!c||u))return Fn[a]?Rr(n,a,t):u?n:{};if(f=Ir(c?{}:n),!t)return tt(f,n)}for(o||(o=[]),i||(i=[]),u=o.length;u--;)if(o[u]==n)return i[u];return o.push(n),i.push(f),(e?Pn:_t)(n,function(e,u){f[u]=ot(e,t,r,u,n,o,i)}),f}function it(n,t,r){
if(typeof n!="function")throw new Ge(L);return su(function(){n.apply(w,r)},t)}function ft(n,t){var e=n?n.length:0,u=[];if(!e)return u;var o=-1,i=xr(),f=i==r,a=f&&t.length>=F&&gu&&lu?new Dn(t):null,c=t.length;a&&(i=Mn,f=false,t=a);n:for(;++o<e;)if(a=n[o],f&&a===a){for(var l=c;l--;)if(t[l]===a)continue n;u.push(a)}else 0>i(t,a,0)&&u.push(a);return u}function at(n,t){var r=true;return Su(n,function(n,e,u){return r=!!t(n,e,u)}),r}function ct(n,t,r,e){var u=e,o=u;return Su(n,function(n,i,f){i=+t(n,i,f),(r(i,u)||i===e&&i===o)&&(u=i,
o=n)}),o}function lt(n,t){var r=[];return Su(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function st(n,t,r,e){var u;return r(n,function(n,r,o){return t(n,r,o)?(u=e?r:n,false):void 0}),u}function pt(n,t,r,e){e||(e=[]);for(var u=-1,o=n.length;++u<o;){var i=n[u];h(i)&&Er(i)&&(r||Oo(i)||pe(i))?t?pt(i,t,r,e):Jn(e,i):r||(e[e.length]=i)}return e}function ht(n,t){Nu(n,t,Re)}function _t(n,t){return Nu(n,t,zo)}function vt(n,t){return Tu(n,t,zo)}function gt(n,t){for(var r=-1,e=t.length,u=-1,o=[];++r<e;){var i=t[r];
ve(n[i])&&(o[++u]=i)}return o}function yt(n,t,r){if(null!=n){r!==w&&r in Br(n)&&(t=[r]),r=0;for(var e=t.length;null!=n&&r<e;)n=n[t[r++]];return r&&r==e?n:w}}function dt(n,t,r,e,u,o){if(n===t)n=true;else if(null==n||null==t||!ge(n)&&!h(t))n=n!==n&&t!==t;else n:{var i=dt,f=Oo(n),a=Oo(t),c=D,l=D;f||(c=ru.call(n),c==B?c=Z:c!=Z&&(f=xe(n))),a||(l=ru.call(t),l==B?l=Z:l!=Z&&xe(t));var s=c==Z,a=l==Z,l=c==l;if(!l||f||s){if(!e&&(c=s&&nu.call(n,"__wrapped__"),a=a&&nu.call(t,"__wrapped__"),c||a)){n=i(c?n.value():n,a?t.value():t,r,e,u,o);
break n}if(l){for(u||(u=[]),o||(o=[]),c=u.length;c--;)if(u[c]==n){n=o[c]==t;break n}u.push(n),o.push(t),n=(f?yr:mr)(n,t,i,r,e,u,o),u.pop(),o.pop()}else n=false}else n=dr(n,t,c)}return n}function mt(n,t,r){var e=t.length,u=e,o=!r;if(null==n)return!u;for(n=Br(n);e--;){var i=t[e];if(o&&i[2]?i[1]!==n[i[0]]:!(i[0]in n))return false}for(;++e<u;){var i=t[e],f=i[0],a=n[f],c=i[1];if(o&&i[2]){if(a===w&&!(f in n))return false}else if(i=r?r(a,c,f):w,i===w?!dt(c,a,r,true):!i)return false}return true}function wt(n,t){var r=-1,e=Er(n)?Be(n.length):[];
return Su(n,function(n,u,o){e[++r]=t(n,u,o)}),e}function bt(n){var t=Ar(n);if(1==t.length&&t[0][2]){var r=t[0][0],e=t[0][1];return function(n){return null==n?false:n[r]===e&&(e!==w||r in Br(n))}}return function(n){return mt(n,t)}}function xt(n,t){var r=Oo(n),e=Wr(n)&&t===t&&!ge(t),u=n+"";return n=Dr(n),function(o){if(null==o)return false;var i=u;if(o=Br(o),!(!r&&e||i in o)){if(o=1==n.length?o:yt(o,Et(n,0,-1)),null==o)return false;i=Zr(n),o=Br(o)}return o[i]===t?t!==w||i in o:dt(t,o[i],w,true)}}function At(n,t,r,e,u){
if(!ge(n))return n;var o=Er(t)&&(Oo(t)||xe(t)),i=o?w:zo(t);return Pn(i||t,function(f,a){if(i&&(a=f,f=t[a]),h(f)){e||(e=[]),u||(u=[]);n:{for(var c=a,l=e,s=u,p=l.length,_=t[c];p--;)if(l[p]==_){n[c]=s[p];break n}var p=n[c],v=r?r(p,_,c,n,t):w,g=v===w;g&&(v=_,Er(_)&&(Oo(_)||xe(_))?v=Oo(p)?p:Er(p)?qn(p):[]:me(_)||pe(_)?v=pe(p)?ke(p):me(p)?p:{}:g=false),l.push(_),s.push(v),g?n[c]=At(v,_,r,l,s):(v===v?v!==p:p===p)&&(n[c]=v)}}else c=n[a],l=r?r(c,f,a,n,t):w,(s=l===w)&&(l=f),l===w&&(!o||a in n)||!s&&(l===l?l===c:c!==c)||(n[a]=l);
}),n}function jt(n){return function(t){return null==t?w:t[n]}}function kt(n){var t=n+"";return n=Dr(n),function(r){return yt(r,n,t)}}function It(n,t){for(var r=n?t.length:0;r--;){var e=t[r];if(e!=u&&Cr(e)){var u=e;pu.call(n,e,1)}}}function Rt(n,t){return n+yu(ku()*(t-n+1))}function Ot(n,t,r,e,u){return u(n,function(n,u,o){r=e?(e=false,n):t(r,n,u,o)}),r}function Et(n,t,r){var e=-1,u=n.length;for(t=null==t?0:+t||0,0>t&&(t=-t>u?0:u+t),r=r===w||r>u?u:+r||0,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Be(u);++e<u;)r[e]=n[e+t];
return r}function Ct(n,t){var r;return Su(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}function Ut(n,t){var r=n.length;for(n.sort(t);r--;)n[r]=n[r].c;return n}function Wt(t,r,e){var u=wr(),o=-1;return r=Gn(r,function(n){return u(n)}),t=wt(t,function(n){return{a:Gn(r,function(t){return t(n)}),b:++o,c:n}}),Ut(t,function(t,r){var u;n:{for(var o=-1,i=t.a,f=r.a,a=i.length,c=e.length;++o<a;)if(u=n(i[o],f[o])){if(o>=c)break n;o=e[o],u*="asc"===o||true===o?1:-1;break n}u=t.b-r.b}return u})}function $t(n,t){
var r=0;return Su(n,function(n,e,u){r+=+t(n,e,u)||0}),r}function St(n,t){var e=-1,u=xr(),o=n.length,i=u==r,f=i&&o>=F,a=f&&gu&&lu?new Dn(void 0):null,c=[];a?(u=Mn,i=false):(f=false,a=t?[]:c);n:for(;++e<o;){var l=n[e],s=t?t(l,e,n):l;if(i&&l===l){for(var p=a.length;p--;)if(a[p]===s)continue n;t&&a.push(s),c.push(l)}else 0>u(a,s,0)&&((t||f)&&a.push(s),c.push(l))}return c}function Ft(n,t){for(var r=-1,e=t.length,u=Be(e);++r<e;)u[r]=n[t[r]];return u}function Nt(n,t,r,e){for(var u=n.length,o=e?u:-1;(e?o--:++o<u)&&t(n[o],o,n););
return r?Et(n,e?0:o,e?o+1:u):Et(n,e?o+1:0,e?u:o)}function Tt(n,t){var r=n;r instanceof zn&&(r=r.value());for(var e=-1,u=t.length;++e<u;)var o=t[e],r=o.func.apply(o.thisArg,Jn([r],o.args));return r}function Lt(n,t,r){var e=0,u=n?n.length:e;if(typeof t=="number"&&t===t&&u<=Eu){for(;e<u;){var o=e+u>>>1,i=n[o];(r?i<=t:i<t)&&null!==i?e=o+1:u=o}return u}return zt(n,t,Fe,r)}function zt(n,t,r,e){t=r(t);for(var u=0,o=n?n.length:0,i=t!==t,f=null===t,a=t===w;u<o;){var c=yu((u+o)/2),l=r(n[c]),s=l!==w,p=l===l;
(i?p||e:f?p&&s&&(e||null!=l):a?p&&(e||s):null==l?0:e?l<=t:l<t)?u=c+1:o=c}return xu(o,Ou)}function Bt(n,t,r){if(typeof n!="function")return Fe;if(t===w)return n;switch(r){case 1:return function(r){return n.call(t,r)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,o){return n.call(t,r,e,u,o)};case 5:return function(r,e,u,o,i){return n.call(t,r,e,u,o,i)}}return function(){return n.apply(t,arguments)}}function Dt(n){var t=new ou(n.byteLength);return new hu(t).set(new hu(n)),
t}function Mt(n,t,r){for(var e=r.length,u=-1,o=bu(n.length-e,0),i=-1,f=t.length,a=Be(f+o);++i<f;)a[i]=t[i];for(;++u<e;)a[r[u]]=n[u];for(;o--;)a[i++]=n[u++];return a}function qt(n,t,r){for(var e=-1,u=r.length,o=-1,i=bu(n.length-u,0),f=-1,a=t.length,c=Be(i+a);++o<i;)c[o]=n[o];for(i=o;++f<a;)c[i+f]=t[f];for(;++e<u;)c[i+r[e]]=n[o++];return c}function Pt(n,t){return function(r,e,u){var o=t?t():{};if(e=wr(e,u,3),Oo(r)){u=-1;for(var i=r.length;++u<i;){var f=r[u];n(o,f,e(f,u,r),r)}}else Su(r,function(t,r,u){
n(o,t,e(t,r,u),u)});return o}}function Kt(n){return le(function(t,r){var e=-1,u=null==t?0:r.length,o=2<u?r[u-2]:w,i=2<u?r[2]:w,f=1<u?r[u-1]:w;for(typeof o=="function"?(o=Bt(o,f,5),u-=2):(o=typeof f=="function"?f:w,u-=o?1:0),i&&Ur(r[0],r[1],i)&&(o=3>u?w:o,u=1);++e<u;)(i=r[e])&&n(t,i,o);return t})}function Vt(n,t){return function(r,e){var u=r?Bu(r):0;if(!Sr(u))return n(r,e);for(var o=t?u:-1,i=Br(r);(t?o--:++o<u)&&false!==e(i[o],o,i););return r}}function Zt(n){return function(t,r,e){var u=Br(t);e=e(t);for(var o=e.length,i=n?o:-1;n?i--:++i<o;){
var f=e[i];if(false===r(u[f],f,u))break}return t}}function Yt(n,t){function r(){return(this&&this!==Zn&&this instanceof r?e:n).apply(t,arguments)}var e=Jt(n);return r}function Gt(n){return function(t){var r=-1;t=$e(Ce(t));for(var e=t.length,u="";++r<e;)u=n(u,t[r],r);return u}}function Jt(n){return function(){var t=arguments;switch(t.length){case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:
return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=$u(n.prototype),t=n.apply(r,t);return ge(t)?t:r}}function Xt(n){function t(r,e,u){return u&&Ur(r,e,u)&&(e=w),r=gr(r,n,w,w,w,w,w,e),r.placeholder=t.placeholder,r}return t}function Ht(n,t){return le(function(r){var e=r[0];return null==e?e:(r.push(t),n.apply(w,r))})}function Qt(n,t){return function(r,e,u){if(u&&Ur(r,e,u)&&(e=w),e=wr(e,u,3),1==e.length){
u=r=Oo(r)?r:zr(r);for(var o=e,i=-1,f=u.length,a=t,c=a;++i<f;){var l=u[i],s=+o(l);n(s,a)&&(a=s,c=l)}if(u=c,!r.length||u!==t)return u}return ct(r,e,n,t)}}function nr(n,r){return function(e,u,o){return u=wr(u,o,3),Oo(e)?(u=t(e,u,r),-1<u?e[u]:w):st(e,u,n)}}function tr(n){return function(r,e,u){return r&&r.length?(e=wr(e,u,3),t(r,e,n)):-1}}function rr(n){return function(t,r,e){return r=wr(r,e,3),st(t,r,n,true)}}function er(n){return function(){for(var t,r=arguments.length,e=n?r:-1,u=0,o=Be(r);n?e--:++e<r;){
var i=o[u++]=arguments[e];if(typeof i!="function")throw new Ge(L);!t&&Ln.prototype.thru&&"wrapper"==br(i)&&(t=new Ln([],true))}for(e=t?-1:r;++e<r;){var i=o[e],u=br(i),f="wrapper"==u?zu(i):w;t=f&&$r(f[0])&&f[1]==(E|k|R|C)&&!f[4].length&&1==f[9]?t[br(f[0])].apply(t,f[3]):1==i.length&&$r(i)?t[u]():t.thru(i)}return function(){var n=arguments,e=n[0];if(t&&1==n.length&&Oo(e)&&e.length>=F)return t.plant(e).value();for(var u=0,n=r?o[u].apply(this,n):e;++u<r;)n=o[u].call(this,n);return n}}}function ur(n,t){
return function(r,e,u){return typeof e=="function"&&u===w&&Oo(r)?n(r,e):t(r,Bt(e,u,3))}}function or(n){return function(t,r,e){return(typeof r!="function"||e!==w)&&(r=Bt(r,e,3)),n(t,r,Re)}}function ir(n){return function(t,r,e){return(typeof r!="function"||e!==w)&&(r=Bt(r,e,3)),n(t,r)}}function fr(n){return function(t,r,e){var u={};return r=wr(r,e,3),_t(t,function(t,e,o){o=r(t,e,o),e=n?o:e,t=n?t:o,u[e]=t}),u}}function ar(n){return function(t,r,e){return t=u(t),(n?t:"")+pr(t,r,e)+(n?"":t)}}function cr(n){
var t=le(function(r,e){var u=v(e,t.placeholder);return gr(r,n,w,e,u)});return t}function lr(n,t){return function(r,e,u,o){var i=3>arguments.length;return typeof e=="function"&&o===w&&Oo(r)?n(r,e,u,i):Ot(r,wr(e,o,4),u,i,t)}}function sr(n,t,r,e,u,o,i,f,a,c){function l(){for(var m=arguments.length,b=m,j=Be(m);b--;)j[b]=arguments[b];if(e&&(j=Mt(j,e,u)),o&&(j=qt(j,o,i)),_||y){var b=l.placeholder,k=v(j,b),m=m-k.length;if(m<c){var I=f?qn(f):w,m=bu(c-m,0),E=_?k:w,k=_?w:k,C=_?j:w,j=_?w:j;return t|=_?R:O,t&=~(_?O:R),
g||(t&=~(x|A)),j=[n,t,r,C,E,j,k,I,a,m],I=sr.apply(w,j),$r(n)&&Du(I,j),I.placeholder=b,I}}if(b=p?r:this,I=h?b[n]:n,f)for(m=j.length,E=xu(f.length,m),k=qn(j);E--;)C=f[E],j[E]=Cr(C,m)?k[C]:w;return s&&a<j.length&&(j.length=a),this&&this!==Zn&&this instanceof l&&(I=d||Jt(n)),I.apply(b,j)}var s=t&E,p=t&x,h=t&A,_=t&k,g=t&j,y=t&I,d=h?w:Jt(n);return l}function pr(n,t,r){return n=n.length,t=+t,n<t&&mu(t)?(t-=n,r=null==r?" ":r+"",Ue(r,vu(t/r.length)).slice(0,t)):""}function hr(n,t,r,e){function u(){for(var t=-1,f=arguments.length,a=-1,c=e.length,l=Be(c+f);++a<c;)l[a]=e[a];
for(;f--;)l[a++]=arguments[++t];return(this&&this!==Zn&&this instanceof u?i:n).apply(o?r:this,l)}var o=t&x,i=Jt(n);return u}function _r(n){var t=Pe[n];return function(n,r){return(r=r===w?0:+r||0)?(r=au(10,r),t(n*r)/r):t(n)}}function vr(n){return function(t,r,e,u){var o=wr(e);return null==e&&o===ut?Lt(t,r,n):zt(t,r,o(e,u,1),n)}}function gr(n,t,r,e,u,o,i,f){var a=t&A;if(!a&&typeof n!="function")throw new Ge(L);var c=e?e.length:0;if(c||(t&=~(R|O),e=u=w),c-=u?u.length:0,t&O){var l=e,s=u;e=u=w}var p=a?w:zu(n);
return r=[n,t,r,e,u,l,s,o,i,f],p&&(e=r[1],t=p[1],f=e|t,u=t==E&&e==k||t==E&&e==C&&r[7].length<=p[8]||t==(E|C)&&e==k,(f<E||u)&&(t&x&&(r[2]=p[2],f|=e&x?0:j),(e=p[3])&&(u=r[3],r[3]=u?Mt(u,e,p[4]):qn(e),r[4]=u?v(r[3],z):qn(p[4])),(e=p[5])&&(u=r[5],r[5]=u?qt(u,e,p[6]):qn(e),r[6]=u?v(r[5],z):qn(p[6])),(e=p[7])&&(r[7]=qn(e)),t&E&&(r[8]=null==r[8]?p[8]:xu(r[8],p[8])),null==r[9]&&(r[9]=p[9]),r[0]=p[0],r[1]=f),t=r[1],f=r[9]),r[9]=null==f?a?0:n.length:bu(f-c,0)||0,(p?Lu:Du)(t==x?Yt(r[0],r[2]):t!=R&&t!=(x|R)||r[4].length?sr.apply(w,r):hr.apply(w,r),r);
}function yr(n,t,r,e,u,o,i){var f=-1,a=n.length,c=t.length;if(a!=c&&(!u||c<=a))return false;for(;++f<a;){var l=n[f],c=t[f],s=e?e(u?c:l,u?l:c,f):w;if(s!==w){if(s)continue;return false}if(u){if(!Hn(t,function(n){return l===n||r(l,n,e,u,o,i)}))return false}else if(l!==c&&!r(l,c,e,u,o,i))return false}return true}function dr(n,t,r){switch(r){case M:case q:return+n==+t;case P:return n.name==t.name&&n.message==t.message;case V:return n!=+n?t!=+t:n==+t;case Y:case G:return n==t+""}return false}function mr(n,t,r,e,u,o,i){var f=zo(n),a=f.length,c=zo(t).length;
if(a!=c&&!u)return false;for(c=a;c--;){var l=f[c];if(!(u?l in t:nu.call(t,l)))return false}for(var s=u;++c<a;){var l=f[c],p=n[l],h=t[l],_=e?e(u?h:p,u?p:h,l):w;if(_===w?!r(p,h,e,u,o,i):!_)return false;s||(s="constructor"==l)}return s||(r=n.constructor,e=t.constructor,!(r!=e&&"constructor"in n&&"constructor"in t)||typeof r=="function"&&r instanceof r&&typeof e=="function"&&e instanceof e)?true:false}function wr(n,t,r){var e=Nn.callback||Se,e=e===Se?ut:e;return r?e(n,t,r):e}function br(n){for(var t=n.name,r=Wu[t],e=r?r.length:0;e--;){
var u=r[e],o=u.func;if(null==o||o==n)return u.name}return t}function xr(n,t,e){var u=Nn.indexOf||Vr,u=u===Vr?r:u;return n?u(n,t,e):u}function Ar(n){n=Oe(n);for(var t=n.length;t--;){var r=n[t][1];n[t][2]=r===r&&!ge(r)}return n}function jr(n,t){var r=null==n?w:n[t];return ye(r)?r:w}function kr(n){var t=n.length,r=new n.constructor(t);return t&&"string"==typeof n[0]&&nu.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function Ir(n){return n=n.constructor,typeof n=="function"&&n instanceof n||(n=Ve),
new n}function Rr(n,t,r){var e=n.constructor;switch(t){case J:return Dt(n);case M:case q:return new e(+n);case X:case H:case Q:case nn:case tn:case rn:case en:case un:case on:return t=n.buffer,new e(r?Dt(t):t,n.byteOffset,n.length);case V:case G:return new e(n);case Y:var u=new e(n.source,kn.exec(n));u.lastIndex=n.lastIndex}return u}function Or(n,t,r){return null==n||Wr(t,n)||(t=Dr(t),n=1==t.length?n:yt(n,Et(t,0,-1)),t=Zr(t)),t=null==n?n:n[t],null==t?w:t.apply(n,r)}function Er(n){return null!=n&&Sr(Bu(n));
}function Cr(n,t){return n=typeof n=="number"||On.test(n)?+n:-1,t=null==t?Cu:t,-1<n&&0==n%1&&n<t}function Ur(n,t,r){if(!ge(r))return false;var e=typeof t;return("number"==e?Er(r)&&Cr(t,r.length):"string"==e&&t in r)?(t=r[t],n===n?n===t:t!==t):false}function Wr(n,t){var r=typeof n;return"string"==r&&dn.test(n)||"number"==r?true:Oo(n)?false:!yn.test(n)||null!=t&&n in Br(t)}function $r(n){var t=br(n);return t in zn.prototype?(t=Nn[t],n===t?true:(t=zu(t),!!t&&n===t[0])):false}function Sr(n){return typeof n=="number"&&-1<n&&0==n%1&&n<=Cu;
}function Fr(n,t){return n===w?t:Eo(n,t,Fr)}function Nr(n,t){n=Br(n);for(var r=-1,e=t.length,u={};++r<e;){var o=t[r];o in n&&(u[o]=n[o])}return u}function Tr(n,t){var r={};return ht(n,function(n,e,u){t(n,e,u)&&(r[e]=n)}),r}function Lr(n){for(var t=Re(n),r=t.length,e=r&&n.length,u=!!e&&Sr(e)&&(Oo(n)||pe(n)),o=-1,i=[];++o<r;){var f=t[o];(u&&Cr(f,e)||nu.call(n,f))&&i.push(f)}return i}function zr(n){return null==n?[]:Er(n)?ge(n)?n:Ve(n):Ee(n)}function Br(n){return ge(n)?n:Ve(n)}function Dr(n){if(Oo(n))return n;
var t=[];return u(n).replace(mn,function(n,r,e,u){t.push(e?u.replace(An,"$1"):r||n)}),t}function Mr(n){return n instanceof zn?n.clone():new Ln(n.__wrapped__,n.__chain__,qn(n.__actions__))}function qr(n,t,r){return n&&n.length?((r?Ur(n,t,r):null==t)&&(t=1),Et(n,0>t?0:t)):[]}function Pr(n,t,r){var e=n?n.length:0;return e?((r?Ur(n,t,r):null==t)&&(t=1),t=e-(+t||0),Et(n,0,0>t?0:t)):[]}function Kr(n){return n?n[0]:w}function Vr(n,t,e){var u=n?n.length:0;if(!u)return-1;if(typeof e=="number")e=0>e?bu(u+e,0):e;else if(e)return e=Lt(n,t),
e<u&&(t===t?t===n[e]:n[e]!==n[e])?e:-1;return r(n,t,e||0)}function Zr(n){var t=n?n.length:0;return t?n[t-1]:w}function Yr(n){return qr(n,1)}function Gr(n,t,e,u){if(!n||!n.length)return[];null!=t&&typeof t!="boolean"&&(u=e,e=Ur(n,t,u)?w:t,t=false);var o=wr();if((null!=e||o!==ut)&&(e=o(e,u,3)),t&&xr()==r){t=e;var i;e=-1,u=n.length;for(var o=-1,f=[];++e<u;){var a=n[e],c=t?t(a,e,n):a;e&&i===c||(i=c,f[++o]=a)}n=f}else n=St(n,e);return n}function Jr(n){if(!n||!n.length)return[];var t=-1,r=0;n=Vn(n,function(n){
return Er(n)?(r=bu(n.length,r),true):void 0});for(var e=Be(r);++t<r;)e[t]=Gn(n,jt(t));return e}function Xr(n,t,r){return n&&n.length?(n=Jr(n),null==t?n:(t=Bt(t,r,4),Gn(n,function(n){return Xn(n,t,w,true)}))):[]}function Hr(n,t){var r=-1,e=n?n.length:0,u={};for(!e||t||Oo(n[0])||(t=[]);++r<e;){var o=n[r];t?u[o]=t[r]:o&&(u[o[0]]=o[1])}return u}function Qr(n){return n=Nn(n),n.__chain__=true,n}function ne(n,t,r){return t.call(r,n)}function te(n,t,r){var e=Oo(n)?Kn:at;return r&&Ur(n,t,r)&&(t=w),(typeof t!="function"||r!==w)&&(t=wr(t,r,3)),
e(n,t)}function re(n,t,r){var e=Oo(n)?Vn:lt;return t=wr(t,r,3),e(n,t)}function ee(n,t,r,e){var u=n?Bu(n):0;return Sr(u)||(n=Ee(n),u=n.length),r=typeof r!="number"||e&&Ur(t,r,e)?0:0>r?bu(u+r,0):r||0,typeof n=="string"||!Oo(n)&&be(n)?r<=u&&-1<n.indexOf(t,r):!!u&&-1<xr(n,t,r)}function ue(n,t,r){var e=Oo(n)?Gn:wt;return t=wr(t,r,3),e(n,t)}function oe(n,t,r){if(r?Ur(n,t,r):null==t){n=zr(n);var e=n.length;return 0<e?n[Rt(0,e-1)]:w}r=-1,n=je(n);var e=n.length,u=e-1;for(t=xu(0>t?0:+t||0,e);++r<t;){var e=Rt(r,u),o=n[e];
n[e]=n[r],n[r]=o}return n.length=t,n}function ie(n,t,r){var e=Oo(n)?Hn:Ct;return r&&Ur(n,t,r)&&(t=w),(typeof t!="function"||r!==w)&&(t=wr(t,r,3)),e(n,t)}function fe(n,t){var r;if(typeof t!="function"){if(typeof n!="function")throw new Ge(L);var e=n;n=t,t=e}return function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=w),r}}function ae(n,t,r){function e(t,r){r&&iu(r),a=p=h=w,t&&(_=ho(),c=n.apply(s,f),p||a||(f=s=w))}function u(){var n=t-(ho()-l);0>=n||n>t?e(h,a):p=su(u,n)}function o(){e(g,p);
}function i(){if(f=arguments,l=ho(),s=this,h=g&&(p||!y),false===v)var r=y&&!p;else{a||y||(_=l);var e=v-(l-_),i=0>=e||e>v;i?(a&&(a=iu(a)),_=l,c=n.apply(s,f)):a||(a=su(o,e))}return i&&p?p=iu(p):p||t===v||(p=su(u,t)),r&&(i=true,c=n.apply(s,f)),!i||p||a||(f=s=w),c}var f,a,c,l,s,p,h,_=0,v=false,g=true;if(typeof n!="function")throw new Ge(L);if(t=0>t?0:+t||0,true===r)var y=true,g=false;else ge(r)&&(y=!!r.leading,v="maxWait"in r&&bu(+r.maxWait||0,t),g="trailing"in r?!!r.trailing:g);return i.cancel=function(){p&&iu(p),a&&iu(a),
_=0,a=p=h=w},i}function ce(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],o=r.cache;return o.has(u)?o.get(u):(e=n.apply(this,e),r.cache=o.set(u,e),e)}if(typeof n!="function"||t&&typeof t!="function")throw new Ge(L);return r.cache=new ce.Cache,r}function le(n,t){if(typeof n!="function")throw new Ge(L);return t=bu(t===w?n.length-1:+t||0,0),function(){for(var r=arguments,e=-1,u=bu(r.length-t,0),o=Be(u);++e<u;)o[e]=r[t+e];switch(t){case 0:return n.call(this,o);case 1:return n.call(this,r[0],o);
case 2:return n.call(this,r[0],r[1],o)}for(u=Be(t+1),e=-1;++e<t;)u[e]=r[e];return u[t]=o,n.apply(this,u)}}function se(n,t){return n>t}function pe(n){return h(n)&&Er(n)&&nu.call(n,"callee")&&!cu.call(n,"callee")}function he(n,t,r,e){return e=(r=typeof r=="function"?Bt(r,e,3):w)?r(n,t):w,e===w?dt(n,t,r):!!e}function _e(n){return h(n)&&typeof n.message=="string"&&ru.call(n)==P}function ve(n){return ge(n)&&ru.call(n)==K}function ge(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function ye(n){
return null==n?false:ve(n)?uu.test(Qe.call(n)):h(n)&&Rn.test(n)}function de(n){return typeof n=="number"||h(n)&&ru.call(n)==V}function me(n){var t;if(!h(n)||ru.call(n)!=Z||pe(n)||!(nu.call(n,"constructor")||(t=n.constructor,typeof t!="function"||t instanceof t)))return false;var r;return ht(n,function(n,t){r=t}),r===w||nu.call(n,r)}function we(n){return ge(n)&&ru.call(n)==Y}function be(n){return typeof n=="string"||h(n)&&ru.call(n)==G}function xe(n){return h(n)&&Sr(n.length)&&!!Sn[ru.call(n)]}function Ae(n,t){
return n<t}function je(n){var t=n?Bu(n):0;return Sr(t)?t?qn(n):[]:Ee(n)}function ke(n){return et(n,Re(n))}function Ie(n){return gt(n,Re(n))}function Re(n){if(null==n)return[];ge(n)||(n=Ve(n));for(var t=n.length,t=t&&Sr(t)&&(Oo(n)||pe(n))&&t||0,r=n.constructor,e=-1,r=typeof r=="function"&&r.prototype===n,u=Be(t),o=0<t;++e<t;)u[e]=e+"";for(var i in n)o&&Cr(i,t)||"constructor"==i&&(r||!nu.call(n,i))||u.push(i);return u}function Oe(n){n=Br(n);for(var t=-1,r=zo(n),e=r.length,u=Be(e);++t<e;){var o=r[t];
u[t]=[o,n[o]]}return u}function Ee(n){return Ft(n,zo(n))}function Ce(n){return(n=u(n))&&n.replace(En,a).replace(xn,"")}function Ue(n,t){var r="";if(n=u(n),t=+t,1>t||!n||!mu(t))return r;do t%2&&(r+=n),t=yu(t/2),n+=n;while(t);return r}function We(n,t,r){var e=n;return(n=u(n))?(r?Ur(e,t,r):null==t)?n.slice(g(n),y(n)+1):(t+="",n.slice(o(n,t),i(n,t)+1)):n}function $e(n,t,r){return r&&Ur(n,t,r)&&(t=w),n=u(n),n.match(t||Wn)||[]}function Se(n,t,r){return r&&Ur(n,t,r)&&(t=w),h(n)?Ne(n):ut(n,t)}function Fe(n){
return n}function Ne(n){return bt(ot(n,true))}function Te(n,t,r){if(null==r){var e=ge(t),u=e?zo(t):w;((u=u&&u.length?gt(t,u):w)?u.length:e)||(u=false,r=t,t=n,n=this)}u||(u=gt(t,zo(t)));var o=true,e=-1,i=ve(n),f=u.length;false===r?o=false:ge(r)&&"chain"in r&&(o=r.chain);for(;++e<f;){r=u[e];var a=t[r];n[r]=a,i&&(n.prototype[r]=function(t){return function(){var r=this.__chain__;if(o||r){var e=n(this.__wrapped__);return(e.__actions__=qn(this.__actions__)).push({func:t,args:arguments,thisArg:n}),e.__chain__=r,e}return t.apply(n,Jn([this.value()],arguments));
}}(a))}return n}function Le(){}function ze(n){return Wr(n)?jt(n):kt(n)}_=_?Yn.defaults(Zn.Object(),_,Yn.pick(Zn,$n)):Zn;var Be=_.Array,De=_.Date,Me=_.Error,qe=_.Function,Pe=_.Math,Ke=_.Number,Ve=_.Object,Ze=_.RegExp,Ye=_.String,Ge=_.TypeError,Je=Be.prototype,Xe=Ve.prototype,He=Ye.prototype,Qe=qe.prototype.toString,nu=Xe.hasOwnProperty,tu=0,ru=Xe.toString,eu=Zn._,uu=Ze("^"+Qe.call(nu).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),ou=_.ArrayBuffer,iu=_.clearTimeout,fu=_.parseFloat,au=Pe.pow,cu=Xe.propertyIsEnumerable,lu=jr(_,"Set"),su=_.setTimeout,pu=Je.splice,hu=_.Uint8Array,_u=jr(_,"WeakMap"),vu=Pe.ceil,gu=jr(Ve,"create"),yu=Pe.floor,du=jr(Be,"isArray"),mu=_.isFinite,wu=jr(Ve,"keys"),bu=Pe.max,xu=Pe.min,Au=jr(De,"now"),ju=_.parseInt,ku=Pe.random,Iu=Ke.NEGATIVE_INFINITY,Ru=Ke.POSITIVE_INFINITY,Ou=4294967294,Eu=2147483647,Cu=9007199254740991,Uu=_u&&new _u,Wu={};
Nn.support={},Nn.templateSettings={escape:_n,evaluate:vn,interpolate:gn,variable:"",imports:{_:Nn}};var $u=function(){function n(){}return function(t){if(ge(t)){n.prototype=t;var r=new n;n.prototype=w}return r||{}}}(),Su=Vt(_t),Fu=Vt(vt,true),Nu=Zt(),Tu=Zt(true),Lu=Uu?function(n,t){return Uu.set(n,t),n}:Fe,zu=Uu?function(n){return Uu.get(n)}:Le,Bu=jt("length"),Du=function(){var n=0,t=0;return function(r,e){var u=ho(),o=S-(u-t);if(t=u,0<o){if(++n>=$)return r}else n=0;return Lu(r,e)}}(),Mu=le(function(n,t){
return h(n)&&Er(n)?ft(n,pt(t,false,true)):[]}),qu=tr(),Pu=tr(true),Ku=le(function(n){for(var t=n.length,e=t,u=Be(l),o=xr(),i=o==r,f=[];e--;){var a=n[e]=Er(a=n[e])?a:[];u[e]=i&&120<=a.length&&gu&&lu?new Dn(e&&a):null}var i=n[0],c=-1,l=i?i.length:0,s=u[0];n:for(;++c<l;)if(a=i[c],0>(s?Mn(s,a):o(f,a,0))){for(e=t;--e;){var p=u[e];if(0>(p?Mn(p,a):o(n[e],a,0)))continue n}s&&s.push(a),f.push(a)}return f}),Vu=le(function(t,r){r=pt(r);var e=rt(t,r);return It(t,r.sort(n)),e}),Zu=vr(),Yu=vr(true),Gu=le(function(n){return St(pt(n,false,true));
}),Ju=le(function(n,t){return Er(n)?ft(n,t):[]}),Xu=le(Jr),Hu=le(function(n){var t=n.length,r=2<t?n[t-2]:w,e=1<t?n[t-1]:w;return 2<t&&typeof r=="function"?t-=2:(r=1<t&&typeof e=="function"?(--t,e):w,e=w),n.length=t,Xr(n,r,e)}),Qu=le(function(n){return n=pt(n),this.thru(function(t){t=Oo(t)?t:[Br(t)];for(var r=n,e=-1,u=t.length,o=-1,i=r.length,f=Be(u+i);++e<u;)f[e]=t[e];for(;++o<i;)f[e++]=r[o];return f})}),no=le(function(n,t){return rt(n,pt(t))}),to=Pt(function(n,t,r){nu.call(n,r)?++n[r]:n[r]=1}),ro=nr(Su),eo=nr(Fu,true),uo=ur(Pn,Su),oo=ur(function(n,t){
for(var r=n.length;r--&&false!==t(n[r],r,n););return n},Fu),io=Pt(function(n,t,r){nu.call(n,r)?n[r].push(t):n[r]=[t]}),fo=Pt(function(n,t,r){n[r]=t}),ao=le(function(n,t,r){var e=-1,u=typeof t=="function",o=Wr(t),i=Er(n)?Be(n.length):[];return Su(n,function(n){var f=u?t:o&&null!=n?n[t]:w;i[++e]=f?f.apply(n,r):Or(n,t,r)}),i}),co=Pt(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),lo=lr(Xn,Su),so=lr(function(n,t,r,e){var u=n.length;for(e&&u&&(r=n[--u]);u--;)r=t(r,n[u],u,n);return r},Fu),po=le(function(n,t){
if(null==n)return[];var r=t[2];return r&&Ur(t[0],t[1],r)&&(t.length=1),Wt(n,pt(t),[])}),ho=Au||function(){return(new De).getTime()},_o=le(function(n,t,r){var e=x;if(r.length)var u=v(r,_o.placeholder),e=e|R;return gr(n,e,t,r,u)}),vo=le(function(n,t){t=t.length?pt(t):Ie(n);for(var r=-1,e=t.length;++r<e;){var u=t[r];n[u]=gr(n[u],x,n)}return n}),go=le(function(n,t,r){var e=x|A;if(r.length)var u=v(r,go.placeholder),e=e|R;return gr(t,e,n,r,u)}),yo=Xt(k),mo=Xt(I),wo=le(function(n,t){return it(n,1,t)}),bo=le(function(n,t,r){
return it(n,t,r)}),xo=er(),Ao=er(true),jo=le(function(n,t){if(t=pt(t),typeof n!="function"||!Kn(t,e))throw new Ge(L);var r=t.length;return le(function(e){for(var u=xu(e.length,r);u--;)e[u]=t[u](e[u]);return n.apply(this,e)})}),ko=cr(R),Io=cr(O),Ro=le(function(n,t){return gr(n,C,w,w,w,pt(t))}),Oo=du||function(n){return h(n)&&Sr(n.length)&&ru.call(n)==D},Eo=Kt(At),Co=Kt(function(n,t,r){return r?nt(n,t,r):tt(n,t)}),Uo=Ht(Co,function(n,t){return n===w?t:n}),Wo=Ht(Eo,Fr),$o=rr(_t),So=rr(vt),Fo=or(Nu),No=or(Tu),To=ir(_t),Lo=ir(vt),zo=wu?function(n){
var t=null==n?w:n.constructor;return typeof t=="function"&&t.prototype===n||typeof n!="function"&&Er(n)?Lr(n):ge(n)?wu(n):[]}:Lr,Bo=fr(true),Do=fr(),Mo=le(function(n,t){if(null==n)return{};if("function"!=typeof t[0])return t=Gn(pt(t),Ye),Nr(n,ft(Re(n),t));var r=Bt(t[0],t[1],3);return Tr(n,function(n,t,e){return!r(n,t,e)})}),qo=le(function(n,t){return null==n?{}:"function"==typeof t[0]?Tr(n,Bt(t[0],t[1],3)):Nr(n,pt(t))}),Po=Gt(function(n,t,r){return t=t.toLowerCase(),n+(r?t.charAt(0).toUpperCase()+t.slice(1):t);
}),Ko=Gt(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Vo=ar(),Zo=ar(true),Yo=Gt(function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}),Go=Gt(function(n,t,r){return n+(r?" ":"")+(t.charAt(0).toUpperCase()+t.slice(1))}),Jo=le(function(n,t){try{return n.apply(w,t)}catch(r){return _e(r)?r:new Me(r)}}),Xo=le(function(n,t){return function(r){return Or(r,n,t)}}),Ho=le(function(n,t){return function(r){return Or(n,r,t)}}),Qo=_r("ceil"),ni=_r("floor"),ti=Qt(se,Iu),ri=Qt(Ae,Ru),ei=_r("round");return Nn.prototype=Tn.prototype,
Ln.prototype=$u(Tn.prototype),Ln.prototype.constructor=Ln,zn.prototype=$u(Tn.prototype),zn.prototype.constructor=zn,Bn.prototype["delete"]=function(n){return this.has(n)&&delete this.__data__[n]},Bn.prototype.get=function(n){return"__proto__"==n?w:this.__data__[n]},Bn.prototype.has=function(n){return"__proto__"!=n&&nu.call(this.__data__,n)},Bn.prototype.set=function(n,t){return"__proto__"!=n&&(this.__data__[n]=t),this},Dn.prototype.push=function(n){var t=this.data;typeof n=="string"||ge(n)?t.set.add(n):t.hash[n]=true;
},ce.Cache=Bn,Nn.after=function(n,t){if(typeof t!="function"){if(typeof n!="function")throw new Ge(L);var r=n;n=t,t=r}return n=mu(n=+n)?n:0,function(){return 1>--n?t.apply(this,arguments):void 0}},Nn.ary=function(n,t,r){return r&&Ur(n,t,r)&&(t=w),t=n&&null==t?n.length:bu(+t||0,0),gr(n,E,w,w,w,w,t)},Nn.assign=Co,Nn.at=no,Nn.before=fe,Nn.bind=_o,Nn.bindAll=vo,Nn.bindKey=go,Nn.callback=Se,Nn.chain=Qr,Nn.chunk=function(n,t,r){t=(r?Ur(n,t,r):null==t)?1:bu(yu(t)||1,1),r=0;for(var e=n?n.length:0,u=-1,o=Be(vu(e/t));r<e;)o[++u]=Et(n,r,r+=t);
return o},Nn.compact=function(n){for(var t=-1,r=n?n.length:0,e=-1,u=[];++t<r;){var o=n[t];o&&(u[++e]=o)}return u},Nn.constant=function(n){return function(){return n}},Nn.countBy=to,Nn.create=function(n,t,r){var e=$u(n);return r&&Ur(n,t,r)&&(t=w),t?tt(e,t):e},Nn.curry=yo,Nn.curryRight=mo,Nn.debounce=ae,Nn.defaults=Uo,Nn.defaultsDeep=Wo,Nn.defer=wo,Nn.delay=bo,Nn.difference=Mu,Nn.drop=qr,Nn.dropRight=Pr,Nn.dropRightWhile=function(n,t,r){return n&&n.length?Nt(n,wr(t,r,3),true,true):[]},Nn.dropWhile=function(n,t,r){
return n&&n.length?Nt(n,wr(t,r,3),true):[]},Nn.fill=function(n,t,r,e){var u=n?n.length:0;if(!u)return[];for(r&&typeof r!="number"&&Ur(n,t,r)&&(r=0,e=u),u=n.length,r=null==r?0:+r||0,0>r&&(r=-r>u?0:u+r),e=e===w||e>u?u:+e||0,0>e&&(e+=u),u=r>e?0:e>>>0,r>>>=0;r<u;)n[r++]=t;return n},Nn.filter=re,Nn.flatten=function(n,t,r){var e=n?n.length:0;return r&&Ur(n,t,r)&&(t=false),e?pt(n,t):[]},Nn.flattenDeep=function(n){return n&&n.length?pt(n,true):[]},Nn.flow=xo,Nn.flowRight=Ao,Nn.forEach=uo,Nn.forEachRight=oo,Nn.forIn=Fo,
Nn.forInRight=No,Nn.forOwn=To,Nn.forOwnRight=Lo,Nn.functions=Ie,Nn.groupBy=io,Nn.indexBy=fo,Nn.initial=function(n){return Pr(n,1)},Nn.intersection=Ku,Nn.invert=function(n,t,r){r&&Ur(n,t,r)&&(t=w),r=-1;for(var e=zo(n),u=e.length,o={};++r<u;){var i=e[r],f=n[i];t?nu.call(o,f)?o[f].push(i):o[f]=[i]:o[f]=i}return o},Nn.invoke=ao,Nn.keys=zo,Nn.keysIn=Re,Nn.map=ue,Nn.mapKeys=Bo,Nn.mapValues=Do,Nn.matches=Ne,Nn.matchesProperty=function(n,t){return xt(n,ot(t,true))},Nn.memoize=ce,Nn.merge=Eo,Nn.method=Xo,Nn.methodOf=Ho,
Nn.mixin=Te,Nn.modArgs=jo,Nn.negate=function(n){if(typeof n!="function")throw new Ge(L);return function(){return!n.apply(this,arguments)}},Nn.omit=Mo,Nn.once=function(n){return fe(2,n)},Nn.pairs=Oe,Nn.partial=ko,Nn.partialRight=Io,Nn.partition=co,Nn.pick=qo,Nn.pluck=function(n,t){return ue(n,ze(t))},Nn.property=ze,Nn.propertyOf=function(n){return function(t){return yt(n,Dr(t),t+"")}},Nn.pull=function(){var n=arguments,t=n[0];if(!t||!t.length)return t;for(var r=0,e=xr(),u=n.length;++r<u;)for(var o=0,i=n[r];-1<(o=e(t,i,o));)pu.call(t,o,1);
return t},Nn.pullAt=Vu,Nn.range=function(n,t,r){r&&Ur(n,t,r)&&(t=r=w),n=+n||0,r=null==r?1:+r||0,null==t?(t=n,n=0):t=+t||0;var e=-1;t=bu(vu((t-n)/(r||1)),0);for(var u=Be(t);++e<t;)u[e]=n,n+=r;return u},Nn.rearg=Ro,Nn.reject=function(n,t,r){var e=Oo(n)?Vn:lt;return t=wr(t,r,3),e(n,function(n,r,e){return!t(n,r,e)})},Nn.remove=function(n,t,r){var e=[];if(!n||!n.length)return e;var u=-1,o=[],i=n.length;for(t=wr(t,r,3);++u<i;)r=n[u],t(r,u,n)&&(e.push(r),o.push(u));return It(n,o),e},Nn.rest=Yr,Nn.restParam=le,
Nn.set=function(n,t,r){if(null==n)return n;var e=t+"";t=null!=n[e]||Wr(t,n)?[e]:Dr(t);for(var e=-1,u=t.length,o=u-1,i=n;null!=i&&++e<u;){var f=t[e];ge(i)&&(e==o?i[f]=r:null==i[f]&&(i[f]=Cr(t[e+1])?[]:{})),i=i[f]}return n},Nn.shuffle=function(n){return oe(n,Ru)},Nn.slice=function(n,t,r){var e=n?n.length:0;return e?(r&&typeof r!="number"&&Ur(n,t,r)&&(t=0,r=e),Et(n,t,r)):[]},Nn.sortBy=function(n,t,r){if(null==n)return[];r&&Ur(n,t,r)&&(t=w);var e=-1;return t=wr(t,r,3),n=wt(n,function(n,r,u){return{a:t(n,r,u),
b:++e,c:n}}),Ut(n,f)},Nn.sortByAll=po,Nn.sortByOrder=function(n,t,r,e){return null==n?[]:(e&&Ur(t,r,e)&&(r=w),Oo(t)||(t=null==t?[]:[t]),Oo(r)||(r=null==r?[]:[r]),Wt(n,t,r))},Nn.spread=function(n){if(typeof n!="function")throw new Ge(L);return function(t){return n.apply(this,t)}},Nn.take=function(n,t,r){return n&&n.length?((r?Ur(n,t,r):null==t)&&(t=1),Et(n,0,0>t?0:t)):[]},Nn.takeRight=function(n,t,r){var e=n?n.length:0;return e?((r?Ur(n,t,r):null==t)&&(t=1),t=e-(+t||0),Et(n,0>t?0:t)):[]},Nn.takeRightWhile=function(n,t,r){
return n&&n.length?Nt(n,wr(t,r,3),false,true):[]},Nn.takeWhile=function(n,t,r){return n&&n.length?Nt(n,wr(t,r,3)):[]},Nn.tap=function(n,t,r){return t.call(r,n),n},Nn.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new Ge(L);return false===r?e=false:ge(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),ae(n,t,{leading:e,maxWait:+t,trailing:u})},Nn.thru=ne,Nn.times=function(n,t,r){if(n=yu(n),1>n||!mu(n))return[];var e=-1,u=Be(xu(n,4294967295));for(t=Bt(t,r,1);++e<n;)4294967295>e?u[e]=t(e):t(e);
return u},Nn.toArray=je,Nn.toPlainObject=ke,Nn.transform=function(n,t,r,e){var u=Oo(n)||xe(n);return t=wr(t,e,4),null==r&&(u||ge(n)?(e=n.constructor,r=u?Oo(n)?new e:[]:$u(ve(e)?e.prototype:w)):r={}),(u?Pn:_t)(n,function(n,e,u){return t(r,n,e,u)}),r},Nn.union=Gu,Nn.uniq=Gr,Nn.unzip=Jr,Nn.unzipWith=Xr,Nn.values=Ee,Nn.valuesIn=function(n){return Ft(n,Re(n))},Nn.where=function(n,t){return re(n,bt(t))},Nn.without=Ju,Nn.wrap=function(n,t){return t=null==t?Fe:t,gr(t,R,w,[n],[])},Nn.xor=function(){for(var n=-1,t=arguments.length;++n<t;){
var r=arguments[n];if(Er(r))var e=e?Jn(ft(e,r),ft(r,e)):r}return e?St(e):[]},Nn.zip=Xu,Nn.zipObject=Hr,Nn.zipWith=Hu,Nn.backflow=Ao,Nn.collect=ue,Nn.compose=Ao,Nn.each=uo,Nn.eachRight=oo,Nn.extend=Co,Nn.iteratee=Se,Nn.methods=Ie,Nn.object=Hr,Nn.select=re,Nn.tail=Yr,Nn.unique=Gr,Te(Nn,Nn),Nn.add=function(n,t){return(+n||0)+(+t||0)},Nn.attempt=Jo,Nn.camelCase=Po,Nn.capitalize=function(n){return(n=u(n))&&n.charAt(0).toUpperCase()+n.slice(1)},Nn.ceil=Qo,Nn.clone=function(n,t,r,e){return t&&typeof t!="boolean"&&Ur(n,t,r)?t=false:typeof t=="function"&&(e=r,
r=t,t=false),typeof r=="function"?ot(n,t,Bt(r,e,1)):ot(n,t)},Nn.cloneDeep=function(n,t,r){return typeof t=="function"?ot(n,true,Bt(t,r,1)):ot(n,true)},Nn.deburr=Ce,Nn.endsWith=function(n,t,r){n=u(n),t+="";var e=n.length;return r=r===w?e:xu(0>r?0:+r||0,e),r-=t.length,0<=r&&n.indexOf(t,r)==r},Nn.escape=function(n){return(n=u(n))&&hn.test(n)?n.replace(sn,c):n},Nn.escapeRegExp=function(n){return(n=u(n))&&bn.test(n)?n.replace(wn,l):n||"(?:)"},Nn.every=te,Nn.find=ro,Nn.findIndex=qu,Nn.findKey=$o,Nn.findLast=eo,
Nn.findLastIndex=Pu,Nn.findLastKey=So,Nn.findWhere=function(n,t){return ro(n,bt(t))},Nn.first=Kr,Nn.floor=ni,Nn.get=function(n,t,r){return n=null==n?w:yt(n,Dr(t),t+""),n===w?r:n},Nn.gt=se,Nn.gte=function(n,t){return n>=t},Nn.has=function(n,t){if(null==n)return false;var r=nu.call(n,t);if(!r&&!Wr(t)){if(t=Dr(t),n=1==t.length?n:yt(n,Et(t,0,-1)),null==n)return false;t=Zr(t),r=nu.call(n,t)}return r||Sr(n.length)&&Cr(t,n.length)&&(Oo(n)||pe(n))},Nn.identity=Fe,Nn.includes=ee,Nn.indexOf=Vr,Nn.inRange=function(n,t,r){
return t=+t||0,r===w?(r=t,t=0):r=+r||0,n>=xu(t,r)&&n<bu(t,r)},Nn.isArguments=pe,Nn.isArray=Oo,Nn.isBoolean=function(n){return true===n||false===n||h(n)&&ru.call(n)==M},Nn.isDate=function(n){return h(n)&&ru.call(n)==q},Nn.isElement=function(n){return!!n&&1===n.nodeType&&h(n)&&!me(n)},Nn.isEmpty=function(n){return null==n?true:Er(n)&&(Oo(n)||be(n)||pe(n)||h(n)&&ve(n.splice))?!n.length:!zo(n).length},Nn.isEqual=he,Nn.isError=_e,Nn.isFinite=function(n){return typeof n=="number"&&mu(n)},Nn.isFunction=ve,Nn.isMatch=function(n,t,r,e){
return r=typeof r=="function"?Bt(r,e,3):w,mt(n,Ar(t),r)},Nn.isNaN=function(n){return de(n)&&n!=+n},Nn.isNative=ye,Nn.isNull=function(n){return null===n},Nn.isNumber=de,Nn.isObject=ge,Nn.isPlainObject=me,Nn.isRegExp=we,Nn.isString=be,Nn.isTypedArray=xe,Nn.isUndefined=function(n){return n===w},Nn.kebabCase=Ko,Nn.last=Zr,Nn.lastIndexOf=function(n,t,r){var e=n?n.length:0;if(!e)return-1;var u=e;if(typeof r=="number")u=(0>r?bu(e+r,0):xu(r||0,e-1))+1;else if(r)return u=Lt(n,t,true)-1,n=n[u],(t===t?t===n:n!==n)?u:-1;
if(t!==t)return p(n,u,true);for(;u--;)if(n[u]===t)return u;return-1},Nn.lt=Ae,Nn.lte=function(n,t){return n<=t},Nn.max=ti,Nn.min=ri,Nn.noConflict=function(){return Zn._=eu,this},Nn.noop=Le,Nn.now=ho,Nn.pad=function(n,t,r){n=u(n),t=+t;var e=n.length;return e<t&&mu(t)?(e=(t-e)/2,t=yu(e),e=vu(e),r=pr("",e,r),r.slice(0,t)+n+r):n},Nn.padLeft=Vo,Nn.padRight=Zo,Nn.parseInt=function(n,t,r){return(r?Ur(n,t,r):null==t)?t=0:t&&(t=+t),n=We(n),ju(n,t||(In.test(n)?16:10))},Nn.random=function(n,t,r){r&&Ur(n,t,r)&&(t=r=w);
var e=null==n,u=null==t;return null==r&&(u&&typeof n=="boolean"?(r=n,n=1):typeof t=="boolean"&&(r=t,u=true)),e&&u&&(t=1,u=false),n=+n||0,u?(t=n,n=0):t=+t||0,r||n%1||t%1?(r=ku(),xu(n+r*(t-n+fu("1e-"+((r+"").length-1))),t)):Rt(n,t)},Nn.reduce=lo,Nn.reduceRight=so,Nn.repeat=Ue,Nn.result=function(n,t,r){var e=null==n?w:n[t];return e===w&&(null==n||Wr(t,n)||(t=Dr(t),n=1==t.length?n:yt(n,Et(t,0,-1)),e=null==n?w:n[Zr(t)]),e=e===w?r:e),ve(e)?e.call(n):e},Nn.round=ei,Nn.runInContext=m,Nn.size=function(n){var t=n?Bu(n):0;
return Sr(t)?t:zo(n).length},Nn.snakeCase=Yo,Nn.some=ie,Nn.sortedIndex=Zu,Nn.sortedLastIndex=Yu,Nn.startCase=Go,Nn.startsWith=function(n,t,r){return n=u(n),r=null==r?0:xu(0>r?0:+r||0,n.length),n.lastIndexOf(t,r)==r},Nn.sum=function(n,t,r){if(r&&Ur(n,t,r)&&(t=w),t=wr(t,r,3),1==t.length){n=Oo(n)?n:zr(n),r=n.length;for(var e=0;r--;)e+=+t(n[r])||0;n=e}else n=$t(n,t);return n},Nn.template=function(n,t,r){var e=Nn.templateSettings;r&&Ur(n,t,r)&&(t=r=w),n=u(n),t=nt(tt({},r||t),e,Qn),r=nt(tt({},t.imports),e.imports,Qn);
var o,i,f=zo(r),a=Ft(r,f),c=0;r=t.interpolate||Cn;var l="__p+='";r=Ze((t.escape||Cn).source+"|"+r.source+"|"+(r===gn?jn:Cn).source+"|"+(t.evaluate||Cn).source+"|$","g");var p="sourceURL"in t?"//# sourceURL="+t.sourceURL+"\n":"";if(n.replace(r,function(t,r,e,u,f,a){return e||(e=u),l+=n.slice(c,a).replace(Un,s),r&&(o=true,l+="'+__e("+r+")+'"),f&&(i=true,l+="';"+f+";\n__p+='"),e&&(l+="'+((__t=("+e+"))==null?'':__t)+'"),c=a+t.length,t}),l+="';",(t=t.variable)||(l="with(obj){"+l+"}"),l=(i?l.replace(fn,""):l).replace(an,"$1").replace(cn,"$1;"),
l="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(o?",__e=_.escape":"")+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}",t=Jo(function(){return qe(f,p+"return "+l).apply(w,a)}),t.source=l,_e(t))throw t;return t},Nn.trim=We,Nn.trimLeft=function(n,t,r){var e=n;return(n=u(n))?n.slice((r?Ur(e,t,r):null==t)?g(n):o(n,t+"")):n},Nn.trimRight=function(n,t,r){var e=n;return(n=u(n))?(r?Ur(e,t,r):null==t)?n.slice(0,y(n)+1):n.slice(0,i(n,t+"")+1):n;
},Nn.trunc=function(n,t,r){r&&Ur(n,t,r)&&(t=w);var e=U;if(r=W,null!=t)if(ge(t)){var o="separator"in t?t.separator:o,e="length"in t?+t.length||0:e;r="omission"in t?u(t.omission):r}else e=+t||0;if(n=u(n),e>=n.length)return n;if(e-=r.length,1>e)return r;if(t=n.slice(0,e),null==o)return t+r;if(we(o)){if(n.slice(e).search(o)){var i,f=n.slice(0,e);for(o.global||(o=Ze(o.source,(kn.exec(o)||"")+"g")),o.lastIndex=0;n=o.exec(f);)i=n.index;t=t.slice(0,null==i?e:i)}}else n.indexOf(o,e)!=e&&(o=t.lastIndexOf(o),
-1<o&&(t=t.slice(0,o)));return t+r},Nn.unescape=function(n){return(n=u(n))&&pn.test(n)?n.replace(ln,d):n},Nn.uniqueId=function(n){var t=++tu;return u(n)+t},Nn.words=$e,Nn.all=te,Nn.any=ie,Nn.contains=ee,Nn.eq=he,Nn.detect=ro,Nn.foldl=lo,Nn.foldr=so,Nn.head=Kr,Nn.include=ee,Nn.inject=lo,Te(Nn,function(){var n={};return _t(Nn,function(t,r){Nn.prototype[r]||(n[r]=t)}),n}(),false),Nn.sample=oe,Nn.prototype.sample=function(n){return this.__chain__||null!=n?this.thru(function(t){return oe(t,n)}):oe(this.value());
},Nn.VERSION=b,Pn("bind bindKey curry curryRight partial partialRight".split(" "),function(n){Nn[n].placeholder=Nn}),Pn(["drop","take"],function(n,t){zn.prototype[n]=function(r){var e=this.__filtered__;if(e&&!t)return new zn(this);r=null==r?1:bu(yu(r)||0,0);var u=this.clone();return e?u.__takeCount__=xu(u.__takeCount__,r):u.__views__.push({size:r,type:n+(0>u.__dir__?"Right":"")}),u},zn.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),Pn(["filter","map","takeWhile"],function(n,t){
var r=t+1,e=r!=T;zn.prototype[n]=function(n,t){var u=this.clone();return u.__iteratees__.push({iteratee:wr(n,t,1),type:r}),u.__filtered__=u.__filtered__||e,u}}),Pn(["first","last"],function(n,t){var r="take"+(t?"Right":"");zn.prototype[n]=function(){return this[r](1).value()[0]}}),Pn(["initial","rest"],function(n,t){var r="drop"+(t?"":"Right");zn.prototype[n]=function(){return this.__filtered__?new zn(this):this[r](1)}}),Pn(["pluck","where"],function(n,t){var r=t?"filter":"map",e=t?bt:ze;zn.prototype[n]=function(n){
return this[r](e(n))}}),zn.prototype.compact=function(){return this.filter(Fe)},zn.prototype.reject=function(n,t){return n=wr(n,t,1),this.filter(function(t){return!n(t)})},zn.prototype.slice=function(n,t){n=null==n?0:+n||0;var r=this;return r.__filtered__&&(0<n||0>t)?new zn(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==w&&(t=+t||0,r=0>t?r.dropRight(-t):r.take(t-n)),r)},zn.prototype.takeRightWhile=function(n,t){return this.reverse().takeWhile(n,t).reverse()},zn.prototype.toArray=function(){return this.take(Ru);
},_t(zn.prototype,function(n,t){var r=/^(?:filter|map|reject)|While$/.test(t),e=/^(?:first|last)$/.test(t),u=Nn[e?"take"+("last"==t?"Right":""):t];u&&(Nn.prototype[t]=function(){function t(n){return e&&i?u(n,1)[0]:u.apply(w,Jn([n],o))}var o=e?[1]:arguments,i=this.__chain__,f=this.__wrapped__,a=!!this.__actions__.length,c=f instanceof zn,l=o[0],s=c||Oo(f);return s&&r&&typeof l=="function"&&1!=l.length&&(c=s=false),l={func:ne,args:[t],thisArg:w},a=c&&!a,e&&!i?a?(f=f.clone(),f.__actions__.push(l),n.call(f)):u.call(w,this.value())[0]:!e&&s?(f=a?f:new zn(this),
f=n.apply(f,o),f.__actions__.push(l),new Ln(f,i)):this.thru(t)})}),Pn("join pop push replace shift sort splice split unshift".split(" "),function(n){var t=(/^(?:replace|split)$/.test(n)?He:Je)[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:join|pop|replace|shift)$/.test(n);Nn.prototype[n]=function(){var n=arguments;return e&&!this.__chain__?t.apply(this.value(),n):this[r](function(r){return t.apply(r,n)})}}),_t(zn.prototype,function(n,t){var r=Nn[t];if(r){var e=r.name;(Wu[e]||(Wu[e]=[])).push({
name:t,func:r})}}),Wu[sr(w,A).name]=[{name:"wrapper",func:w}],zn.prototype.clone=function(){var n=new zn(this.__wrapped__);return n.__actions__=qn(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=qn(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=qn(this.__views__),n},zn.prototype.reverse=function(){if(this.__filtered__){var n=new zn(this);n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},zn.prototype.value=function(){
var n,t=this.__wrapped__.value(),r=this.__dir__,e=Oo(t),u=0>r,o=e?t.length:0;n=o;for(var i=this.__views__,f=0,a=-1,c=i.length;++a<c;){var l=i[a],s=l.size;switch(l.type){case"drop":f+=s;break;case"dropRight":n-=s;break;case"take":n=xu(n,f+s);break;case"takeRight":f=bu(f,n-s)}}if(n={start:f,end:n},i=n.start,f=n.end,n=f-i,i=u?f:i-1,f=this.__iteratees__,a=f.length,c=0,l=xu(n,this.__takeCount__),!e||o<F||o==n&&l==n)return Tt(u&&e?t.reverse():t,this.__actions__);e=[];n:for(;n--&&c<l;){for(i+=r,u=-1,o=t[i];++u<a;){
var p=f[u],s=p.type,p=p.iteratee(o);if(s==T)o=p;else if(!p){if(s==N)continue n;break n}}e[c++]=o}return e},Nn.prototype.chain=function(){return Qr(this)},Nn.prototype.commit=function(){return new Ln(this.value(),this.__chain__)},Nn.prototype.concat=Qu,Nn.prototype.plant=function(n){for(var t,r=this;r instanceof Tn;){var e=Mr(r);t?u.__wrapped__=e:t=e;var u=e,r=r.__wrapped__}return u.__wrapped__=n,t},Nn.prototype.reverse=function(){function n(n){return r&&0>r.__dir__?n:n.reverse()}var t=this.__wrapped__;
if(t instanceof zn){var r=t;return this.__actions__.length&&(r=new zn(this)),r=r.reverse(),r.__actions__.push({func:ne,args:[n],thisArg:w}),new Ln(r,this.__chain__)}return this.thru(n)},Nn.prototype.toString=function(){return this.value()+""},Nn.prototype.run=Nn.prototype.toJSON=Nn.prototype.valueOf=Nn.prototype.value=function(){return Tt(this.__wrapped__,this.__actions__)},Nn.prototype.collect=Nn.prototype.map,Nn.prototype.head=Nn.prototype.first,Nn.prototype.select=Nn.prototype.filter,Nn.prototype.tail=Nn.prototype.rest,
Nn}var w,b="3.10.0",x=1,A=2,j=4,k=8,I=16,R=32,O=64,E=128,C=256,U=30,W="...",$=150,S=16,F=200,N=1,T=2,L="Expected a function",z="__lodash_placeholder__",B="[object Arguments]",D="[object Array]",M="[object Boolean]",q="[object Date]",P="[object Error]",K="[object Function]",V="[object Number]",Z="[object Object]",Y="[object RegExp]",G="[object String]",J="[object ArrayBuffer]",X="[object Float32Array]",H="[object Float64Array]",Q="[object Int8Array]",nn="[object Int16Array]",tn="[object Int32Array]",rn="[object Uint8Array]",en="[object Uint8ClampedArray]",un="[object Uint16Array]",on="[object Uint32Array]",fn=/\b__p\+='';/g,an=/\b(__p\+=)''\+/g,cn=/(__e\(.*?\)|\b__t\))\+'';/g,ln=/&(?:amp|lt|gt|quot|#39|#96);/g,sn=/[&<>"'`]/g,pn=RegExp(ln.source),hn=RegExp(sn.source),_n=/<%-([\s\S]+?)%>/g,vn=/<%([\s\S]+?)%>/g,gn=/<%=([\s\S]+?)%>/g,yn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,dn=/^\w*$/,mn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g,wn=/^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g,bn=RegExp(wn.source),xn=/[\u0300-\u036f\ufe20-\ufe23]/g,An=/\\(\\)?/g,jn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,kn=/\w*$/,In=/^0[xX]/,Rn=/^\[object .+?Constructor\]$/,On=/^\d+$/,En=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,Cn=/($^)/,Un=/['\n\r\u2028\u2029\\]/g,Wn=RegExp("[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?=[A-Z\\xc0-\\xd6\\xd8-\\xde][a-z\\xdf-\\xf6\\xf8-\\xff]+)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+|[A-Z\\xc0-\\xd6\\xd8-\\xde]+|[0-9]+","g"),$n="Array ArrayBuffer Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Math Number Object RegExp Set String _ clearTimeout isFinite parseFloat parseInt setTimeout TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap".split(" "),Sn={};
Sn[X]=Sn[H]=Sn[Q]=Sn[nn]=Sn[tn]=Sn[rn]=Sn[en]=Sn[un]=Sn[on]=true,Sn[B]=Sn[D]=Sn[J]=Sn[M]=Sn[q]=Sn[P]=Sn[K]=Sn["[object Map]"]=Sn[V]=Sn[Z]=Sn[Y]=Sn["[object Set]"]=Sn[G]=Sn["[object WeakMap]"]=false;var Fn={};Fn[B]=Fn[D]=Fn[J]=Fn[M]=Fn[q]=Fn[X]=Fn[H]=Fn[Q]=Fn[nn]=Fn[tn]=Fn[V]=Fn[Z]=Fn[Y]=Fn[G]=Fn[rn]=Fn[en]=Fn[un]=Fn[on]=true,Fn[P]=Fn[K]=Fn["[object Map]"]=Fn["[object Set]"]=Fn["[object WeakMap]"]=false;var Nn={"\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"},Tn={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","`":"&#96;"},Ln={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'","&#96;":"`"},zn={"function":true,object:true},Bn={0:"x30",1:"x31",2:"x32",3:"x33",4:"x34",5:"x35",6:"x36",7:"x37",8:"x38",9:"x39",A:"x41",B:"x42",C:"x43",D:"x44",E:"x45",F:"x46",a:"x61",b:"x62",c:"x63",d:"x64",e:"x65",f:"x66",n:"x6e",r:"x72",t:"x74",u:"x75",v:"x76",x:"x78"},Dn={"\\":"\\",
"'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Mn=zn[typeof exports]&&exports&&!exports.nodeType&&exports,qn=zn[typeof module]&&module&&!module.nodeType&&module,Pn=zn[typeof self]&&self&&self.Object&&self,Kn=zn[typeof window]&&window&&window.Object&&window,Vn=qn&&qn.exports===Mn&&Mn,Zn=Mn&&qn&&typeof global=="object"&&global&&global.Object&&global||Kn!==(this&&this.window)&&Kn||Pn||this,Yn=m();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Zn._=Yn, define(function(){
return Yn})):Mn&&qn?Vn?(qn.exports=Yn)._=Yn:Mn._=Yn:Zn._=Yn}).call(this);

12555
lodash.src.js Normal file

File diff suppressed because it is too large Load Diff

5837
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,66 +1,33 @@
{ {
"name": "lodash", "name": "lodash",
"version": "4.17.20", "version": "3.10.0",
"license": "MIT", "main": "lodash.src.js",
"private": true, "private": true,
"main": "lodash.js",
"engines": {
"node": ">=4.0.0"
},
"scripts": {
"build": "npm run build:main && npm run build:fp",
"build:fp": "node lib/fp/build-dist.js",
"build:fp-modules": "node lib/fp/build-modules.js",
"build:main": "node lib/main/build-dist.js",
"build:main-modules": "node lib/main/build-modules.js",
"doc": "node lib/main/build-doc github && npm run test:doc",
"doc:fp": "node lib/fp/build-doc",
"doc:site": "node lib/main/build-doc site",
"doc:sitehtml": "optional-dev-dependency marky-markdown@^9.0.1 && npm run doc:site && node lib/main/build-site",
"pretest": "npm run build",
"style": "npm run style:main && npm run style:fp && npm run style:perf && npm run style:test",
"style:fp": "jscs fp/*.js lib/**/*.js",
"style:main": "jscs lodash.js",
"style:perf": "jscs perf/*.js perf/**/*.js",
"style:test": "jscs test/*.js test/**/*.js",
"test": "npm run test:main && npm run test:fp",
"test:doc": "markdown-doctest doc/*.md",
"test:fp": "node test/test-fp",
"test:main": "node test/test",
"validate": "npm run style && npm run test"
},
"devDependencies": { "devDependencies": {
"async": "^2.6.3", "curl-amd": "0.8.12",
"benchmark": "^2.1.3", "dojo": "~1.10.0",
"chalk": "^1.1.3", "jquery": "~1.11.0",
"cheerio": "^0.22.0", "platform": "~1.3.0",
"codecov.io": "~0.1.6", "qunit-extras": "~1.4.0",
"coveralls": "^2.11.15", "qunitjs": "~1.18.0",
"curl-amd": "~0.8.12", "requirejs": "~2.1.0"
"docdown": "~0.7.2",
"dojo": "^1.15.0",
"ecstatic": "^2.2.2",
"fs-extra": "~1.0.0",
"glob": "^7.1.4",
"istanbul": "0.4.5",
"jquery": "^3.4.1",
"jscs": "^3.0.7",
"lodash": "4.17.14",
"lodash-doc-globals": "^0.1.1",
"markdown-doctest": "^0.9.1",
"optional-dev-dependency": "^2.0.0",
"platform": "^1.3.3",
"qunit-extras": "^3.0.0",
"qunitjs": "^2.1.0",
"request": "^2.88.0",
"requirejs": "^2.3.6",
"sauce-tunnel": "^2.5.0",
"uglify-js": "2.7.5",
"webpack": "^1.14.0"
}, },
"greenkeeper": { "volo": {
"type": "directory",
"ignore": [ "ignore": [
"lodash" ".*",
"*.custom.*",
"*.log",
"*.map",
"*.md",
"lodash.src.js",
"bower.json",
"component.json",
"doc",
"node_modules",
"perf",
"test",
"vendor"
] ]
} }
} }

View File

@@ -15,8 +15,27 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/**
* Registers an event listener on an element.
*
* @private
* @param {Element} element The element.
* @param {string} eventName The name of the event.
* @param {Function} handler The event handler.
* @returns {Element} The element.
*/
function addListener(element, eventName, handler) {
if (typeof element.addEventListener != 'undefined') {
element.addEventListener(eventName, handler, false);
} else if (typeof element.attachEvent != 'undefined') {
element.attachEvent('on' + eventName, handler);
}
}
/*--------------------------------------------------------------------------*/
// Initialize controls. // Initialize controls.
addEventListener('load', function() { addListener(window, 'load', function() {
function eventHandler(event) { function eventHandler(event) {
var buildIndex = buildList.selectedIndex, var buildIndex = buildList.selectedIndex,
otherIndex = otherList.selectedIndex, otherIndex = otherList.selectedIndex,
@@ -39,7 +58,10 @@
span1.innerHTML = span1.innerHTML =
'<label for="perf-build">Build: </label>' + '<label for="perf-build">Build: </label>' +
'<select id="perf-build">' + '<select id="perf-build">' +
'<option value="lodash">lodash (production)</option>' + '<option value="lodash-compat">lodash (compat)</option>' +
'<option value="lodash-modern">lodash (modern)</option>' +
'<option value="lodash-custom-dev">lodash (custom development)</option>' +
'<option value="lodash-custom">lodash (custom production)</option>' +
'</select>'; '</select>';
var span2 = document.createElement('span'); var span2 = document.createElement('span');
@@ -49,7 +71,10 @@
'<select id="perf-other">' + '<select id="perf-other">' +
'<option value="underscore-dev">Underscore (development)</option>' + '<option value="underscore-dev">Underscore (development)</option>' +
'<option value="underscore">Underscore (production)</option>' + '<option value="underscore">Underscore (production)</option>' +
'<option value="lodash">lodash</option>' + '<option value="lodash-compat">lodash (compat)</option>' +
'<option value="lodash-modern">lodash (modern)</option>' +
'<option value="lodash-custom-dev">lodash (custom development)</option>' +
'<option value="lodash-custom">lodash (custom production)</option>' +
'</select>'; '</select>';
var buildList = span1.lastChild, var buildList = span1.lastChild,
@@ -61,8 +86,11 @@
buildList.selectedIndex = (function() { buildList.selectedIndex = (function() {
switch (build) { switch (build) {
case 'lodash': case 'lodash-compat': return 0;
case null: return 0; case 'lodash-custom-dev': return 2;
case 'lodash-custom': return 3;
case 'lodash-modern':
case null: return 1;
} }
return -1; return -1;
}()); }());
@@ -70,23 +98,29 @@
otherList.selectedIndex = (function() { otherList.selectedIndex = (function() {
switch (other) { switch (other) {
case 'underscore-dev': return 0; case 'underscore-dev': return 0;
case 'lodash': return 2; case 'lodash-compat': return 2;
case 'lodash-modern': return 3;
case 'lodash-custom-dev': return 4;
case 'lodash-custom': return 5;
case 'underscore': case 'underscore':
case null: return 1; case null: return 1;
} }
return -1; return -1;
}()); }());
buildList.addEventListener('change', eventHandler); addListener(buildList, 'change', eventHandler);
otherList.addEventListener('change', eventHandler); addListener(otherList, 'change', eventHandler);
}); });
// The lodash build file path. // The lodash build file path.
ui.buildPath = (function() { ui.buildPath = (function() {
var result; var result;
switch (build) { switch (build) {
case null: build = 'lodash'; case 'lodash-compat': result = 'lodash.compat.min.js'; break;
case 'lodash': result = 'dist/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-modern';
case 'lodash-modern': result = 'lodash.min.js'; break;
default: return build; default: return build;
} }
return basePath + result; return basePath + result;
@@ -96,7 +130,10 @@
ui.otherPath = (function() { ui.otherPath = (function() {
var result; var result;
switch (other) { switch (other) {
case 'lodash': result = 'dist/lodash.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 '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; case 'underscore': result = 'vendor/underscore/underscore-min.js'; break;

View File

@@ -9,35 +9,28 @@
padding: 0; padding: 0;
height: 100%; height: 100%;
} }
applet {
position: absolute;
left: -9999em;
}
#FirebugUI { #FirebugUI {
top: 2.5em; top: 2em;
} }
#perf-toolbar { #perf-toolbar {
background-color: #EEE; background-color: #EEE;
color: #5E740B; color: #5E740B;
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
font-size: small; font-size: small;
padding: 0.5em 1em 0.5em 1em; padding: 0.5em 0 0.5em 2em;
overflow: hidden; overflow: hidden;
} }
#perf-toolbar label {
display: inline-block;
margin-right: 0.5em;
}
#perf-toolbar span {
display: inline-block;
float: right;
line-height: 2.1em;
margin-left: 1em;
margin-top: 0;
}
</style> </style>
</head> </head>
<body> <body>
<div id="perf-toolbar"></div> <div id="perf-toolbar"></div>
<script src="../lodash.js"></script>
<script src="../node_modules/platform/platform.js"></script> <script src="../node_modules/platform/platform.js"></script>
<script src="../node_modules/benchmark/benchmark.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="../vendor/firebug-lite/src/firebug-lite-debug.js"></script>
<script src="./asset/perf-ui.js"></script> <script src="./asset/perf-ui.js"></script>
<script> <script>
@@ -73,6 +66,15 @@
setTimeout(run, 15); setTimeout(run, 15);
} }
// 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')) {
// load applet
document.write('<applet code="nano" archive="../vendor/benchmark.js/nano.jar"></applet>');
}
}
window.onload = init; window.onload = init;
}()); }());
</script> </script>

View File

@@ -1,5 +1,4 @@
;(function() { ;(function() {
'use strict';
/** Used to access the Firebug Lite panel (set by `run`). */ /** Used to access the Firebug Lite panel (set by `run`). */
var fbPanel; var fbPanel;
@@ -39,16 +38,16 @@
result = params; result = params;
} }
var last = result[result.length - 1]; var last = result[result.length - 1];
result = (result.length > min && !/perf(?:\.js)?$/.test(last)) ? last : '../lodash.js'; result = (result.length > min && !/perf(?:\.js)?$/.test(last)) ? last : '../lodash.src.js';
if (!amd) { if (!amd) {
try { try {
result = require('fs').realpathSync(result); result = require('fs').realpathSync(result);
} catch (e) {} } catch(e) {}
try { try {
result = require.resolve(result); result = require.resolve(result);
} catch (e) {} } catch(e) {}
} }
return result; return result;
}()); }());
@@ -83,10 +82,19 @@
/** Used to queue benchmark suites. */ /** Used to queue benchmark suites. */
var 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 if in a Java environment. */
var isJava = !isBrowser && /Java/.test(toString.call(root.java));
/** Use a single "load" function. */ /** Use a single "load" function. */
var load = (typeof require == 'function' && !amd) var load = (typeof require == 'function' && !amd)
? require ? require
: noop; : (isJava && root.load) || noop;
/** Load lodash. */ /** Load lodash. */
var lodash = root.lodash || (root.lodash = ( var lodash = root.lodash || (root.lodash = (
@@ -96,19 +104,19 @@
lodash.noConflict() lodash.noConflict()
)); ));
/** Load Underscore. */
var _ = root.underscore || (root.underscore = (
_ = load('../vendor/underscore/underscore.js') || root._,
_._ || _
));
/** Load Benchmark.js. */ /** Load Benchmark.js. */
var Benchmark = root.Benchmark || (root.Benchmark = ( var Benchmark = root.Benchmark || (root.Benchmark = (
Benchmark = load('../node_modules/benchmark/benchmark.js') || root.Benchmark, Benchmark = load('../vendor/benchmark.js/benchmark.js') || root.Benchmark,
Benchmark = Benchmark.Benchmark || Benchmark, Benchmark = Benchmark.Benchmark || Benchmark,
Benchmark.runInContext(lodash.extend({}, root, { '_': lodash })) Benchmark.runInContext(lodash.extend({}, root, { '_': lodash }))
)); ));
/** Load Underscore. */
var _ = root._ || (root._ = (
_ = load('../vendor/underscore/underscore.js') || root._,
_._ || _
));
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/** /**
@@ -197,7 +205,7 @@
fbPanel.getElementById('fbPanel1'); fbPanel.getElementById('fbPanel1');
log('\nSit back and relax, this may take a while.'); log('\nSit back and relax, this may take a while.');
suites[0].run({ 'async': true }); suites[0].run({ 'async': !isJava });
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -250,7 +258,7 @@
if (suites.length) { if (suites.length) {
// Run next suite. // Run next suite.
suites[0].run({ 'async': true }); suites[0].run({ 'async': !isJava });
} }
else { else {
var aMeanHz = getGeometricMean(score.a), var aMeanHz = getGeometricMean(score.a),
@@ -276,7 +284,7 @@
lodash.extend(Benchmark.options, { lodash.extend(Benchmark.options, {
'async': true, 'async': true,
'setup': '\ 'setup': '\
var _ = global.underscore,\ var _ = global._,\
lodash = global.lodash,\ lodash = global.lodash,\
belt = this.name == buildName ? lodash : _;\ belt = this.name == buildName ? lodash : _;\
\ \
@@ -343,8 +351,8 @@
square = function(v) { return v * v; };\ square = function(v) { return v * v; };\
\ \
var largeArray = belt.range(10000),\ var largeArray = belt.range(10000),\
_chaining = _(largeArray).chain(),\ _chaining = _.chain ? _(largeArray).chain() : _(largeArray),\
lodashChaining = lodash(largeArray).chain();\ lodashChaining = lodash(largeArray);\
}\ }\
if (typeof compact != "undefined") {\ if (typeof compact != "undefined") {\
var uncompacted = numbers.slice();\ var uncompacted = numbers.slice();\
@@ -352,13 +360,13 @@
uncompacted[6] = null;\ uncompacted[6] = null;\
uncompacted[18] = "";\ uncompacted[18] = "";\
}\ }\
if (typeof flowRight != "undefined") {\ if (typeof compose != "undefined") {\
var compAddOne = function(n) { return n + 1; },\ var compAddOne = function(n) { return n + 1; },\
compAddTwo = function(n) { return n + 2; },\ compAddTwo = function(n) { return n + 2; },\
compAddThree = function(n) { return n + 3; };\ compAddThree = function(n) { return n + 3; };\
\ \
var _composed = _.flowRight && _.flowRight(compAddThree, compAddTwo, compAddOne),\ var _composed = _.compose(compAddThree, compAddTwo, compAddOne),\
lodashComposed = lodash.flowRight && lodash.flowRight(compAddThree, compAddTwo, compAddOne);\ lodashComposed = lodash.compose(compAddThree, compAddTwo, compAddOne);\
}\ }\
if (typeof countBy != "undefined" || typeof omit != "undefined") {\ if (typeof countBy != "undefined" || typeof omit != "undefined") {\
var wordToNumber = {\ var wordToNumber = {\
@@ -453,8 +461,11 @@
if (typeof matches != "undefined") {\ if (typeof matches != "undefined") {\
var source = { "num": 9 };\ var source = { "num": 9 };\
\ \
var _matcher = (_.matches || _.noop)(source),\ var _findWhere = _.findWhere || _.find,\
lodashMatcher = (lodash.matches || lodash.noop)(source);\ _matcher = (_.matches || _.createCallback || _.noop)(source);\
\
var lodashFindWhere = lodash.findWhere || lodash.find,\
lodashMatcher = (lodash.matches || lodash.createCallback || lodash.noop)(source);\
}\ }\
if (typeof multiArrays != "undefined") {\ if (typeof multiArrays != "undefined") {\
var twentyValues = belt.shuffle(belt.range(20)),\ var twentyValues = belt.shuffle(belt.range(20)),\
@@ -560,11 +571,11 @@
suites.push( suites.push(
Benchmark.Suite('`_.assign`') Benchmark.Suite('`_.assign`')
.add(buildName, { .add(buildName, {
'fn': 'lodashAssign({}, { "a": 1, "b": 2, "c": 3 })', 'fn': 'lodashAssign({}, object)',
'teardown': 'function assign(){}' 'teardown': 'function assign(){}'
}) })
.add(otherName, { .add(otherName, {
'fn': '_assign({}, { "a": 1, "b": 2, "c": 3 })', 'fn': '_assign({}, object)',
'teardown': 'function assign(){}' 'teardown': 'function assign(){}'
}) })
); );
@@ -572,11 +583,11 @@
suites.push( suites.push(
Benchmark.Suite('`_.assign` with multiple sources') Benchmark.Suite('`_.assign` with multiple sources')
.add(buildName, { .add(buildName, {
'fn': 'lodashAssign({}, { "a": 1, "b": 2 }, { "c": 3, "d": 4 })', 'fn': 'lodashAssign({}, object, object)',
'teardown': 'function assign(){}' 'teardown': 'function assign(){}'
}) })
.add(otherName, { .add(otherName, {
'fn': '_assign({}, { "a": 1, "b": 2 }, { "c": 3, "d": 4 })', 'fn': '_assign({}, object, object)',
'teardown': 'function assign(){}' 'teardown': 'function assign(){}'
}) })
); );
@@ -634,13 +645,25 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.bindAll`') Benchmark.Suite('`_.bindAll` iterating arguments')
.add(buildName, { .add(buildName, {
'fn': 'lodash.bindAll(bindAllObjects[++bindAllCount], funcNames)', 'fn': 'lodash.bindAll.apply(lodash, [bindAllObjects[++bindAllCount]].concat(funcNames))',
'teardown': 'function bindAll(){}' 'teardown': 'function bindAll(){}'
}) })
.add(otherName, { .add(otherName, {
'fn': '_.bindAll(bindAllObjects[++bindAllCount], funcNames)', 'fn': '_.bindAll.apply(_, [bindAllObjects[++bindAllCount]].concat(funcNames))',
'teardown': 'function bindAll(){}'
})
);
suites.push(
Benchmark.Suite('`_.bindAll` iterating the `object`')
.add(buildName, {
'fn': 'lodash.bindAll(bindAllObjects[++bindAllCount])',
'teardown': 'function bindAll(){}'
})
.add(otherName, {
'fn': '_.bindAll(bindAllObjects[++bindAllCount])',
'teardown': 'function bindAll(){}' 'teardown': 'function bindAll(){}'
}) })
); );
@@ -683,6 +706,32 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
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('composed call')
.add(buildName, {
'fn': 'lodashComposed(0)',
'teardown': 'function compose(){}'
})
.add(otherName, {
'fn': '_composed(0)',
'teardown': 'function compose(){}'
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.countBy` with `callback` iterating an array') Benchmark.Suite('`_.countBy` with `callback` iterating an array')
.add(buildName, '\ .add(buildName, '\
@@ -783,6 +832,22 @@
) )
); );
suites.push(
Benchmark.Suite('`_.each` iterating an array with `thisArg` (slow path)')
.add(buildName, '\
var result = [];\
lodash.each(numbers, function(num, index) {\
result.push(num + this["key" + index]);\
}, object)'
)
.add(otherName, '\
var result = [];\
_.each(numbers, function(num, index) {\
result.push(num + this["key" + index]);\
}, object)'
)
);
suites.push( suites.push(
Benchmark.Suite('`_.each` iterating an object') Benchmark.Suite('`_.each` iterating an object')
.add(buildName, '\ .add(buildName, '\
@@ -845,6 +910,20 @@
) )
); );
suites.push(
Benchmark.Suite('`_.filter` iterating an array with `thisArg` (slow path)')
.add(buildName, '\
lodash.filter(numbers, function(num, index) {\
return this["key" + index] % 2;\
}, object)'
)
.add(otherName, '\
_.filter(numbers, function(num, index) {\
return this["key" + index] % 2;\
}, object)'
)
);
suites.push( suites.push(
Benchmark.Suite('`_.filter` iterating an object') Benchmark.Suite('`_.filter` iterating an object')
.add(buildName, '\ .add(buildName, '\
@@ -859,18 +938,6 @@
) )
); );
suites.push(
Benchmark.Suite('`_.filter` with `_.matches` shorthand')
.add(buildName, {
'fn': 'lodash.filter(objects, source)',
'teardown': 'function matches(){}'
})
.add(otherName, {
'fn': '_.filter(objects, source)',
'teardown': 'function matches(){}'
})
);
suites.push( suites.push(
Benchmark.Suite('`_.filter` with `_.matches` predicate') Benchmark.Suite('`_.filter` with `_.matches` predicate')
.add(buildName, { .add(buildName, {
@@ -914,17 +981,19 @@
); );
// Avoid Underscore induced `OutOfMemoryError` in Rhino and Ringo. // Avoid Underscore induced `OutOfMemoryError` in Rhino and Ringo.
suites.push( if (!isJava) {
Benchmark.Suite('`_.find` with `_.matches` shorthand') suites.push(
.add(buildName, { Benchmark.Suite('`_.find` with `_.matches` shorthand')
'fn': 'lodash.find(objects, source)', .add(buildName, {
'teardown': 'function matches(){}' 'fn': 'lodashFindWhere(objects, source)',
}) 'teardown': 'function matches(){}'
.add(otherName, { })
'fn': '_.find(objects, source)', .add(otherName, {
'teardown': 'function matches(){}' 'fn': '_findWhere(objects, source)',
}) 'teardown': 'function matches(){}'
); })
);
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -940,60 +1009,32 @@
}) })
); );
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.flattenDeep` nested arrays of numbers') Benchmark.Suite('`_.flatten` nested arrays of numbers with `isDeep`')
.add(buildName, { .add(buildName, {
'fn': 'lodash.flattenDeep(nestedNumbers)', 'fn': 'lodash.flatten(nestedNumbers, lodashFlattenDeep)',
'teardown': 'function flatten(){}' 'teardown': 'function flatten(){}'
}) })
.add(otherName, { .add(otherName, {
'fn': '_.flattenDeep(nestedNumbers)', 'fn': '_.flatten(nestedNumbers, _flattenDeep)',
'teardown': 'function flatten(){}' 'teardown': 'function flatten(){}'
}) })
); );
suites.push( suites.push(
Benchmark.Suite('`_.flattenDeep` nest arrays of objects') Benchmark.Suite('`_.flatten` nest arrays of objects with `isDeep`')
.add(buildName, { .add(buildName, {
'fn': 'lodash.flattenDeep(nestedObjects)', 'fn': 'lodash.flatten(nestedObjects, lodashFlattenDeep)',
'teardown': 'function flatten(){}' 'teardown': 'function flatten(){}'
}) })
.add(otherName, { .add(otherName, {
'fn': '_.flattenDeep(nestedObjects)', 'fn': '_.flatten(nestedObjects, _flattenDeep)',
'teardown': 'function flatten(){}' 'teardown': 'function flatten(){}'
}) })
); );
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.flowRight`')
.add(buildName, {
'fn': 'lodash.flowRight(compAddThree, compAddTwo, compAddOne)',
'teardown': 'function flowRight(){}'
})
.add(otherName, {
'fn': '_.flowRight(compAddThree, compAddTwo, compAddOne)',
'teardown': 'function flowRight(){}'
})
);
suites.push(
Benchmark.Suite('composed call')
.add(buildName, {
'fn': 'lodashComposed(0)',
'teardown': 'function flowRight(){}'
})
.add(otherName, {
'fn': '_composed(0)',
'teardown': 'function flowRight(){}'
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.functions`') Benchmark.Suite('`_.functions`')
.add(buildName, '\ .add(buildName, '\
@@ -1045,37 +1086,73 @@
suites.push( suites.push(
Benchmark.Suite('`_.includes` searching an array') Benchmark.Suite('`_.includes` searching an array')
.add(buildName, '\ .add(buildName, '\
lodash.includes(numbers, limit - 1)' lodash.include(numbers, limit - 1)'
) )
.add(otherName, '\ .add(otherName, '\
_.includes(numbers, limit - 1)' _.include(numbers, limit - 1)'
) )
); );
suites.push( suites.push(
Benchmark.Suite('`_.includes` searching an object') Benchmark.Suite('`_.includes` searching an object')
.add(buildName, '\ .add(buildName, '\
lodash.includes(object, limit - 1)' lodash.include(object, limit - 1)'
) )
.add(otherName, '\ .add(otherName, '\
_.includes(object, limit - 1)' _.include(object, limit - 1)'
) )
); );
if (lodash.includes('ab', 'ab') && _.includes('ab', 'ab')) { if (lodash.include('ab', 'ab') && _.include('ab', 'ab')) {
suites.push( suites.push(
Benchmark.Suite('`_.includes` searching a string') Benchmark.Suite('`_.includes` searching a string')
.add(buildName, '\ .add(buildName, '\
lodash.includes(strNumbers, "," + (limit - 1))' lodash.include(strNumbers, "," + (limit - 1))'
) )
.add(otherName, '\ .add(otherName, '\
_.includes(strNumbers, "," + (limit - 1))' _.include(strNumbers, "," + (limit - 1))'
) )
); );
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.indexBy` with `callback` iterating an array')
.add(buildName, '\
lodash.indexBy(numbers, function(num) { return num >> 1; })'
)
.add(otherName, '\
_.indexBy(numbers, function(num) { return num >> 1; })'
)
);
suites.push(
Benchmark.Suite('`_.indexBy` with `property` name iterating an array')
.add(buildName, {
'fn': 'lodash.indexBy(words, "length")',
'teardown': 'function countBy(){}'
})
.add(otherName, {
'fn': '_.indexBy(words, "length")',
'teardown': 'function countBy(){}'
})
);
suites.push(
Benchmark.Suite('`_.indexBy` with `callback` iterating an object')
.add(buildName, {
'fn': 'lodash.indexBy(wordToNumber, function(num) { return num >> 1; })',
'teardown': 'function countBy(){}'
})
.add(otherName, {
'fn': '_.indexBy(wordToNumber, function(num) { return num >> 1; })',
'teardown': 'function countBy(){}'
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.indexOf`') Benchmark.Suite('`_.indexOf`')
.add(buildName, { .add(buildName, {
@@ -1088,6 +1165,18 @@
}) })
); );
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(){}'
})
);
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
@@ -1127,42 +1216,42 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.invokeMap` iterating an array') Benchmark.Suite('`_.invoke` iterating an array')
.add(buildName, '\ .add(buildName, '\
lodash.invokeMap(numbers, "toFixed")' lodash.invoke(numbers, "toFixed")'
) )
.add(otherName, '\ .add(otherName, '\
_.invokeMap(numbers, "toFixed")' _.invoke(numbers, "toFixed")'
) )
); );
suites.push( suites.push(
Benchmark.Suite('`_.invokeMap` with arguments iterating an array') Benchmark.Suite('`_.invoke` with arguments iterating an array')
.add(buildName, '\ .add(buildName, '\
lodash.invokeMap(numbers, "toFixed", 1)' lodash.invoke(numbers, "toFixed", 1)'
) )
.add(otherName, '\ .add(otherName, '\
_.invokeMap(numbers, "toFixed", 1)' _.invoke(numbers, "toFixed", 1)'
) )
); );
suites.push( suites.push(
Benchmark.Suite('`_.invokeMap` with a function for `path` iterating an array') Benchmark.Suite('`_.invoke` with a function for `path` iterating an array')
.add(buildName, '\ .add(buildName, '\
lodash.invokeMap(numbers, Number.prototype.toFixed, 1)' lodash.invoke(numbers, Number.prototype.toFixed, 1)'
) )
.add(otherName, '\ .add(otherName, '\
_.invokeMap(numbers, Number.prototype.toFixed, 1)' _.invoke(numbers, Number.prototype.toFixed, 1)'
) )
); );
suites.push( suites.push(
Benchmark.Suite('`_.invokeMap` iterating an object') Benchmark.Suite('`_.invoke` iterating an object')
.add(buildName, '\ .add(buildName, '\
lodash.invokeMap(object, "toFixed", 1)' lodash.invoke(object, "toFixed", 1)'
) )
.add(otherName, '\ .add(otherName, '\
_.invokeMap(object, "toFixed", 1)' _.invoke(object, "toFixed", 1)'
) )
); );
@@ -1324,6 +1413,18 @@
}) })
); );
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(){}'
})
);
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
@@ -1340,6 +1441,20 @@
) )
); );
suites.push(
Benchmark.Suite('`_.map` with `thisArg` iterating an array (slow path)')
.add(buildName, '\
lodash.map(objects, function(value, index) {\
return this["key" + index] + value.num;\
}, object)'
)
.add(otherName, '\
_.map(objects, function(value, index) {\
return this["key" + index] + value.num;\
}, object)'
)
);
suites.push( suites.push(
Benchmark.Suite('`_.map` iterating an object') Benchmark.Suite('`_.map` iterating an object')
.add(buildName, '\ .add(buildName, '\
@@ -1354,16 +1469,6 @@
) )
); );
suites.push(
Benchmark.Suite('`_.map` with `_.property` shorthand')
.add(buildName, '\
lodash.map(objects, "num")'
)
.add(otherName, '\
_.map(objects, "num")'
)
);
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
@@ -1414,6 +1519,18 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.pairs`')
.add(buildName, '\
lodash.pairs(object)'
)
.add(otherName, '\
_.pairs(object)'
)
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.partial` (slow path)') Benchmark.Suite('`_.partial` (slow path)')
.add(buildName, { .add(buildName, {
@@ -1454,6 +1571,20 @@
) )
); );
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( suites.push(
Benchmark.Suite('`_.partition` iterating an object') Benchmark.Suite('`_.partition` iterating an object')
.add(buildName, '\ .add(buildName, '\
@@ -1482,6 +1613,18 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.pluck`')
.add(buildName, '\
lodash.pluck(objects, "num")'
)
.add(otherName, '\
_.pluck(objects, "num")'
)
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.reduce` iterating an array') Benchmark.Suite('`_.reduce` iterating an array')
.add(buildName, '\ .add(buildName, '\
@@ -1564,6 +1707,20 @@
) )
); );
suites.push(
Benchmark.Suite('`_.reject` iterating an array with `thisArg` (slow path)')
.add(buildName, '\
lodash.reject(numbers, function(num, index) {\
return this["key" + index] % 2;\
}, object)'
)
.add(otherName, '\
_.reject(numbers, function(num, index) {\
return this["key" + index] % 2;\
}, object)'
)
);
suites.push( suites.push(
Benchmark.Suite('`_.reject` iterating an object') Benchmark.Suite('`_.reject` iterating an object')
.add(buildName, '\ .add(buildName, '\
@@ -1581,12 +1738,12 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.sampleSize`') Benchmark.Suite('`_.sample` with an `n`')
.add(buildName, '\ .add(buildName, '\
lodash.sampleSize(numbers, limit / 2)' lodash.sample(numbers, limit / 2)'
) )
.add(otherName, '\ .add(otherName, '\
_.sampleSize(numbers, limit / 2)' _.sample(numbers, limit / 2)'
) )
); );
@@ -1630,6 +1787,20 @@
) )
); );
suites.push(
Benchmark.Suite('`_.some` with `thisArg` iterating an array (slow path)')
.add(buildName, '\
lodash.some(objects, function(value, index) {\
return this["key" + index] == (limit - 1);\
}, object)'
)
.add(otherName, '\
_.some(objects, function(value, index) {\
return this["key" + index] == (limit - 1);\
}, object)'
)
);
suites.push( suites.push(
Benchmark.Suite('`_.some` iterating an object') Benchmark.Suite('`_.some` iterating an object')
.add(buildName, '\ .add(buildName, '\
@@ -1656,6 +1827,16 @@
) )
); );
suites.push(
Benchmark.Suite('`_.sortBy` with `callback` and `thisArg` (slow path)')
.add(buildName, '\
lodash.sortBy(numbers, function(num) { return this.sin(num); }, Math)'
)
.add(otherName, '\
_.sortBy(numbers, function(num) { return this.sin(num); }, Math)'
)
);
suites.push( suites.push(
Benchmark.Suite('`_.sortBy` with `property` name') Benchmark.Suite('`_.sortBy` with `property` name')
.add(buildName, { .add(buildName, {
@@ -1680,20 +1861,18 @@
) )
); );
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.sortedIndexBy`') Benchmark.Suite('`_.sortedIndex` with `callback`')
.add(buildName, { .add(buildName, {
'fn': '\ 'fn': '\
lodash.sortedIndexBy(words, "twenty-five", function(value) {\ lodash.sortedIndex(words, "twenty-five", function(value) {\
return wordToNumber[value];\ return wordToNumber[value];\
})', })',
'teardown': 'function countBy(){}' 'teardown': 'function countBy(){}'
}) })
.add(otherName, { .add(otherName, {
'fn': '\ 'fn': '\
_.sortedIndexBy(words, "twenty-five", function(value) {\ _.sortedIndex(words, "twenty-five", function(value) {\
return wordToNumber[value];\ return wordToNumber[value];\
})', })',
'teardown': 'function countBy(){}' 'teardown': 'function countBy(){}'
@@ -1702,34 +1881,6 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.sortedIndexOf`')
.add(buildName, {
'fn': 'lodash.sortedIndexOf(hundredSortedValues, 99)',
'teardown': 'function multiArrays(){}'
})
.add(otherName, {
'fn': '_.sortedIndexOf(hundredSortedValues, 99)',
'teardown': 'function multiArrays(){}'
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.sortedLastIndexOf`')
.add(buildName, {
'fn': 'lodash.sortedLastIndexOf(hundredSortedValues, 0)',
'teardown': 'function multiArrays(){}'
})
.add(otherName, {
'fn': '_.sortedLastIndexOf(hundredSortedValues, 0)',
'teardown': 'function multiArrays(){}'
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.sum`') Benchmark.Suite('`_.sum`')
.add(buildName, '\ .add(buildName, '\
@@ -1792,6 +1943,18 @@
) )
); );
suites.push(
Benchmark.Suite('`_.times` with `thisArg` (slow path)')
.add(buildName, '\
var result = [];\
lodash.times(limit, function(n) { result.push(this.sin(n)); }, Math)'
)
.add(otherName, '\
var result = [];\
_.times(limit, function(n) { result.push(this.sin(n)); }, Math)'
)
);
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
@@ -1816,18 +1979,6 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.toPairs`')
.add(buildName, '\
lodash.toPairs(object)'
)
.add(otherName, '\
_.toPairs(object)'
)
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.unescape` string without html entities') Benchmark.Suite('`_.unescape` string without html entities')
.add(buildName, '\ .add(buildName, '\
@@ -1884,6 +2035,20 @@
) )
); );
suites.push(
Benchmark.Suite('`_.uniq` with `callback`')
.add(buildName, '\
lodash.uniq(numbers.concat(twoNumbers, fourNumbers), function(num) {\
return num % 2;\
})'
)
.add(otherName, '\
_.uniq(numbers.concat(twoNumbers, fourNumbers), function(num) {\
return num % 2;\
})'
)
);
suites.push( suites.push(
Benchmark.Suite('`_.uniq` iterating an array of 200 elements') Benchmark.Suite('`_.uniq` iterating an array of 200 elements')
.add(buildName, { .add(buildName, {
@@ -1898,22 +2063,6 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.uniqBy`')
.add(buildName, '\
lodash.uniqBy(numbers.concat(twoNumbers, fourNumbers), function(num) {\
return num % 2;\
})'
)
.add(otherName, '\
_.uniqBy(numbers.concat(twoNumbers, fourNumbers), function(num) {\
return num % 2;\
})'
)
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.values`') Benchmark.Suite('`_.values`')
.add(buildName, '\ .add(buildName, '\
@@ -1926,6 +2075,20 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.where`')
.add(buildName, {
'fn': 'lodash.where(objects, source)',
'teardown': 'function matches(){}'
})
.add(otherName, {
'fn': '_.where(objects, source)',
'teardown': 'function matches(){}'
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.without`') Benchmark.Suite('`_.without`')
.add(buildName, '\ .add(buildName, '\

14
perf/run-perf.sh Executable file
View File

@@ -0,0 +1,14 @@
cd "$(dirname "$0")"
echo "Running performance suite in node..."
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 ../lodash.src.js
done
echo ""
echo "Running performance suite in a browser..."
open index.html

157
test/asset/set.js Normal file
View File

@@ -0,0 +1,157 @@
;(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');
/** 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. */
var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
/** Detect free variable `self`. */
var freeSelf = objectTypes[typeof self] && self && self.Object && self;
/** Detect free variable `window`. */
var freeWindow = objectTypes[typeof window] && window && window.Object && window;
/**
* 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 = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;
/*--------------------------------------------------------------------------*/
/**
* 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));

View File

@@ -15,8 +15,27 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/**
* Registers an event listener on an element.
*
* @private
* @param {Element} element The element.
* @param {string} eventName The name of the event.
* @param {Function} handler The event handler.
* @returns {Element} The element.
*/
function addListener(element, eventName, handler) {
if (typeof element.addEventListener != 'undefined') {
element.addEventListener(eventName, handler, false);
} else if (typeof element.attachEvent != 'undefined') {
element.attachEvent('on' + eventName, handler);
}
}
/*--------------------------------------------------------------------------*/
// Initialize controls. // Initialize controls.
addEventListener('load', function() { addListener(window, 'load', function() {
function eventHandler(event) { function eventHandler(event) {
var buildIndex = buildList.selectedIndex, var buildIndex = buildList.selectedIndex,
loaderIndex = loaderList.selectedIndex, loaderIndex = loaderList.selectedIndex,
@@ -40,15 +59,17 @@
setTimeout(init, 15); setTimeout(init, 15);
return; return;
} }
toolbar.insertBefore(span2, toolbar.lastChild); toolbar.appendChild(span1);
toolbar.insertBefore(span1, span2); toolbar.appendChild(span2);
buildList.selectedIndex = (function() { buildList.selectedIndex = (function() {
switch (build) { switch (build) {
case 'lodash': return 1; case 'lodash-compat': return 1;
case 'lodash-core-dev': return 2; case 'lodash-modern-dev': return 2;
case 'lodash-core': return 3; case 'lodash-modern': return 3;
case 'lodash-dev': case 'lodash-custom-dev': return 4;
case 'lodash-custom': return 5;
case 'lodash-compat-dev':
case null: return 0; case null: return 0;
} }
return -1; return -1;
@@ -65,21 +86,25 @@
return -1; return -1;
}()); }());
buildList.addEventListener('change', eventHandler); addListener(buildList, 'change', eventHandler);
loaderList.addEventListener('change', eventHandler); addListener(loaderList, 'change', eventHandler);
} }
var span1 = document.createElement('span'); var span1 = document.createElement('span');
span1.style.cssText = 'float:right';
span1.innerHTML = span1.innerHTML =
'<label for="qunit-build">Build: </label>' + '<label for="qunit-build">Build: </label>' +
'<select id="qunit-build">' + '<select id="qunit-build">' +
'<option value="lodash-dev">lodash (development)</option>' + '<option value="lodash-compat-dev">lodash (compat development)</option>' +
'<option value="lodash">lodash (production)</option>' + '<option value="lodash-compat">lodash (compat production)</option>' +
'<option value="lodash-core-dev">lodash-core (development)</option>' + '<option value="lodash-modern-dev">lodash (modern development)</option>' +
'<option value="lodash-core">lodash-core (production)</option>' + '<option value="lodash-modern">lodash (modern production)</option>' +
'<option value="lodash-custom-dev">lodash (custom development)</option>' +
'<option value="lodash-custom">lodash (custom production)</option>' +
'</select>'; '</select>';
var span2 = document.createElement('span'); var span2 = document.createElement('span');
span2.style.cssText = 'float:right';
span2.innerHTML = span2.innerHTML =
'<label for="qunit-loader">Loader: </label>' + '<label for="qunit-loader">Loader: </label>' +
'<select id="qunit-loader">' + '<select id="qunit-loader">' +
@@ -89,12 +114,6 @@
'<option value="requirejs">RequireJS</option>' + '<option value="requirejs">RequireJS</option>' +
'</select>'; '</select>';
span1.style.cssText =
span2.style.cssText = 'display:inline-block;float:right;line-height:2.1em;margin-left:1em;margin-top:0;';
span1.firstChild.style.cssText =
span2.firstChild.style.cssText = 'display:inline-block;margin-right:.5em;';
var buildList = span1.lastChild, var buildList = span1.lastChild,
loaderList = span2.lastChild; loaderList = span2.lastChild;
@@ -105,15 +124,29 @@
init(); init();
}); });
// 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|es6?|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 lodash is in strict mode.
ui.isStrict = /\bes6?\b/.test([location.pathname, location.search]);
// The lodash build file path. // The lodash build file path.
ui.buildPath = (function() { ui.buildPath = (function() {
var result; var result;
switch (build) { switch (build) {
case 'lodash': result = 'dist/lodash.min.js'; break; case 'lodash-compat': result = 'lodash.compat.min.js'; break;
case 'lodash-core-dev': result = 'dist/lodash.core.js'; break; case 'lodash-modern-dev': result = 'lodash.js'; break;
case 'lodash-core': result = 'dist/lodash.core.min.js'; break; case 'lodash-modern': result = 'lodash.min.js'; break;
case null: build = 'lodash-dev'; case 'lodash-custom-dev': result = 'lodash.custom.js'; break;
case 'lodash-dev': result = 'lodash.js'; break; case 'lodash-custom': result = 'lodash.custom.min.js'; break;
case null: build = 'lodash-compat-dev';
case 'lodash-compat-dev': result = 'lodash.src.js'; break;
default: return build; default: return build;
} }
return basePath + result; return basePath + result;
@@ -132,21 +165,6 @@
return basePath + result; return basePath + result;
}()); }());
// Used to indicate testing a core build.
ui.isCore = /\bcore(\.min)?\.js\b/.test(ui.buildPath);
// 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 lodash is in strict mode.
ui.isStrict = /\bes\b/.test([location.pathname, location.search]);
ui.urlParams = { 'build': build, 'loader': loader }; ui.urlParams = { 'build': build, 'loader': loader };
ui.timing = { 'loadEventEnd': 0 }; ui.timing = { 'loadEventEnd': 0 };

102
test/asset/weakmap.js Normal file
View File

@@ -0,0 +1,102 @@
;(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');
/** 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. */
var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
/** Detect free variable `self`. */
var freeSelf = objectTypes[typeof self] && self && self.Object && self;
/** Detect free variable `window`. */
var freeWindow = objectTypes[typeof window] && window && window.Object && window;
/**
* 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 = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;
/*--------------------------------------------------------------------------*/
/**
* 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));

View File

@@ -1,17 +1,12 @@
'use strict';
self.console || (self.console = { 'log': function() {} }); self.console || (self.console = { 'log': function() {} });
addEventListener('message', function(e) { addEventListener('message', function(e) {
if (e.data) { if (e.data) {
try { try {
importScripts('../' + e.data); importScripts('../' + e.data);
} catch (e) { } catch(e) {
var lineNumber = e.lineNumber, self._ = { 'VERSION': e.message };
message = (lineNumber == null ? '' : (lineNumber + ': ')) + e.message;
self._ = { 'VERSION': message };
} }
postMessage(_.VERSION); postMessage(_.VERSION);
} }
}); }, false);

View File

@@ -22,69 +22,27 @@
<script src="../vendor/json-js/json2.js"></script> <script src="../vendor/json-js/json2.js"></script>
<script src="../node_modules/platform/platform.js"></script> <script src="../node_modules/platform/platform.js"></script>
<script src="./asset/test-ui.js"></script> <script src="./asset/test-ui.js"></script>
<script src="../lodash.js"></script> <script src="../lodash.src.js"></script>
<script> <script>
QUnit.config.asyncRetries = 10;
QUnit.config.hidepassed = true;
var mixinPrereqs = (function() { var mixinPrereqs = (function() {
var aliasToReal = {
'indexBy': 'keyBy',
'invoke': 'invokeMap'
};
var keyMap = {
'rest': 'tail'
};
var lodash = _.noConflict(); var lodash = _.noConflict();
return function(_) { return function(_) {
lodash(_) _.mixin({
.defaultsDeep({ 'templateSettings': lodash.templateSettings }) 'debounce': _.debounce || lodash.debounce,
.mixin(lodash.pick(lodash, lodash.difference([ 'defer': _.defer || lodash.defer,
'countBy', 'pluck': _.pluck || lodash.pluck
'debounce',
'difference',
'find',
'findIndex',
'findLastIndex',
'groupBy',
'includes',
'invert',
'invokeMap',
'keyBy',
'omit',
'partition',
'reduceRight',
'reject',
'sample',
'without'
], lodash.functions(_))))
.value();
lodash.forOwn(keyMap, function(realName, otherName) {
_[otherName] = lodash[realName];
_.prototype[otherName] = lodash.prototype[realName];
}); });
lodash.forOwn(aliasToReal, function(realName, alias) {
_[alias] = _[realName];
_.prototype[alias] = _.prototype[realName];
});
return _;
}; };
}()); }());
// Load prerequisite scripts. QUnit.config.asyncRetries = 10;
document.write(ui.urlParams.loader == 'none' QUnit.config.hidepassed = true;
? '<script src="' + ui.buildPath + '"><\/script>'
: '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>' // Load test scripts.
); document.write(ui.urlParams.loader != 'none'
</script> ? '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>'
<script> : ([
if (ui.urlParams.loader == 'none') { '<script src="' + ui.buildPath + '"><\/script>',
mixinPrereqs(_);
document.write([
'<script src="../node_modules/jquery/dist/jquery.js"><\/script>', '<script src="../node_modules/jquery/dist/jquery.js"><\/script>',
'<script src="../vendor/backbone/backbone.js"><\/script>', '<script src="../vendor/backbone/backbone.js"><\/script>',
'<script src="../vendor/backbone/test/setup/dom-setup.js"><\/script>', '<script src="../vendor/backbone/test/setup/dom-setup.js"><\/script>',
@@ -96,8 +54,8 @@
'<script src="../vendor/backbone/test/router.js"><\/script>', '<script src="../vendor/backbone/test/router.js"><\/script>',
'<script src="../vendor/backbone/test/view.js"><\/script>', '<script src="../vendor/backbone/test/view.js"><\/script>',
'<script src="../vendor/backbone/test/sync.js"><\/script>' '<script src="../vendor/backbone/test/sync.js"><\/script>'
].join('\n')); ].join('\n'))
} );
</script> </script>
<script> <script>
(function() { (function() {
@@ -105,6 +63,7 @@
curl.config({ 'apiName': 'require' }); curl.config({ 'apiName': 'require' });
} }
if (!window.require) { if (!window.require) {
mixinPrereqs(_);
return; return;
} }
var reBasename = /[\w.-]+$/, var reBasename = /[\w.-]+$/,
@@ -148,20 +107,24 @@
QUnit.config.autostart = false; QUnit.config.autostart = false;
require(getConfig(), ['underscore'], function(lodash) { require(getConfig(), ['underscore', 'backbone'], function(lodash) {
_ = mixinPrereqs(lodash); mixinPrereqs(lodash);
require(getConfig(), ['backbone'], function() {
require(getConfig(), [ if (ui.isModularize) {
'test/setup/dom-setup', window._ = lodash;
'test/setup/environment', }
'test/noconflict', require(getConfig(), [
'test/events', 'test/setup/dom-setup',
'test/model', 'test/setup/environment',
'test/collection', 'test/noconflict',
'test/router', 'test/events',
'test/view', 'test/model',
'test/sync' 'test/collection',
], QUnit.start); 'test/router',
'test/view',
'test/sync'
], function() {
QUnit.start();
}); });
}); });
}()); }());

View File

@@ -1,41 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>lodash-fp Test Suite</title>
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
</head>
<body>
<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="../lodash.js"></script>
<script src="../dist/lodash.fp.js"></script>
<script src="../dist/mapping.fp.js"></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="./test-fp.js"></script>
<div id="qunit"></div>
<script>
// Set a more readable browser name.
window.onload = function() {
var timeoutId = setInterval(function() {
var ua = document.getElementById('qunit-userAgent');
if (ua) {
ua.innerHTML = platform;
clearInterval(timeoutId);
}
}, 16);
};
</script>
</body>
</html>

View File

@@ -5,7 +5,7 @@
<title>lodash Test Suite</title> <title>lodash Test Suite</title>
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css"> <link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
<style> <style>
#exports, #module { #exports {
display: none; display: none;
} }
</style> </style>
@@ -22,33 +22,35 @@
}; };
} }
</script> </script>
<script src="../node_modules/lodash/lodash.js"></script>
<script>var lodashStable = _.noConflict();</script>
<script src="../node_modules/qunitjs/qunit/qunit.js"></script> <script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<script src="../node_modules/qunit-extras/qunit-extras.js"></script> <script src="../node_modules/qunit-extras/qunit-extras.js"></script>
<script src="../node_modules/platform/platform.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> <script src="./asset/test-ui.js"></script>
<div id="qunit"></div> <div id="qunit"></div>
<div id="exports"></div> <div id="exports"></div>
<div id="module"></div>
<script> <script>
function setProperty(object, key, value) { var setProperty = (function() {
try { var _defineProperty = Object.defineProperty;
Object.defineProperty(object, key, { return function(object, key, value) {
'configurable': true, try {
'enumerable': false, _defineProperty(object, key, {
'writable': true, 'configurable': true,
'value': value 'enumerable': false,
}); 'writable': true,
} catch (e) { 'value': value
object[key] = value; });
} } catch(e) {
return object; object[key] = value;
} }
};
}());
function addBizarroMethods() { function addBizarroMethods() {
var funcProto = Function.prototype, var funcProto = Function.prototype,
objectProto = Object.prototype; objectProto = Object.prototype,
stringProto = String.prototype;
var hasOwnProperty = objectProto.hasOwnProperty, var hasOwnProperty = objectProto.hasOwnProperty,
fnToString = funcProto.toString, fnToString = funcProto.toString,
@@ -62,11 +64,9 @@
return value; return value;
}; };
} }
function createToString(funcName) { function createToString(funcName) {
return constant(nativeString.replace(reToString, funcName)); return constant(nativeString.replace(reToString, funcName));
} }
// Allow bypassing native checks. // Allow bypassing native checks.
setProperty(funcProto, 'toString', (function() { setProperty(funcProto, 'toString', (function() {
function wrapper() { function wrapper() {
@@ -82,42 +82,29 @@
funcProto._method = noop; funcProto._method = noop;
// Set bad shims. // Set bad shims.
setProperty(Object, '_create', Object.create); setProperty(Array, '_isArray', Array.isArray);
setProperty(Object, 'create', undefined); setProperty(Array, 'isArray', noop);
setProperty(Object, '_getOwnPropertySymbols', Object.getOwnPropertySymbols); setProperty(Date, '_now', Date.now);
setProperty(Object, 'getOwnPropertySymbols', undefined); setProperty(Date, 'now', noop);
setProperty(Object, '_keys', Object.keys);
setProperty(Object, 'keys', noop);
setProperty(objectProto, '_propertyIsEnumerable', propertyIsEnumerable); setProperty(objectProto, '_propertyIsEnumerable', propertyIsEnumerable);
setProperty(objectProto, 'propertyIsEnumerable', function(key) { setProperty(objectProto, 'propertyIsEnumerable', function(key) {
return !(key == 'valueOf' && this && this.valueOf === 1) && _propertyIsEnumerable.call(this, key); if (key == '1' && this && typeof this == 'object' &&
hasOwnProperty.call(this, 'callee') &&
!propertyIsEnumerable.call(this, 'callee') &&
this.length === 2 && this[0] === 1 && this[1] === 0) {
throw new Error;
}
return propertyIsEnumerable.call(this, key);
}); });
setProperty(window, '_Map', window.Map);
if (_Map) {
setProperty(window, 'Map', (function(Map) {
var count = 0;
return function() {
if (count++) {
return new Map;
}
var result = {};
setProperty(window, 'Map', Map);
return result;
};
}(_Map)));
setProperty(Map, 'toString', createToString('Map'));
}
setProperty(window, '_Promise', window.Promise);
setProperty(window, 'Promise', noop);
setProperty(window, '_Set', window.Set); setProperty(window, '_Set', window.Set);
setProperty(window, 'Set', noop); setProperty(window, 'Set', noop);
setProperty(window, '_Symbol', window.Symbol);
setProperty(window, 'Symbol', undefined);
setProperty(window, '_WeakMap', window.WeakMap); setProperty(window, '_WeakMap', window.WeakMap);
setProperty(window, 'WeakMap', noop); setProperty(window, 'WeakMap', noop);
@@ -132,58 +119,46 @@
function removeBizarroMethods() { function removeBizarroMethods() {
var funcProto = Function.prototype, var funcProto = Function.prototype,
objectProto = Object.prototype; objectProto = Object.prototype,
stringProto = String.prototype;
setProperty(objectProto, 'propertyIsEnumerable', objectProto._propertyIsEnumerable); if (Array._isArray) {
setProperty(Array, 'isArray', Array._isArray);
if (Object._create) {
Object.create = Object._create;
} else { } else {
delete Object.create; delete Array.isArray;
} }
if (Object._getOwnPropertySymbols) { if (Date._now) {
Object.getOwnPropertySymbols = Object._getOwnPropertySymbols; setProperty(Date, 'now', Date._now);
} else { } else {
delete Object.getOwnPropertySymbols; delete Date.now;
} }
if (_Map) { if (Object._keys) {
Map = _Map; setProperty(Object, 'keys', Object._keys);
} else { } else {
setProperty(window, 'Map', undefined); delete Object.keys;
} }
if (_Promise) { if (window._Set) {
Promise = _Promise;
} else {
setProperty(window, 'Promise', undefined);
}
if (_Set) {
Set = _Set; Set = _Set;
} else {
setProperty(window, 'Set', undefined);
} }
if (_Symbol) {
Symbol = _Symbol;
}
if (_WeakMap) {
WeakMap = _WeakMap;
} else {
setProperty(window, 'WeakMap', undefined);
}
setProperty(window, '_Map', undefined);
setProperty(window, '_Promise', undefined);
setProperty(window, '_Set', undefined); setProperty(window, '_Set', undefined);
setProperty(window, '_Symbol', undefined);
if (window._WeakMap) {
WeakMap = _WeakMap;
}
setProperty(window, '_WeakMap', undefined); setProperty(window, '_WeakMap', undefined);
setProperty(window, 'WinRTError', undefined); setProperty(window, 'WinRTError', undefined);
setProperty(window, 'exports', document.getElementById('exports')); setProperty(window, 'exports', undefined);
setProperty(window, 'global', undefined); setProperty(window, 'global', undefined);
setProperty(window, 'module', document.getElementById('module')); setProperty(window, 'module', undefined);
setProperty(objectProto, 'propertyIsEnumerable', objectProto._propertyIsEnumerable);
delete Array._isArray;
delete Date._now;
delete Object._keys;
delete funcProto._method; delete funcProto._method;
delete Object._create;
delete Object._getOwnPropertySymbols;
delete objectProto._propertyIsEnumerable; delete objectProto._propertyIsEnumerable;
} }
@@ -291,17 +266,20 @@
underscoreModule = underscore.result(underscore, 'noConflict') || underscore; underscoreModule = underscore.result(underscore, 'noConflict') || underscore;
underscoreModule.moduleName = 'underscore'; underscoreModule.moduleName = 'underscore';
} }
window._ = lodash; if (ui.isModularize) {
window._ = lodash;
}
if (ui.isModularize) { if (ui.isModularize) {
require(getConfig(), [ require(getConfig(), [
'lodash/_baseEach', 'lodash/internal/baseEach',
'lodash/_isIndex', 'lodash/internal/isIndex',
'lodash/_isIterateeCall' 'lodash/internal/isIterateeCall',
], function(baseEach, isIndex, isIterateeCall) { 'lodash/internal/isLength'
], function(baseEach, isIndex, isIterateeCall, isLength) {
lodash._baseEach = baseEach; lodash._baseEach = baseEach;
lodash._isIndex = isIndex; lodash._isIndex = isIndex;
lodash._isIterateeCall = isIterateeCall; lodash._isIterateeCall = isIterateeCall;
lodash._isLength = isLength;
loadTests(); loadTests();
}); });
} else { } else {

View File

@@ -1,27 +0,0 @@
#!/usr/bin/env node
'use strict';
var _ = require('../lodash'),
fs = require('fs'),
path = require('path');
var args = (args = process.argv)
.slice((args[0] === process.execPath || args[0] === 'node') ? 2 : 0);
var filePath = path.resolve(args[1]),
reLine = /.*/gm;
var pattern = (function() {
var result = args[0],
delimiter = result.charAt(0),
lastIndex = result.lastIndexOf(delimiter);
return RegExp(result.slice(1, lastIndex), result.slice(lastIndex + 1));
}());
/*----------------------------------------------------------------------------*/
fs.writeFileSync(filePath, fs.readFileSync(filePath, 'utf8').replace(pattern, function(match) {
var snippet = _.slice(arguments, -3, -2)[0];
return match.replace(snippet, snippet.replace(reLine, ''));
}));

14
test/run-test.sh Normal file
View File

@@ -0,0 +1,14 @@
cd "$(dirname "$0")"
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 ""
echo "Testing in a browser..."
open index.html

View File

@@ -4,6 +4,11 @@
/** Environment shortcut. */ /** Environment shortcut. */
var env = process.env; 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. */ /** Load Node.js modules. */
var EventEmitter = require('events').EventEmitter, var EventEmitter = require('events').EventEmitter,
http = require('http'), http = require('http'),
@@ -12,7 +17,7 @@ var EventEmitter = require('events').EventEmitter,
util = require('util'); util = require('util');
/** Load other modules. */ /** Load other modules. */
var _ = require('../lodash.js'), var _ = require('../lodash.src.js'),
chalk = require('chalk'), chalk = require('chalk'),
ecstatic = require('ecstatic'), ecstatic = require('ecstatic'),
request = require('request'), request = require('request'),
@@ -92,23 +97,31 @@ var browserNameMap = {
'googlechrome': 'Chrome', 'googlechrome': 'Chrome',
'iehta': 'Internet Explorer', 'iehta': 'Internet Explorer',
'ipad': 'iPad', 'ipad': 'iPad',
'iphone': 'iPhone', 'iphone': 'iPhone'
'microsoftedge': 'Edge'
}; };
/** List of platforms to load the runner on. */ /** List of platforms to load the runner on. */
var platforms = [ var platforms = [
['Linux', 'android', '5.1'], ['Linux', 'android', '5.0'],
['Windows 10', 'chrome', '54'], ['Linux', 'android', '4.4'],
['Windows 10', 'chrome', '53'], ['Linux', 'android', '4.0'],
['Windows 10', 'firefox', '50'], ['Windows 8.1', 'firefox', '38'],
['Windows 10', 'firefox', '49'], ['Windows 8.1', 'firefox', '37'],
['Windows 10', 'microsoftedge', '14'], ['Windows 8.1', 'firefox', '20'],
['Windows 10', 'internet explorer', '11'], ['Windows 8.1', 'chrome', '43'],
['Windows 8.1', 'chrome', '42'],
['Windows 8.1', 'internet explorer', '11'],
['Windows 8', 'internet explorer', '10'], ['Windows 8', 'internet explorer', '10'],
['Windows 7', 'internet explorer', '9'], ['Windows 7', 'internet explorer', '9'],
['macOS 10.12', 'safari', '10'], ['Windows 7', 'internet explorer', '8'],
['OS X 10.11', 'safari', '9'] ['Windows XP', 'internet explorer', '7'],
['Windows XP', 'internet explorer', '6'],
['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. */ /** Used to tailor the `platforms` array. */
@@ -119,7 +132,7 @@ var isAMD = _.includes(tags, 'amd'),
// The platforms to test IE compatibility modes. // The platforms to test IE compatibility modes.
if (compatMode) { if (compatMode) {
platforms = [ platforms = [
['Windows 10', 'internet explorer', '11'], ['Windows 8.1', 'internet explorer', '11'],
['Windows 8', 'internet explorer', '10'], ['Windows 8', 'internet explorer', '10'],
['Windows 7', 'internet explorer', '9'], ['Windows 7', 'internet explorer', '9'],
['Windows 7', 'internet explorer', '8'] ['Windows 7', 'internet explorer', '8']
@@ -208,7 +221,18 @@ if (tunneled) {
* @returns {string} Returns the formal browser name. * @returns {string} Returns the formal browser name.
*/ */
function browserName(identifier) { function browserName(identifier) {
return browserNameMap[identifier] || _.startCase(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(' ');
} }
/** /**
@@ -252,7 +276,7 @@ function isJobId(value) {
*/ */
function logInline(text) { function logInline(text) {
var blankLine = _.repeat(' ', _.size(prevLine)); var blankLine = _.repeat(' ', _.size(prevLine));
prevLine = text = _.truncate(text, { 'length': 40 }); prevLine = text = _.trunc(text, 40);
process.stdout.write(text + blankLine.slice(text.length) + '\r'); process.stdout.write(text + blankLine.slice(text.length) + '\r');
} }
@@ -274,7 +298,7 @@ function logThrobber() {
* @returns {Array} Returns the new converted array. * @returns {Array} Returns the new converted array.
*/ */
function optionToArray(name, string) { function optionToArray(name, string) {
return _.compact(_.invokeMap((optionToValue(name, string) || '').split(/, */), 'trim')); return _.compact(_.invoke((optionToValue(name, string) || '').split(/, */), 'trim'));
} }
/** /**
@@ -288,7 +312,7 @@ function optionToArray(name, string) {
function optionToValue(name, string) { function optionToValue(name, string) {
var result = string.match(RegExp('^' + name + '(?:=([\\s\\S]+))?$')); var result = string.match(RegExp('^' + name + '(?:=([\\s\\S]+))?$'));
if (result) { if (result) {
result = _.get(result, 1); result = _.result(result, 1);
result = result ? _.trim(result) : true; result = result ? _.trim(result) : true;
} }
if (result === 'false') { if (result === 'false') {
@@ -360,8 +384,8 @@ function onJobStart(error, res, body) {
if (this.stopping) { if (this.stopping) {
return; return;
} }
var statusCode = _.get(res, 'statusCode'), var statusCode = _.result(res, 'statusCode'),
taskId = _.first(_.get(body, 'js tests')); taskId = _.first(_.result(body, 'js tests'));
if (error || !taskId || statusCode != 200) { if (error || !taskId || statusCode != 200) {
if (this.attempts < this.retries) { if (this.attempts < this.retries) {
@@ -402,19 +426,19 @@ function onJobStatus(error, res, body) {
if (!this.running || this.stopping) { if (!this.running || this.stopping) {
return; return;
} }
var completed = _.get(body, 'completed', false), var completed = _.result(body, 'completed', false),
data = _.first(_.get(body, 'js tests')), data = _.first(_.result(body, 'js tests')),
elapsed = (_.now() - this.timestamp) / 1000, elapsed = (_.now() - this.timestamp) / 1000,
jobId = _.get(data, 'job_id', null), jobId = _.result(data, 'job_id', null),
jobResult = _.get(data, 'result', null), jobResult = _.result(data, 'result', null),
jobStatus = _.get(data, 'status', ''), jobStatus = _.result(data, 'status', ''),
jobUrl = _.get(data, 'url', null), jobUrl = _.result(data, 'url', null),
expired = (elapsed >= queueTimeout && !_.includes(jobStatus, 'in progress')), expired = (elapsed >= queueTimeout && !_.includes(jobStatus, 'in progress')),
options = this.options, options = this.options,
platform = options.platforms[0]; platform = options.platforms[0];
if (_.isObject(jobResult)) { if (_.isObject(jobResult)) {
var message = _.get(jobResult, 'message'); var message = _.result(jobResult, 'message');
} else { } else {
if (typeof jobResult == 'string') { if (typeof jobResult == 'string') {
message = jobResult; message = jobResult;
@@ -434,9 +458,9 @@ function onJobStatus(error, res, body) {
this._pollerId = _.delay(_.bind(this.status, this), this.statusInterval * 1000); this._pollerId = _.delay(_.bind(this.status, this), this.statusInterval * 1000);
return; return;
} }
var description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + _.startCase(platform[0]), var description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + capitalizeWords(platform[0]),
errored = !jobResult || !jobResult.passed || reError.test(message) || reError.test(jobStatus), errored = !jobResult || !jobResult.passed || reError.test(message) || reError.test(jobStatus),
failures = _.get(jobResult, 'failed'), failures = _.result(jobResult, 'failed'),
label = options.name + ':', label = options.name + ':',
tunnel = this.tunnel; tunnel = this.tunnel;
@@ -457,7 +481,7 @@ function onJobStatus(error, res, body) {
return; return;
} }
else { else {
if (message === undefined) { if (typeof message == 'undefined') {
message = 'Results are unavailable. ' + details; message = 'Results are unavailable. ' + details;
} }
console.error(label, description, chalk.red('failed') + ';', message); console.error(label, description, chalk.red('failed') + ';', message);
@@ -536,7 +560,7 @@ util.inherits(Job, EventEmitter);
* @param {Object} Returns the job instance. * @param {Object} Returns the job instance.
*/ */
Job.prototype.remove = function(callback) { Job.prototype.remove = function(callback) {
this.once('remove', _.iteratee(callback)); this.once('remove', _.callback(callback));
if (this.removing) { if (this.removing) {
return this; return this;
} }
@@ -561,7 +585,7 @@ Job.prototype.remove = function(callback) {
* @param {Object} Returns the job instance. * @param {Object} Returns the job instance.
*/ */
Job.prototype.reset = function(callback) { Job.prototype.reset = function(callback) {
this.once('reset', _.iteratee(callback)); this.once('reset', _.callback(callback));
if (this.resetting) { if (this.resetting) {
return this; return this;
} }
@@ -577,7 +601,7 @@ Job.prototype.reset = function(callback) {
* @param {Object} Returns the job instance. * @param {Object} Returns the job instance.
*/ */
Job.prototype.restart = function(callback) { Job.prototype.restart = function(callback) {
this.once('restart', _.iteratee(callback)); this.once('restart', _.callback(callback));
if (this.restarting) { if (this.restarting) {
return this; return this;
} }
@@ -585,7 +609,7 @@ Job.prototype.restart = function(callback) {
var options = this.options, var options = this.options,
platform = options.platforms[0], platform = options.platforms[0],
description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + _.startCase(platform[0]), description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + capitalizeWords(platform[0]),
label = options.name + ':'; label = options.name + ':';
logInline(); logInline();
@@ -602,7 +626,7 @@ Job.prototype.restart = function(callback) {
* @param {Object} Returns the job instance. * @param {Object} Returns the job instance.
*/ */
Job.prototype.start = function(callback) { Job.prototype.start = function(callback) {
this.once('start', _.iteratee(callback)); this.once('start', _.callback(callback));
if (this.starting || this.running) { if (this.starting || this.running) {
return this; return this;
} }
@@ -623,7 +647,7 @@ Job.prototype.start = function(callback) {
* @param {Object} Returns the job instance. * @param {Object} Returns the job instance.
*/ */
Job.prototype.status = function(callback) { Job.prototype.status = function(callback) {
this.once('status', _.iteratee(callback)); this.once('status', _.callback(callback));
if (this.checking || this.removing || this.resetting || this.restarting || this.starting || this.stopping) { if (this.checking || this.removing || this.resetting || this.restarting || this.starting || this.stopping) {
return this; return this;
} }
@@ -645,7 +669,7 @@ Job.prototype.status = function(callback) {
* @param {Object} Returns the job instance. * @param {Object} Returns the job instance.
*/ */
Job.prototype.stop = function(callback) { Job.prototype.stop = function(callback) {
this.once('stop', _.iteratee(callback)); this.once('stop', _.callback(callback));
if (this.stopping) { if (this.stopping) {
return this; return this;
} }
@@ -683,14 +707,14 @@ function Tunnel(properties) {
var active = [], var active = [],
queue = []; queue = [];
var all = _.map(this.platforms, _.bind(function(platform) { var all = _.map(this.platforms, function(platform) {
return new Job(_.merge({ return new Job(_.merge({
'user': this.user, 'user': this.user,
'pass': this.pass, 'pass': this.pass,
'tunnel': this, 'tunnel': this,
'options': { 'platforms': [platform] } 'options': { 'platforms': [platform] }
}, this.job)); }, this.job));
}, this)); }, this);
var completed = 0, var completed = 0,
restarted = [], restarted = [],
@@ -698,7 +722,7 @@ function Tunnel(properties) {
total = all.length, total = all.length,
tunnel = this; tunnel = this;
_.invokeMap(all, 'on', 'complete', function() { _.invoke(all, 'on', 'complete', function() {
_.pull(active, this); _.pull(active, this);
if (success) { if (success) {
success = !this.failed; success = !this.failed;
@@ -710,7 +734,7 @@ function Tunnel(properties) {
tunnel.dequeue(); tunnel.dequeue();
}); });
_.invokeMap(all, 'on', 'restart', function() { _.invoke(all, 'on', 'restart', function() {
if (!_.includes(restarted, this)) { if (!_.includes(restarted, this)) {
restarted.push(this); restarted.push(this);
} }
@@ -744,7 +768,7 @@ util.inherits(Tunnel, EventEmitter);
* @param {Function} callback The function called once the tunnel is restarted. * @param {Function} callback The function called once the tunnel is restarted.
*/ */
Tunnel.prototype.restart = function(callback) { Tunnel.prototype.restart = function(callback) {
this.once('restart', _.iteratee(callback)); this.once('restart', _.callback(callback));
if (this.restarting) { if (this.restarting) {
return this; return this;
} }
@@ -758,7 +782,7 @@ Tunnel.prototype.restart = function(callback) {
all = jobs.all; all = jobs.all;
var reset = _.after(all.length, _.bind(this.stop, this, onGenericRestart)), var reset = _.after(all.length, _.bind(this.stop, this, onGenericRestart)),
stop = _.after(active.length, _.partial(_.invokeMap, all, 'reset', reset)); stop = _.after(active.length, _.partial(_.invoke, all, 'reset', reset));
if (_.isEmpty(active)) { if (_.isEmpty(active)) {
_.defer(stop); _.defer(stop);
@@ -766,7 +790,7 @@ Tunnel.prototype.restart = function(callback) {
if (_.isEmpty(all)) { if (_.isEmpty(all)) {
_.defer(reset); _.defer(reset);
} }
_.invokeMap(active, 'stop', function() { _.invoke(active, 'stop', function() {
_.pull(active, this); _.pull(active, this);
stop(); stop();
}); });
@@ -786,7 +810,7 @@ Tunnel.prototype.restart = function(callback) {
* @param {Object} Returns the tunnel instance. * @param {Object} Returns the tunnel instance.
*/ */
Tunnel.prototype.start = function(callback) { Tunnel.prototype.start = function(callback) {
this.once('start', _.iteratee(callback)); this.once('start', _.callback(callback));
if (this.starting || this.running) { if (this.starting || this.running) {
return this; return this;
} }
@@ -810,16 +834,13 @@ Tunnel.prototype.start = function(callback) {
* @param {Object} Returns the tunnel instance. * @param {Object} Returns the tunnel instance.
*/ */
Tunnel.prototype.dequeue = function() { Tunnel.prototype.dequeue = function() {
var count = 0, var jobs = this.jobs,
jobs = this.jobs,
active = jobs.active, active = jobs.active,
queue = jobs.queue, queue = jobs.queue,
throttled = this.throttled; throttled = this.throttled;
while (queue.length && (active.length < throttled)) { while (queue.length && (active.length < throttled)) {
var job = queue.shift(); active.push(queue.shift().start());
active.push(job);
_.delay(_.bind(job.start, job), ++count * 1000);
} }
return this; return this;
}; };
@@ -832,7 +853,7 @@ Tunnel.prototype.dequeue = function() {
* @param {Object} Returns the tunnel instance. * @param {Object} Returns the tunnel instance.
*/ */
Tunnel.prototype.stop = function(callback) { Tunnel.prototype.stop = function(callback) {
this.once('stop', _.iteratee(callback)); this.once('stop', _.callback(callback));
if (this.stopping) { if (this.stopping) {
return this; return this;
} }
@@ -857,7 +878,7 @@ Tunnel.prototype.stop = function(callback) {
if (_.isEmpty(active)) { if (_.isEmpty(active)) {
_.defer(stop); _.defer(stop);
} }
_.invokeMap(active, 'stop', function() { _.invoke(active, 'stop', function() {
_.pull(active, this); _.pull(active, this);
stop(); stop();
}); });

File diff suppressed because it is too large Load Diff

29043
test/test.js

File diff suppressed because it is too large Load Diff

View File

@@ -23,91 +23,50 @@
<script src="../node_modules/jquery/dist/jquery.js"></script> <script src="../node_modules/jquery/dist/jquery.js"></script>
<script src="../node_modules/platform/platform.js"></script> <script src="../node_modules/platform/platform.js"></script>
<script src="./asset/test-ui.js"></script> <script src="./asset/test-ui.js"></script>
<script src="../lodash.js"></script>
<script> <script>
QUnit.config.asyncRetries = 10; QUnit.config.asyncRetries = 10;
QUnit.config.hidepassed = true; QUnit.config.hidepassed = true;
// Excuse tests we intentionally fail or those with problems.
QUnit.config.excused = { QUnit.config.excused = {
'Arrays': { 'Arrays': {
'chunk': [
'defaults to empty array (chunk size 0)'
],
'difference': [
'can perform an OO-style difference'
],
'drop': [ 'drop': [
'is an alias for rest' 'alias for rest'
], ],
'first': [ 'first': [
'returns an empty array when n <= 0 (0 case)', 'can pass an index to first',
'returns an empty array when n <= 0 (negative case)', '[1,2]',
'can fetch the first n elements',
'returns the whole array if n > length'
],
'findIndex': [
'called with context'
],
'findLastIndex': [
'called with context'
],
'flatten': [
'supports empty arrays',
'can flatten nested arrays',
'works on an arguments object',
'can handle very deep arrays'
],
'indexOf': [
"sorted indexOf doesn't uses binary search",
'0' '0'
], ],
'flatten': [
'Flattens empty arrays',
'can flatten nested arrays',
'can shallowly flatten nested arrays',
'works on an arguments object',
'can shallowly flatten arrays containing only other arrays'
],
'initial': [ 'initial': [
'returns all but the last n elements', 'initial can take an index',
'returns an empty array when n > length', 'initial can take a large index',
'works on an arguments object' 'initial works on arguments object'
], ],
'intersection': [ 'intersection': [
'can perform an OO-style intersection' 'can perform an OO-style intersection'
], ],
'last': [ 'last': [
'returns an empty array when n <= 0 (0 case)', 'can pass an index to last',
'returns an empty array when n <= 0 (negative case)', '0'
'can fetch the last n elements',
'returns the whole array if n > length'
], ],
'lastIndexOf': [ 'lastIndexOf': [
'should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`',
'should treat non-number `fromIndex` values as `array.length`',
'[0,-1,-1]' '[0,-1,-1]'
], ],
'object': [
'an array of pairs zipped together into an object',
'an object converted to pairs and back to an object'
],
'rest': [ 'rest': [
'returns the whole array when index is 0', 'working rest(0)',
'returns elements starting at the given index', 'rest can take an index',
'works on an arguments object' 'works on arguments object'
],
'sortedIndex': [
'2',
'3'
],
'tail': [
'is an alias for rest'
], ],
'take': [ 'take': [
'is an alias for first' 'alias for first'
],
'uniq': [
'uses the result of `iterator` for uniqueness comparisons (unsorted case)',
'`sorted` argument defaults to false when omitted',
'when `iterator` is a string, uses that key for comparisons (unsorted case)',
'uses the result of `iterator` for uniqueness comparisons (sorted case)',
'when `iterator` is a string, uses that key for comparisons (sorted case)',
'can use falsey pluck like iterator'
],
'union': [
'can perform an OO-style union'
] ]
}, },
'Chaining': { 'Chaining': {
@@ -119,190 +78,69 @@
] ]
}, },
'Collections': { 'Collections': {
'lookupIterator with contexts': true,
'Iterating objects with sketchy length properties': true,
'Resistant to collection length and properties changing while iterating': true,
'countBy': [
'{}',
'[{}]'
],
'each': [
'context object property accessed'
],
'every': [
'Can be called with object',
'Died on test #15',
'context works'
],
'filter': [ 'filter': [
'given context',
'OO-filter' 'OO-filter'
], ],
'find': [
'called with context'
],
'findWhere': [
'checks properties given function'
],
'groupBy': [
'{}',
'[{}]'
],
'includes': [
"doesn't delegate to binary search"
],
'invoke': [ 'invoke': [
'handles null & undefined' 'handles null & undefined'
], ],
'map': [ 'map': [
'tripled numbers with context',
'OO-style doubled numbers' 'OO-style doubled numbers'
], ],
'max': [ 'Resistant to collection length and properties changing while iterating': [
'can handle null/undefined', 'Died on test #50'
'can perform a computation-based max',
'Maximum value of an empty object',
'Maximum value of an empty array',
'Maximum value of a non-numeric collection',
'Finds correct max in array starting with num and containing a NaN',
'Finds correct max in array starting with NaN',
'Respects iterator return value of -Infinity',
'String keys use property iterator',
'Iterator context',
'Lookup falsy iterator'
],
'min': [
'can handle null/undefined',
'can perform a computation-based min',
'Minimum value of an empty object',
'Minimum value of an empty array',
'Minimum value of a non-numeric collection',
'Finds correct min in array starting with NaN',
'Respects iterator return value of Infinity',
'String keys use property iterator',
'Iterator context',
'Lookup falsy iterator'
],
'partition': [
'can reference the array index',
'Died on test #8',
'partition takes a context argument'
],
'pluck': [
'[1]'
],
'reduce': [
'can reduce with a context object'
],
'reject': [
'Returns empty list given empty array'
],
'sample': [
'behaves correctly on negative n',
'Died on test #3'
],
'some': [
'Can be called with object',
'Died on test #17',
'context works'
],
'where': [
'checks properties given function'
],
'Can use various collection methods on NodeLists': [
'<span id="id2"></span>'
] ]
}, },
'Functions': { 'Functions': {
'debounce asap': true,
'debounce asap cancel': true,
'debounce asap recursively': true,
'debounce after system time is set backwards': true,
'debounce re-entrant': true,
'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,
'before': true,
'bind': [ 'bind': [
'Died on test #2' 'Died on test #2'
], ],
'bindAll': [ 'bindAll': [
'throws an error for bindAll with no functions named' 'throws an error for bindAll with no functions named'
], ],
'debounce': [
'incr was debounced'
],
'iteratee': [
'"bbiz"',
'"foo"',
'1'
],
'memoize': [ 'memoize': [
'{"bar":"BAR","foo":"FOO"}', '{"bar":"BAR","foo":"FOO"}',
'Died on test #8' '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,
'debounce asap': true
}, },
'Objects': { 'Objects': {
'#1929 Typed Array constructors are functions': true, '#1929 Typed Array constructors are functions': true,
'allKeys': [ 'allKeys': true,
'is not fooled by sparse arrays; see issue #95', 'extendOwn': true,
'is not fooled by sparse arrays with additional properties', 'mapObject': true,
'[]' 'matcher': true,
], 'matcher ': true,
'extend': [ 'extend': [
'extending null results in null', 'extend copies all properties from source'
'extending undefined results in undefined'
],
'extendOwn': [
'extending non-objects results in returning the non-object value',
'extending undefined results in undefined'
],
'functions': [
'also looks up functions on the prototype'
], ],
'isEqual': [ 'isEqual': [
'`0` is not equal to `-0`', '`0` is not equal to `-0`',
'Commutative equality is implemented for `0` and `-0`', 'Commutative equality is implemented for `0` and `-0`',
'`new Number(0)` and `-0` are not equal', '`new Number(0)` and `-0` are not equal',
'Commutative equality is implemented for `new Number(0)` and `-0`', 'Commutative equality is implemented for `new Number(0)` and `-0`'
'Invalid dates are not equal',
'false'
], ],
'isFinite': [ 'isFinite': [
'Numeric strings are numbers', 'Numeric strings are numbers',
'Number instances can be finite' 'Number instances can be finite'
], ],
'isSet': [ 'isMatch': [
'Died on test #9' 'inherited and own properties are checked on the test object',
], 'doesnt falsey match constructor on undefined/null'
'findKey': [
'called with context'
], ],
'keys': [ 'keys': [
'is not fooled by sparse arrays; see issue #95', 'is not fooled by sparse arrays; see issue #95',
'[]' '[]'
], ],
'mapObject': [ 'matches': [
'keep context', 'inherited and own properties are checked on the test object',
'called with context', 'doesnt fasley match constructor on undefined/null'
'mapValue identity'
],
'omit': [
'can accept a predicate',
'function is given context'
],
'pick': [
'can accept a predicate and context',
'function is given context'
] ]
}, },
'Utility': { 'Utility': {
'_.escape & unescape': [
'` is escaped',
'` can be unescaped',
'can escape multiple occurances of `',
'multiple occurrences of ` can be unescaped'
],
'now': [ 'now': [
'Produces the correct time in milliseconds' 'Produces the correct time in milliseconds'
], ],
@@ -312,75 +150,19 @@
} }
}; };
var mixinPrereqs = (function() { // Only excuse in Sauce Labs (buggy Safari and timers).
var aliasToReal = {
'all': 'every',
'allKeys': 'keysIn',
'any': 'some',
'collect': 'map',
'compose': 'flowRight',
'contains': 'includes',
'detect': 'find',
'extendOwn': 'assign',
'findWhere': 'find',
'foldl': 'reduce',
'foldr': 'reduceRight',
'include': 'includes',
'indexBy': 'keyBy',
'inject': 'reduce',
'invoke': 'invokeMap',
'mapObject': 'mapValues',
'matcher': 'matches',
'methods': 'functions',
'object': 'zipObject',
'pairs': 'toPairs',
'pluck': 'map',
'restParam': 'restArgs',
'select': 'filter',
'unique': 'uniq',
'where': 'filter'
};
var keyMap = {
'rest': 'tail',
'restArgs': 'rest'
};
var lodash = _.noConflict();
return function(_) {
lodash(_)
.defaultsDeep({ 'templateSettings': lodash.templateSettings })
.mixin(lodash.pick(lodash, lodash.difference(lodash.functions(lodash), lodash.functions(_))))
.value();
lodash.forOwn(keyMap, function(realName, otherName) {
_[otherName] = lodash[realName];
_.prototype[otherName] = lodash.prototype[realName];
});
lodash.forOwn(aliasToReal, function(realName, alias) {
_[alias] = _[realName];
_.prototype[alias] = _.prototype[realName];
});
return _;
};
}());
// Only excuse in Sauce Labs.
if (!ui.isSauceLabs) { if (!ui.isSauceLabs) {
delete QUnit.config.excused.Functions['throttle repeatedly with results'];
delete QUnit.config.excused.Functions['more throttle does not trigger leading call when leading is set to false'];
delete QUnit.config.excused.Functions['throttle does not trigger trailing call when trailing is set to false']; 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.Utility.now; delete QUnit.config.excused.Utility.now;
} }
// Load prerequisite scripts. // Load test scripts.
document.write(ui.urlParams.loader == 'none' document.write(ui.urlParams.loader != 'none'
? '<script src="' + ui.buildPath + '"><\/script>' ? '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>'
: '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>' : ([
); '<script src="' + ui.buildPath + '"><\/script>',
</script>
<script>
if (ui.urlParams.loader == 'none') {
mixinPrereqs(_);
document.write([
'<script src="../vendor/underscore/test/collections.js"><\/script>', '<script src="../vendor/underscore/test/collections.js"><\/script>',
'<script src="../vendor/underscore/test/arrays.js"><\/script>', '<script src="../vendor/underscore/test/arrays.js"><\/script>',
'<script src="../vendor/underscore/test/functions.js"><\/script>', '<script src="../vendor/underscore/test/functions.js"><\/script>',
@@ -388,8 +170,8 @@
'<script src="../vendor/underscore/test/cross-document.js"><\/script>', '<script src="../vendor/underscore/test/cross-document.js"><\/script>',
'<script src="../vendor/underscore/test/utility.js"><\/script>', '<script src="../vendor/underscore/test/utility.js"><\/script>',
'<script src="../vendor/underscore/test/chaining.js"><\/script>' '<script src="../vendor/underscore/test/chaining.js"><\/script>'
].join('\n')); ].join('\n'))
} );
</script> </script>
<script> <script>
(function() { (function() {
@@ -399,13 +181,6 @@
if (!window.require) { if (!window.require) {
return; return;
} }
// Wrap to work around tests assuming Node `require` use.
require = (function(func) {
return function() {
return arguments[0] === '..' ? window._ : func.apply(null, arguments);
};
}(require));
var reBasename = /[\w.-]+$/, var reBasename = /[\w.-]+$/,
basePath = ('//' + location.host + location.pathname.replace(reBasename, '')).replace(/\btest\/$/, ''), basePath = ('//' + location.host + location.pathname.replace(reBasename, '')).replace(/\btest\/$/, ''),
modulePath = ui.buildPath.replace(/\.js$/, ''), modulePath = ui.buildPath.replace(/\.js$/, ''),
@@ -444,12 +219,11 @@
} }
QUnit.config.autostart = false; QUnit.config.autostart = false;
QUnit.config.excused.Functions.iteratee = true;
QUnit.config.excused.Utility.noConflict = true;
QUnit.config.excused.Utility['noConflict (node vm)'] = true;
require(getConfig(), [moduleId], function(lodash) { require(getConfig(), [moduleId], function(lodash) {
_ = mixinPrereqs(lodash); if (ui.isModularize) {
window._ = lodash;
}
require(getConfig(), [ require(getConfig(), [
'test/collections', 'test/collections',
'test/arrays', 'test/arrays',
@@ -458,7 +232,9 @@
'test/cross-document', 'test/cross-document',
'test/utility', 'test/utility',
'test/chaining' 'test/chaining'
], QUnit.start); ], function() {
QUnit.start();
});
}); });
}()); }());
</script> </script>

View File

@@ -1,4 +1,4 @@
Copyright (c) 2010-2016 Jeremy Ashkenas, DocumentCloud Copyright (c) 2010-2015 Jeremy Ashkenas, DocumentCloud
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation

View File

@@ -1,6 +1,6 @@
// Backbone.js 1.3.3 // Backbone.js 1.2.1
// (c) 2010-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // (c) 2010-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Backbone may be freely distributed under the MIT license. // Backbone may be freely distributed under the MIT license.
// For all details and documentation: // For all details and documentation:
// http://backbonejs.org // http://backbonejs.org
@@ -9,8 +9,8 @@
// Establish the root object, `window` (`self`) in the browser, or `global` on the server. // Establish the root object, `window` (`self`) in the browser, or `global` on the server.
// We use `self` instead of `window` for `WebWorker` support. // We use `self` instead of `window` for `WebWorker` support.
var root = (typeof self == 'object' && self.self === self && self) || var root = (typeof self == 'object' && self.self == self && self) ||
(typeof global == 'object' && global.global === global && global); (typeof global == 'object' && global.global == global && global);
// Set up Backbone appropriately for the environment. Start with AMD. // Set up Backbone appropriately for the environment. Start with AMD.
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
@@ -23,7 +23,7 @@
// Next for Node.js or CommonJS. jQuery may not be needed as a module. // Next for Node.js or CommonJS. jQuery may not be needed as a module.
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
var _ = require('underscore'), $; var _ = require('underscore'), $;
try { $ = require('jquery'); } catch (e) {} try { $ = require('jquery'); } catch(e) {}
factory(root, exports, _, $); factory(root, exports, _, $);
// Finally, as a browser global. // Finally, as a browser global.
@@ -31,7 +31,7 @@
root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
} }
})(function(root, Backbone, _, $) { }(function(root, Backbone, _, $) {
// Initial Setup // Initial Setup
// ------------- // -------------
@@ -41,10 +41,10 @@
var previousBackbone = root.Backbone; var previousBackbone = root.Backbone;
// Create a local reference to a common array method we'll want to use later. // Create a local reference to a common array method we'll want to use later.
var slice = Array.prototype.slice; var slice = [].slice;
// Current version of the library. Keep in sync with `package.json`. // Current version of the library. Keep in sync with `package.json`.
Backbone.VERSION = '1.3.3'; Backbone.VERSION = '1.2.1';
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
// the `$` variable. // the `$` variable.
@@ -68,13 +68,8 @@
// form param named `model`. // form param named `model`.
Backbone.emulateJSON = false; Backbone.emulateJSON = false;
// Proxy Backbone class methods to Underscore functions, wrapping the model's // Proxy Underscore methods to a Backbone class' prototype using a
// `attributes` object or collection's `models` array behind the scenes. // particular attribute as the data argument
//
// collection.filter(function(model) { return model.get('age') > 10 });
// collection.each(this.addView);
//
// `Function#apply` can be slow so we use the method's arg count, if we know it.
var addMethod = function(length, method, attribute) { var addMethod = function(length, method, attribute) {
switch (length) { switch (length) {
case 1: return function() { case 1: return function() {
@@ -84,10 +79,10 @@
return _[method](this[attribute], value); return _[method](this[attribute], value);
}; };
case 3: return function(iteratee, context) { case 3: return function(iteratee, context) {
return _[method](this[attribute], cb(iteratee, this), context); return _[method](this[attribute], iteratee, context);
}; };
case 4: return function(iteratee, defaultVal, context) { case 4: return function(iteratee, defaultVal, context) {
return _[method](this[attribute], cb(iteratee, this), defaultVal, context); return _[method](this[attribute], iteratee, defaultVal, context);
}; };
default: return function() { default: return function() {
var args = slice.call(arguments); var args = slice.call(arguments);
@@ -102,26 +97,12 @@
}); });
}; };
// Support `collection.sortBy('attr')` and `collection.findWhere({id: 1})`.
var cb = function(iteratee, instance) {
if (_.isFunction(iteratee)) return iteratee;
if (_.isObject(iteratee) && !instance._isModel(iteratee)) return modelMatcher(iteratee);
if (_.isString(iteratee)) return function(model) { return model.get(iteratee); };
return iteratee;
};
var modelMatcher = function(attrs) {
var matcher = _.matches(attrs);
return function(model) {
return matcher(model.attributes);
};
};
// Backbone.Events // Backbone.Events
// --------------- // ---------------
// A module that can be mixed in to *any object* in order to provide it with // A module that can be mixed in to *any object* in order to provide it with
// a custom event channel. You may bind a callback to an event with `on` or // custom events. You may bind with `on` or remove with `off` callback
// remove with `off`; `trigger`-ing an event fires all callbacks in // functions to an event; `trigger`-ing an event fires all callbacks in
// succession. // succession.
// //
// var object = {}; // var object = {};
@@ -136,25 +117,26 @@
// Iterates over the standard `event, callback` (as well as the fancy multiple // Iterates over the standard `event, callback` (as well as the fancy multiple
// space-separated events `"change blur", callback` and jQuery-style event // space-separated events `"change blur", callback` and jQuery-style event
// maps `{event: callback}`). // maps `{event: callback}`), reducing them by manipulating `memo`.
var eventsApi = function(iteratee, events, name, callback, opts) { // Passes a normalized single event name and callback, as well as any
// optional `opts`.
var eventsApi = function(iteratee, memo, name, callback, opts) {
var i = 0, names; var i = 0, names;
if (name && typeof name === 'object') { if (name && typeof name === 'object') {
// Handle event maps. // Handle event maps.
if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback; if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
for (names = _.keys(name); i < names.length ; i++) { for (names = _.keys(name); i < names.length ; i++) {
events = eventsApi(iteratee, events, names[i], name[names[i]], opts); memo = iteratee(memo, names[i], name[names[i]], opts);
} }
} else if (name && eventSplitter.test(name)) { } else if (name && eventSplitter.test(name)) {
// Handle space-separated event names by delegating them individually. // Handle space separated event names.
for (names = name.split(eventSplitter); i < names.length; i++) { for (names = name.split(eventSplitter); i < names.length; i++) {
events = iteratee(events, names[i], callback, opts); memo = iteratee(memo, names[i], callback, opts);
} }
} else { } else {
// Finally, standard events. memo = iteratee(memo, name, callback, opts);
events = iteratee(events, name, callback, opts);
} }
return events; return memo;
}; };
// Bind an event to a `callback` function. Passing `"all"` will bind // Bind an event to a `callback` function. Passing `"all"` will bind
@@ -163,12 +145,13 @@
return internalOn(this, name, callback, context); return internalOn(this, name, callback, context);
}; };
// Guard the `listening` argument from the public API. // An internal use `on` function, used to guard the `listening` argument from
// the public API.
var internalOn = function(obj, name, callback, context, listening) { var internalOn = function(obj, name, callback, context, listening) {
obj._events = eventsApi(onApi, obj._events || {}, name, callback, { obj._events = eventsApi(onApi, obj._events || {}, name, callback, {
context: context, context: context,
ctx: obj, ctx: obj,
listening: listening listening: listening
}); });
if (listening) { if (listening) {
@@ -180,9 +163,8 @@
}; };
// Inversion-of-control versions of `on`. Tell *this* object to listen to // Inversion-of-control versions of `on`. Tell *this* object to listen to
// an event in another object... keeping track of what it's listening to // an event in another object... keeping track of what it's listening to.
// for easier unbinding later. Events.listenTo = function(obj, name, callback) {
Events.listenTo = function(obj, name, callback) {
if (!obj) return this; if (!obj) return this;
var id = obj._listenId || (obj._listenId = _.uniqueId('l')); var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
var listeningTo = this._listeningTo || (this._listeningTo = {}); var listeningTo = this._listeningTo || (this._listeningTo = {});
@@ -207,7 +189,7 @@
var context = options.context, ctx = options.ctx, listening = options.listening; var context = options.context, ctx = options.ctx, listening = options.listening;
if (listening) listening.count++; if (listening) listening.count++;
handlers.push({callback: callback, context: context, ctx: context || ctx, listening: listening}); handlers.push({ callback: callback, context: context, ctx: context || ctx, listening: listening });
} }
return events; return events;
}; };
@@ -216,18 +198,18 @@
// callbacks with that function. If `callback` is null, removes all // callbacks with that function. If `callback` is null, removes all
// callbacks for the event. If `name` is null, removes all bound // callbacks for the event. If `name` is null, removes all bound
// callbacks for all events. // callbacks for all events.
Events.off = function(name, callback, context) { Events.off = function(name, callback, context) {
if (!this._events) return this; if (!this._events) return this;
this._events = eventsApi(offApi, this._events, name, callback, { this._events = eventsApi(offApi, this._events, name, callback, {
context: context, context: context,
listeners: this._listeners listeners: this._listeners
}); });
return this; return this;
}; };
// Tell this object to stop listening to either specific events ... or // Tell this object to stop listening to either specific events ... or
// to every object it's currently listening to. // to every object it's currently listening to.
Events.stopListening = function(obj, name, callback) { Events.stopListening = function(obj, name, callback) {
var listeningTo = this._listeningTo; var listeningTo = this._listeningTo;
if (!listeningTo) return this; if (!listeningTo) return this;
@@ -242,12 +224,14 @@
listening.obj.off(name, callback, this); listening.obj.off(name, callback, this);
} }
if (_.isEmpty(listeningTo)) this._listeningTo = void 0;
return this; return this;
}; };
// The reducing API that removes a callback from the `events` object. // The reducing API that removes a callback from the `events` object.
var offApi = function(events, name, callback, options) { var offApi = function(events, name, callback, options) {
// No events to consider.
if (!events) return; if (!events) return;
var i = 0, listening; var i = 0, listening;
@@ -298,22 +282,21 @@
delete events[name]; delete events[name];
} }
} }
return events; if (_.size(events)) return events;
}; };
// Bind an event to only be triggered a single time. After the first time // Bind an event to only be triggered a single time. After the first time
// the callback is invoked, its listener will be removed. If multiple events // the callback is invoked, it will be removed. When multiple events are
// are passed in using the space-separated syntax, the handler will fire // passed in using the space-separated syntax, the event will fire once for every
// once for each event, not once for a combination of all events. // event you passed in, not once for a combination of all events
Events.once = function(name, callback, context) { Events.once = function(name, callback, context) {
// Map the event into a `{event: once}` object. // Map the event into a `{event: once}` object.
var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this)); var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this));
if (typeof name === 'string' && context == null) callback = void 0; return this.on(events, void 0, context);
return this.on(events, callback, context);
}; };
// Inversion-of-control versions of `once`. // Inversion-of-control versions of `once`.
Events.listenToOnce = function(obj, name, callback) { Events.listenToOnce = function(obj, name, callback) {
// Map the event into a `{event: once}` object. // Map the event into a `{event: once}` object.
var events = eventsApi(onceMap, {}, name, callback, _.bind(this.stopListening, this, obj)); var events = eventsApi(onceMap, {}, name, callback, _.bind(this.stopListening, this, obj));
return this.listenTo(obj, events); return this.listenTo(obj, events);
@@ -336,7 +319,7 @@
// passed the same arguments as `trigger` is, apart from the event name // passed the same arguments as `trigger` is, apart from the event name
// (unless you're listening on `"all"`, which will cause your callback to // (unless you're listening on `"all"`, which will cause your callback to
// receive the true name of the event as the first argument). // receive the true name of the event as the first argument).
Events.trigger = function(name) { Events.trigger = function(name) {
if (!this._events) return this; if (!this._events) return this;
var length = Math.max(0, arguments.length - 1); var length = Math.max(0, arguments.length - 1);
@@ -348,7 +331,7 @@
}; };
// Handles triggering the appropriate event callbacks. // Handles triggering the appropriate event callbacks.
var triggerApi = function(objEvents, name, callback, args) { var triggerApi = function(objEvents, name, cb, args) {
if (objEvents) { if (objEvents) {
var events = objEvents[name]; var events = objEvents[name];
var allEvents = objEvents.all; var allEvents = objEvents.all;
@@ -394,13 +377,11 @@
var Model = Backbone.Model = function(attributes, options) { var Model = Backbone.Model = function(attributes, options) {
var attrs = attributes || {}; var attrs = attributes || {};
options || (options = {}); options || (options = {});
this.preinitialize.apply(this, arguments);
this.cid = _.uniqueId(this.cidPrefix); this.cid = _.uniqueId(this.cidPrefix);
this.attributes = {}; this.attributes = {};
if (options.collection) this.collection = options.collection; if (options.collection) this.collection = options.collection;
if (options.parse) attrs = this.parse(attrs, options) || {}; if (options.parse) attrs = this.parse(attrs, options) || {};
var defaults = _.result(this, 'defaults'); attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
attrs = _.defaults(_.extend({}, defaults, attrs), defaults);
this.set(attrs, options); this.set(attrs, options);
this.changed = {}; this.changed = {};
this.initialize.apply(this, arguments); this.initialize.apply(this, arguments);
@@ -423,10 +404,6 @@
// You may want to override this if you're experiencing name clashes with model ids. // You may want to override this if you're experiencing name clashes with model ids.
cidPrefix: 'c', cidPrefix: 'c',
// preinitialize is an empty function by default. You can override it with a function
// or object. preinitialize will run before any instantiation logic is run in the Model.
preinitialize: function(){},
// Initialize is an empty function by default. Override it with your own // Initialize is an empty function by default. Override it with your own
// initialization logic. // initialization logic.
initialize: function(){}, initialize: function(){},
@@ -499,6 +476,9 @@
var changed = this.changed; var changed = this.changed;
var prev = this._previousAttributes; var prev = this._previousAttributes;
// Check for changes of `id`.
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
// For each `set` attribute, update or delete the current value. // For each `set` attribute, update or delete the current value.
for (var attr in attrs) { for (var attr in attrs) {
val = attrs[attr]; val = attrs[attr];
@@ -511,9 +491,6 @@
unset ? delete current[attr] : current[attr] = val; unset ? delete current[attr] : current[attr] = val;
} }
// Update the `id`.
if (this.idAttribute in attrs) this.id = this.get(this.idAttribute);
// Trigger all relevant attribute changes. // Trigger all relevant attribute changes.
if (!silent) { if (!silent) {
if (changes.length) this._pending = options; if (changes.length) this._pending = options;
@@ -567,14 +544,12 @@
if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
var old = this._changing ? this._previousAttributes : this.attributes; var old = this._changing ? this._previousAttributes : this.attributes;
var changed = {}; var changed = {};
var hasChanged;
for (var attr in diff) { for (var attr in diff) {
var val = diff[attr]; var val = diff[attr];
if (_.isEqual(old[attr], val)) continue; if (_.isEqual(old[attr], val)) continue;
changed[attr] = val; changed[attr] = val;
hasChanged = true;
} }
return hasChanged ? changed : false; return _.size(changed) ? changed : false;
}, },
// Get the previous value of an attribute, recorded at the time the last // Get the previous value of an attribute, recorded at the time the last
@@ -627,8 +602,8 @@
// the model will be valid when the attributes, if any, are set. // the model will be valid when the attributes, if any, are set.
if (attrs && !wait) { if (attrs && !wait) {
if (!this.set(attrs, options)) return false; if (!this.set(attrs, options)) return false;
} else if (!this._validate(attrs, options)) { } else {
return false; if (!this._validate(attrs, options)) return false;
} }
// After a successful server-side save, the client is (optionally) // After a successful server-side save, the client is (optionally)
@@ -722,7 +697,7 @@
// Check if the model is currently in a valid state. // Check if the model is currently in a valid state.
isValid: function(options) { isValid: function(options) {
return this._validate({}, _.extend({}, options, {validate: true})); return this._validate({}, _.defaults({validate: true}, options));
}, },
// Run validation against the next complete set of model attributes, // Run validation against the next complete set of model attributes,
@@ -738,10 +713,9 @@
}); });
// Underscore methods that we want to implement on the Model, mapped to the // Underscore methods that we want to implement on the Model.
// number of arguments they take. var modelMethods = { keys: 1, values: 1, pairs: 1, invert: 1, pick: 0,
var modelMethods = {keys: 1, values: 1, pairs: 1, invert: 1, pick: 0, omit: 0, chain: 1, isEmpty: 1 };
omit: 0, chain: 1, isEmpty: 1};
// Mix in each Underscore method as a proxy to `Model#attributes`. // Mix in each Underscore method as a proxy to `Model#attributes`.
addUnderscoreMethods(Model, modelMethods, 'attributes'); addUnderscoreMethods(Model, modelMethods, 'attributes');
@@ -761,7 +735,6 @@
// its models in sort order, as they're added and removed. // its models in sort order, as they're added and removed.
var Collection = Backbone.Collection = function(models, options) { var Collection = Backbone.Collection = function(models, options) {
options || (options = {}); options || (options = {});
this.preinitialize.apply(this, arguments);
if (options.model) this.model = options.model; if (options.model) this.model = options.model;
if (options.comparator !== void 0) this.comparator = options.comparator; if (options.comparator !== void 0) this.comparator = options.comparator;
this._reset(); this._reset();
@@ -773,17 +746,6 @@
var setOptions = {add: true, remove: true, merge: true}; var setOptions = {add: true, remove: true, merge: true};
var addOptions = {add: true, remove: false}; var addOptions = {add: true, remove: false};
// Splices `insert` into `array` at index `at`.
var splice = function(array, insert, at) {
at = Math.min(Math.max(at, 0), array.length);
var tail = Array(array.length - at);
var length = insert.length;
var i;
for (i = 0; i < tail.length; i++) tail[i] = array[i + at];
for (i = 0; i < length; i++) array[i + at] = insert[i];
for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i];
};
// Define the Collection's inheritable methods. // Define the Collection's inheritable methods.
_.extend(Collection.prototype, Events, { _.extend(Collection.prototype, Events, {
@@ -791,11 +753,6 @@
// This should be overridden in most cases. // This should be overridden in most cases.
model: Model, model: Model,
// preinitialize is an empty function by default. You can override it with a function
// or object. preinitialize will run before any instantiation logic is run in the Collection.
preinitialize: function(){},
// Initialize is an empty function by default. Override it with your own // Initialize is an empty function by default. Override it with your own
// initialization logic. // initialization logic.
initialize: function(){}, initialize: function(){},
@@ -811,9 +768,7 @@
return Backbone.sync.apply(this, arguments); return Backbone.sync.apply(this, arguments);
}, },
// Add a model, or list of models to the set. `models` may be Backbone // Add a model, or list of models to the set.
// Models or raw JavaScript objects to be converted to Models, or any
// combination of the two.
add: function(models, options) { add: function(models, options) {
return this.set(models, _.extend({merge: false}, options, addOptions)); return this.set(models, _.extend({merge: false}, options, addOptions));
}, },
@@ -822,12 +777,9 @@
remove: function(models, options) { remove: function(models, options) {
options = _.extend({}, options); options = _.extend({}, options);
var singular = !_.isArray(models); var singular = !_.isArray(models);
models = singular ? [models] : models.slice(); models = singular ? [models] : _.clone(models);
var removed = this._removeModels(models, options); var removed = this._removeModels(models, options);
if (!options.silent && removed.length) { if (!options.silent && removed) this.trigger('update', this, options);
options.changes = {added: [], merged: [], removed: removed};
this.trigger('update', this, options);
}
return singular ? removed[0] : removed; return singular ? removed[0] : removed;
}, },
@@ -836,114 +788,97 @@
// already exist in the collection, as necessary. Similar to **Model#set**, // already exist in the collection, as necessary. Similar to **Model#set**,
// the core operation for updating the data contained by the collection. // the core operation for updating the data contained by the collection.
set: function(models, options) { set: function(models, options) {
if (models == null) return; options = _.defaults({}, options, setOptions);
if (options.parse && !this._isModel(models)) models = this.parse(models, options);
options = _.extend({}, setOptions, options);
if (options.parse && !this._isModel(models)) {
models = this.parse(models, options) || [];
}
var singular = !_.isArray(models); var singular = !_.isArray(models);
models = singular ? [models] : models.slice(); models = singular ? (models ? [models] : []) : models.slice();
var id, model, attrs, existing, sort;
var at = options.at; var at = options.at;
if (at != null) at = +at; if (at != null) at = +at;
if (at > this.length) at = this.length;
if (at < 0) at += this.length + 1; if (at < 0) at += this.length + 1;
var sortable = this.comparator && (at == null) && options.sort !== false;
var set = [];
var toAdd = [];
var toMerge = [];
var toRemove = [];
var modelMap = {};
var add = options.add;
var merge = options.merge;
var remove = options.remove;
var sort = false;
var sortable = this.comparator && at == null && options.sort !== false;
var sortAttr = _.isString(this.comparator) ? this.comparator : null; var sortAttr = _.isString(this.comparator) ? this.comparator : null;
var toAdd = [], toRemove = [], modelMap = {};
var add = options.add, merge = options.merge, remove = options.remove;
var order = !sortable && add && remove ? [] : false;
var orderChanged = false;
// Turn bare objects into model references, and prevent invalid models // Turn bare objects into model references, and prevent invalid models
// from being added. // from being added.
var model, i; for (var i = 0; i < models.length; i++) {
for (i = 0; i < models.length; i++) { attrs = models[i];
model = models[i];
// If a duplicate is found, prevent it from being added and // If a duplicate is found, prevent it from being added and
// optionally merge it into the existing model. // optionally merge it into the existing model.
var existing = this.get(model); if (existing = this.get(attrs)) {
if (existing) { if (remove) modelMap[existing.cid] = true;
if (merge && model !== existing) { if (merge && attrs !== existing) {
var attrs = this._isModel(model) ? model.attributes : model; attrs = this._isModel(attrs) ? attrs.attributes : attrs;
if (options.parse) attrs = existing.parse(attrs, options); if (options.parse) attrs = existing.parse(attrs, options);
existing.set(attrs, options); existing.set(attrs, options);
toMerge.push(existing); if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
if (sortable && !sort) sort = existing.hasChanged(sortAttr);
}
if (!modelMap[existing.cid]) {
modelMap[existing.cid] = true;
set.push(existing);
} }
models[i] = existing; models[i] = existing;
// If this is a new, valid model, push it to the `toAdd` list. // If this is a new, valid model, push it to the `toAdd` list.
} else if (add) { } else if (add) {
model = models[i] = this._prepareModel(model, options); model = models[i] = this._prepareModel(attrs, options);
if (model) { if (!model) continue;
toAdd.push(model); toAdd.push(model);
this._addReference(model, options); this._addReference(model, options);
modelMap[model.cid] = true;
set.push(model);
}
} }
// Do not add multiple models with the same `id`.
model = existing || model;
if (!model) continue;
id = this.modelId(model.attributes);
if (order && (model.isNew() || !modelMap[id])) {
order.push(model);
// Check to see if this is actually a new model at this index.
orderChanged = orderChanged || !this.models[i] || model.cid !== this.models[i].cid;
}
modelMap[id] = true;
} }
// Remove stale models. // Remove nonexistent models if appropriate.
if (remove) { if (remove) {
for (i = 0; i < this.length; i++) { for (var i = 0; i < this.length; i++) {
model = this.models[i]; if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
if (!modelMap[model.cid]) toRemove.push(model);
} }
if (toRemove.length) this._removeModels(toRemove, options); if (toRemove.length) this._removeModels(toRemove, options);
} }
// See if sorting is needed, update `length` and splice in new models. // See if sorting is needed, update `length` and splice in new models.
var orderChanged = false; if (toAdd.length || orderChanged) {
var replace = !sortable && add && remove;
if (set.length && replace) {
orderChanged = this.length !== set.length || _.some(this.models, function(m, index) {
return m !== set[index];
});
this.models.length = 0;
splice(this.models, set, 0);
this.length = this.models.length;
} else if (toAdd.length) {
if (sortable) sort = true; if (sortable) sort = true;
splice(this.models, toAdd, at == null ? this.length : at); this.length += toAdd.length;
this.length = this.models.length; if (at != null) {
for (var i = 0; i < toAdd.length; i++) {
this.models.splice(at + i, 0, toAdd[i]);
}
} else {
if (order) this.models.length = 0;
var orderedModels = order || toAdd;
for (var i = 0; i < orderedModels.length; i++) {
this.models.push(orderedModels[i]);
}
}
} }
// Silently sort the collection if appropriate. // Silently sort the collection if appropriate.
if (sort) this.sort({silent: true}); if (sort) this.sort({silent: true});
// Unless silenced, it's time to fire all appropriate add/sort/update events. // Unless silenced, it's time to fire all appropriate add/sort events.
if (!options.silent) { if (!options.silent) {
for (i = 0; i < toAdd.length; i++) { var addOpts = at != null ? _.clone(options) : options;
if (at != null) options.index = at + i; for (var i = 0; i < toAdd.length; i++) {
model = toAdd[i]; if (at != null) addOpts.index = at + i;
model.trigger('add', model, this, options); (model = toAdd[i]).trigger('add', model, this, addOpts);
} }
if (sort || orderChanged) this.trigger('sort', this, options); if (sort || orderChanged) this.trigger('sort', this, options);
if (toAdd.length || toRemove.length || toMerge.length) { if (toAdd.length || toRemove.length) this.trigger('update', this, options);
options.changes = {
added: toAdd,
removed: toRemove,
merged: toMerge
};
this.trigger('update', this, options);
}
} }
// Return the added (or merged) model (or models). // Return the added (or merged) model (or models).
@@ -993,18 +928,11 @@
return slice.apply(this.models, arguments); return slice.apply(this.models, arguments);
}, },
// Get a model from the set by id, cid, model object with id or cid // Get a model from the set by id.
// properties, or an attributes object that is transformed through modelId.
get: function(obj) { get: function(obj) {
if (obj == null) return void 0; if (obj == null) return void 0;
return this._byId[obj] || var id = this.modelId(this._isModel(obj) ? obj.attributes : obj);
this._byId[this.modelId(obj.attributes || obj)] || return this._byId[obj] || this._byId[id] || this._byId[obj.cid];
obj.cid && this._byId[obj.cid];
},
// Returns `true` if the model is in the collection.
has: function(obj) {
return this.get(obj) != null;
}, },
// Get the model at the given index. // Get the model at the given index.
@@ -1016,7 +944,10 @@
// Return models with matching attributes. Useful for simple cases of // Return models with matching attributes. Useful for simple cases of
// `filter`. // `filter`.
where: function(attrs, first) { where: function(attrs, first) {
return this[first ? 'find' : 'filter'](attrs); var matches = _.matches(attrs);
return this[first ? 'find' : 'filter'](function(model) {
return matches(model.attributes);
});
}, },
// Return the first model with matching attributes. Useful for simple cases // Return the first model with matching attributes. Useful for simple cases
@@ -1029,26 +960,23 @@
// normal circumstances, as the set will maintain sort order as each item // normal circumstances, as the set will maintain sort order as each item
// is added. // is added.
sort: function(options) { sort: function(options) {
var comparator = this.comparator; if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
if (!comparator) throw new Error('Cannot sort a set without a comparator');
options || (options = {}); options || (options = {});
var length = comparator.length;
if (_.isFunction(comparator)) comparator = _.bind(comparator, this);
// Run sort based on type of `comparator`. // Run sort based on type of `comparator`.
if (length === 1 || _.isString(comparator)) { if (_.isString(this.comparator) || this.comparator.length === 1) {
this.models = this.sortBy(comparator); this.models = this.sortBy(this.comparator, this);
} else { } else {
this.models.sort(comparator); this.models.sort(_.bind(this.comparator, this));
} }
if (!options.silent) this.trigger('sort', this, options); if (!options.silent) this.trigger('sort', this, options);
return this; return this;
}, },
// Pluck an attribute from each model in the collection. // Pluck an attribute from each model in the collection.
pluck: function(attr) { pluck: function(attr) {
return this.map(attr + ''); return _.invoke(this.models, 'get', attr);
}, },
// Fetch the default set of models for this collection, resetting the // Fetch the default set of models for this collection, resetting the
@@ -1079,9 +1007,9 @@
if (!wait) this.add(model, options); if (!wait) this.add(model, options);
var collection = this; var collection = this;
var success = options.success; var success = options.success;
options.success = function(m, resp, callbackOpts) { options.success = function(model, resp, callbackOpts) {
if (wait) collection.add(m, callbackOpts); if (wait) collection.add(model, callbackOpts);
if (success) success.call(callbackOpts.context, m, resp, callbackOpts); if (success) success.call(callbackOpts.context, model, resp, callbackOpts);
}; };
model.save(null, options); model.save(null, options);
return model; return model;
@@ -1102,7 +1030,7 @@
}, },
// Define how to uniquely identify models in the collection. // Define how to uniquely identify models in the collection.
modelId: function(attrs) { modelId: function (attrs) {
return attrs[this.model.prototype.idAttribute || 'id']; return attrs[this.model.prototype.idAttribute || 'id'];
}, },
@@ -1130,6 +1058,7 @@
}, },
// Internal method called by both remove and set. // Internal method called by both remove and set.
// Returns removed models, or false if nothing is removed.
_removeModels: function(models, options) { _removeModels: function(models, options) {
var removed = []; var removed = [];
for (var i = 0; i < models.length; i++) { for (var i = 0; i < models.length; i++) {
@@ -1140,12 +1069,6 @@
this.models.splice(index, 1); this.models.splice(index, 1);
this.length--; this.length--;
// Remove references before triggering 'remove' event to prevent an
// infinite loop. #3693
delete this._byId[model.cid];
var id = this.modelId(model.attributes);
if (id != null) delete this._byId[id];
if (!options.silent) { if (!options.silent) {
options.index = index; options.index = index;
model.trigger('remove', model, this, options); model.trigger('remove', model, this, options);
@@ -1154,12 +1077,12 @@
removed.push(model); removed.push(model);
this._removeReference(model, options); this._removeReference(model, options);
} }
return removed; return removed.length ? removed : false;
}, },
// Method for checking whether an object should be considered a model for // Method for checking whether an object should be considered a model for
// the purposes of adding to the collection. // the purposes of adding to the collection.
_isModel: function(model) { _isModel: function (model) {
return model instanceof Model; return model instanceof Model;
}, },
@@ -1185,16 +1108,14 @@
// events simply proxy through. "add" and "remove" events that originate // events simply proxy through. "add" and "remove" events that originate
// in other collections are ignored. // in other collections are ignored.
_onModelEvent: function(event, model, collection, options) { _onModelEvent: function(event, model, collection, options) {
if (model) { if ((event === 'add' || event === 'remove') && collection !== this) return;
if ((event === 'add' || event === 'remove') && collection !== this) return; if (event === 'destroy') this.remove(model, options);
if (event === 'destroy') this.remove(model, options); if (event === 'change') {
if (event === 'change') { var prevId = this.modelId(model.previousAttributes());
var prevId = this.modelId(model.previousAttributes()); var id = this.modelId(model.attributes);
var id = this.modelId(model.attributes); if (prevId !== id) {
if (prevId !== id) { if (prevId != null) delete this._byId[prevId];
if (prevId != null) delete this._byId[prevId]; if (id != null) this._byId[id] = model;
if (id != null) this._byId[id] = model;
}
} }
} }
this.trigger.apply(this, arguments); this.trigger.apply(this, arguments);
@@ -1205,18 +1126,31 @@
// Underscore methods that we want to implement on the Collection. // Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented // 90% of the core usefulness of Backbone Collections is actually implemented
// right here: // right here:
var collectionMethods = {forEach: 3, each: 3, map: 3, collect: 3, reduce: 0, var collectionMethods = { forEach: 3, each: 3, map: 3, collect: 3, reduce: 4,
foldl: 0, inject: 0, reduceRight: 0, foldr: 0, find: 3, detect: 3, filter: 3, foldl: 4, inject: 4, reduceRight: 4, foldr: 4, find: 3, detect: 3, filter: 3,
select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 3, includes: 3, select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 2,
contains: 3, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3, contains: 2, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3,
head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3, head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3,
without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3, without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3,
isEmpty: 1, chain: 1, sample: 3, partition: 3, groupBy: 3, countBy: 3, isEmpty: 1, chain: 1, sample: 3, partition: 3 };
sortBy: 3, indexBy: 3, findIndex: 3, findLastIndex: 3};
// Mix in each Underscore method as a proxy to `Collection#models`. // Mix in each Underscore method as a proxy to `Collection#models`.
addUnderscoreMethods(Collection, collectionMethods, 'models'); addUnderscoreMethods(Collection, collectionMethods, 'models');
// Underscore methods that take a property name as an argument.
var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
// Use attributes instead of properties.
_.each(attributeMethods, function(method) {
if (!_[method]) return;
Collection.prototype[method] = function(value, context) {
var iterator = _.isFunction(value) ? value : function(model) {
return model.get(value);
};
return _[method](this.models, iterator, context);
};
});
// Backbone.View // Backbone.View
// ------------- // -------------
@@ -1232,7 +1166,6 @@
// if an existing element is not provided... // if an existing element is not provided...
var View = Backbone.View = function(options) { var View = Backbone.View = function(options) {
this.cid = _.uniqueId('view'); this.cid = _.uniqueId('view');
this.preinitialize.apply(this, arguments);
_.extend(this, _.pick(options, viewOptions)); _.extend(this, _.pick(options, viewOptions));
this._ensureElement(); this._ensureElement();
this.initialize.apply(this, arguments); this.initialize.apply(this, arguments);
@@ -1241,7 +1174,7 @@
// Cached regex to split keys for `delegate`. // Cached regex to split keys for `delegate`.
var delegateEventSplitter = /^(\S+)\s*(.*)$/; var delegateEventSplitter = /^(\S+)\s*(.*)$/;
// List of view options to be set as properties. // List of view options to be merged as properties.
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
// Set up all inheritable **Backbone.View** properties and methods. // Set up all inheritable **Backbone.View** properties and methods.
@@ -1256,10 +1189,6 @@
return this.$el.find(selector); return this.$el.find(selector);
}, },
// preinitialize is an empty function by default. You can override it with a function
// or object. preinitialize will run before any instantiation logic is run in the View
preinitialize: function(){},
// Initialize is an empty function by default. Override it with your own // Initialize is an empty function by default. Override it with your own
// initialization logic. // initialization logic.
initialize: function(){}, initialize: function(){},
@@ -1467,9 +1396,9 @@
var methodMap = { var methodMap = {
'create': 'POST', 'create': 'POST',
'update': 'PUT', 'update': 'PUT',
'patch': 'PATCH', 'patch': 'PATCH',
'delete': 'DELETE', 'delete': 'DELETE',
'read': 'GET' 'read': 'GET'
}; };
// Set the default implementation of `Backbone.ajax` to proxy through to `$`. // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
@@ -1485,7 +1414,6 @@
// matched. Creating a new one sets its `routes` hash, if not set statically. // matched. Creating a new one sets its `routes` hash, if not set statically.
var Router = Backbone.Router = function(options) { var Router = Backbone.Router = function(options) {
options || (options = {}); options || (options = {});
this.preinitialize.apply(this, arguments);
if (options.routes) this.routes = options.routes; if (options.routes) this.routes = options.routes;
this._bindRoutes(); this._bindRoutes();
this.initialize.apply(this, arguments); this.initialize.apply(this, arguments);
@@ -1501,10 +1429,6 @@
// Set up all inheritable **Backbone.Router** properties and methods. // Set up all inheritable **Backbone.Router** properties and methods.
_.extend(Router.prototype, Events, { _.extend(Router.prototype, Events, {
// preinitialize is an empty function by default. You can override it with a function
// or object. preinitialize will run before any instantiation logic is run in the Router.
preinitialize: function(){},
// Initialize is an empty function by default. Override it with your own // Initialize is an empty function by default. Override it with your own
// initialization logic. // initialization logic.
initialize: function(){}, initialize: function(){},
@@ -1594,7 +1518,7 @@
// falls back to polling. // falls back to polling.
var History = Backbone.History = function() { var History = Backbone.History = function() {
this.handlers = []; this.handlers = [];
this.checkUrl = _.bind(this.checkUrl, this); _.bindAll(this, 'checkUrl');
// Ensure that `History` can be used outside of the browser. // Ensure that `History` can be used outside of the browser.
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
@@ -1631,8 +1555,8 @@
// Does the pathname match the root? // Does the pathname match the root?
matchRoot: function() { matchRoot: function() {
var path = this.decodeFragment(this.location.pathname); var path = this.decodeFragment(this.location.pathname);
var rootPath = path.slice(0, this.root.length - 1) + '/'; var root = path.slice(0, this.root.length - 1) + '/';
return rootPath === this.root; return root === this.root;
}, },
// Unicode characters in `location.pathname` are percent encoded so they're // Unicode characters in `location.pathname` are percent encoded so they're
@@ -1687,7 +1611,7 @@
this.options = _.extend({root: '/'}, this.options, options); this.options = _.extend({root: '/'}, this.options, options);
this.root = this.options.root; this.root = this.options.root;
this._wantsHashChange = this.options.hashChange !== false; this._wantsHashChange = this.options.hashChange !== false;
this._hasHashChange = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7); this._hasHashChange = 'onhashchange' in window;
this._useHashChange = this._wantsHashChange && this._hasHashChange; this._useHashChange = this._wantsHashChange && this._hasHashChange;
this._wantsPushState = !!this.options.pushState; this._wantsPushState = !!this.options.pushState;
this._hasPushState = !!(this.history && this.history.pushState); this._hasPushState = !!(this.history && this.history.pushState);
@@ -1704,8 +1628,8 @@
// If we've started off with a route from a `pushState`-enabled // 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... // browser, but we're currently in a browser that doesn't support it...
if (!this._hasPushState && !this.atRoot()) { if (!this._hasPushState && !this.atRoot()) {
var rootPath = this.root.slice(0, -1) || '/'; var root = this.root.slice(0, -1) || '/';
this.location.replace(rootPath + '#' + this.getPath()); this.location.replace(root + '#' + this.getPath());
// Return immediately as browser will do redirect to new url // Return immediately as browser will do redirect to new url
return true; return true;
@@ -1734,7 +1658,7 @@
} }
// Add a cross-platform `addEventListener` shim for older browsers. // Add a cross-platform `addEventListener` shim for older browsers.
var addEventListener = window.addEventListener || function(eventName, listener) { var addEventListener = window.addEventListener || function (eventName, listener) {
return attachEvent('on' + eventName, listener); return attachEvent('on' + eventName, listener);
}; };
@@ -1755,7 +1679,7 @@
// but possibly useful for unit testing Routers. // but possibly useful for unit testing Routers.
stop: function() { stop: function() {
// Add a cross-platform `removeEventListener` shim for older browsers. // Add a cross-platform `removeEventListener` shim for older browsers.
var removeEventListener = window.removeEventListener || function(eventName, listener) { var removeEventListener = window.removeEventListener || function (eventName, listener) {
return detachEvent('on' + eventName, listener); return detachEvent('on' + eventName, listener);
}; };
@@ -1806,7 +1730,7 @@
// If the root doesn't match, no routes can match either. // If the root doesn't match, no routes can match either.
if (!this.matchRoot()) return false; if (!this.matchRoot()) return false;
fragment = this.fragment = this.getFragment(fragment); fragment = this.fragment = this.getFragment(fragment);
return _.some(this.handlers, function(handler) { return _.any(this.handlers, function(handler) {
if (handler.route.test(fragment)) { if (handler.route.test(fragment)) {
handler.callback(fragment); handler.callback(fragment);
return true; return true;
@@ -1829,20 +1753,17 @@
fragment = this.getFragment(fragment || ''); fragment = this.getFragment(fragment || '');
// Don't include a trailing slash on the root. // Don't include a trailing slash on the root.
var rootPath = this.root; var root = this.root;
if (fragment === '' || fragment.charAt(0) === '?') { if (fragment === '' || fragment.charAt(0) === '?') {
rootPath = rootPath.slice(0, -1) || '/'; root = root.slice(0, -1) || '/';
} }
var url = rootPath + fragment; var url = root + fragment;
// Strip the fragment of the query and hash for matching. // Strip the hash and decode for matching.
fragment = fragment.replace(pathStripper, ''); fragment = this.decodeFragment(fragment.replace(pathStripper, ''));
// Decode for matching. if (this.fragment === fragment) return;
var decodedFragment = this.decodeFragment(fragment); this.fragment = fragment;
if (this.fragment === decodedFragment) return;
this.fragment = decodedFragment;
// If pushState is available, we use it to set the fragment as a real URL. // If pushState is available, we use it to set the fragment as a real URL.
if (this._usePushState) { if (this._usePushState) {
@@ -1852,7 +1773,7 @@
// fragment to store history. // fragment to store history.
} else if (this._wantsHashChange) { } else if (this._wantsHashChange) {
this._updateHash(this.location, fragment, options.replace); this._updateHash(this.location, fragment, options.replace);
if (this.iframe && fragment !== this.getHash(this.iframe.contentWindow)) { if (this.iframe && (fragment !== this.getHash(this.iframe.contentWindow))) {
var iWindow = this.iframe.contentWindow; var iWindow = this.iframe.contentWindow;
// Opening and closing the iframe tricks IE7 and earlier to push a // Opening and closing the iframe tricks IE7 and earlier to push a
@@ -1914,9 +1835,14 @@
_.extend(child, parent, staticProps); _.extend(child, parent, staticProps);
// Set the prototype chain to inherit from `parent`, without calling // Set the prototype chain to inherit from `parent`, without calling
// `parent`'s constructor function and add the prototype properties. // `parent` constructor function.
child.prototype = _.create(parent.prototype, protoProps); var Surrogate = function(){ this.constructor = child; };
child.prototype.constructor = child; Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate;
// Add prototype properties (instance properties) to the subclass,
// if supplied.
if (protoProps) _.extend(child.prototype, protoProps);
// Set a convenience property in case the parent's prototype is needed // Set a convenience property in case the parent's prototype is needed
// later. // later.
@@ -1943,4 +1869,5 @@
}; };
return Backbone; return Backbone;
});
}));

File diff suppressed because it is too large Load Diff

View File

@@ -1,44 +1,42 @@
(function(QUnit) { (function() {
QUnit.module('Backbone.Events'); module("Backbone.Events");
QUnit.test('on and trigger', function(assert) { test("on and trigger", 2, function() {
assert.expect(2); var obj = { counter: 0 };
var obj = {counter: 0}; _.extend(obj,Backbone.Events);
_.extend(obj, Backbone.Events);
obj.on('event', function() { obj.counter += 1; }); obj.on('event', function() { obj.counter += 1; });
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counter, 1, 'counter should be incremented.'); equal(obj.counter,1,'counter should be incremented.');
obj.trigger('event'); obj.trigger('event');
obj.trigger('event'); obj.trigger('event');
obj.trigger('event'); obj.trigger('event');
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counter, 5, 'counter should be incremented five times.'); equal(obj.counter, 5, 'counter should be incremented five times.');
}); });
QUnit.test('binding and triggering multiple events', function(assert) { test("binding and triggering multiple events", 4, function() {
assert.expect(4); var obj = { counter: 0 };
var obj = {counter: 0};
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
obj.on('a b c', function() { obj.counter += 1; }); obj.on('a b c', function() { obj.counter += 1; });
obj.trigger('a'); obj.trigger('a');
assert.equal(obj.counter, 1); equal(obj.counter, 1);
obj.trigger('a b'); obj.trigger('a b');
assert.equal(obj.counter, 3); equal(obj.counter, 3);
obj.trigger('c'); obj.trigger('c');
assert.equal(obj.counter, 4); equal(obj.counter, 4);
obj.off('a c'); obj.off('a c');
obj.trigger('a b c'); obj.trigger('a b c');
assert.equal(obj.counter, 5); equal(obj.counter, 5);
}); });
QUnit.test('binding and triggering with event maps', function(assert) { test("binding and triggering with event maps", function() {
var obj = {counter: 0}; var obj = { counter: 0 };
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
var increment = function() { var increment = function() {
@@ -52,85 +50,54 @@
}, obj); }, obj);
obj.trigger('a'); obj.trigger('a');
assert.equal(obj.counter, 1); equal(obj.counter, 1);
obj.trigger('a b'); obj.trigger('a b');
assert.equal(obj.counter, 3); equal(obj.counter, 3);
obj.trigger('c'); obj.trigger('c');
assert.equal(obj.counter, 4); equal(obj.counter, 4);
obj.off({ obj.off({
a: increment, a: increment,
c: increment c: increment
}, obj); }, obj);
obj.trigger('a b c'); obj.trigger('a b c');
assert.equal(obj.counter, 5); equal(obj.counter, 5);
}); });
QUnit.test('binding and triggering multiple event names with event maps', function(assert) { test("binding and trigger with event maps context", 2, function() {
var obj = {counter: 0}; var obj = { counter: 0 };
_.extend(obj, Backbone.Events);
var increment = function() {
this.counter += 1;
};
obj.on({
'a b c': increment
});
obj.trigger('a');
assert.equal(obj.counter, 1);
obj.trigger('a b');
assert.equal(obj.counter, 3);
obj.trigger('c');
assert.equal(obj.counter, 4);
obj.off({
'a c': increment
});
obj.trigger('a b c');
assert.equal(obj.counter, 5);
});
QUnit.test('binding and trigger with event maps context', function(assert) {
assert.expect(2);
var obj = {counter: 0};
var context = {}; var context = {};
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
obj.on({ obj.on({
a: function() { a: function() {
assert.strictEqual(this, context, 'defaults `context` to `callback` param'); strictEqual(this, context, 'defaults `context` to `callback` param');
} }
}, context).trigger('a'); }, context).trigger('a');
obj.off().on({ obj.off().on({
a: function() { a: function() {
assert.strictEqual(this, context, 'will not override explicit `context` param'); strictEqual(this, context, 'will not override explicit `context` param');
} }
}, this, context).trigger('a'); }, this, context).trigger('a');
}); });
QUnit.test('listenTo and stopListening', function(assert) { test("listenTo and stopListening", 1, function() {
assert.expect(1);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
a.listenTo(b, 'all', function(){ assert.ok(true); }); a.listenTo(b, 'all', function(){ ok(true); });
b.trigger('anything'); b.trigger('anything');
a.listenTo(b, 'all', function(){ assert.ok(false); }); a.listenTo(b, 'all', function(){ ok(false); });
a.stopListening(); a.stopListening();
b.trigger('anything'); b.trigger('anything');
}); });
QUnit.test('listenTo and stopListening with event maps', function(assert) { test("listenTo and stopListening with event maps", 4, function() {
assert.expect(4);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
var cb = function(){ assert.ok(true); }; var cb = function(){ ok(true); };
a.listenTo(b, {event: cb}); a.listenTo(b, {event: cb});
b.trigger('event'); b.trigger('event');
a.listenTo(b, {event2: cb}); a.listenTo(b, {event2: cb});
@@ -141,11 +108,10 @@
b.trigger('event event2'); b.trigger('event event2');
}); });
QUnit.test('stopListening with omitted args', function(assert) { test("stopListening with omitted args", 2, function () {
assert.expect(2);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
var cb = function() { assert.ok(true); }; var cb = function () { ok(true); };
a.listenTo(b, 'event', cb); a.listenTo(b, 'event', cb);
b.on('event', cb); b.on('event', cb);
a.listenTo(b, 'event2', cb); a.listenTo(b, 'event2', cb);
@@ -158,237 +124,219 @@
b.trigger('event2'); b.trigger('event2');
}); });
QUnit.test('listenToOnce', function(assert) { test("listenToOnce", 2, function() {
assert.expect(2);
// Same as the previous test, but we use once rather than having to explicitly unbind // Same as the previous test, but we use once rather than having to explicitly unbind
var obj = {counterA: 0, counterB: 0}; var obj = { counterA: 0, counterB: 0 };
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
var incrA = function(){ obj.counterA += 1; obj.trigger('event'); }; var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
var incrB = function(){ obj.counterB += 1; }; var incrB = function(){ obj.counterB += 1; };
obj.listenToOnce(obj, 'event', incrA); obj.listenToOnce(obj, 'event', incrA);
obj.listenToOnce(obj, 'event', incrB); obj.listenToOnce(obj, 'event', incrB);
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.'); equal(obj.counterA, 1, 'counterA should have only been incremented once.');
assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.'); equal(obj.counterB, 1, 'counterB should have only been incremented once.');
}); });
QUnit.test('listenToOnce and stopListening', function(assert) { test("listenToOnce and stopListening", 1, function() {
assert.expect(1);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, 'all', function() { assert.ok(true); }); a.listenToOnce(b, 'all', function() { ok(true); });
b.trigger('anything'); b.trigger('anything');
b.trigger('anything'); b.trigger('anything');
a.listenToOnce(b, 'all', function() { assert.ok(false); }); a.listenToOnce(b, 'all', function() { ok(false); });
a.stopListening(); a.stopListening();
b.trigger('anything'); b.trigger('anything');
}); });
QUnit.test('listenTo, listenToOnce and stopListening', function(assert) { test("listenTo, listenToOnce and stopListening", 1, function() {
assert.expect(1);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, 'all', function() { assert.ok(true); }); a.listenToOnce(b, 'all', function() { ok(true); });
b.trigger('anything'); b.trigger('anything');
b.trigger('anything'); b.trigger('anything');
a.listenTo(b, 'all', function() { assert.ok(false); }); a.listenTo(b, 'all', function() { ok(false); });
a.stopListening(); a.stopListening();
b.trigger('anything'); b.trigger('anything');
}); });
QUnit.test('listenTo and stopListening with event maps', function(assert) { test("listenTo and stopListening with event maps", 1, function() {
assert.expect(1);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
a.listenTo(b, {change: function(){ assert.ok(true); }}); a.listenTo(b, {change: function(){ ok(true); }});
b.trigger('change'); b.trigger('change');
a.listenTo(b, {change: function(){ assert.ok(false); }}); a.listenTo(b, {change: function(){ ok(false); }});
a.stopListening(); a.stopListening();
b.trigger('change'); b.trigger('change');
}); });
QUnit.test('listenTo yourself', function(assert) { test("listenTo yourself", 1, function(){
assert.expect(1);
var e = _.extend({}, Backbone.Events); var e = _.extend({}, Backbone.Events);
e.listenTo(e, 'foo', function(){ assert.ok(true); }); e.listenTo(e, "foo", function(){ ok(true); });
e.trigger('foo'); e.trigger("foo");
}); });
QUnit.test('listenTo yourself cleans yourself up with stopListening', function(assert) { test("listenTo yourself cleans yourself up with stopListening", 1, function(){
assert.expect(1);
var e = _.extend({}, Backbone.Events); var e = _.extend({}, Backbone.Events);
e.listenTo(e, 'foo', function(){ assert.ok(true); }); e.listenTo(e, "foo", function(){ ok(true); });
e.trigger('foo'); e.trigger("foo");
e.stopListening(); e.stopListening();
e.trigger('foo'); e.trigger("foo");
}); });
QUnit.test('stopListening cleans up references', function(assert) { test("stopListening cleans up references", 12, function() {
assert.expect(12);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
var fn = function() {}; var fn = function() {};
b.on('event', fn); b.on('event', fn);
a.listenTo(b, 'event', fn).stopListening(); a.listenTo(b, 'event', fn).stopListening();
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1); equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn).stopListening(b); a.listenTo(b, 'event', fn).stopListening(b);
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1); equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn).stopListening(b, 'event'); a.listenTo(b, 'event', fn).stopListening(b, 'event');
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1); equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn).stopListening(b, 'event', fn); a.listenTo(b, 'event', fn).stopListening(b, 'event', fn);
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1); equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
}); });
QUnit.test('stopListening cleans up references from listenToOnce', function(assert) { test("stopListening cleans up references from listenToOnce", 12, function() {
assert.expect(12);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
var fn = function() {}; var fn = function() {};
b.on('event', fn); b.on('event', fn);
a.listenToOnce(b, 'event', fn).stopListening(); a.listenToOnce(b, 'event', fn).stopListening();
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1); equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenToOnce(b, 'event', fn).stopListening(b); a.listenToOnce(b, 'event', fn).stopListening(b);
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1); equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenToOnce(b, 'event', fn).stopListening(b, 'event'); a.listenToOnce(b, 'event', fn).stopListening(b, 'event');
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1); equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenToOnce(b, 'event', fn).stopListening(b, 'event', fn); a.listenToOnce(b, 'event', fn).stopListening(b, 'event', fn);
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1); equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
}); });
QUnit.test('listenTo and off cleaning up references', function(assert) { test("listenTo and off cleaning up references", 8, function() {
assert.expect(8);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
var fn = function() {}; var fn = function() {};
a.listenTo(b, 'event', fn); a.listenTo(b, 'event', fn);
b.off(); b.off();
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn); a.listenTo(b, 'event', fn);
b.off('event'); b.off('event');
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn); a.listenTo(b, 'event', fn);
b.off(null, fn); b.off(null, fn);
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn); a.listenTo(b, 'event', fn);
b.off(null, null, a); b.off(null, null, a);
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._listeners), 0); equal(_.size(b._listeners), 0);
}); });
QUnit.test('listenTo and stopListening cleaning up references', function(assert) { test("listenTo and stopListening cleaning up references", 2, function() {
assert.expect(2);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
a.listenTo(b, 'all', function(){ assert.ok(true); }); a.listenTo(b, 'all', function(){ ok(true); });
b.trigger('anything'); b.trigger('anything');
a.listenTo(b, 'other', function(){ assert.ok(false); }); a.listenTo(b, 'other', function(){ ok(false); });
a.stopListening(b, 'other'); a.stopListening(b, 'other');
a.stopListening(b, 'all'); a.stopListening(b, 'all');
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
}); });
QUnit.test('listenToOnce without context cleans up references after the event has fired', function(assert) { test("listenToOnce without context cleans up references after the event has fired", 2, function() {
assert.expect(2);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, 'all', function(){ assert.ok(true); }); a.listenToOnce(b, 'all', function(){ ok(true); });
b.trigger('anything'); b.trigger('anything');
assert.equal(_.size(a._listeningTo), 0); equal(_.size(a._listeningTo), 0);
}); });
QUnit.test('listenToOnce with event maps cleans up references', function(assert) { test("listenToOnce with event maps cleans up references", 2, function() {
assert.expect(2);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, { a.listenToOnce(b, {
one: function() { assert.ok(true); }, one: function() { ok(true); },
two: function() { assert.ok(false); } two: function() { ok(false); }
}); });
b.trigger('one'); b.trigger('one');
assert.equal(_.size(a._listeningTo), 1); equal(_.size(a._listeningTo), 1);
}); });
QUnit.test('listenToOnce with event maps binds the correct `this`', function(assert) { test("listenToOnce with event maps binds the correct `this`", 1, function() {
assert.expect(1);
var a = _.extend({}, Backbone.Events); var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, { a.listenToOnce(b, {
one: function() { assert.ok(this === a); }, one: function() { ok(this === a); },
two: function() { assert.ok(false); } two: function() { ok(false); }
}); });
b.trigger('one'); b.trigger('one');
}); });
QUnit.test("listenTo with empty callback doesn't throw an error", function(assert) { test("listenTo with empty callback doesn't throw an error", 1, function(){
assert.expect(1);
var e = _.extend({}, Backbone.Events); var e = _.extend({}, Backbone.Events);
e.listenTo(e, 'foo', null); e.listenTo(e, "foo", null);
e.trigger('foo'); e.trigger("foo");
assert.ok(true); ok(true);
}); });
QUnit.test('trigger all for each event', function(assert) { test("trigger all for each event", 3, function() {
assert.expect(3); var a, b, obj = { counter: 0 };
var a, b, obj = {counter: 0};
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
obj.on('all', function(event) { obj.on('all', function(event) {
obj.counter++; obj.counter++;
if (event === 'a') a = true; if (event == 'a') a = true;
if (event === 'b') b = true; if (event == 'b') b = true;
}) })
.trigger('a b'); .trigger('a b');
assert.ok(a); ok(a);
assert.ok(b); ok(b);
assert.equal(obj.counter, 2); equal(obj.counter, 2);
}); });
QUnit.test('on, then unbind all functions', function(assert) { test("on, then unbind all functions", 1, function() {
assert.expect(1); var obj = { counter: 0 };
var obj = {counter: 0}; _.extend(obj,Backbone.Events);
_.extend(obj, Backbone.Events);
var callback = function() { obj.counter += 1; }; var callback = function() { obj.counter += 1; };
obj.on('event', callback); obj.on('event', callback);
obj.trigger('event'); obj.trigger('event');
obj.off('event'); obj.off('event');
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counter, 1, 'counter should have only been incremented once.'); equal(obj.counter, 1, 'counter should have only been incremented once.');
}); });
QUnit.test('bind two callbacks, unbind only one', function(assert) { test("bind two callbacks, unbind only one", 2, function() {
assert.expect(2); var obj = { counterA: 0, counterB: 0 };
var obj = {counterA: 0, counterB: 0}; _.extend(obj,Backbone.Events);
_.extend(obj, Backbone.Events);
var callback = function() { obj.counterA += 1; }; var callback = function() { obj.counterA += 1; };
obj.on('event', callback); obj.on('event', callback);
obj.on('event', function() { obj.counterB += 1; }); obj.on('event', function() { obj.counterB += 1; });
obj.trigger('event'); obj.trigger('event');
obj.off('event', callback); obj.off('event', callback);
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.'); equal(obj.counterA, 1, 'counterA should have only been incremented once.');
assert.equal(obj.counterB, 2, 'counterB should have been incremented twice.'); equal(obj.counterB, 2, 'counterB should have been incremented twice.');
}); });
QUnit.test('unbind a callback in the midst of it firing', function(assert) { test("unbind a callback in the midst of it firing", 1, function() {
assert.expect(1);
var obj = {counter: 0}; var obj = {counter: 0};
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
var callback = function() { var callback = function() {
@@ -399,13 +347,12 @@
obj.trigger('event'); obj.trigger('event');
obj.trigger('event'); obj.trigger('event');
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counter, 1, 'the callback should have been unbound.'); equal(obj.counter, 1, 'the callback should have been unbound.');
}); });
QUnit.test('two binds that unbind themeselves', function(assert) { test("two binds that unbind themeselves", 2, function() {
assert.expect(2); var obj = { counterA: 0, counterB: 0 };
var obj = {counterA: 0, counterB: 0}; _.extend(obj,Backbone.Events);
_.extend(obj, Backbone.Events);
var incrA = function(){ obj.counterA += 1; obj.off('event', incrA); }; var incrA = function(){ obj.counterA += 1; obj.off('event', incrA); };
var incrB = function(){ obj.counterB += 1; obj.off('event', incrB); }; var incrB = function(){ obj.counterB += 1; obj.off('event', incrB); };
obj.on('event', incrA); obj.on('event', incrA);
@@ -413,64 +360,48 @@
obj.trigger('event'); obj.trigger('event');
obj.trigger('event'); obj.trigger('event');
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.'); equal(obj.counterA, 1, 'counterA should have only been incremented once.');
assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.'); equal(obj.counterB, 1, 'counterB should have only been incremented once.');
}); });
QUnit.test('bind a callback with a default context when none supplied', function(assert) { test("bind a callback with a supplied context", 1, function () {
assert.expect(1); var TestClass = function () {
var obj = _.extend({
assertTrue: function() {
assert.equal(this, obj, '`this` was bound to the callback');
}
}, Backbone.Events);
obj.once('event', obj.assertTrue);
obj.trigger('event');
});
QUnit.test('bind a callback with a supplied context', function(assert) {
assert.expect(1);
var TestClass = function() {
return this; return this;
}; };
TestClass.prototype.assertTrue = function() { TestClass.prototype.assertTrue = function () {
assert.ok(true, '`this` was bound to the callback'); ok(true, '`this` was bound to the callback');
}; };
var obj = _.extend({}, Backbone.Events); var obj = _.extend({},Backbone.Events);
obj.on('event', function() { this.assertTrue(); }, new TestClass); obj.on('event', function () { this.assertTrue(); }, (new TestClass));
obj.trigger('event'); obj.trigger('event');
}); });
QUnit.test('nested trigger with unbind', function(assert) { test("nested trigger with unbind", 1, function () {
assert.expect(1); var obj = { counter: 0 };
var obj = {counter: 0};
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
var incr1 = function(){ obj.counter += 1; obj.off('event', incr1); obj.trigger('event'); }; var incr1 = function(){ obj.counter += 1; obj.off('event', incr1); obj.trigger('event'); };
var incr2 = function(){ obj.counter += 1; }; var incr2 = function(){ obj.counter += 1; };
obj.on('event', incr1); obj.on('event', incr1);
obj.on('event', incr2); obj.on('event', incr2);
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counter, 3, 'counter should have been incremented three times'); equal(obj.counter, 3, 'counter should have been incremented three times');
}); });
QUnit.test('callback list is not altered during trigger', function(assert) { test("callback list is not altered during trigger", 2, function () {
assert.expect(2);
var counter = 0, obj = _.extend({}, Backbone.Events); var counter = 0, obj = _.extend({}, Backbone.Events);
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var incrOn = function(){ obj.on('event all', incr); }; var incrOn = function(){ obj.on('event all', incr); };
var incrOff = function(){ obj.off('event all', incr); }; var incrOff = function(){ obj.off('event all', incr); };
obj.on('event all', incrOn).trigger('event'); obj.on('event all', incrOn).trigger('event');
assert.equal(counter, 0, 'on does not alter callback list'); equal(counter, 0, 'on does not alter callback list');
obj.off().on('event', incrOff).on('event all', incr).trigger('event'); obj.off().on('event', incrOff).on('event all', incr).trigger('event');
assert.equal(counter, 2, 'off does not alter callback list'); equal(counter, 2, 'off does not alter callback list');
}); });
QUnit.test("#1282 - 'all' callback list is retrieved after each event.", function(assert) { test("#1282 - 'all' callback list is retrieved after each event.", 1, function() {
assert.expect(1);
var counter = 0; var counter = 0;
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
var incr = function(){ counter++; }; var incr = function(){ counter++; };
@@ -478,68 +409,61 @@
obj.on('y', incr).on('all', incr); obj.on('y', incr).on('all', incr);
}) })
.trigger('x y'); .trigger('x y');
assert.strictEqual(counter, 2); strictEqual(counter, 2);
}); });
QUnit.test('if no callback is provided, `on` is a noop', function(assert) { test("if no callback is provided, `on` is a noop", 0, function() {
assert.expect(0);
_.extend({}, Backbone.Events).on('test').trigger('test'); _.extend({}, Backbone.Events).on('test').trigger('test');
}); });
QUnit.test('if callback is truthy but not a function, `on` should throw an error just like jQuery', function(assert) { test("if callback is truthy but not a function, `on` should throw an error just like jQuery", 1, function() {
assert.expect(1);
var view = _.extend({}, Backbone.Events).on('test', 'noop'); var view = _.extend({}, Backbone.Events).on('test', 'noop');
assert.raises(function() { throws(function() {
view.trigger('test'); view.trigger('test');
}); });
}); });
QUnit.test('remove all events for a specific context', function(assert) { test("remove all events for a specific context", 4, function() {
assert.expect(4);
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
obj.on('x y all', function() { assert.ok(true); }); obj.on('x y all', function() { ok(true); });
obj.on('x y all', function() { assert.ok(false); }, obj); obj.on('x y all', function() { ok(false); }, obj);
obj.off(null, null, obj); obj.off(null, null, obj);
obj.trigger('x y'); obj.trigger('x y');
}); });
QUnit.test('remove all events for a specific callback', function(assert) { test("remove all events for a specific callback", 4, function() {
assert.expect(4);
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
var success = function() { assert.ok(true); }; var success = function() { ok(true); };
var fail = function() { assert.ok(false); }; var fail = function() { ok(false); };
obj.on('x y all', success); obj.on('x y all', success);
obj.on('x y all', fail); obj.on('x y all', fail);
obj.off(null, fail); obj.off(null, fail);
obj.trigger('x y'); obj.trigger('x y');
}); });
QUnit.test('#1310 - off does not skip consecutive events', function(assert) { test("#1310 - off does not skip consecutive events", 0, function() {
assert.expect(0);
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
obj.on('event', function() { assert.ok(false); }, obj); obj.on('event', function() { ok(false); }, obj);
obj.on('event', function() { assert.ok(false); }, obj); obj.on('event', function() { ok(false); }, obj);
obj.off(null, null, obj); obj.off(null, null, obj);
obj.trigger('event'); obj.trigger('event');
}); });
QUnit.test('once', function(assert) { test("once", 2, function() {
assert.expect(2);
// Same as the previous test, but we use once rather than having to explicitly unbind // Same as the previous test, but we use once rather than having to explicitly unbind
var obj = {counterA: 0, counterB: 0}; var obj = { counterA: 0, counterB: 0 };
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
var incrA = function(){ obj.counterA += 1; obj.trigger('event'); }; var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
var incrB = function(){ obj.counterB += 1; }; var incrB = function(){ obj.counterB += 1; };
obj.once('event', incrA); obj.once('event', incrA);
obj.once('event', incrB); obj.once('event', incrB);
obj.trigger('event'); obj.trigger('event');
assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.'); equal(obj.counterA, 1, 'counterA should have only been incremented once.');
assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.'); equal(obj.counterB, 1, 'counterB should have only been incremented once.');
}); });
QUnit.test('once variant one', function(assert) { test("once variant one", 3, function() {
assert.expect(3); var f = function(){ ok(true); };
var f = function(){ assert.ok(true); };
var a = _.extend({}, Backbone.Events).once('event', f); var a = _.extend({}, Backbone.Events).once('event', f);
var b = _.extend({}, Backbone.Events).on('event', f); var b = _.extend({}, Backbone.Events).on('event', f);
@@ -550,9 +474,8 @@
b.trigger('event'); b.trigger('event');
}); });
QUnit.test('once variant two', function(assert) { test("once variant two", 3, function() {
assert.expect(3); var f = function(){ ok(true); };
var f = function(){ assert.ok(true); };
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
obj obj
@@ -562,9 +485,8 @@
.trigger('event'); .trigger('event');
}); });
QUnit.test('once with off', function(assert) { test("once with off", 0, function() {
assert.expect(0); var f = function(){ ok(true); };
var f = function(){ assert.ok(true); };
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
obj.once('event', f); obj.once('event', f);
@@ -572,8 +494,8 @@
obj.trigger('event'); obj.trigger('event');
}); });
QUnit.test('once with event maps', function(assert) { test("once with event maps", function() {
var obj = {counter: 0}; var obj = { counter: 0 };
_.extend(obj, Backbone.Events); _.extend(obj, Backbone.Events);
var increment = function() { var increment = function() {
@@ -587,120 +509,98 @@
}, obj); }, obj);
obj.trigger('a'); obj.trigger('a');
assert.equal(obj.counter, 1); equal(obj.counter, 1);
obj.trigger('a b'); obj.trigger('a b');
assert.equal(obj.counter, 2); equal(obj.counter, 2);
obj.trigger('c'); obj.trigger('c');
assert.equal(obj.counter, 3); equal(obj.counter, 3);
obj.trigger('a b c'); obj.trigger('a b c');
assert.equal(obj.counter, 3); equal(obj.counter, 3);
}); });
QUnit.test('bind a callback with a supplied context using once with object notation', function(assert) { test("once with off only by context", 0, function() {
assert.expect(1);
var obj = {counter: 0};
var context = {};
_.extend(obj, Backbone.Events);
obj.once({
a: function() {
assert.strictEqual(this, context, 'defaults `context` to `callback` param');
}
}, context).trigger('a');
});
QUnit.test('once with off only by context', function(assert) {
assert.expect(0);
var context = {}; var context = {};
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
obj.once('event', function(){ assert.ok(false); }, context); obj.once('event', function(){ ok(false); }, context);
obj.off(null, null, context); obj.off(null, null, context);
obj.trigger('event'); obj.trigger('event');
}); });
QUnit.test('Backbone object inherits Events', function(assert) { test("Backbone object inherits Events", function() {
assert.ok(Backbone.on === Backbone.Events.on); ok(Backbone.on === Backbone.Events.on);
}); });
QUnit.test('once with asynchronous events', function(assert) { asyncTest("once with asynchronous events", 1, function() {
var done = assert.async(); var func = _.debounce(function() { ok(true); start(); }, 50);
assert.expect(1);
var func = _.debounce(function() { assert.ok(true); done(); }, 50);
var obj = _.extend({}, Backbone.Events).once('async', func); var obj = _.extend({}, Backbone.Events).once('async', func);
obj.trigger('async'); obj.trigger('async');
obj.trigger('async'); obj.trigger('async');
}); });
QUnit.test('once with multiple events.', function(assert) { test("once with multiple events.", 2, function() {
assert.expect(2);
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
obj.once('x y', function() { assert.ok(true); }); obj.once('x y', function() { ok(true); });
obj.trigger('x y'); obj.trigger('x y');
}); });
QUnit.test('Off during iteration with once.', function(assert) { test("Off during iteration with once.", 2, function() {
assert.expect(2);
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
var f = function(){ this.off('event', f); }; var f = function(){ this.off('event', f); };
obj.on('event', f); obj.on('event', f);
obj.once('event', function(){}); obj.once('event', function(){});
obj.on('event', function(){ assert.ok(true); }); obj.on('event', function(){ ok(true); });
obj.trigger('event'); obj.trigger('event');
obj.trigger('event'); obj.trigger('event');
}); });
QUnit.test('`once` on `all` should work as expected', function(assert) { test("`once` on `all` should work as expected", 1, function() {
assert.expect(1);
Backbone.once('all', function() { Backbone.once('all', function() {
assert.ok(true); ok(true);
Backbone.trigger('all'); Backbone.trigger('all');
}); });
Backbone.trigger('all'); Backbone.trigger('all');
}); });
QUnit.test('once without a callback is a noop', function(assert) { test("once without a callback is a noop", 0, function() {
assert.expect(0);
_.extend({}, Backbone.Events).once('event').trigger('event'); _.extend({}, Backbone.Events).once('event').trigger('event');
}); });
QUnit.test('listenToOnce without a callback is a noop', function(assert) { test("listenToOnce without a callback is a noop", 0, function() {
assert.expect(0);
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
obj.listenToOnce(obj, 'event').trigger('event'); obj.listenToOnce(obj, 'event').trigger('event');
}); });
QUnit.test('event functions are chainable', function(assert) { test("event functions are chainable", function() {
var obj = _.extend({}, Backbone.Events); var obj = _.extend({}, Backbone.Events);
var obj2 = _.extend({}, Backbone.Events); var obj2 = _.extend({}, Backbone.Events);
var fn = function() {}; var fn = function() {};
assert.equal(obj, obj.trigger('noeventssetyet')); equal(obj, obj.trigger('noeventssetyet'));
assert.equal(obj, obj.off('noeventssetyet')); equal(obj, obj.off('noeventssetyet'));
assert.equal(obj, obj.stopListening('noeventssetyet')); equal(obj, obj.stopListening('noeventssetyet'));
assert.equal(obj, obj.on('a', fn)); equal(obj, obj.on('a', fn));
assert.equal(obj, obj.once('c', fn)); equal(obj, obj.once('c', fn));
assert.equal(obj, obj.trigger('a')); equal(obj, obj.trigger('a'));
assert.equal(obj, obj.listenTo(obj2, 'a', fn)); equal(obj, obj.listenTo(obj2, 'a', fn));
assert.equal(obj, obj.listenToOnce(obj2, 'b', fn)); equal(obj, obj.listenToOnce(obj2, 'b', fn));
assert.equal(obj, obj.off('a c')); equal(obj, obj.off('a c'));
assert.equal(obj, obj.stopListening(obj2, 'a')); equal(obj, obj.stopListening(obj2, 'a'));
assert.equal(obj, obj.stopListening()); equal(obj, obj.stopListening());
}); });
QUnit.test('#3448 - listenToOnce with space-separated events', function(assert) { test("#3448 - listenToOnce with space-separated events", 2, function() {
assert.expect(2);
var one = _.extend({}, Backbone.Events); var one = _.extend({}, Backbone.Events);
var two = _.extend({}, Backbone.Events); var two = _.extend({}, Backbone.Events);
var count = 1; var count = 1;
one.listenToOnce(two, 'x y', function(n) { assert.ok(n === count++); }); one.listenToOnce(two, 'x y', function(n) { ok(n === count++); });
two.trigger('x', 1); two.trigger('x', 1);
two.trigger('x', 1); two.trigger('x', 1);
two.trigger('y', 2); two.trigger('y', 2);
two.trigger('y', 2); two.trigger('y', 2);
}); });
})(QUnit); })();

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,12 @@
(function(QUnit) { (function() {
QUnit.module('Backbone.noConflict'); module("Backbone.noConflict");
QUnit.test('noConflict', function(assert) { test('noConflict', 2, function() {
assert.expect(2);
var noconflictBackbone = Backbone.noConflict(); var noconflictBackbone = Backbone.noConflict();
assert.equal(window.Backbone, undefined, 'Returned window.Backbone'); equal(window.Backbone, undefined, 'Returned window.Backbone');
window.Backbone = noconflictBackbone; window.Backbone = noconflictBackbone;
assert.equal(window.Backbone, noconflictBackbone, 'Backbone is still pointing to the original Backbone'); equal(window.Backbone, noconflictBackbone, 'Backbone is still pointing to the original Backbone');
}); });
})(QUnit); })();

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,6 @@
$('body').append( $('body').append(
'<div id="qunit"></div>' + '<div id="qunit"></div>' +
'<div id="qunit-fixture"></div>' '<div id="qunit-fixture">' +
); '<div id="testElement"><h1>Test</h1></div>' +
'</div>'
);

View File

@@ -1,4 +1,4 @@
(function(QUnit) { (function() {
var sync = Backbone.sync; var sync = Backbone.sync;
var ajax = Backbone.ajax; var ajax = Backbone.ajax;
@@ -8,13 +8,11 @@
var pushState = history.pushState; var pushState = history.pushState;
var replaceState = history.replaceState; var replaceState = history.replaceState;
QUnit.config.noglobals = true;
QUnit.testStart(function() { QUnit.testStart(function() {
var env = QUnit.config.current.testEnvironment; var env = QUnit.config.current.testEnvironment;
// We never want to actually call these during tests. // We never want to actually call these during tests.
history.pushState = history.replaceState = function() {}; history.pushState = history.replaceState = function(){};
// Capture ajax settings for comparison. // Capture ajax settings for comparison.
Backbone.ajax = function(settings) { Backbone.ajax = function(settings) {
@@ -42,4 +40,4 @@
history.replaceState = replaceState; history.replaceState = replaceState;
}); });
})(QUnit); })();

View File

@@ -1,239 +1,221 @@
(function(QUnit) { (function() {
var Library = Backbone.Collection.extend({ var Library = Backbone.Collection.extend({
url: function() { return '/library'; } url : function() { return '/library'; }
}); });
var library; var library;
var attrs = { var attrs = {
title: 'The Tempest', title : "The Tempest",
author: 'Bill Shakespeare', author : "Bill Shakespeare",
length: 123 length : 123
}; };
QUnit.module('Backbone.sync', { module("Backbone.sync", {
beforeEach: function(assert) { setup : function() {
library = new Library; library = new Library;
library.create(attrs, {wait: false}); library.create(attrs, {wait: false});
}, },
afterEach: function(assert) { teardown: function() {
Backbone.emulateHTTP = false; Backbone.emulateHTTP = false;
} }
}); });
QUnit.test('read', function(assert) { test("read", 4, function() {
assert.expect(4);
library.fetch(); library.fetch();
assert.equal(this.ajaxSettings.url, '/library'); equal(this.ajaxSettings.url, '/library');
assert.equal(this.ajaxSettings.type, 'GET'); equal(this.ajaxSettings.type, 'GET');
assert.equal(this.ajaxSettings.dataType, 'json'); equal(this.ajaxSettings.dataType, 'json');
assert.ok(_.isEmpty(this.ajaxSettings.data)); ok(_.isEmpty(this.ajaxSettings.data));
}); });
QUnit.test('passing data', function(assert) { test("passing data", 3, function() {
assert.expect(3);
library.fetch({data: {a: 'a', one: 1}}); library.fetch({data: {a: 'a', one: 1}});
assert.equal(this.ajaxSettings.url, '/library'); equal(this.ajaxSettings.url, '/library');
assert.equal(this.ajaxSettings.data.a, 'a'); equal(this.ajaxSettings.data.a, 'a');
assert.equal(this.ajaxSettings.data.one, 1); equal(this.ajaxSettings.data.one, 1);
}); });
QUnit.test('create', function(assert) { test("create", 6, function() {
assert.expect(6); equal(this.ajaxSettings.url, '/library');
assert.equal(this.ajaxSettings.url, '/library'); equal(this.ajaxSettings.type, 'POST');
assert.equal(this.ajaxSettings.type, 'POST'); equal(this.ajaxSettings.dataType, 'json');
assert.equal(this.ajaxSettings.dataType, 'json');
var data = JSON.parse(this.ajaxSettings.data); var data = JSON.parse(this.ajaxSettings.data);
assert.equal(data.title, 'The Tempest'); equal(data.title, 'The Tempest');
assert.equal(data.author, 'Bill Shakespeare'); equal(data.author, 'Bill Shakespeare');
assert.equal(data.length, 123); equal(data.length, 123);
}); });
QUnit.test('update', function(assert) { test("update", 7, function() {
assert.expect(7);
library.first().save({id: '1-the-tempest', author: 'William Shakespeare'}); library.first().save({id: '1-the-tempest', author: 'William Shakespeare'});
assert.equal(this.ajaxSettings.url, '/library/1-the-tempest'); equal(this.ajaxSettings.url, '/library/1-the-tempest');
assert.equal(this.ajaxSettings.type, 'PUT'); equal(this.ajaxSettings.type, 'PUT');
assert.equal(this.ajaxSettings.dataType, 'json'); equal(this.ajaxSettings.dataType, 'json');
var data = JSON.parse(this.ajaxSettings.data); var data = JSON.parse(this.ajaxSettings.data);
assert.equal(data.id, '1-the-tempest'); equal(data.id, '1-the-tempest');
assert.equal(data.title, 'The Tempest'); equal(data.title, 'The Tempest');
assert.equal(data.author, 'William Shakespeare'); equal(data.author, 'William Shakespeare');
assert.equal(data.length, 123); equal(data.length, 123);
}); });
QUnit.test('update with emulateHTTP and emulateJSON', function(assert) { test("update with emulateHTTP and emulateJSON", 7, function() {
assert.expect(7);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, { library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, {
emulateHTTP: true, emulateHTTP: true,
emulateJSON: true emulateJSON: true
}); });
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'POST'); equal(this.ajaxSettings.type, 'POST');
assert.equal(this.ajaxSettings.dataType, 'json'); equal(this.ajaxSettings.dataType, 'json');
assert.equal(this.ajaxSettings.data._method, 'PUT'); equal(this.ajaxSettings.data._method, 'PUT');
var data = JSON.parse(this.ajaxSettings.data.model); var data = JSON.parse(this.ajaxSettings.data.model);
assert.equal(data.id, '2-the-tempest'); equal(data.id, '2-the-tempest');
assert.equal(data.author, 'Tim Shakespeare'); equal(data.author, 'Tim Shakespeare');
assert.equal(data.length, 123); equal(data.length, 123);
}); });
QUnit.test('update with just emulateHTTP', function(assert) { test("update with just emulateHTTP", 6, function() {
assert.expect(6);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, { library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, {
emulateHTTP: true emulateHTTP: true
}); });
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'POST'); equal(this.ajaxSettings.type, 'POST');
assert.equal(this.ajaxSettings.contentType, 'application/json'); equal(this.ajaxSettings.contentType, 'application/json');
var data = JSON.parse(this.ajaxSettings.data); var data = JSON.parse(this.ajaxSettings.data);
assert.equal(data.id, '2-the-tempest'); equal(data.id, '2-the-tempest');
assert.equal(data.author, 'Tim Shakespeare'); equal(data.author, 'Tim Shakespeare');
assert.equal(data.length, 123); equal(data.length, 123);
}); });
QUnit.test('update with just emulateJSON', function(assert) { test("update with just emulateJSON", 6, function() {
assert.expect(6);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, { library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, {
emulateJSON: true emulateJSON: true
}); });
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'PUT'); equal(this.ajaxSettings.type, 'PUT');
assert.equal(this.ajaxSettings.contentType, 'application/x-www-form-urlencoded'); equal(this.ajaxSettings.contentType, 'application/x-www-form-urlencoded');
var data = JSON.parse(this.ajaxSettings.data.model); var data = JSON.parse(this.ajaxSettings.data.model);
assert.equal(data.id, '2-the-tempest'); equal(data.id, '2-the-tempest');
assert.equal(data.author, 'Tim Shakespeare'); equal(data.author, 'Tim Shakespeare');
assert.equal(data.length, 123); equal(data.length, 123);
}); });
QUnit.test('read model', function(assert) { test("read model", 3, function() {
assert.expect(3);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
library.first().fetch(); library.first().fetch();
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'GET'); equal(this.ajaxSettings.type, 'GET');
assert.ok(_.isEmpty(this.ajaxSettings.data)); ok(_.isEmpty(this.ajaxSettings.data));
}); });
QUnit.test('destroy', function(assert) { test("destroy", 3, function() {
assert.expect(3);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
library.first().destroy({wait: true}); library.first().destroy({wait: true});
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'DELETE'); equal(this.ajaxSettings.type, 'DELETE');
assert.equal(this.ajaxSettings.data, null); equal(this.ajaxSettings.data, null);
}); });
QUnit.test('destroy with emulateHTTP', function(assert) { test("destroy with emulateHTTP", 3, function() {
assert.expect(3);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
library.first().destroy({ library.first().destroy({
emulateHTTP: true, emulateHTTP: true,
emulateJSON: true emulateJSON: true
}); });
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'POST'); equal(this.ajaxSettings.type, 'POST');
assert.equal(JSON.stringify(this.ajaxSettings.data), '{"_method":"DELETE"}'); equal(JSON.stringify(this.ajaxSettings.data), '{"_method":"DELETE"}');
}); });
QUnit.test('urlError', function(assert) { test("urlError", 2, function() {
assert.expect(2);
var model = new Backbone.Model(); var model = new Backbone.Model();
assert.raises(function() { throws(function() {
model.fetch(); model.fetch();
}); });
model.fetch({url: '/one/two'}); model.fetch({url: '/one/two'});
assert.equal(this.ajaxSettings.url, '/one/two'); equal(this.ajaxSettings.url, '/one/two');
}); });
QUnit.test('#1052 - `options` is optional.', function(assert) { test("#1052 - `options` is optional.", 0, function() {
assert.expect(0);
var model = new Backbone.Model(); var model = new Backbone.Model();
model.url = '/test'; model.url = '/test';
Backbone.sync('create', model); Backbone.sync('create', model);
}); });
QUnit.test('Backbone.ajax', function(assert) { test("Backbone.ajax", 1, function() {
assert.expect(1); Backbone.ajax = function(settings){
Backbone.ajax = function(settings) { strictEqual(settings.url, '/test');
assert.strictEqual(settings.url, '/test');
}; };
var model = new Backbone.Model(); var model = new Backbone.Model();
model.url = '/test'; model.url = '/test';
Backbone.sync('create', model); Backbone.sync('create', model);
}); });
QUnit.test('Call provided error callback on error.', function(assert) { test("Call provided error callback on error.", 1, function() {
assert.expect(1);
var model = new Backbone.Model; var model = new Backbone.Model;
model.url = '/test'; model.url = '/test';
Backbone.sync('read', model, { Backbone.sync('read', model, {
error: function() { assert.ok(true); } error: function() { ok(true); }
}); });
this.ajaxSettings.error(); this.ajaxSettings.error();
}); });
QUnit.test('Use Backbone.emulateHTTP as default.', function(assert) { test('Use Backbone.emulateHTTP as default.', 2, function() {
assert.expect(2);
var model = new Backbone.Model; var model = new Backbone.Model;
model.url = '/test'; model.url = '/test';
Backbone.emulateHTTP = true; Backbone.emulateHTTP = true;
model.sync('create', model); model.sync('create', model);
assert.strictEqual(this.ajaxSettings.emulateHTTP, true); strictEqual(this.ajaxSettings.emulateHTTP, true);
Backbone.emulateHTTP = false; Backbone.emulateHTTP = false;
model.sync('create', model); model.sync('create', model);
assert.strictEqual(this.ajaxSettings.emulateHTTP, false); strictEqual(this.ajaxSettings.emulateHTTP, false);
}); });
QUnit.test('Use Backbone.emulateJSON as default.', function(assert) { test('Use Backbone.emulateJSON as default.', 2, function() {
assert.expect(2);
var model = new Backbone.Model; var model = new Backbone.Model;
model.url = '/test'; model.url = '/test';
Backbone.emulateJSON = true; Backbone.emulateJSON = true;
model.sync('create', model); model.sync('create', model);
assert.strictEqual(this.ajaxSettings.emulateJSON, true); strictEqual(this.ajaxSettings.emulateJSON, true);
Backbone.emulateJSON = false; Backbone.emulateJSON = false;
model.sync('create', model); model.sync('create', model);
assert.strictEqual(this.ajaxSettings.emulateJSON, false); strictEqual(this.ajaxSettings.emulateJSON, false);
}); });
QUnit.test('#1756 - Call user provided beforeSend function.', function(assert) { test("#1756 - Call user provided beforeSend function.", 4, function() {
assert.expect(4);
Backbone.emulateHTTP = true; Backbone.emulateHTTP = true;
var model = new Backbone.Model; var model = new Backbone.Model;
model.url = '/test'; model.url = '/test';
var xhr = { var xhr = {
setRequestHeader: function(header, value) { setRequestHeader: function(header, value) {
assert.strictEqual(header, 'X-HTTP-Method-Override'); strictEqual(header, 'X-HTTP-Method-Override');
assert.strictEqual(value, 'DELETE'); strictEqual(value, 'DELETE');
} }
}; };
model.sync('delete', model, { model.sync('delete', model, {
beforeSend: function(_xhr) { beforeSend: function(_xhr) {
assert.ok(_xhr === xhr); ok(_xhr === xhr);
return false; return false;
} }
}); });
assert.strictEqual(this.ajaxSettings.beforeSend(xhr), false); strictEqual(this.ajaxSettings.beforeSend(xhr), false);
}); });
QUnit.test('#2928 - Pass along `textStatus` and `errorThrown`.', function(assert) { test('#2928 - Pass along `textStatus` and `errorThrown`.', 2, function() {
assert.expect(2);
var model = new Backbone.Model; var model = new Backbone.Model;
model.url = '/test'; model.url = '/test';
model.on('error', function(m, xhr, options) { model.on('error', function(model, xhr, options) {
assert.strictEqual(options.textStatus, 'textStatus'); strictEqual(options.textStatus, 'textStatus');
assert.strictEqual(options.errorThrown, 'errorThrown'); strictEqual(options.errorThrown, 'errorThrown');
}); });
model.fetch(); model.fetch();
this.ajaxSettings.error({}, 'textStatus', 'errorThrown'); this.ajaxSettings.error({}, 'textStatus', 'errorThrown');
}); });
})(QUnit); })();

View File

@@ -1,137 +1,98 @@
(function(QUnit) { (function() {
var view; var view;
QUnit.module('Backbone.View', { module("Backbone.View", {
beforeEach: function() {
$('#qunit-fixture').append(
'<div id="testElement"><h1>Test</h1></div>'
);
setup: function() {
view = new Backbone.View({ view = new Backbone.View({
id: 'test-view', id : 'test-view',
className: 'test-view', className : 'test-view',
other: 'non-special-option' other : 'non-special-option'
}); });
},
afterEach: function() {
$('#testElement').remove();
$('#test-view').remove();
} }
}); });
QUnit.test('constructor', function(assert) { test("constructor", 3, function() {
assert.expect(3); equal(view.el.id, 'test-view');
assert.equal(view.el.id, 'test-view'); equal(view.el.className, 'test-view');
assert.equal(view.el.className, 'test-view'); equal(view.el.other, void 0);
assert.equal(view.el.other, void 0);
}); });
QUnit.test('$', function(assert) { test("$", 2, function() {
assert.expect(2); var view = new Backbone.View;
var myView = new Backbone.View; view.setElement('<p><a><b>test</b></a></p>');
myView.setElement('<p><a><b>test</b></a></p>'); var result = view.$('a b');
var result = myView.$('a b');
assert.strictEqual(result[0].innerHTML, 'test'); strictEqual(result[0].innerHTML, 'test');
assert.ok(result.length === +result.length); ok(result.length === +result.length);
}); });
QUnit.test('$el', function(assert) { test("$el", 3, function() {
assert.expect(3); var view = new Backbone.View;
var myView = new Backbone.View; view.setElement('<p><a><b>test</b></a></p>');
myView.setElement('<p><a><b>test</b></a></p>'); strictEqual(view.el.nodeType, 1);
assert.strictEqual(myView.el.nodeType, 1);
assert.ok(myView.$el instanceof Backbone.$); ok(view.$el instanceof Backbone.$);
assert.strictEqual(myView.$el[0], myView.el); strictEqual(view.$el[0], view.el);
}); });
QUnit.test('initialize', function(assert) { test("initialize", 1, function() {
assert.expect(1);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
initialize: function() { initialize: function() {
this.one = 1; this.one = 1;
} }
}); });
assert.strictEqual(new View().one, 1); strictEqual(new View().one, 1);
}); });
QUnit.test('preinitialize', function(assert) { test("render", 1, function() {
assert.expect(1); var view = new Backbone.View;
var View = Backbone.View.extend({ equal(view.render(), view, '#render returns the view instance');
preinitialize: function() {
this.one = 1;
}
});
assert.strictEqual(new View().one, 1);
}); });
QUnit.test('preinitialize occurs before the view is set up', function(assert) { test("delegateEvents", 6, function() {
assert.expect(2);
var View = Backbone.View.extend({
preinitialize: function() {
assert.equal(this.el, undefined);
}
});
var _view = new View({});
assert.notEqual(_view.el, undefined);
});
QUnit.test('render', function(assert) {
assert.expect(1);
var myView = new Backbone.View;
assert.equal(myView.render(), myView, '#render returns the view instance');
});
QUnit.test('delegateEvents', function(assert) {
assert.expect(6);
var counter1 = 0, counter2 = 0; var counter1 = 0, counter2 = 0;
var myView = new Backbone.View({el: '#testElement'}); var view = new Backbone.View({el: '#testElement'});
myView.increment = function() { counter1++; }; view.increment = function(){ counter1++; };
myView.$el.on('click', function() { counter2++; }); view.$el.on('click', function(){ counter2++; });
var events = {'click h1': 'increment'}; var events = {'click h1': 'increment'};
myView.delegateEvents(events); view.delegateEvents(events);
myView.$('h1').trigger('click'); view.$('h1').trigger('click');
assert.equal(counter1, 1); equal(counter1, 1);
assert.equal(counter2, 1); equal(counter2, 1);
myView.$('h1').trigger('click'); view.$('h1').trigger('click');
assert.equal(counter1, 2); equal(counter1, 2);
assert.equal(counter2, 2); equal(counter2, 2);
myView.delegateEvents(events); view.delegateEvents(events);
myView.$('h1').trigger('click'); view.$('h1').trigger('click');
assert.equal(counter1, 3); equal(counter1, 3);
assert.equal(counter2, 3); equal(counter2, 3);
}); });
QUnit.test('delegate', function(assert) { test("delegate", 3, function() {
assert.expect(3); var view = new Backbone.View({el: '#testElement'});
var myView = new Backbone.View({el: '#testElement'}); view.delegate('click', 'h1', function() {
myView.delegate('click', 'h1', function() { ok(true);
assert.ok(true);
}); });
myView.delegate('click', function() { view.delegate('click', function() {
assert.ok(true); ok(true);
}); });
myView.$('h1').trigger('click'); view.$('h1').trigger('click');
assert.equal(myView.delegate(), myView, '#delegate returns the view instance'); equal(view.delegate(), view, '#delegate returns the view instance');
}); });
QUnit.test('delegateEvents allows functions for callbacks', function(assert) { test("delegateEvents allows functions for callbacks", 3, function() {
assert.expect(3); var view = new Backbone.View({el: '<p></p>'});
var myView = new Backbone.View({el: '<p></p>'}); view.counter = 0;
myView.counter = 0;
var events = { var events = {
click: function() { click: function() {
@@ -139,147 +100,137 @@
} }
}; };
myView.delegateEvents(events); view.delegateEvents(events);
myView.$el.trigger('click'); view.$el.trigger('click');
assert.equal(myView.counter, 1); equal(view.counter, 1);
myView.$el.trigger('click'); view.$el.trigger('click');
assert.equal(myView.counter, 2); equal(view.counter, 2);
myView.delegateEvents(events); view.delegateEvents(events);
myView.$el.trigger('click'); view.$el.trigger('click');
assert.equal(myView.counter, 3); equal(view.counter, 3);
}); });
QUnit.test('delegateEvents ignore undefined methods', function(assert) {
assert.expect(0); test("delegateEvents ignore undefined methods", 0, function() {
var myView = new Backbone.View({el: '<p></p>'}); var view = new Backbone.View({el: '<p></p>'});
myView.delegateEvents({click: 'undefinedMethod'}); view.delegateEvents({'click': 'undefinedMethod'});
myView.$el.trigger('click'); view.$el.trigger('click');
}); });
QUnit.test('undelegateEvents', function(assert) { test("undelegateEvents", 7, function() {
assert.expect(7);
var counter1 = 0, counter2 = 0; var counter1 = 0, counter2 = 0;
var myView = new Backbone.View({el: '#testElement'}); var view = new Backbone.View({el: '#testElement'});
myView.increment = function() { counter1++; }; view.increment = function(){ counter1++; };
myView.$el.on('click', function() { counter2++; }); view.$el.on('click', function(){ counter2++; });
var events = {'click h1': 'increment'}; var events = {'click h1': 'increment'};
myView.delegateEvents(events); view.delegateEvents(events);
myView.$('h1').trigger('click'); view.$('h1').trigger('click');
assert.equal(counter1, 1); equal(counter1, 1);
assert.equal(counter2, 1); equal(counter2, 1);
myView.undelegateEvents(); view.undelegateEvents();
myView.$('h1').trigger('click'); view.$('h1').trigger('click');
assert.equal(counter1, 1); equal(counter1, 1);
assert.equal(counter2, 2); equal(counter2, 2);
myView.delegateEvents(events); view.delegateEvents(events);
myView.$('h1').trigger('click'); view.$('h1').trigger('click');
assert.equal(counter1, 2); equal(counter1, 2);
assert.equal(counter2, 3); equal(counter2, 3);
assert.equal(myView.undelegateEvents(), myView, '#undelegateEvents returns the view instance'); equal(view.undelegateEvents(), view, '#undelegateEvents returns the view instance');
}); });
QUnit.test('undelegate', function(assert) { test("undelegate", 1, function() {
assert.expect(1); view = new Backbone.View({el: '#testElement'});
var myView = new Backbone.View({el: '#testElement'}); view.delegate('click', function() { ok(false); });
myView.delegate('click', function() { assert.ok(false); }); view.delegate('click', 'h1', function() { ok(false); });
myView.delegate('click', 'h1', function() { assert.ok(false); });
myView.undelegate('click'); view.undelegate('click');
myView.$('h1').trigger('click'); view.$('h1').trigger('click');
myView.$el.trigger('click'); view.$el.trigger('click');
assert.equal(myView.undelegate(), myView, '#undelegate returns the view instance'); equal(view.undelegate(), view, '#undelegate returns the view instance');
}); });
QUnit.test('undelegate with passed handler', function(assert) { test("undelegate with passed handler", 1, function() {
assert.expect(1); view = new Backbone.View({el: '#testElement'});
var myView = new Backbone.View({el: '#testElement'}); var listener = function() { ok(false); };
var listener = function() { assert.ok(false); }; view.delegate('click', listener);
myView.delegate('click', listener); view.delegate('click', function() { ok(true); });
myView.delegate('click', function() { assert.ok(true); }); view.undelegate('click', listener);
myView.undelegate('click', listener); view.$el.trigger('click');
myView.$el.trigger('click');
}); });
QUnit.test('undelegate with selector', function(assert) { test("undelegate with selector", 2, function() {
assert.expect(2); view = new Backbone.View({el: '#testElement'});
var myView = new Backbone.View({el: '#testElement'}); view.delegate('click', function() { ok(true); });
myView.delegate('click', function() { assert.ok(true); }); view.delegate('click', 'h1', function() { ok(false); });
myView.delegate('click', 'h1', function() { assert.ok(false); }); view.undelegate('click', 'h1');
myView.undelegate('click', 'h1'); view.$('h1').trigger('click');
myView.$('h1').trigger('click'); view.$el.trigger('click');
myView.$el.trigger('click');
}); });
QUnit.test('undelegate with handler and selector', function(assert) { test("undelegate with handler and selector", 2, function() {
assert.expect(2); view = new Backbone.View({el: '#testElement'});
var myView = new Backbone.View({el: '#testElement'}); view.delegate('click', function() { ok(true); });
myView.delegate('click', function() { assert.ok(true); }); var handler = function(){ ok(false); };
var handler = function() { assert.ok(false); }; view.delegate('click', 'h1', handler);
myView.delegate('click', 'h1', handler); view.undelegate('click', 'h1', handler);
myView.undelegate('click', 'h1', handler); view.$('h1').trigger('click');
myView.$('h1').trigger('click'); view.$el.trigger('click');
myView.$el.trigger('click');
}); });
QUnit.test('tagName can be provided as a string', function(assert) { test("tagName can be provided as a string", 1, function() {
assert.expect(1);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
tagName: 'span' tagName: 'span'
}); });
assert.equal(new View().el.tagName, 'SPAN'); equal(new View().el.tagName, 'SPAN');
}); });
QUnit.test('tagName can be provided as a function', function(assert) { test("tagName can be provided as a function", 1, function() {
assert.expect(1);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
tagName: function() { tagName: function() {
return 'p'; return 'p';
} }
}); });
assert.ok(new View().$el.is('p')); ok(new View().$el.is('p'));
}); });
QUnit.test('_ensureElement with DOM node el', function(assert) { test("_ensureElement with DOM node el", 1, function() {
assert.expect(1);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
el: document.body el: document.body
}); });
assert.equal(new View().el, document.body); equal(new View().el, document.body);
}); });
QUnit.test('_ensureElement with string el', function(assert) { test("_ensureElement with string el", 3, function() {
assert.expect(3);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
el: 'body' el: "body"
}); });
assert.strictEqual(new View().el, document.body); strictEqual(new View().el, document.body);
View = Backbone.View.extend({ View = Backbone.View.extend({
el: '#testElement > h1' el: "#testElement > h1"
}); });
assert.strictEqual(new View().el, $('#testElement > h1').get(0)); strictEqual(new View().el, $("#testElement > h1").get(0));
View = Backbone.View.extend({ View = Backbone.View.extend({
el: '#nonexistent' el: "#nonexistent"
}); });
assert.ok(!new View().el); ok(!new View().el);
}); });
QUnit.test('with className and id functions', function(assert) { test("with className and id functions", 2, function() {
assert.expect(2);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
className: function() { className: function() {
return 'className'; return 'className';
@@ -289,54 +240,33 @@
} }
}); });
assert.strictEqual(new View().el.className, 'className'); strictEqual(new View().el.className, 'className');
assert.strictEqual(new View().el.id, 'id'); strictEqual(new View().el.id, 'id');
}); });
QUnit.test('with attributes', function(assert) { test("with attributes", 2, function() {
assert.expect(2);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
attributes: { attributes: {
'id': 'id', id: 'id',
'class': 'class' 'class': 'class'
} }
}); });
assert.strictEqual(new View().el.className, 'class'); strictEqual(new View().el.className, 'class');
assert.strictEqual(new View().el.id, 'id'); strictEqual(new View().el.id, 'id');
}); });
QUnit.test('with attributes as a function', function(assert) { test("with attributes as a function", 1, function() {
assert.expect(1);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
attributes: function() { attributes: function() {
return {'class': 'dynamic'}; return {'class': 'dynamic'};
} }
}); });
assert.strictEqual(new View().el.className, 'dynamic'); strictEqual(new View().el.className, 'dynamic');
}); });
QUnit.test('should default to className/id properties', function(assert) { test("multiple views per element", 3, function() {
assert.expect(4);
var View = Backbone.View.extend({
className: 'backboneClass',
id: 'backboneId',
attributes: {
'class': 'attributeClass',
'id': 'attributeId'
}
});
var myView = new View;
assert.strictEqual(myView.el.className, 'backboneClass');
assert.strictEqual(myView.el.id, 'backboneId');
assert.strictEqual(myView.$el.attr('class'), 'backboneClass');
assert.strictEqual(myView.$el.attr('id'), 'backboneId');
});
QUnit.test('multiple views per element', function(assert) {
assert.expect(3);
var count = 0; var count = 0;
var $el = $('<p></p>'); var $el = $('<p></p>');
@@ -350,112 +280,105 @@
}); });
var view1 = new View; var view1 = new View;
$el.trigger('click'); $el.trigger("click");
assert.equal(1, count); equal(1, count);
var view2 = new View; var view2 = new View;
$el.trigger('click'); $el.trigger("click");
assert.equal(3, count); equal(3, count);
view1.delegateEvents(); view1.delegateEvents();
$el.trigger('click'); $el.trigger("click");
assert.equal(5, count); equal(5, count);
}); });
QUnit.test('custom events', function(assert) { test("custom events", 2, function() {
assert.expect(2);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
el: $('body'), el: $('body'),
events: { events: {
fake$event: function() { assert.ok(true); } "fake$event": function() { ok(true); }
} }
}); });
var myView = new View; var view = new View;
$('body').trigger('fake$event').trigger('fake$event'); $('body').trigger('fake$event').trigger('fake$event');
$('body').off('fake$event'); $('body').off('fake$event');
$('body').trigger('fake$event'); $('body').trigger('fake$event');
}); });
QUnit.test('#1048 - setElement uses provided object.', function(assert) { test("#1048 - setElement uses provided object.", 2, function() {
assert.expect(2);
var $el = $('body'); var $el = $('body');
var myView = new Backbone.View({el: $el}); var view = new Backbone.View({el: $el});
assert.ok(myView.$el === $el); ok(view.$el === $el);
myView.setElement($el = $($el)); view.setElement($el = $($el));
assert.ok(myView.$el === $el); ok(view.$el === $el);
}); });
QUnit.test('#986 - Undelegate before changing element.', function(assert) { test("#986 - Undelegate before changing element.", 1, function() {
assert.expect(1);
var button1 = $('<button></button>'); var button1 = $('<button></button>');
var button2 = $('<button></button>'); var button2 = $('<button></button>');
var View = Backbone.View.extend({ var View = Backbone.View.extend({
events: { events: {
click: function(e) { click: function(e) {
assert.ok(myView.el === e.target); ok(view.el === e.target);
} }
} }
}); });
var myView = new View({el: button1}); var view = new View({el: button1});
myView.setElement(button2); view.setElement(button2);
button1.trigger('click'); button1.trigger('click');
button2.trigger('click'); button2.trigger('click');
}); });
QUnit.test('#1172 - Clone attributes object', function(assert) { test("#1172 - Clone attributes object", 2, function() {
assert.expect(2);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
attributes: {foo: 'bar'} attributes: {foo: 'bar'}
}); });
var view1 = new View({id: 'foo'}); var view1 = new View({id: 'foo'});
assert.strictEqual(view1.el.id, 'foo'); strictEqual(view1.el.id, 'foo');
var view2 = new View(); var view2 = new View();
assert.ok(!view2.el.id); ok(!view2.el.id);
}); });
QUnit.test('views stopListening', function(assert) { test("views stopListening", 0, function() {
assert.expect(0);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
initialize: function() { initialize: function() {
this.listenTo(this.model, 'all x', function() { assert.ok(false); }); this.listenTo(this.model, 'all x', function(){ ok(false); });
this.listenTo(this.collection, 'all x', function() { assert.ok(false); }); this.listenTo(this.collection, 'all x', function(){ ok(false); });
} }
}); });
var myView = new View({ var view = new View({
model: new Backbone.Model, model: new Backbone.Model,
collection: new Backbone.Collection collection: new Backbone.Collection
}); });
myView.stopListening(); view.stopListening();
myView.model.trigger('x'); view.model.trigger('x');
myView.collection.trigger('x'); view.collection.trigger('x');
}); });
QUnit.test('Provide function for el.', function(assert) { test("Provide function for el.", 2, function() {
assert.expect(2);
var View = Backbone.View.extend({ var View = Backbone.View.extend({
el: function() { el: function() {
return '<p><a></a></p>'; return "<p><a></a></p>";
} }
}); });
var myView = new View; var view = new View;
assert.ok(myView.$el.is('p')); ok(view.$el.is('p'));
assert.ok(myView.$el.has('a')); ok(view.$el.has('a'));
}); });
QUnit.test('events passed in options', function(assert) { test("events passed in options", 1, function() {
assert.expect(1);
var counter = 0; var counter = 0;
var View = Backbone.View.extend({ var View = Backbone.View.extend({
@@ -465,52 +388,50 @@
} }
}); });
var myView = new View({ var view = new View({
events: { events: {
'click h1': 'increment' 'click h1': 'increment'
} }
}); });
myView.$('h1').trigger('click').trigger('click'); view.$('h1').trigger('click').trigger('click');
assert.equal(counter, 2); equal(counter, 2);
}); });
QUnit.test('remove', function(assert) { test("remove", 2, function() {
assert.expect(2); var view = new Backbone.View;
var myView = new Backbone.View;
document.body.appendChild(view.el); document.body.appendChild(view.el);
myView.delegate('click', function() { assert.ok(false); }); view.delegate('click', function() { ok(false); });
myView.listenTo(myView, 'all x', function() { assert.ok(false); }); view.listenTo(view, 'all x', function() { ok(false); });
assert.equal(myView.remove(), myView, '#remove returns the view instance'); equal(view.remove(), view, '#remove returns the view instance');
myView.$el.trigger('click'); view.$el.trigger('click');
myView.trigger('x'); view.trigger('x');
// In IE8 and below, parentNode still exists but is not document.body. // In IE8 and below, parentNode still exists but is not document.body.
assert.notEqual(myView.el.parentNode, document.body); notEqual(view.el.parentNode, document.body);
}); });
QUnit.test('setElement', function(assert) { test("setElement", 3, function() {
assert.expect(3); var view = new Backbone.View({
var myView = new Backbone.View({
events: { events: {
click: function() { assert.ok(false); } click: function() { ok(false); }
} }
}); });
myView.events = { view.events = {
click: function() { assert.ok(true); } click: function() { ok(true); }
}; };
var oldEl = myView.el; var oldEl = view.el;
var $oldEl = myView.$el; var $oldEl = view.$el;
myView.setElement(document.createElement('div')); view.setElement(document.createElement('div'));
$oldEl.click(); $oldEl.click();
myView.$el.click(); view.$el.click();
assert.notEqual(oldEl, myView.el); notEqual(oldEl, view.el);
assert.notEqual($oldEl, myView.$el); notEqual($oldEl, view.$el);
}); });
})(QUnit); })();

22
vendor/benchmark.js/LICENSE vendored Normal file
View File

@@ -0,0 +1,22 @@
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/>
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.

2875
vendor/benchmark.js/benchmark.js vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
vendor/benchmark.js/nano.jar vendored Normal file

Binary file not shown.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Copyright (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative
Reporters & Editors Reporters & Editors
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person

View File

@@ -3,407 +3,398 @@
QUnit.module('Arrays'); QUnit.module('Arrays');
QUnit.test('first', function(assert) { test('first', function() {
assert.equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array'); equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array');
assert.equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"'); equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"');
assert.deepEqual(_.first([1, 2, 3], 0), [], 'returns an empty array when n <= 0 (0 case)'); deepEqual(_.first([1, 2, 3], 0), [], 'can pass an index to first');
assert.deepEqual(_.first([1, 2, 3], -1), [], 'returns an empty array when n <= 0 (negative case)'); deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can pass an index to first');
assert.deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can fetch the first n elements'); deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'can pass an index to first');
assert.deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'returns the whole array if n > length');
var result = (function(){ return _.first(arguments); }(4, 3, 2, 1)); var result = (function(){ return _.first(arguments); }(4, 3, 2, 1));
assert.equal(result, 4, 'works on an arguments object'); equal(result, 4, 'works on an arguments object.');
result = _.map([[1, 2, 3], [1, 2, 3]], _.first); result = _.map([[1, 2, 3], [1, 2, 3]], _.first);
assert.deepEqual(result, [1, 1], 'works well with _.map'); deepEqual(result, [1, 1], 'works well with _.map');
assert.equal(_.first(null), void 0, 'returns undefined when called on null'); result = (function() { return _.first([1, 2, 3], 2); }());
deepEqual(result, [1, 2]);
Array.prototype[0] = 'boo'; equal(_.first(null), undefined, 'handles nulls');
assert.equal(_.first([]), void 0, 'return undefined when called on a empty array'); strictEqual(_.first([1, 2, 3], -1).length, 0);
delete Array.prototype[0];
}); });
QUnit.test('head', function(assert) { test('head', function() {
assert.strictEqual(_.head, _.first, 'is an alias for first'); strictEqual(_.first, _.head, 'alias for first');
}); });
QUnit.test('take', function(assert) { test('take', function() {
assert.strictEqual(_.take, _.first, 'is an alias for first'); strictEqual(_.first, _.take, 'alias for first');
}); });
QUnit.test('rest', function(assert) { test('rest', function() {
var numbers = [1, 2, 3, 4]; var numbers = [1, 2, 3, 4];
assert.deepEqual(_.rest(numbers), [2, 3, 4], 'fetches all but the first element'); deepEqual(_.rest(numbers), [2, 3, 4], 'working rest()');
assert.deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'returns the whole array when index is 0'); deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'working rest(0)');
assert.deepEqual(_.rest(numbers, 2), [3, 4], 'returns elements starting at the given index'); deepEqual(_.rest(numbers, 2), [3, 4], 'rest can take an index');
var result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4)); var result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4));
assert.deepEqual(result, [2, 3, 4], 'works on an arguments object'); deepEqual(result, [2, 3, 4], 'works on arguments object');
result = _.map([[1, 2, 3], [1, 2, 3]], _.rest); result = _.map([[1, 2, 3], [1, 2, 3]], _.rest);
assert.deepEqual(_.flatten(result), [2, 3, 2, 3], 'works well with _.map'); 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');
}); });
QUnit.test('tail', function(assert) { test('tail', function() {
assert.strictEqual(_.tail, _.rest, 'is an alias for rest'); strictEqual(_.rest, _.tail, 'alias for rest');
}); });
QUnit.test('drop', function(assert) { test('drop', function() {
assert.strictEqual(_.drop, _.rest, 'is an alias for rest'); strictEqual(_.rest, _.drop, 'alias for rest');
}); });
QUnit.test('initial', function(assert) { test('initial', function() {
assert.deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'returns all but the last element'); deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'working initial()');
assert.deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'returns all but the last n elements'); deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'initial can take an index');
assert.deepEqual(_.initial([1, 2, 3, 4], 6), [], 'returns an empty array when n > length'); deepEqual(_.initial([1, 2, 3, 4], 6), [], 'initial can take a large index');
var result = (function(){ return _(arguments).initial(); }(1, 2, 3, 4)); var result = (function(){ return _(arguments).initial(); }(1, 2, 3, 4));
assert.deepEqual(result, [1, 2, 3], 'works on an arguments object'); deepEqual(result, [1, 2, 3], 'initial works on arguments object');
result = _.map([[1, 2, 3], [1, 2, 3]], _.initial); result = _.map([[1, 2, 3], [1, 2, 3]], _.initial);
assert.deepEqual(_.flatten(result), [1, 2, 1, 2], 'works well with _.map'); deepEqual(_.flatten(result), [1, 2, 1, 2], 'initial works with _.map');
}); });
QUnit.test('last', function(assert) { test('last', function() {
assert.equal(_.last([1, 2, 3]), 3, 'can pull out the last element of an array'); equal(_.last([1, 2, 3]), 3, 'can pull out the last element of an array');
assert.equal(_([1, 2, 3]).last(), 3, 'can perform OO-style "last()"'); deepEqual(_.last([1, 2, 3], 0), [], 'can pass an index to last');
assert.deepEqual(_.last([1, 2, 3], 0), [], 'returns an empty array when n <= 0 (0 case)'); deepEqual(_.last([1, 2, 3], 2), [2, 3], 'can pass an index to last');
assert.deepEqual(_.last([1, 2, 3], -1), [], 'returns an empty array when n <= 0 (negative case)'); deepEqual(_.last([1, 2, 3], 5), [1, 2, 3], 'can pass an index to last');
assert.deepEqual(_.last([1, 2, 3], 2), [2, 3], 'can fetch the last n elements');
assert.deepEqual(_.last([1, 2, 3], 5), [1, 2, 3], 'returns the whole array if n > length');
var result = (function(){ return _(arguments).last(); }(1, 2, 3, 4)); var result = (function(){ return _(arguments).last(); }(1, 2, 3, 4));
assert.equal(result, 4, 'works on an arguments object'); equal(result, 4, 'works on an arguments object');
result = _.map([[1, 2, 3], [1, 2, 3]], _.last); result = _.map([[1, 2, 3], [1, 2, 3]], _.last);
assert.deepEqual(result, [3, 3], 'works well with _.map'); deepEqual(result, [3, 3], 'works well with _.map');
assert.equal(_.last(null), void 0, 'returns undefined when called on null');
var arr = []; equal(_.last(null), undefined, 'handles nulls');
arr[-1] = 'boo'; strictEqual(_.last([1, 2, 3], -1).length, 0);
assert.equal(_.last(arr), void 0, 'return undefined when called on a empty array');
}); });
QUnit.test('compact', function(assert) { test('compact', function() {
assert.deepEqual(_.compact([1, false, null, 0, '', void 0, NaN, 2]), [1, 2], 'removes all falsy values'); equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values');
var result = (function(){ return _.compact(arguments); }(0, 1, false, 2, false, 3)); var result = (function(){ return _.compact(arguments).length; }(0, 1, false, 2, false, 3));
assert.deepEqual(result, [1, 2, 3], 'works on an arguments object'); equal(result, 3, 'works on an arguments object');
result = _.map([[1, false, false], [false, false, 3]], _.compact);
assert.deepEqual(result, [[1], [3]], 'works well with _.map');
}); });
QUnit.test('flatten', function(assert) { test('flatten', function() {
assert.deepEqual(_.flatten(null), [], 'supports null'); deepEqual(_.flatten(null), [], 'Flattens supports null');
assert.deepEqual(_.flatten(void 0), [], 'supports undefined'); deepEqual(_.flatten(void 0), [], 'Flattens supports undefined');
assert.deepEqual(_.flatten([[], [[]], []]), [], 'supports empty arrays'); deepEqual(_.flatten([[], [[]], []]), [], 'Flattens empty arrays');
assert.deepEqual(_.flatten([[], [[]], []], true), [[]], 'can shallowly flatten empty arrays'); deepEqual(_.flatten([[], [[]], []], true), [[]], 'Flattens empty arrays');
var list = [1, [2], [3, [[[4]]]]]; var list = [1, [2], [3, [[[4]]]]];
assert.deepEqual(_.flatten(list), [1, 2, 3, 4], 'can flatten nested arrays'); deepEqual(_.flatten(list), [1, 2, 3, 4], 'can flatten nested arrays');
assert.deepEqual(_.flatten(list, true), [1, 2, 3, [[[4]]]], 'can shallowly 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]]]])); var result = (function(){ return _.flatten(arguments); }(1, [2], [3, [[[4]]]]));
assert.deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); deepEqual(result, [1, 2, 3, 4], 'works on an arguments object');
list = [[1], [2], [3], [[4]]]; list = [[1], [2], [3], [[4]]];
assert.deepEqual(_.flatten(list, true), [1, 2, 3, [4]], 'can shallowly flatten arrays containing only other arrays'); deepEqual(_.flatten(list, true), [1, 2, 3, [4]], 'can shallowly flatten arrays containing only other arrays');
assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3], true).length, 23, 'can flatten medium length arrays'); equal(_.flatten([_.range(10), _.range(10), 5, 1, 3], true).length, 23);
assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23, 'can shallowly flatten medium length arrays'); equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23);
assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'can handle massive arrays'); equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'Flatten can handle massive collections');
assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'can handle massive arrays in shallow mode'); equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'Flatten can handle massive collections');
var x = _.range(100000);
for (var i = 0; i < 1000; i++) x = [x];
assert.deepEqual(_.flatten(x), _.range(100000), 'can handle very deep arrays');
assert.deepEqual(_.flatten(x, true), x[0], 'can handle very deep arrays in shallow mode');
}); });
QUnit.test('without', function(assert) { test('without', function() {
var list = [1, 2, 1, 0, 3, 1, 4]; var list = [1, 2, 1, 0, 3, 1, 4];
assert.deepEqual(_.without(list, 0, 1), [2, 3, 4], 'removes all instances of the given values'); 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)); var result = (function(){ return _.without(arguments, 0, 1); }(1, 2, 1, 0, 3, 1, 4));
assert.deepEqual(result, [2, 3, 4], 'works on an arguments object'); deepEqual(result, [2, 3, 4], 'works on an arguments object');
list = [{one: 1}, {two: 2}]; list = [{one : 1}, {two : 2}];
assert.deepEqual(_.without(list, {one: 1}), list, 'compares objects by reference (value case)'); equal(_.without(list, {one : 1}).length, 2, 'uses real object identity for comparisons.');
assert.deepEqual(_.without(list, list[0]), [{two: 2}], 'compares objects by reference (reference case)'); equal(_.without(list, list[0]).length, 1, 'ditto.');
}); });
QUnit.test('sortedIndex', function(assert) { test('sortedIndex', function() {
var numbers = [10, 20, 30, 40, 50]; var numbers = [10, 20, 30, 40, 50], num = 35;
var indexFor35 = _.sortedIndex(numbers, 35); var indexForNum = _.sortedIndex(numbers, num);
assert.equal(indexFor35, 3, 'finds the index at which a value should be inserted to retain order'); equal(indexForNum, 3, '35 should be inserted at index 3');
var indexFor30 = _.sortedIndex(numbers, 30); var indexFor30 = _.sortedIndex(numbers, 30);
assert.equal(indexFor30, 2, 'finds the smallest index at which a value could be inserted to retain order'); equal(indexFor30, 2, '30 should be inserted at index 2');
var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}]; var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}];
var iterator = function(obj){ return obj.x; }; var iterator = function(obj){ return obj.x; };
assert.strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2, 'uses the result of `iterator` for order comparisons'); strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2);
assert.strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3, 'when `iterator` is a string, uses that key for order comparisons'); strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3);
var context = {1: 2, 2: 3, 3: 4}; var context = {1: 2, 2: 3, 3: 4};
iterator = function(obj){ return this[obj]; }; iterator = function(obj){ return this[obj]; };
assert.strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1, 'can execute its iterator in the given context'); strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1);
var values = [0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, var values = [0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647];
1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647]; var array = Array(Math.pow(2, 32) - 1);
var largeArray = Array(Math.pow(2, 32) - 1);
var length = values.length; var length = values.length;
// Sparsely populate `array`
while (length--) { while (length--) {
largeArray[values[length]] = values[length]; array[values[length]] = values[length];
} }
assert.equal(_.sortedIndex(largeArray, 2147483648), 2147483648, 'works with large indexes'); equal(_.sortedIndex(array, 2147483648), 2147483648, 'should work with large indexes');
}); });
QUnit.test('uniq', function(assert) { test('uniq', function() {
var list = [1, 2, 1, 3, 1, 4]; var list = [1, 2, 1, 3, 1, 4];
assert.deepEqual(_.uniq(list), [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]; list = [1, 1, 1, 2, 2, 3];
assert.deepEqual(_.uniq(list, true), [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 expected = [{name: 'Moe'}, {name: 'Curly'}, {name: 'Larry'}]; var iterator = function(value) { return value.name; };
var iterator = function(stooge) { return stooge.name; }; deepEqual(_.map(_.uniq(list, false, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator');
assert.deepEqual(_.uniq(list, false, iterator), expected, 'uses the result of `iterator` for uniqueness comparisons (unsorted case)');
assert.deepEqual(_.uniq(list, iterator), expected, '`sorted` argument defaults to false when omitted');
assert.deepEqual(_.uniq(list, 'name'), expected, 'when `iterator` is a string, uses that key for comparisons (unsorted case)');
list = [{score: 8}, {score: 10}, {score: 10}]; 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');
expected = [{score: 8}, {score: 10}];
iterator = function(item) { return item.score; }; iterator = function(value) { return value + 1; };
assert.deepEqual(_.uniq(list, true, iterator), expected, 'uses the result of `iterator` for uniqueness comparisons (sorted case)'); list = [1, 2, 2, 3, 4, 4];
assert.deepEqual(_.uniq(list, true, 'score'), expected, 'when `iterator` is a string, uses that key for comparisons (sorted case)'); deepEqual(_.uniq(list, true, iterator), [1, 2, 3, 4], 'iterator works with sorted array');
var kittens = [
{kitten: 'Celery', cuteness: 8},
{kitten: 'Juniper', cuteness: 10},
{kitten: 'Spottis', cuteness: 10}
];
var expected = [
{kitten: 'Celery', cuteness: 8},
{kitten: 'Juniper', cuteness: 10}
];
deepEqual(_.uniq(kittens, true, 'cuteness'), expected, 'string iterator works with sorted array');
assert.deepEqual(_.uniq([{0: 1}, {0: 1}, {0: 1}, {0: 2}], 0), [{0: 1}, {0: 2}], 'can use falsey pluck like iterator');
var result = (function(){ return _.uniq(arguments); }(1, 2, 1, 3, 1, 4)); var result = (function(){ return _.uniq(arguments); }(1, 2, 1, 3, 1, 4));
assert.deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); deepEqual(result, [1, 2, 3, 4], 'works on an arguments object');
var a = {}, b = {}, c = {}; var a = {}, b = {}, c = {};
assert.deepEqual(_.uniq([a, b, a, b, c]), [a, b, c], 'works on values that can be tested for equivalency but not ordered'); deepEqual(_.uniq([a, b, a, b, c]), [a, b, c], 'works on values that can be tested for equivalency but not ordered');
assert.deepEqual(_.uniq(null), [], 'returns an empty array when `array` is not iterable'); deepEqual(_.uniq(null), []);
var context = {}; var context = {};
list = [3]; list = [3];
_.uniq(list, function(value, index, array) { _.uniq(list, function(value, index, array) {
assert.strictEqual(this, context, 'executes its iterator in the given context'); strictEqual(this, context);
assert.strictEqual(value, 3, 'passes its iterator the value'); strictEqual(value, 3);
assert.strictEqual(index, 0, 'passes its iterator the index'); strictEqual(index, 0);
assert.strictEqual(array, list, 'passes its iterator the entire array'); strictEqual(array, list);
}, context); }, context);
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');
}); });
QUnit.test('unique', function(assert) { test('unique', function() {
assert.strictEqual(_.unique, _.uniq, 'is an alias for uniq'); strictEqual(_.uniq, _.unique, 'alias for uniq');
}); });
QUnit.test('intersection', function(assert) { test('intersection', function() {
var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho']; var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho'];
assert.deepEqual(_.intersection(stooges, leaders), ['moe'], 'can find the set intersection of two arrays'); deepEqual(_.intersection(stooges, leaders), ['moe'], 'can take the set intersection of two arrays');
assert.deepEqual(_(stooges).intersection(leaders), ['moe'], 'can perform an OO-style intersection'); deepEqual(_(stooges).intersection(leaders), ['moe'], 'can perform an OO-style intersection');
var result = (function(){ return _.intersection(arguments, leaders); }('moe', 'curly', 'larry')); var result = (function(){ return _.intersection(arguments, leaders); }('moe', 'curly', 'larry'));
assert.deepEqual(result, ['moe'], 'works on an arguments object'); deepEqual(result, ['moe'], 'works on an arguments object');
var theSixStooges = ['moe', 'moe', 'curly', 'curly', 'larry', 'larry']; var theSixStooges = ['moe', 'moe', 'curly', 'curly', 'larry', 'larry'];
assert.deepEqual(_.intersection(theSixStooges, leaders), ['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]); result = _.intersection([2, 4, 3, 1], [1, 2, 3]);
assert.deepEqual(result, [2, 3, 1], 'preserves the order of the first array'); deepEqual(result, [2, 3, 1], 'preserves order of first array');
result = _.intersection(null, [1, 2, 3]); result = _.intersection(null, [1, 2, 3]);
assert.deepEqual(result, [], 'returns an empty array when passed null as the first argument'); 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); result = _.intersection([1, 2, 3], null);
assert.deepEqual(result, [], 'returns an empty array when passed null as an argument beyond the first'); 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');
}); });
QUnit.test('union', function(assert) { test('union', function() {
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]); var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]);
assert.deepEqual(result, [1, 2, 3, 30, 40], 'can find the union of a list of arrays'); deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays');
result = _([1, 2, 3]).union([2, 30, 1], [1, 40]);
assert.deepEqual(result, [1, 2, 3, 30, 40], 'can perform an OO-style union');
result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]); result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]);
assert.deepEqual(result, [1, 2, 3, 30, 40, [1]], 'can find 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');
result = _.union([10, 20], [1, 30, 10], [0, 40]); var args = null;
assert.deepEqual(result, [10, 20, 1, 30, 0, 40], 'orders values by their first encounter'); (function(){ args = arguments; }(1, 2, 3));
result = _.union(args, [2, 30, 1], [1, 40]);
deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays');
result = (function(){ return _.union(arguments, [2, 30, 1], [1, 40]); }(1, 2, 3)); result = _.union([1, 2, 3], 4);
assert.deepEqual(result, [1, 2, 3, 30, 40], 'works on an arguments object'); deepEqual(result, [1, 2, 3], 'restrict the union to arrays only');
assert.deepEqual(_.union([1, 2, 3], 4), [1, 2, 3], 'restricts the union to arrays only');
}); });
QUnit.test('difference', function(assert) { test('difference', function() {
var result = _.difference([1, 2, 3], [2, 30, 40]); var result = _.difference([1, 2, 3], [2, 30, 40]);
assert.deepEqual(result, [1, 3], 'can find the difference of two arrays'); deepEqual(result, [1, 3], 'takes the difference of two arrays');
result = _([1, 2, 3]).difference([2, 30, 40]);
assert.deepEqual(result, [1, 3], 'can perform an OO-style difference');
result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]); result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]);
assert.deepEqual(result, [3, 4], 'can find the difference of three arrays'); deepEqual(result, [3, 4], 'takes the difference of three arrays');
result = _.difference([8, 9, 3, 1], [3, 8]);
assert.deepEqual(result, [9, 1], 'preserves the order of the first array');
result = (function(){ return _.difference(arguments, [2, 30, 40]); }(1, 2, 3));
assert.deepEqual(result, [1, 3], 'works on an arguments object');
result = _.difference([1, 2, 3], 1); result = _.difference([1, 2, 3], 1);
assert.deepEqual(result, [1, 2, 3], 'restrict the difference to arrays only'); deepEqual(result, [1, 2, 3], 'restrict the difference to arrays only');
}); });
QUnit.test('zip', function(assert) { test('zip', function() {
var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true]; var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];
assert.deepEqual(_.zip(names, ages, leaders), [ deepEqual(_.zip(names, ages, leaders), [
['moe', 30, true], ['moe', 30, true],
['larry', 40, void 0], ['larry', 40, undefined],
['curly', 50, void 0] ['curly', 50, undefined]
], 'zipped together arrays of different lengths'); ], 'zipped together arrays of different lengths');
var stooges = _.zip(['moe', 30, 'stooge 1'], ['larry', 40, 'stooge 2'], ['curly', 50, 'stooge 3']); var stooges = _.zip(['moe', 30, 'stooge 1'], ['larry', 40, 'stooge 2'], ['curly', 50, 'stooge 3']);
assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs'); deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs');
// In the case of different lengths of the tuples, undefined values // In the case of difference lengths of the tuples undefineds
// should be used as placeholder // should be used as placeholder
stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']);
assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [void 0, void 0, 'extra data']], 'zipped pairs with empties'); deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [undefined, undefined, 'extra data']], 'zipped pairs with empties');
var empty = _.zip([]); var empty = _.zip([]);
assert.deepEqual(empty, [], 'unzipped empty'); deepEqual(empty, [], 'unzipped empty');
assert.deepEqual(_.zip(null), [], 'handles null'); deepEqual(_.zip(null), [], 'handles null');
assert.deepEqual(_.zip(), [], '_.zip() returns []'); deepEqual(_.zip(), [], '_.zip() returns []');
}); });
QUnit.test('unzip', function(assert) { test('unzip', function() {
assert.deepEqual(_.unzip(null), [], 'handles null'); deepEqual(_.unzip(null), [], 'handles null');
assert.deepEqual(_.unzip([['a', 'b'], [1, 2]]), [['a', 1], ['b', 2]]); deepEqual(_.unzip([['a', 'b'], [1, 2]]), [['a', 1], ['b', 2]]);
// complements zip // complements zip
var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
assert.deepEqual(_.unzip(zipped), [['fred', 'barney'], [30, 40], [true, false]]); deepEqual(_.unzip(zipped), [['fred', 'barney'], [30, 40], [true, false]]);
zipped = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); zipped = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']);
assert.deepEqual(_.unzip(zipped), [['moe', 30, void 0], ['larry', 40, void 0], ['curly', 50, 'extra data']], 'Uses length of largest array'); deepEqual(_.unzip(zipped), [['moe', 30, void 0], ['larry', 40, void 0], ['curly', 50, 'extra data']], 'Uses length of largest array');
}); });
QUnit.test('object', function(assert) { test('object', function() {
var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]); var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
var shouldBe = {moe: 30, larry: 40, curly: 50}; var shouldBe = {moe: 30, larry: 40, curly: 50};
assert.deepEqual(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]]); result = _.object([['one', 1], ['two', 2], ['three', 3]]);
shouldBe = {one: 1, two: 2, three: 3}; shouldBe = {one: 1, two: 2, three: 3};
assert.deepEqual(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}; var stooges = {moe: 30, larry: 40, curly: 50};
assert.deepEqual(_.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');
assert.deepEqual(_.object(null), {}, 'handles nulls'); deepEqual(_.object(null), {}, 'handles nulls');
}); });
QUnit.test('indexOf', function(assert) { test('indexOf', function() {
var numbers = [1, 2, 3]; var numbers = [1, 2, 3];
assert.equal(_.indexOf(numbers, 2), 1, 'can compute indexOf'); equal(_.indexOf(numbers, 2), 1, 'can compute indexOf');
var result = (function(){ return _.indexOf(arguments, 2); }(1, 2, 3)); var result = (function(){ return _.indexOf(arguments, 2); }(1, 2, 3));
assert.equal(result, 1, 'works on an arguments object'); equal(result, 1, 'works on an arguments object');
_.each([null, void 0, [], false], function(val) { _.each([null, void 0, [], false], function(val) {
var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val); var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val);
assert.equal(_.indexOf(val, 2), -1, msg); equal(_.indexOf(val, 2), -1, msg);
assert.equal(_.indexOf(val, 2, -1), -1, msg); equal(_.indexOf(val, 2, -1), -1, msg);
assert.equal(_.indexOf(val, 2, -20), -1, msg); equal(_.indexOf(val, 2, -20), -1, msg);
assert.equal(_.indexOf(val, 2, 15), -1, msg); equal(_.indexOf(val, 2, 15), -1, msg);
}); });
var num = 35; var num = 35;
numbers = [10, 20, 30, 40, 50]; numbers = [10, 20, 30, 40, 50];
var index = _.indexOf(numbers, num, true); var index = _.indexOf(numbers, num, true);
assert.equal(index, -1, '35 is not in the list'); equal(index, -1, '35 is not in the list');
numbers = [10, 20, 30, 40, 50]; num = 40; numbers = [10, 20, 30, 40, 50]; num = 40;
index = _.indexOf(numbers, num, true); index = _.indexOf(numbers, num, true);
assert.equal(index, 3, '40 is in the list'); equal(index, 3, '40 is in the list');
numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40; numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40;
assert.equal(_.indexOf(numbers, num, true), 1, '40 is in the list'); equal(_.indexOf(numbers, num, true), 1, '40 is in the list');
assert.equal(_.indexOf(numbers, 6, true), -1, '6 isnt in the list'); equal(_.indexOf(numbers, 6, true), -1, '6 isnt in the list');
assert.equal(_.indexOf([1, 2, 5, 4, 6, 7], 5, true), -1, 'sorted indexOf doesn\'t uses binary search'); equal(_.indexOf([1, 2, 5, 4, 6, 7], 5, true), -1, 'sorted indexOf doesn\'t uses binary search');
assert.ok(_.every(['1', [], {}, null], function() { ok(_.every(['1', [], {}, null], function() {
return _.indexOf(numbers, num, {}) === 1; return _.indexOf(numbers, num, {}) === 1;
}), 'non-nums as fromIndex make indexOf assume sorted'); }), 'non-nums as fromIndex make indexOf assume sorted');
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
index = _.indexOf(numbers, 2, 5); index = _.indexOf(numbers, 2, 5);
assert.equal(index, 7, 'supports the fromIndex argument'); equal(index, 7, 'supports the fromIndex argument');
index = _.indexOf([,,, 0], void 0); index = _.indexOf([,,,], undefined);
assert.equal(index, 0, 'treats sparse arrays as if they were dense'); equal(index, 0, 'treats sparse arrays as if they were dense');
var array = [1, 2, 3, 1, 2, 3]; var array = [1, 2, 3, 1, 2, 3];
assert.strictEqual(_.indexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index'); strictEqual(_.indexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index');
assert.strictEqual(_.indexOf(array, 1, -2), -1, 'neg `fromIndex` starts at the right index'); strictEqual(_.indexOf(array, 1, -2), -1, 'neg `fromIndex` starts at the right index');
assert.strictEqual(_.indexOf(array, 2, -3), 4); strictEqual(_.indexOf(array, 2, -3), 4);
_.each([-6, -8, -Infinity], function(fromIndex) { _.each([-6, -8, -Infinity], function(fromIndex) {
assert.strictEqual(_.indexOf(array, 1, fromIndex), 0); strictEqual(_.indexOf(array, 1, fromIndex), 0);
}); });
assert.strictEqual(_.indexOf([1, 2, 3], 1, true), 0); strictEqual(_.indexOf([1, 2, 3], 1, true), 0);
index = _.indexOf([], void 0, true); index = _.indexOf([], undefined, true);
assert.equal(index, -1, 'empty array with truthy `isSorted` returns -1'); equal(index, -1, 'empty array with truthy `isSorted` returns -1');
}); });
QUnit.test('indexOf with NaN', function(assert) { test('indexOf with NaN', function() {
assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN), 2, 'Expected [1, 2, NaN] to contain NaN'); strictEqual(_.indexOf([1, 2, NaN, NaN], NaN), 2, 'Expected [1, 2, NaN] to contain NaN');
assert.strictEqual(_.indexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); strictEqual(_.indexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN');
assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, 1), 2, 'startIndex does not affect result'); strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, 1), 2, 'startIndex does not affect result');
assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, -2), 2, 'startIndex does not affect result'); strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, -2), 2, 'startIndex does not affect result');
(function() { (function() {
assert.strictEqual(_.indexOf(arguments, NaN), 2, 'Expected arguments [1, 2, NaN] to contain NaN'); strictEqual(_.indexOf(arguments, NaN), 2, 'Expected arguments [1, 2, NaN] to contain NaN');
}(1, 2, NaN, NaN)); }(1, 2, NaN, NaN));
}); });
QUnit.test('indexOf with +- 0', function(assert) { test('indexOf with +- 0', function() {
_.each([-0, +0], function(val) { _.each([-0, +0], function(val) {
assert.strictEqual(_.indexOf([1, 2, val, val], val), 2); strictEqual(_.indexOf([1, 2, val, val], val), 2);
assert.strictEqual(_.indexOf([1, 2, val, val], -val), 2); strictEqual(_.indexOf([1, 2, val, val], -val), 2);
}); });
}); });
QUnit.test('lastIndexOf', function(assert) { test('lastIndexOf', function() {
var numbers = [1, 0, 1]; var numbers = [1, 0, 1];
var falsey = [void 0, '', 0, false, NaN, null, void 0]; var falsey = [void 0, '', 0, false, NaN, null, undefined];
assert.equal(_.lastIndexOf(numbers, 1), 2); equal(_.lastIndexOf(numbers, 1), 2);
numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0]; numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0];
numbers.lastIndexOf = null; numbers.lastIndexOf = null;
assert.equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function'); equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function');
assert.equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element'); 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));
assert.equal(result, 5, 'works on an arguments object'); equal(result, 5, 'works on an arguments object');
_.each([null, void 0, [], false], function(val) { _.each([null, void 0, [], false], function(val) {
var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val); var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val);
assert.equal(_.lastIndexOf(val, 2), -1, msg); equal(_.lastIndexOf(val, 2), -1, msg);
assert.equal(_.lastIndexOf(val, 2, -1), -1, msg); equal(_.lastIndexOf(val, 2, -1), -1, msg);
assert.equal(_.lastIndexOf(val, 2, -20), -1, msg); equal(_.lastIndexOf(val, 2, -20), -1, msg);
assert.equal(_.lastIndexOf(val, 2, 15), -1, msg); equal(_.lastIndexOf(val, 2, 15), -1, msg);
}); });
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
var index = _.lastIndexOf(numbers, 2, 2); var index = _.lastIndexOf(numbers, 2, 2);
assert.equal(index, 1, 'supports the fromIndex argument'); equal(index, 1, 'supports the fromIndex argument');
var array = [1, 2, 3, 1, 2, 3]; var array = [1, 2, 3, 1, 2, 3];
assert.strictEqual(_.lastIndexOf(array, 1, 0), 0, 'starts at the correct from idx'); strictEqual(_.lastIndexOf(array, 1, 0), 0, 'starts at the correct from idx');
assert.strictEqual(_.lastIndexOf(array, 3), 5, 'should return the index of the last matched value'); strictEqual(_.lastIndexOf(array, 3), 5, 'should return the index of the last matched value');
assert.strictEqual(_.lastIndexOf(array, 4), -1, 'should return `-1` for an unmatched value'); strictEqual(_.lastIndexOf(array, 4), -1, 'should return `-1` for an unmatched value');
assert.strictEqual(_.lastIndexOf(array, 1, 2), 0, 'should work with a positive `fromIndex`'); strictEqual(_.lastIndexOf(array, 1, 2), 0, 'should work with a positive `fromIndex`');
_.each([6, 8, Math.pow(2, 32), Infinity], function(fromIndex) { _.each([6, 8, Math.pow(2, 32), Infinity], function(fromIndex) {
assert.strictEqual(_.lastIndexOf(array, void 0, fromIndex), -1); strictEqual(_.lastIndexOf(array, undefined, fromIndex), -1);
assert.strictEqual(_.lastIndexOf(array, 1, fromIndex), 3); strictEqual(_.lastIndexOf(array, 1, fromIndex), 3);
assert.strictEqual(_.lastIndexOf(array, '', fromIndex), -1); strictEqual(_.lastIndexOf(array, '', fromIndex), -1);
}); });
var expected = _.map(falsey, function(value) { var expected = _.map(falsey, function(value) {
@@ -414,150 +405,133 @@
return _.lastIndexOf(array, 3, fromIndex); return _.lastIndexOf(array, 3, fromIndex);
}); });
assert.deepEqual(actual, expected, 'should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`'); deepEqual(actual, expected, 'should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`');
assert.strictEqual(_.lastIndexOf(array, 3, '1'), 5, 'should treat non-number `fromIndex` values as `array.length`'); strictEqual(_.lastIndexOf(array, 3, '1'), 5, 'should treat non-number `fromIndex` values as `array.length`');
assert.strictEqual(_.lastIndexOf(array, 3, true), 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`');
assert.strictEqual(_.lastIndexOf(array, 2, -3), 1, 'should work with a negative `fromIndex`'); strictEqual(_.lastIndexOf(array, 2, -3), 1, 'should work with a negative `fromIndex`');
assert.strictEqual(_.lastIndexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index'); strictEqual(_.lastIndexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index');
assert.deepEqual(_.map([-6, -8, -Infinity], function(fromIndex) { deepEqual(_.map([-6, -8, -Infinity], function(fromIndex) {
return _.lastIndexOf(array, 1, fromIndex); return _.lastIndexOf(array, 1, fromIndex);
}), [0, -1, -1]); }), [0, -1, -1]);
}); });
QUnit.test('lastIndexOf with NaN', function(assert) { test('lastIndexOf with NaN', function() {
assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN), 3, 'Expected [1, 2, NaN] to contain NaN'); strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN), 3, 'Expected [1, 2, NaN] to contain NaN');
assert.strictEqual(_.lastIndexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); strictEqual(_.lastIndexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN');
assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, 2), 2, 'fromIndex does not affect result'); strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, 2), 2, 'fromIndex does not affect result');
assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, -2), 2, 'fromIndex does not affect result'); strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, -2), 2, 'fromIndex does not affect result');
(function() { (function() {
assert.strictEqual(_.lastIndexOf(arguments, NaN), 3, 'Expected arguments [1, 2, NaN] to contain NaN'); strictEqual(_.lastIndexOf(arguments, NaN), 3, 'Expected arguments [1, 2, NaN] to contain NaN');
}(1, 2, NaN, NaN)); }(1, 2, NaN, NaN));
}); });
QUnit.test('lastIndexOf with +- 0', function(assert) { test('lastIndexOf with +- 0', function() {
_.each([-0, +0], function(val) { _.each([-0, +0], function(val) {
assert.strictEqual(_.lastIndexOf([1, 2, val, val], val), 3); strictEqual(_.lastIndexOf([1, 2, val, val], val), 3);
assert.strictEqual(_.lastIndexOf([1, 2, val, val], -val), 3); strictEqual(_.lastIndexOf([1, 2, val, val], -val), 3);
assert.strictEqual(_.lastIndexOf([-1, 1, 2], -val), -1); strictEqual(_.lastIndexOf([-1, 1, 2], -val), -1);
}); });
}); });
QUnit.test('findIndex', function(assert) { test('findIndex', function() {
var objects = [ var objects = [
{a: 0, b: 0}, {'a': 0, 'b': 0},
{a: 1, b: 1}, {'a': 1, 'b': 1},
{a: 2, b: 2}, {'a': 2, 'b': 2},
{a: 0, b: 0} {'a': 0, 'b': 0}
]; ];
assert.equal(_.findIndex(objects, function(obj) { equal(_.findIndex(objects, function(obj) {
return obj.a === 0; return obj.a === 0;
}), 0); }), 0);
assert.equal(_.findIndex(objects, function(obj) { equal(_.findIndex(objects, function(obj) {
return obj.b * obj.a === 4; return obj.b * obj.a === 4;
}), 2); }), 2);
assert.equal(_.findIndex(objects, 'a'), 1, 'Uses lookupIterator'); equal(_.findIndex(objects, 'a'), 1, 'Uses lookupIterator');
assert.equal(_.findIndex(objects, function(obj) { equal(_.findIndex(objects, function(obj) {
return obj.b * obj.a === 5; return obj.b * obj.a === 5;
}), -1); }), -1);
assert.equal(_.findIndex(null, _.noop), -1); equal(_.findIndex(null, _.noop), -1);
assert.strictEqual(_.findIndex(objects, function(a) { strictEqual(_.findIndex(objects, function(a) {
return a.foo === null; return a.foo === null;
}), -1); }), -1);
_.findIndex([{a: 1}], function(a, key, obj) { _.findIndex([{a: 1}], function(a, key, obj) {
assert.equal(key, 0); equal(key, 0);
assert.deepEqual(obj, [{a: 1}]); deepEqual(obj, [{a: 1}]);
assert.strictEqual(this, objects, 'called with context'); strictEqual(this, objects, 'called with context');
}, objects); }, objects);
var sparse = []; var sparse = [];
sparse[20] = {a: 2, b: 2}; sparse[20] = {'a': 2, 'b': 2};
assert.equal(_.findIndex(sparse, function(obj) { equal(_.findIndex(sparse, function(obj) {
return obj && obj.b * obj.a === 4; return obj && obj.b * obj.a === 4;
}), 20, 'Works with sparse arrays'); }), 20, 'Works with sparse arrays');
var array = [1, 2, 3, 4]; var array = [1, 2, 3, 4];
array.match = 55; array.match = 55;
assert.strictEqual(_.findIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); strictEqual(_.findIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys');
}); });
QUnit.test('findLastIndex', function(assert) { test('findLastIndex', function() {
var objects = [ var objects = [
{a: 0, b: 0}, {'a': 0, 'b': 0},
{a: 1, b: 1}, {'a': 1, 'b': 1},
{a: 2, b: 2}, {'a': 2, 'b': 2},
{a: 0, b: 0} {'a': 0, 'b': 0}
]; ];
assert.equal(_.findLastIndex(objects, function(obj) { equal(_.findLastIndex(objects, function(obj) {
return obj.a === 0; return obj.a === 0;
}), 3); }), 3);
assert.equal(_.findLastIndex(objects, function(obj) { equal(_.findLastIndex(objects, function(obj) {
return obj.b * obj.a === 4; return obj.b * obj.a === 4;
}), 2); }), 2);
assert.equal(_.findLastIndex(objects, 'a'), 2, 'Uses lookupIterator'); equal(_.findLastIndex(objects, 'a'), 2, 'Uses lookupIterator');
assert.equal(_.findLastIndex(objects, function(obj) { equal(_.findLastIndex(objects, function(obj) {
return obj.b * obj.a === 5; return obj.b * obj.a === 5;
}), -1); }), -1);
assert.equal(_.findLastIndex(null, _.noop), -1); equal(_.findLastIndex(null, _.noop), -1);
assert.strictEqual(_.findLastIndex(objects, function(a) { strictEqual(_.findLastIndex(objects, function(a) {
return a.foo === null; return a.foo === null;
}), -1); }), -1);
_.findLastIndex([{a: 1}], function(a, key, obj) { _.findLastIndex([{a: 1}], function(a, key, obj) {
assert.equal(key, 0); equal(key, 0);
assert.deepEqual(obj, [{a: 1}]); deepEqual(obj, [{a: 1}]);
assert.strictEqual(this, objects, 'called with context'); strictEqual(this, objects, 'called with context');
}, objects); }, objects);
var sparse = []; var sparse = [];
sparse[20] = {a: 2, b: 2}; sparse[20] = {'a': 2, 'b': 2};
assert.equal(_.findLastIndex(sparse, function(obj) { equal(_.findLastIndex(sparse, function(obj) {
return obj && obj.b * obj.a === 4; return obj && obj.b * obj.a === 4;
}), 20, 'Works with sparse arrays'); }), 20, 'Works with sparse arrays');
var array = [1, 2, 3, 4]; var array = [1, 2, 3, 4];
array.match = 55; array.match = 55;
assert.strictEqual(_.findLastIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); strictEqual(_.findLastIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys');
}); });
QUnit.test('range', function(assert) { test('range', function() {
assert.deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array'); deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array');
assert.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(4), [0, 1, 2, 3], 'range with a single positive argument generates an array of elements 0,1,2,...,n-1');
assert.deepEqual(_.range(5, 8), [5, 6, 7], 'range with two arguments a &amp; b, a&lt;b generates an array of elements a,a+1,a+2,...,b-2,b-1'); deepEqual(_.range(5, 8), [5, 6, 7], 'range with two arguments a &amp; b, a&lt;b generates an array of elements a,a+1,a+2,...,b-2,b-1');
assert.deepEqual(_.range(3, 10, 3), [3, 6, 9], 'range with three arguments a &amp; b &amp; c, c &lt; b-a, a &lt; b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) &lt; c'); deepEqual(_.range(8, 5), [], 'range with two arguments a &amp; b, b&lt;a generates an empty array');
assert.deepEqual(_.range(3, 10, 15), [3], 'range with three arguments a &amp; b &amp; c, c &gt; b-a, a &lt; b generates an array with a single element, equal to a'); deepEqual(_.range(3, 10, 3), [3, 6, 9], 'range with three arguments a &amp; b &amp; c, c &lt; b-a, a &lt; b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) &lt; c');
assert.deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a &amp; b &amp; c, a &gt; b, c &lt; 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b'); deepEqual(_.range(3, 10, 15), [3], 'range with three arguments a &amp; b &amp; c, c &gt; b-a, a &lt; b generates an array with a single element, equal to a');
assert.deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs'); deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a &amp; b &amp; c, a &gt; b, c &lt; 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b');
assert.strictEqual(1 / _.range(-0, 1)[0], -Infinity, 'should preserve -0'); deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs');
assert.deepEqual(_.range(8, 5), [8, 7, 6], 'negative range generates descending array');
assert.deepEqual(_.range(-3), [0, -1, -2], 'negative range generates descending array');
}); });
QUnit.test('chunk', function(assert) {
assert.deepEqual(_.chunk([], 2), [], 'chunk for empty array returns an empty array');
assert.deepEqual(_.chunk([1, 2, 3], 0), [], 'chunk into parts of 0 elements returns empty array');
assert.deepEqual(_.chunk([1, 2, 3], -1), [], 'chunk into parts of negative amount of elements returns an empty array');
assert.deepEqual(_.chunk([1, 2, 3]), [], 'defaults to empty array (chunk size 0)');
assert.deepEqual(_.chunk([1, 2, 3], 1), [[1], [2], [3]], 'chunk into parts of 1 elements returns original array');
assert.deepEqual(_.chunk([1, 2, 3], 3), [[1, 2, 3]], 'chunk into parts of current array length elements returns the original array');
assert.deepEqual(_.chunk([1, 2, 3], 5), [[1, 2, 3]], 'chunk into parts of more then current array length elements returns the original array');
assert.deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 2), [[10, 20], [30, 40], [50, 60], [70]], 'chunk into parts of less then current array length elements');
assert.deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 3), [[10, 20, 30], [40, 50, 60], [70]], 'chunk into parts of less then current array length elements');
});
}()); }());

View File

@@ -3,7 +3,7 @@
QUnit.module('Chaining'); QUnit.module('Chaining');
QUnit.test('map/flatten/reduce', function(assert) { test('map/flatten/reduce', function() {
var lyrics = [ var lyrics = [
'I\'m a lumberjack and I\'m okay', 'I\'m a lumberjack and I\'m okay',
'I sleep all night and I work all day', 'I sleep all night and I work all day',
@@ -17,13 +17,12 @@
hash[l] = hash[l] || 0; hash[l] = hash[l] || 0;
hash[l]++; hash[l]++;
return hash; return hash;
}, {}) }, {}).value();
.value(); equal(counts.a, 16, 'counted all the letters in the song');
assert.equal(counts.a, 16, 'counted all the letters in the song'); equal(counts.e, 10, 'counted all the letters in the song');
assert.equal(counts.e, 10, 'counted all the letters in the song');
}); });
QUnit.test('select/reject/sortBy', function(assert) { test('select/reject/sortBy', function() {
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
numbers = _(numbers).chain().select(function(n) { numbers = _(numbers).chain().select(function(n) {
return n % 2 === 0; return n % 2 === 0;
@@ -32,10 +31,10 @@
}).sortBy(function(n) { }).sortBy(function(n) {
return -n; return -n;
}).value(); }).value();
assert.deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers');
}); });
QUnit.test('select/reject/sortBy in functional style', function(assert) { test('select/reject/sortBy in functional style', function() {
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
numbers = _.chain(numbers).select(function(n) { numbers = _.chain(numbers).select(function(n) {
return n % 2 === 0; return n % 2 === 0;
@@ -44,10 +43,10 @@
}).sortBy(function(n) { }).sortBy(function(n) {
return -n; return -n;
}).value(); }).value();
assert.deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers');
}); });
QUnit.test('reverse/concat/unshift/pop/map', function(assert) { test('reverse/concat/unshift/pop/map', function() {
var numbers = [1, 2, 3, 4, 5]; var numbers = [1, 2, 3, 4, 5];
numbers = _(numbers).chain() numbers = _(numbers).chain()
.reverse() .reverse()
@@ -56,44 +55,44 @@
.pop() .pop()
.map(function(n){ return n * 2; }) .map(function(n){ return n * 2; })
.value(); .value();
assert.deepEqual(numbers, [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.');
}); });
QUnit.test('splice', function(assert) { test('splice', function() {
var instance = _([1, 2, 3, 4, 5]).chain(); var instance = _([1, 2, 3, 4, 5]).chain();
assert.deepEqual(instance.splice(1, 3).value(), [1, 5]); deepEqual(instance.splice(1, 3).value(), [1, 5]);
assert.deepEqual(instance.splice(1, 0).value(), [1, 5]); deepEqual(instance.splice(1, 0).value(), [1, 5]);
assert.deepEqual(instance.splice(1, 1).value(), [1]); deepEqual(instance.splice(1, 1).value(), [1]);
assert.deepEqual(instance.splice(0, 1).value(), [], '#397 Can create empty array'); deepEqual(instance.splice(0, 1).value(), [], '#397 Can create empty array');
}); });
QUnit.test('shift', function(assert) { test('shift', function() {
var instance = _([1, 2, 3]).chain(); var instance = _([1, 2, 3]).chain();
assert.deepEqual(instance.shift().value(), [2, 3]); deepEqual(instance.shift().value(), [2, 3]);
assert.deepEqual(instance.shift().value(), [3]); deepEqual(instance.shift().value(), [3]);
assert.deepEqual(instance.shift().value(), [], '#397 Can create empty array'); deepEqual(instance.shift().value(), [], '#397 Can create empty array');
}); });
QUnit.test('pop', function(assert) { test('pop', function() {
var instance = _([1, 2, 3]).chain(); var instance = _([1, 2, 3]).chain();
assert.deepEqual(instance.pop().value(), [1, 2]); deepEqual(instance.pop().value(), [1, 2]);
assert.deepEqual(instance.pop().value(), [1]); deepEqual(instance.pop().value(), [1]);
assert.deepEqual(instance.pop().value(), [], '#397 Can create empty array'); deepEqual(instance.pop().value(), [], '#397 Can create empty array');
}); });
QUnit.test('chaining works in small stages', function(assert) { test('chaining works in small stages', function() {
var o = _([1, 2, 3, 4]).chain(); var o = _([1, 2, 3, 4]).chain();
assert.deepEqual(o.filter(function(i) { return i < 3; }).value(), [1, 2]); deepEqual(o.filter(function(i) { return i < 3; }).value(), [1, 2]);
assert.deepEqual(o.filter(function(i) { return i > 2; }).value(), [3, 4]); deepEqual(o.filter(function(i) { return i > 2; }).value(), [3, 4]);
}); });
QUnit.test('#1562: Engine proxies for chained functions', function(assert) { test('#1562: Engine proxies for chained functions', function() {
var wrapped = _(512); var wrapped = _(512);
assert.strictEqual(wrapped.toJSON(), 512); strictEqual(wrapped.toJSON(), 512);
assert.strictEqual(wrapped.valueOf(), 512); strictEqual(wrapped.valueOf(), 512);
assert.strictEqual(+wrapped, 512); strictEqual(+wrapped, 512);
assert.strictEqual(wrapped.toString(), '512'); strictEqual(wrapped.toString(), '512');
assert.strictEqual('' + wrapped, '512'); strictEqual('' + wrapped, '512');
}); });
}()); }());

File diff suppressed because it is too large Load Diff

View File

@@ -33,95 +33,95 @@
); );
iDoc.close(); iDoc.close();
QUnit.test('isEqual', function(assert) { test('isEqual', function() {
assert.notOk(_.isEqual(iNumber, 101)); ok(!_.isEqual(iNumber, 101));
assert.ok(_.isEqual(iNumber, 100)); ok(_.isEqual(iNumber, 100));
// Objects from another frame. // Objects from another frame.
assert.ok(_.isEqual({}, iObject), 'Objects with equivalent members created in different documents are equal'); ok(_.isEqual({}, iObject), 'Objects with equivalent members created in different documents are equal');
// Array from another frame. // Array from another frame.
assert.ok(_.isEqual([1, 2, 3], iArray), 'Arrays with equivalent elements created in different documents are equal'); ok(_.isEqual([1, 2, 3], iArray), 'Arrays with equivalent elements created in different documents are equal');
}); });
QUnit.test('isEmpty', function(assert) { test('isEmpty', function() {
assert.notOk(_([iNumber]).isEmpty(), '[1] is not empty'); ok(!_([iNumber]).isEmpty(), '[1] is not empty');
assert.notOk(_.isEmpty(iArray), '[] is empty'); ok(!_.isEmpty(iArray), '[] is empty');
assert.ok(_.isEmpty(iObject), '{} is empty'); ok(_.isEmpty(iObject), '{} is empty');
}); });
QUnit.test('isElement', function(assert) { test('isElement', function() {
assert.notOk(_.isElement('div'), 'strings are not dom elements'); ok(!_.isElement('div'), 'strings are not dom elements');
assert.ok(_.isElement(document.body), 'the body tag is a DOM element'); ok(_.isElement(document.body), 'the body tag is a DOM element');
assert.ok(_.isElement(iElement), 'even from another frame'); ok(_.isElement(iElement), 'even from another frame');
}); });
QUnit.test('isArguments', function(assert) { test('isArguments', function() {
assert.ok(_.isArguments(iArguments), 'even from another frame'); ok(_.isArguments(iArguments), 'even from another frame');
}); });
QUnit.test('isObject', function(assert) { test('isObject', function() {
assert.ok(_.isObject(iElement), 'even from another frame'); ok(_.isObject(iElement), 'even from another frame');
assert.ok(_.isObject(iFunction), 'even from another frame'); ok(_.isObject(iFunction), 'even from another frame');
}); });
QUnit.test('isArray', function(assert) { test('isArray', function() {
assert.ok(_.isArray(iArray), 'even from another frame'); ok(_.isArray(iArray), 'even from another frame');
}); });
QUnit.test('isString', function(assert) { test('isString', function() {
assert.ok(_.isString(iString), 'even from another frame'); ok(_.isString(iString), 'even from another frame');
}); });
QUnit.test('isNumber', function(assert) { test('isNumber', function() {
assert.ok(_.isNumber(iNumber), 'even from another frame'); ok(_.isNumber(iNumber), 'even from another frame');
}); });
QUnit.test('isBoolean', function(assert) { test('isBoolean', function() {
assert.ok(_.isBoolean(iBoolean), 'even from another frame'); ok(_.isBoolean(iBoolean), 'even from another frame');
}); });
QUnit.test('isFunction', function(assert) { test('isFunction', function() {
assert.ok(_.isFunction(iFunction), 'even from another frame'); ok(_.isFunction(iFunction), 'even from another frame');
}); });
QUnit.test('isDate', function(assert) { test('isDate', function() {
assert.ok(_.isDate(iDate), 'even from another frame'); ok(_.isDate(iDate), 'even from another frame');
}); });
QUnit.test('isRegExp', function(assert) { test('isRegExp', function() {
assert.ok(_.isRegExp(iRegExp), 'even from another frame'); ok(_.isRegExp(iRegExp), 'even from another frame');
}); });
QUnit.test('isNaN', function(assert) { test('isNaN', function() {
assert.ok(_.isNaN(iNaN), 'even from another frame'); ok(_.isNaN(iNaN), 'even from another frame');
}); });
QUnit.test('isNull', function(assert) { test('isNull', function() {
assert.ok(_.isNull(iNull), 'even from another frame'); ok(_.isNull(iNull), 'even from another frame');
}); });
QUnit.test('isUndefined', function(assert) { test('isUndefined', function() {
assert.ok(_.isUndefined(iUndefined), 'even from another frame'); ok(_.isUndefined(iUndefined), 'even from another frame');
}); });
QUnit.test('isError', function(assert) { test('isError', function() {
assert.ok(_.isError(iError), 'even from another frame'); ok(_.isError(iError), 'even from another frame');
}); });
if (typeof ActiveXObject != 'undefined') { if (typeof ActiveXObject != 'undefined') {
QUnit.test('IE host objects', function(assert) { test('IE host objects', function() {
var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); var xml = new ActiveXObject('Msxml2.DOMDocument.3.0');
assert.notOk(_.isNumber(xml)); ok(!_.isNumber(xml));
assert.notOk(_.isBoolean(xml)); ok(!_.isBoolean(xml));
assert.notOk(_.isNaN(xml)); ok(!_.isNaN(xml));
assert.notOk(_.isFunction(xml)); ok(!_.isFunction(xml));
assert.notOk(_.isNull(xml)); ok(!_.isNull(xml));
assert.notOk(_.isUndefined(xml)); ok(!_.isUndefined(xml));
}); });
QUnit.test('#1621 IE 11 compat mode DOM elements are not functions', function(assert) { test('#1621 IE 11 compat mode DOM elements are not functions', function() {
var fn = function() {}; var fn = function() {};
var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); var xml = new ActiveXObject('Msxml2.DOMDocument.3.0');
var div = document.createElement('div'); var div = document.createElement('div');
@@ -132,10 +132,10 @@
_.isFunction(fn); _.isFunction(fn);
} }
assert.equal(_.isFunction(xml), false); equal(_.isFunction(xml), false);
assert.equal(_.isFunction(div), false); equal(_.isFunction(div), false);
assert.equal(_.isFunction(fn), true); equal(_.isFunction(fn), true);
}); });
} }
}()); }());

View File

@@ -4,65 +4,65 @@
QUnit.module('Functions'); QUnit.module('Functions');
QUnit.config.asyncRetries = 3; QUnit.config.asyncRetries = 3;
QUnit.test('bind', function(assert) { test('bind', function() {
var context = {name: 'moe'}; 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); var bound = _.bind(func, context);
assert.equal(bound(), 'name: moe', 'can bind a function to a context'); equal(bound(), 'name: moe', 'can bind a function to a context');
bound = _(func).bind(context); bound = _(func).bind(context);
assert.equal(bound(), 'name: moe', 'can do OO-style binding'); equal(bound(), 'name: moe', 'can do OO-style binding');
bound = _.bind(func, null, 'curly'); bound = _.bind(func, null, 'curly');
var result = bound(); var result = bound();
// Work around a PhantomJS bug when applying a function with null|undefined. // Work around a PhantomJS bug when applying a function with null|undefined.
assert.ok(result === 'name: curly' || result === 'name: ' + window.name, 'can bind without specifying a context'); ok(result === 'name: curly' || result === 'name: ' + window.name, 'can bind without specifying a context');
func = function(salutation, name) { return salutation + ': ' + name; }; func = function(salutation, name) { return salutation + ': ' + name; };
func = _.bind(func, this, 'hello'); func = _.bind(func, this, 'hello');
assert.equal(func('moe'), 'hello: moe', 'the function was partially applied in advance'); equal(func('moe'), 'hello: moe', 'the function was partially applied in advance');
func = _.bind(func, this, 'curly'); func = _.bind(func, this, 'curly');
assert.equal(func(), 'hello: curly', 'the function was completely applied in advance'); equal(func(), 'hello: curly', 'the function was completely applied in advance');
func = function(salutation, firstname, lastname) { return salutation + ': ' + firstname + ' ' + lastname; }; func = function(salutation, firstname, lastname) { return salutation + ': ' + firstname + ' ' + lastname; };
func = _.bind(func, this, 'hello', 'moe', 'curly'); func = _.bind(func, this, 'hello', 'moe', 'curly');
assert.equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments'); equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments');
func = function(ctx, message) { assert.equal(this, ctx, message); }; func = function(context, message) { equal(this, context, message); };
_.bind(func, 0, 0, 'can bind a function to `0`')(); _.bind(func, 0, 0, 'can bind a function to `0`')();
_.bind(func, '', '', 'can bind a function to an empty string')(); _.bind(func, '', '', 'can bind a function to an empty string')();
_.bind(func, false, false, 'can bind a function to `false`')(); _.bind(func, false, false, 'can bind a function to `false`')();
// These tests are only meaningful when using a browser without a native bind 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 // To test this with a modern browser, set underscore's nativeBind to undefined
var F = function() { return this; }; 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 Boundf = boundf; // make eslint happy.
var newBoundf = new Boundf(); var newBoundf = new Boundf();
assert.equal(newBoundf.hello, void 0, 'function should not be bound to the context, to comply with ECMAScript 5'); equal(newBoundf.hello, undefined, 'function should not be bound to the context, to comply with ECMAScript 5');
assert.equal(boundf().hello, 'moe curly', "When called without the new operator, it's OK to be bound to the context"); equal(boundf().hello, 'moe curly', "When called without the new operator, it's OK to be bound to the context");
assert.ok(newBoundf instanceof F, 'a bound instance is an instance of the original function'); ok(newBoundf instanceof F, 'a bound instance is an instance of the original function');
assert.raises(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function'); throws(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function');
}); });
QUnit.test('partial', function(assert) { test('partial', function() {
var obj = {name: 'moe'}; var obj = {name: 'moe'};
var func = function() { return this.name + ' ' + _.toArray(arguments).join(' '); }; var func = function() { return this.name + ' ' + _.toArray(arguments).join(' '); };
obj.func = _.partial(func, 'a', 'b'); obj.func = _.partial(func, 'a', 'b');
assert.equal(obj.func('c', 'd'), 'moe a b c d', 'can partially apply'); equal(obj.func('c', 'd'), 'moe a b c d', 'can partially apply');
obj.func = _.partial(func, _, 'b', _, 'd'); obj.func = _.partial(func, _, 'b', _, 'd');
assert.equal(obj.func('a', 'c'), 'moe a b c d', 'can partially apply with placeholders'); equal(obj.func('a', 'c'), 'moe a b c d', 'can partially apply with placeholders');
func = _.partial(function() { return arguments.length; }, _, 'b', _, 'd'); func = _.partial(function() { return arguments.length; }, _, 'b', _, 'd');
assert.equal(func('a', 'c', 'e'), 5, 'accepts more arguments than the number of placeholders'); equal(func('a', 'c', 'e'), 5, 'accepts more arguments than the number of placeholders');
assert.equal(func('a'), 4, 'accepts fewer 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'); func = _.partial(function() { return typeof arguments[2]; }, _, 'b', _, 'd');
assert.equal(func('a'), 'undefined', 'unfilled placeholders are undefined'); equal(func('a'), 'undefined', 'unfilled placeholders are undefined');
// passes context // passes context
function MyWidget(name, options) { function MyWidget(name, options) {
@@ -74,93 +74,78 @@
}; };
var MyWidgetWithCoolOpts = _.partial(MyWidget, _, {a: 1}); var MyWidgetWithCoolOpts = _.partial(MyWidget, _, {a: 1});
var widget = new MyWidgetWithCoolOpts('foo'); var widget = new MyWidgetWithCoolOpts('foo');
assert.ok(widget instanceof MyWidget, 'Can partially bind a constructor'); ok(widget instanceof MyWidget, 'Can partially bind a constructor');
assert.equal(widget.get(), 'foo', 'keeps prototype'); equal(widget.get(), 'foo', 'keeps prototype');
assert.deepEqual(widget.options, {a: 1}); deepEqual(widget.options, {a: 1});
_.partial.placeholder = obj;
func = _.partial(function() { return arguments.length; }, obj, 'b', obj, 'd');
assert.equal(func('a'), 4, 'allows the placeholder to be swapped out');
_.partial.placeholder = {};
func = _.partial(function() { return arguments.length; }, obj, 'b', obj, 'd');
assert.equal(func('a'), 5, 'swapping the placeholder preserves previously bound arguments');
_.partial.placeholder = _;
}); });
QUnit.test('bindAll', function(assert) { test('bindAll', function() {
var curly = {name: 'curly'}; var curly = {name : 'curly'}, moe = {
var moe = { name : 'moe',
name: 'moe', getName : function() { return 'name: ' + this.name; },
getName: function() { return 'name: ' + this.name; }, sayHi : function() { return 'hi: ' + this.name; }
sayHi: function() { return 'hi: ' + this.name; }
}; };
curly.getName = moe.getName; curly.getName = moe.getName;
_.bindAll(moe, 'getName', 'sayHi'); _.bindAll(moe, 'getName', 'sayHi');
curly.sayHi = moe.sayHi; curly.sayHi = moe.sayHi;
assert.equal(curly.getName(), 'name: curly', 'unbound function is bound to current object'); equal(curly.getName(), 'name: curly', 'unbound function is bound to current object');
assert.equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object'); equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object');
curly = {name: 'curly'}; curly = {name : 'curly'};
moe = { moe = {
name: 'moe', name : 'moe',
getName: function() { return 'name: ' + this.name; }, 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)); } sayLast : function() { return this.sayHi(_.last(arguments)); }
}; };
assert.raises(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named'); throws(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named');
assert.raises(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined'); throws(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined');
assert.raises(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function'); throws(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function');
_.bindAll(moe, 'sayHi', 'sayLast'); _.bindAll(moe, 'sayHi', 'sayLast');
curly.sayHi = moe.sayHi; curly.sayHi = moe.sayHi;
assert.equal(curly.sayHi(), 'hi: moe'); equal(curly.sayHi(), 'hi: moe');
var sayLast = moe.sayLast; var sayLast = moe.sayLast;
assert.equal(sayLast(1, 2, 3, 4, 5, 6, 7, 'Tom'), 'hi: moe', 'createCallback works with any number of arguments'); equal(sayLast(1, 2, 3, 4, 5, 6, 7, 'Tom'), 'hi: moe', 'createCallback works with any number of arguments');
_.bindAll(moe, ['getName']);
var getName = moe.getName;
assert.equal(getName(), 'name: moe', 'flattens arguments into a single list');
}); });
QUnit.test('memoize', function(assert) { test('memoize', function() {
var fib = function(n) { var fib = function(n) {
return n < 2 ? n : fib(n - 1) + fib(n - 2); return n < 2 ? n : fib(n - 1) + fib(n - 2);
}; };
assert.equal(fib(10), 55, 'a memoized version of fibonacci produces identical results'); equal(fib(10), 55, 'a memoized version of fibonacci produces identical results');
fib = _.memoize(fib); // Redefine `fib` for memoization fib = _.memoize(fib); // Redefine `fib` for memoization
assert.equal(fib(10), 55, 'a memoized version of fibonacci produces identical results'); equal(fib(10), 55, 'a memoized version of fibonacci produces identical results');
var o = function(str) { var o = function(str) {
return str; return str;
}; };
var fastO = _.memoize(o); var fastO = _.memoize(o);
assert.equal(o('toString'), 'toString', 'checks hasOwnProperty'); equal(o('toString'), 'toString', 'checks hasOwnProperty');
assert.equal(fastO('toString'), 'toString', 'checks hasOwnProperty'); equal(fastO('toString'), 'toString', 'checks hasOwnProperty');
// Expose the cache. // Expose the cache.
var upper = _.memoize(function(s) { var upper = _.memoize(function(s) {
return s.toUpperCase(); return s.toUpperCase();
}); });
assert.equal(upper('foo'), 'FOO'); equal(upper('foo'), 'FOO');
assert.equal(upper('bar'), 'BAR'); equal(upper('bar'), 'BAR');
assert.deepEqual(upper.cache, {foo: 'FOO', bar: 'BAR'}); deepEqual(upper.cache, {foo: 'FOO', bar: 'BAR'});
upper.cache = {foo: 'BAR', bar: 'FOO'}; upper.cache = {foo: 'BAR', bar: 'FOO'};
assert.equal(upper('foo'), 'BAR'); equal(upper('foo'), 'BAR');
assert.equal(upper('bar'), 'FOO'); equal(upper('bar'), 'FOO');
var hashed = _.memoize(function(key) { var hashed = _.memoize(function(key) {
//https://github.com/jashkenas/underscore/pull/1679#discussion_r13736209 //https://github.com/jashkenas/underscore/pull/1679#discussion_r13736209
assert.ok(/[a-z]+/.test(key), 'hasher doesn\'t change keys'); ok(/[a-z]+/.test(key), 'hasher doesn\'t change keys');
return key; return key;
}, function(key) { }, function(key) {
return key.toUpperCase(); return key.toUpperCase();
}); });
hashed('yep'); hashed('yep');
assert.deepEqual(hashed.cache, {YEP: 'yep'}, 'takes a hasher'); deepEqual(hashed.cache, {'YEP': 'yep'}, 'takes a hasher');
// Test that the hash function can be used to swizzle the key. // Test that the hash function can be used to swizzle the key.
var objCacher = _.memoize(function(value, key) { var objCacher = _.memoize(function(value, key) {
@@ -170,94 +155,78 @@
}); });
var myObj = objCacher('a', 'alpha'); var myObj = objCacher('a', 'alpha');
var myObjAlias = objCacher('b', 'alpha'); var myObjAlias = objCacher('b', 'alpha');
assert.notStrictEqual(myObj, void 0, 'object is created if second argument used as key'); notStrictEqual(myObj, undefined, 'object is created if second argument used as key');
assert.strictEqual(myObj, myObjAlias, 'object is cached if second argument used as key'); strictEqual(myObj, myObjAlias, 'object is cached if second argument used as key');
assert.strictEqual(myObj.value, 'a', 'object is not modified if second argument used as key'); strictEqual(myObj.value, 'a', 'object is not modified if second argument used as key');
}); });
QUnit.test('delay', function(assert) { asyncTest('delay', 2, function() {
assert.expect(2);
var done = assert.async();
var delayed = false; var delayed = false;
_.delay(function(){ delayed = true; }, 100); _.delay(function(){ delayed = true; }, 100);
setTimeout(function(){ assert.notOk(delayed, "didn't delay the function quite yet"); }, 50); setTimeout(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
setTimeout(function(){ assert.ok(delayed, 'delayed the function'); done(); }, 150); setTimeout(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
}); });
QUnit.test('defer', function(assert) { asyncTest('defer', 1, function() {
assert.expect(1);
var done = assert.async();
var deferred = false; var deferred = false;
_.defer(function(bool){ deferred = bool; }, true); _.defer(function(bool){ deferred = bool; }, true);
_.delay(function(){ assert.ok(deferred, 'deferred the function'); done(); }, 50); _.delay(function(){ ok(deferred, 'deferred the function'); start(); }, 50);
}); });
QUnit.test('throttle', function(assert) { asyncTest('throttle', 2, function() {
assert.expect(2);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 32); var throttledIncr = _.throttle(incr, 32);
throttledIncr(); throttledIncr(); throttledIncr(); throttledIncr();
assert.equal(counter, 1, 'incr was called immediately'); equal(counter, 1, 'incr was called immediately');
_.delay(function(){ assert.equal(counter, 2, 'incr was throttled'); done(); }, 64); _.delay(function(){ equal(counter, 2, 'incr was throttled'); start(); }, 64);
}); });
QUnit.test('throttle arguments', function(assert) { asyncTest('throttle arguments', 2, function() {
assert.expect(2);
var done = assert.async();
var value = 0; var value = 0;
var update = function(val){ value = val; }; var update = function(val){ value = val; };
var throttledUpdate = _.throttle(update, 32); var throttledUpdate = _.throttle(update, 32);
throttledUpdate(1); throttledUpdate(2); throttledUpdate(1); throttledUpdate(2);
_.delay(function(){ throttledUpdate(3); }, 64); _.delay(function(){ throttledUpdate(3); }, 64);
assert.equal(value, 1, 'updated to latest value'); equal(value, 1, 'updated to latest value');
_.delay(function(){ assert.equal(value, 3, 'updated to latest value'); done(); }, 96); _.delay(function(){ equal(value, 3, 'updated to latest value'); start(); }, 96);
}); });
QUnit.test('throttle once', function(assert) { asyncTest('throttle once', 2, function() {
assert.expect(2);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ return ++counter; }; var incr = function(){ return ++counter; };
var throttledIncr = _.throttle(incr, 32); var throttledIncr = _.throttle(incr, 32);
var result = throttledIncr(); var result = throttledIncr();
_.delay(function(){ _.delay(function(){
assert.equal(result, 1, 'throttled functions return their value'); equal(result, 1, 'throttled functions return their value');
assert.equal(counter, 1, 'incr was called once'); done(); equal(counter, 1, 'incr was called once'); start();
}, 64); }, 64);
}); });
QUnit.test('throttle twice', function(assert) { asyncTest('throttle twice', 1, function() {
assert.expect(1);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 32); var throttledIncr = _.throttle(incr, 32);
throttledIncr(); throttledIncr(); throttledIncr(); throttledIncr();
_.delay(function(){ assert.equal(counter, 2, 'incr was called twice'); done(); }, 64); _.delay(function(){ equal(counter, 2, 'incr was called twice'); start(); }, 64);
}); });
QUnit.test('more throttling', function(assert) { asyncTest('more throttling', 3, function() {
assert.expect(3);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 30); var throttledIncr = _.throttle(incr, 30);
throttledIncr(); throttledIncr(); throttledIncr(); throttledIncr();
assert.equal(counter, 1); equal(counter, 1);
_.delay(function(){ _.delay(function(){
assert.equal(counter, 2); equal(counter, 2);
throttledIncr(); throttledIncr();
assert.equal(counter, 3); equal(counter, 3);
done(); start();
}, 85); }, 85);
}); });
QUnit.test('throttle repeatedly with results', function(assert) { asyncTest('throttle repeatedly with results', 6, function() {
assert.expect(6);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ return ++counter; }; var incr = function(){ return ++counter; };
var throttledIncr = _.throttle(incr, 100); var throttledIncr = _.throttle(incr, 100);
@@ -269,19 +238,17 @@
_.delay(saveResult, 160); _.delay(saveResult, 160);
_.delay(saveResult, 230); _.delay(saveResult, 230);
_.delay(function() { _.delay(function() {
assert.equal(results[0], 1, 'incr was called once'); equal(results[0], 1, 'incr was called once');
assert.equal(results[1], 1, 'incr was throttled'); equal(results[1], 1, 'incr was throttled');
assert.equal(results[2], 1, 'incr was throttled'); equal(results[2], 1, 'incr was throttled');
assert.equal(results[3], 2, 'incr was called twice'); equal(results[3], 2, 'incr was called twice');
assert.equal(results[4], 2, 'incr was throttled'); equal(results[4], 2, 'incr was throttled');
assert.equal(results[5], 3, 'incr was called trailing'); equal(results[5], 3, 'incr was called trailing');
done(); start();
}, 300); }, 300);
}); });
QUnit.test('throttle triggers trailing call when invoked repeatedly', function(assert) { asyncTest('throttle triggers trailing call when invoked repeatedly', 2, function() {
assert.expect(2);
var done = assert.async();
var counter = 0; var counter = 0;
var limit = 48; var limit = 48;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
@@ -292,33 +259,29 @@
throttledIncr(); throttledIncr();
} }
var lastCount = counter; var lastCount = counter;
assert.ok(counter > 1); ok(counter > 1);
_.delay(function() { _.delay(function() {
assert.ok(counter > lastCount); ok(counter > lastCount);
done(); start();
}, 96); }, 96);
}); });
QUnit.test('throttle does not trigger leading call when leading is set to false', function(assert) { asyncTest('throttle does not trigger leading call when leading is set to false', 2, function() {
assert.expect(2);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 60, {leading: false}); var throttledIncr = _.throttle(incr, 60, {leading: false});
throttledIncr(); throttledIncr(); throttledIncr(); throttledIncr();
assert.equal(counter, 0); equal(counter, 0);
_.delay(function() { _.delay(function() {
assert.equal(counter, 1); equal(counter, 1);
done(); start();
}, 96); }, 96);
}); });
QUnit.test('more throttle does not trigger leading call when leading is set to false', function(assert) { asyncTest('more throttle does not trigger leading call when leading is set to false', 3, function() {
assert.expect(3);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100, {leading: false}); var throttledIncr = _.throttle(incr, 100, {leading: false});
@@ -327,83 +290,75 @@
_.delay(throttledIncr, 50); _.delay(throttledIncr, 50);
_.delay(throttledIncr, 60); _.delay(throttledIncr, 60);
_.delay(throttledIncr, 200); _.delay(throttledIncr, 200);
assert.equal(counter, 0); equal(counter, 0);
_.delay(function() { _.delay(function() {
assert.equal(counter, 1); equal(counter, 1);
}, 250); }, 250);
_.delay(function() { _.delay(function() {
assert.equal(counter, 2); equal(counter, 2);
done(); start();
}, 350); }, 350);
}); });
QUnit.test('one more throttle with leading: false test', function(assert) { asyncTest('one more throttle with leading: false test', 2, function() {
assert.expect(2);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100, {leading: false}); var throttledIncr = _.throttle(incr, 100, {leading: false});
var time = new Date; var time = new Date;
while (new Date - time < 350) throttledIncr(); while (new Date - time < 350) throttledIncr();
assert.ok(counter <= 3); ok(counter <= 3);
_.delay(function() { _.delay(function() {
assert.ok(counter <= 4); ok(counter <= 4);
done(); start();
}, 200); }, 200);
}); });
QUnit.test('throttle does not trigger trailing call when trailing is set to false', function(assert) { asyncTest('throttle does not trigger trailing call when trailing is set to false', 4, function() {
assert.expect(4);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 60, {trailing: false}); var throttledIncr = _.throttle(incr, 60, {trailing: false});
throttledIncr(); throttledIncr(); throttledIncr(); throttledIncr(); throttledIncr(); throttledIncr();
assert.equal(counter, 1); equal(counter, 1);
_.delay(function() { _.delay(function() {
assert.equal(counter, 1); equal(counter, 1);
throttledIncr(); throttledIncr(); throttledIncr(); throttledIncr();
assert.equal(counter, 2); equal(counter, 2);
_.delay(function() { _.delay(function() {
assert.equal(counter, 2); equal(counter, 2);
done(); start();
}, 96); }, 96);
}, 96); }, 96);
}); });
QUnit.test('throttle continues to function after system time is set backwards', function(assert) { asyncTest('throttle continues to function after system time is set backwards', 2, function() {
assert.expect(2);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100); var throttledIncr = _.throttle(incr, 100);
var origNowFunc = _.now; var origNowFunc = _.now;
throttledIncr(); throttledIncr();
assert.equal(counter, 1); equal(counter, 1);
_.now = function() { _.now = function () {
return new Date(2013, 0, 1, 1, 1, 1); return new Date(2013, 0, 1, 1, 1, 1);
}; };
_.delay(function() { _.delay(function() {
throttledIncr(); throttledIncr();
assert.equal(counter, 2); equal(counter, 2);
done(); start();
_.now = origNowFunc; _.now = origNowFunc;
}, 200); }, 200);
}); });
QUnit.test('throttle re-entrant', function(assert) { asyncTest('throttle re-entrant', 2, function() {
assert.expect(2);
var done = assert.async();
var sequence = [ var sequence = [
['b1', 'b2'], ['b1', 'b2'],
['c1', 'c2'] ['c1', 'c2']
@@ -419,120 +374,50 @@
}; };
throttledAppend = _.throttle(append, 32); throttledAppend = _.throttle(append, 32);
throttledAppend.call('a1', 'a2'); throttledAppend.call('a1', 'a2');
assert.equal(value, 'a1a2'); equal(value, 'a1a2');
_.delay(function(){ _.delay(function(){
assert.equal(value, 'a1a2c1c2b1b2', 'append was throttled successfully'); equal(value, 'a1a2c1c2b1b2', 'append was throttled successfully');
done(); start();
}, 100); }, 100);
}); });
QUnit.test('throttle cancel', function(assert) { asyncTest('debounce', 1, function() {
var done = assert.async();
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 32);
throttledIncr();
throttledIncr.cancel();
throttledIncr();
throttledIncr();
assert.equal(counter, 2, 'incr was called immediately');
_.delay(function(){ assert.equal(counter, 3, 'incr was throttled'); done(); }, 64);
});
QUnit.test('throttle cancel with leading: false', function(assert) {
var done = assert.async();
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 32, {leading: false});
throttledIncr();
throttledIncr.cancel();
assert.equal(counter, 0, 'incr was throttled');
_.delay(function(){ assert.equal(counter, 0, 'incr was throttled'); done(); }, 64);
});
QUnit.test('debounce', function(assert) {
assert.expect(1);
var done = assert.async();
var counter = 0; var counter = 0;
var incr = function(){ counter++; }; var incr = function(){ counter++; };
var debouncedIncr = _.debounce(incr, 32); var debouncedIncr = _.debounce(incr, 32);
debouncedIncr(); debouncedIncr(); debouncedIncr(); debouncedIncr();
_.delay(debouncedIncr, 16); _.delay(debouncedIncr, 16);
_.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); done(); }, 96); _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 96);
}); });
QUnit.test('debounce cancel', function(assert) { asyncTest('debounce asap', 4, function() {
assert.expect(1);
var done = assert.async();
var counter = 0;
var incr = function(){ counter++; };
var debouncedIncr = _.debounce(incr, 32);
debouncedIncr();
debouncedIncr.cancel();
_.delay(function(){ assert.equal(counter, 0, 'incr was not called'); done(); }, 96);
});
QUnit.test('debounce asap', function(assert) {
assert.expect(6);
var done = assert.async();
var a, b, c;
var counter = 0;
var incr = function(){ return ++counter; };
var debouncedIncr = _.debounce(incr, 64, true);
a = debouncedIncr();
b = debouncedIncr();
assert.equal(a, 1);
assert.equal(b, 1);
assert.equal(counter, 1, 'incr was called immediately');
_.delay(debouncedIncr, 16);
_.delay(debouncedIncr, 32);
_.delay(debouncedIncr, 48);
_.delay(function(){
assert.equal(counter, 1, 'incr was debounced');
c = debouncedIncr();
assert.equal(c, 2);
assert.equal(counter, 2, 'incr was called again');
done();
}, 128);
});
QUnit.test('debounce asap cancel', function(assert) {
assert.expect(4);
var done = assert.async();
var a, b; var a, b;
var counter = 0; var counter = 0;
var incr = function(){ return ++counter; }; var incr = function(){ return ++counter; };
var debouncedIncr = _.debounce(incr, 64, true); var debouncedIncr = _.debounce(incr, 64, true);
a = debouncedIncr(); a = debouncedIncr();
debouncedIncr.cancel();
b = debouncedIncr(); b = debouncedIncr();
assert.equal(a, 1); equal(a, 1);
assert.equal(b, 2); equal(b, 1);
assert.equal(counter, 2, 'incr was called immediately'); equal(counter, 1, 'incr was called immediately');
_.delay(debouncedIncr, 16); _.delay(debouncedIncr, 16);
_.delay(debouncedIncr, 32); _.delay(debouncedIncr, 32);
_.delay(debouncedIncr, 48); _.delay(debouncedIncr, 48);
_.delay(function(){ assert.equal(counter, 2, 'incr was debounced'); done(); }, 128); _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 128);
}); });
QUnit.test('debounce asap recursively', function(assert) { asyncTest('debounce asap recursively', 2, function() {
assert.expect(2);
var done = assert.async();
var counter = 0; var counter = 0;
var debouncedIncr = _.debounce(function(){ var debouncedIncr = _.debounce(function(){
counter++; counter++;
if (counter < 10) debouncedIncr(); if (counter < 10) debouncedIncr();
}, 32, true); }, 32, true);
debouncedIncr(); debouncedIncr();
assert.equal(counter, 1, 'incr was called immediately'); equal(counter, 1, 'incr was called immediately');
_.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); done(); }, 96); _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 96);
}); });
QUnit.test('debounce after system time is set backwards', function(assert) { asyncTest('debounce after system time is set backwards', 2, function() {
assert.expect(2);
var done = assert.async();
var counter = 0; var counter = 0;
var origNowFunc = _.now; var origNowFunc = _.now;
var debouncedIncr = _.debounce(function(){ var debouncedIncr = _.debounce(function(){
@@ -540,23 +425,21 @@
}, 100, true); }, 100, true);
debouncedIncr(); debouncedIncr();
assert.equal(counter, 1, 'incr was called immediately'); equal(counter, 1, 'incr was called immediately');
_.now = function() { _.now = function () {
return new Date(2013, 0, 1, 1, 1, 1); return new Date(2013, 0, 1, 1, 1, 1);
}; };
_.delay(function() { _.delay(function() {
debouncedIncr(); debouncedIncr();
assert.equal(counter, 2, 'incr was debounced successfully'); equal(counter, 2, 'incr was debounced successfully');
done(); start();
_.now = origNowFunc; _.now = origNowFunc;
}, 200); }, 200);
}); });
QUnit.test('debounce re-entrant', function(assert) { asyncTest('debounce re-entrant', 2, function() {
assert.expect(2);
var done = assert.async();
var sequence = [ var sequence = [
['b1', 'b2'] ['b1', 'b2']
]; ];
@@ -571,81 +454,80 @@
}; };
debouncedAppend = _.debounce(append, 32); debouncedAppend = _.debounce(append, 32);
debouncedAppend.call('a1', 'a2'); debouncedAppend.call('a1', 'a2');
assert.equal(value, ''); equal(value, '');
_.delay(function(){ _.delay(function(){
assert.equal(value, 'a1a2b1b2', 'append was debounced successfully'); equal(value, 'a1a2b1b2', 'append was debounced successfully');
done(); start();
}, 100); }, 100);
}); });
QUnit.test('once', function(assert) { test('once', function() {
var num = 0; var num = 0;
var increment = _.once(function(){ return ++num; }); var increment = _.once(function(){ return ++num; });
increment(); increment();
increment(); increment();
assert.equal(num, 1); equal(num, 1);
assert.equal(increment(), 1, 'stores a memo to the last value'); equal(increment(), 1, 'stores a memo to the last value');
}); });
QUnit.test('Recursive onced function.', function(assert) { test('Recursive onced function.', 1, function() {
assert.expect(1);
var f = _.once(function(){ var f = _.once(function(){
assert.ok(true); ok(true);
f(); f();
}); });
f(); f();
}); });
QUnit.test('wrap', function(assert) { test('wrap', function() {
var greet = function(name){ return 'hi: ' + name; }; var greet = function(name){ return 'hi: ' + name; };
var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); }); var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); });
assert.equal(backwards('moe'), 'hi: moe eom', 'wrapped the salutation function'); equal(backwards('moe'), 'hi: moe eom', 'wrapped the salutation function');
var inner = function(){ return 'Hello '; }; var inner = function(){ return 'Hello '; };
var obj = {name: 'Moe'}; var obj = {name : 'Moe'};
obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; }); obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; });
assert.equal(obj.hi(), 'Hello Moe'); equal(obj.hi(), 'Hello Moe');
var noop = function(){}; var noop = function(){};
var wrapped = _.wrap(noop, function(){ 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'); var ret = wrapped(['whats', 'your'], 'vector', 'victor');
assert.deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']); deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']);
}); });
QUnit.test('negate', function(assert) { test('negate', function() {
var isOdd = function(n){ return n & 1; }; var isOdd = function(n){ return n & 1; };
assert.equal(_.negate(isOdd)(2), true, 'should return the complement of the given function'); equal(_.negate(isOdd)(2), true, 'should return the complement of the given function');
assert.equal(_.negate(isOdd)(3), false, 'should return the complement of the given function'); equal(_.negate(isOdd)(3), false, 'should return the complement of the given function');
}); });
QUnit.test('compose', function(assert) { test('compose', function() {
var greet = function(name){ return 'hi: ' + name; }; var greet = function(name){ return 'hi: ' + name; };
var exclaim = function(sentence){ return sentence + '!'; }; var exclaim = function(sentence){ return sentence + '!'; };
var composed = _.compose(exclaim, greet); var composed = _.compose(exclaim, greet);
assert.equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another'); equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another');
composed = _.compose(greet, exclaim); composed = _.compose(greet, exclaim);
assert.equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative'); equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative');
// f(g(h(x, y, z))) // f(g(h(x, y, z)))
function h(x, y, z) { function h(x, y, z) {
assert.equal(arguments.length, 3, 'First function called with multiple args'); equal(arguments.length, 3, 'First function called with multiple args');
return z * y; return z * y;
} }
function g(x) { function g(x) {
assert.equal(arguments.length, 1, 'Composed function is called with 1 argument'); equal(arguments.length, 1, 'Composed function is called with 1 argument');
return x; return x;
} }
function f(x) { function f(x) {
assert.equal(arguments.length, 1, 'Composed function is called with 1 argument'); equal(arguments.length, 1, 'Composed function is called with 1 argument');
return x * 2; return x * 2;
} }
composed = _.compose(f, g, h); composed = _.compose(f, g, h);
assert.equal(composed(1, 2, 3), 12); equal(composed(1, 2, 3), 12);
}); });
QUnit.test('after', function(assert) { test('after', function() {
var testAfter = function(afterAmount, timesCalled) { var testAfter = function(afterAmount, timesCalled) {
var afterCalled = 0; var afterCalled = 0;
var after = _.after(afterAmount, function() { var after = _.after(afterAmount, function() {
@@ -655,13 +537,13 @@
return afterCalled; return afterCalled;
}; };
assert.equal(testAfter(5, 5), 1, 'after(N) should fire after being called N times'); equal(testAfter(5, 5), 1, 'after(N) should fire after being called N times');
assert.equal(testAfter(5, 4), 0, 'after(N) should not fire unless called N times'); equal(testAfter(5, 4), 0, 'after(N) should not fire unless called N times');
assert.equal(testAfter(0, 0), 0, 'after(0) should not fire immediately'); equal(testAfter(0, 0), 0, 'after(0) should not fire immediately');
assert.equal(testAfter(0, 1), 1, 'after(0) should fire when first invoked'); equal(testAfter(0, 1), 1, 'after(0) should fire when first invoked');
}); });
QUnit.test('before', function(assert) { test('before', function() {
var testBefore = function(beforeAmount, timesCalled) { var testBefore = function(beforeAmount, timesCalled) {
var beforeCalled = 0; var beforeCalled = 0;
var before = _.before(beforeAmount, function() { beforeCalled++; }); var before = _.before(beforeAmount, function() { beforeCalled++; });
@@ -669,97 +551,31 @@
return beforeCalled; return beforeCalled;
}; };
assert.equal(testBefore(5, 5), 4, 'before(N) should not fire after being called N times'); equal(testBefore(5, 5), 4, 'before(N) should not fire after being called N times');
assert.equal(testBefore(5, 4), 4, 'before(N) should fire before being called N times'); equal(testBefore(5, 4), 4, 'before(N) should fire before being called N times');
assert.equal(testBefore(0, 0), 0, 'before(0) should not fire immediately'); equal(testBefore(0, 0), 0, 'before(0) should not fire immediately');
assert.equal(testBefore(0, 1), 0, 'before(0) should not fire when first invoked'); equal(testBefore(0, 1), 0, 'before(0) should not fire when first invoked');
var context = {num: 0}; var context = {num: 0};
var increment = _.before(3, function(){ return ++this.num; }); var increment = _.before(3, function(){ return ++this.num; });
_.times(10, increment, context); _.times(10, increment, context);
assert.equal(increment(), 2, 'stores a memo to the last value'); equal(increment(), 2, 'stores a memo to the last value');
assert.equal(context.num, 2, 'provides context'); equal(context.num, 2, 'provides context');
}); });
QUnit.test('iteratee', function(assert) { test('iteratee', function() {
var identity = _.iteratee(); var identity = _.iteratee();
assert.equal(identity, _.identity, '_.iteratee is exposed as an external function.'); equal(identity, _.identity, '_.iteratee is exposed as an external function.');
function fn() { function fn() {
return arguments; return arguments;
} }
_.each([_.iteratee(fn), _.iteratee(fn, {})], function(cb) { _.each([_.iteratee(fn), _.iteratee(fn, {})], function(cb) {
assert.equal(cb().length, 0); equal(cb().length, 0);
assert.deepEqual(_.toArray(cb(1, 2, 3)), _.range(1, 4)); deepEqual(_.toArray(cb(1, 2, 3)), _.range(1, 4));
assert.deepEqual(_.toArray(cb(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), _.range(1, 11)); deepEqual(_.toArray(cb(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), _.range(1, 11));
}); });
// Test custom iteratee
var builtinIteratee = _.iteratee;
_.iteratee = function(value) {
// RegEx values return a function that returns the number of matches
if (_.isRegExp(value)) return function(obj) {
return (obj.match(value) || []).length;
};
return value;
};
var collection = ['foo', 'bar', 'bbiz'];
// Test all methods that claim to be transformed through `_.iteratee`
assert.deepEqual(_.countBy(collection, /b/g), {0: 1, 1: 1, 2: 1});
assert.equal(_.every(collection, /b/g), false);
assert.deepEqual(_.filter(collection, /b/g), ['bar', 'bbiz']);
assert.equal(_.find(collection, /b/g), 'bar');
assert.equal(_.findIndex(collection, /b/g), 1);
assert.equal(_.findKey(collection, /b/g), 1);
assert.equal(_.findLastIndex(collection, /b/g), 2);
assert.deepEqual(_.groupBy(collection, /b/g), {0: ['foo'], 1: ['bar'], 2: ['bbiz']});
assert.deepEqual(_.indexBy(collection, /b/g), {0: 'foo', 1: 'bar', 2: 'bbiz'});
assert.deepEqual(_.map(collection, /b/g), [0, 1, 2]);
assert.equal(_.max(collection, /b/g), 'bbiz');
assert.equal(_.min(collection, /b/g), 'foo');
assert.deepEqual(_.partition(collection, /b/g), [['bar', 'bbiz'], ['foo']]);
assert.deepEqual(_.reject(collection, /b/g), ['foo']);
assert.equal(_.some(collection, /b/g), true);
assert.deepEqual(_.sortBy(collection, /b/g), ['foo', 'bar', 'bbiz']);
assert.equal(_.sortedIndex(collection, 'blah', /b/g), 1);
assert.deepEqual(_.uniq(collection, /b/g), ['foo', 'bar', 'bbiz']);
var objCollection = {a: 'foo', b: 'bar', c: 'bbiz'};
assert.deepEqual(_.mapObject(objCollection, /b/g), {a: 0, b: 1, c: 2});
// Restore the builtin iteratee
_.iteratee = builtinIteratee;
});
QUnit.test('restArgs', function(assert) {
assert.expect(10);
_.restArgs(function(a, args) {
assert.strictEqual(a, 1);
assert.deepEqual(args, [2, 3], 'collects rest arguments into an array');
})(1, 2, 3);
_.restArgs(function(a, args) {
assert.strictEqual(a, void 0);
assert.deepEqual(args, [], 'passes empty array if there are not enough arguments');
})();
_.restArgs(function(a, b, c, args) {
assert.strictEqual(arguments.length, 4);
assert.deepEqual(args, [4, 5], 'works on functions with many named parameters');
})(1, 2, 3, 4, 5);
var obj = {};
_.restArgs(function() {
assert.strictEqual(this, obj, 'invokes function with this context');
}).call(obj);
_.restArgs(function(array, iteratee, context) {
assert.deepEqual(array, [1, 2, 3, 4], 'startIndex can be used manually specify index of rest parameter');
assert.strictEqual(iteratee, void 0);
assert.strictEqual(context, void 0);
}, 0)(1, 2, 3, 4);
}); });
}()); }());

File diff suppressed because it is too large Load Diff

View File

@@ -4,218 +4,181 @@
QUnit.module('Utility', { QUnit.module('Utility', {
beforeEach: function() { setup: function() {
templateSettings = _.clone(_.templateSettings); templateSettings = _.clone(_.templateSettings);
}, },
afterEach: function() { teardown: function() {
_.templateSettings = templateSettings; _.templateSettings = templateSettings;
} }
}); });
if (typeof this == 'object') { test('#750 - Return _ instance.', 2, function() {
QUnit.test('noConflict', function(assert) {
var underscore = _.noConflict();
assert.equal(underscore.identity(1), 1);
if (typeof require != 'function') {
assert.equal(this._, void 0, 'global underscore is removed');
this._ = underscore;
} else if (typeof global !== 'undefined') {
delete global._;
}
});
}
if (typeof require == 'function') {
QUnit.test('noConflict (node vm)', function(assert) {
assert.expect(2);
var done = assert.async();
var fs = require('fs');
var vm = require('vm');
var filename = __dirname + '/../underscore.js';
fs.readFile(filename, function(err, content){
var sandbox = vm.createScript(
content + 'this.underscore = this._.noConflict();',
filename
);
var context = {_: 'oldvalue'};
sandbox.runInNewContext(context);
assert.equal(context._, 'oldvalue');
assert.equal(context.underscore.VERSION, _.VERSION);
done();
});
});
}
QUnit.test('#750 - Return _ instance.', function(assert) {
assert.expect(2);
var instance = _([]); var instance = _([]);
assert.strictEqual(_(instance), instance); ok(_(instance) === instance);
assert.strictEqual(new _(instance), instance); ok(new _(instance) === instance);
}); });
QUnit.test('identity', function(assert) { test('identity', function() {
var stooge = {name: 'moe'}; var stooge = {name : 'moe'};
assert.equal(_.identity(stooge), stooge, 'stooge is the same as his identity'); equal(_.identity(stooge), stooge, 'stooge is the same as his identity');
}); });
QUnit.test('constant', function(assert) { test('constant', function() {
var stooge = {name: 'moe'}; var stooge = {name : 'moe'};
assert.equal(_.constant(stooge)(), stooge, 'should create a function that returns stooge'); equal(_.constant(stooge)(), stooge, 'should create a function that returns stooge');
}); });
QUnit.test('noop', function(assert) { test('noop', function() {
assert.strictEqual(_.noop('curly', 'larry', 'moe'), void 0, 'should always return undefined'); strictEqual(_.noop('curly', 'larry', 'moe'), undefined, 'should always return undefined');
}); });
QUnit.test('property', function(assert) { test('property', function() {
var stooge = {name: 'moe'}; var stooge = {name : 'moe'};
assert.equal(_.property('name')(stooge), 'moe', 'should return the property with the given name'); equal(_.property('name')(stooge), 'moe', 'should return the property with the given name');
assert.equal(_.property('name')(null), void 0, 'should return undefined for null values'); equal(_.property('name')(null), undefined, 'should return undefined for null values');
assert.equal(_.property('name')(void 0), void 0, 'should return undefined for undefined values'); equal(_.property('name')(undefined), undefined, 'should return undefined for undefined values');
}); });
QUnit.test('propertyOf', function(assert) { test('propertyOf', function() {
var stoogeRanks = _.propertyOf({curly: 2, moe: 1, larry: 3}); var stoogeRanks = _.propertyOf({curly: 2, moe: 1, larry: 3});
assert.equal(stoogeRanks('curly'), 2, 'should return the property with the given name'); equal(stoogeRanks('curly'), 2, 'should return the property with the given name');
assert.equal(stoogeRanks(null), void 0, 'should return undefined for null values'); equal(stoogeRanks(null), undefined, 'should return undefined for null values');
assert.equal(stoogeRanks(void 0), void 0, 'should return undefined for undefined values'); equal(stoogeRanks(undefined), undefined, 'should return undefined for undefined values');
function MoreStooges() { this.shemp = 87; } function MoreStooges() { this.shemp = 87; }
MoreStooges.prototype = {curly: 2, moe: 1, larry: 3}; MoreStooges.prototype = {curly: 2, moe: 1, larry: 3};
var moreStoogeRanks = _.propertyOf(new MoreStooges()); var moreStoogeRanks = _.propertyOf(new MoreStooges());
assert.equal(moreStoogeRanks('curly'), 2, 'should return properties from further up the prototype chain'); equal(moreStoogeRanks('curly'), 2, 'should return properties from further up the prototype chain');
var nullPropertyOf = _.propertyOf(null); var nullPropertyOf = _.propertyOf(null);
assert.equal(nullPropertyOf('curly'), void 0, 'should return undefined when obj is null'); equal(nullPropertyOf('curly'), undefined, 'should return undefined when obj is null');
var undefPropertyOf = _.propertyOf(void 0); var undefPropertyOf = _.propertyOf(undefined);
assert.equal(undefPropertyOf('curly'), void 0, 'should return undefined when obj is undefined'); equal(undefPropertyOf('curly'), undefined, 'should return undefined when obj is undefined');
}); });
QUnit.test('random', function(assert) { test('random', function() {
var array = _.range(1000); var array = _.range(1000);
var min = Math.pow(2, 31); var min = Math.pow(2, 31);
var max = Math.pow(2, 62); var max = Math.pow(2, 62);
assert.ok(_.every(array, function() { ok(_.every(array, function() {
return _.random(min, max) >= min; 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');
assert.ok(_.some(array, function() { ok(_.some(array, function() {
return _.random(Number.MAX_VALUE) > 0; 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`');
}); });
QUnit.test('now', function(assert) { test('now', function() {
var diff = _.now() - new Date().getTime(); var diff = _.now() - new Date().getTime();
assert.ok(diff <= 0 && diff > -5, 'Produces the correct time in milliseconds');//within 5ms ok(diff <= 0 && diff > -5, 'Produces the correct time in milliseconds');//within 5ms
}); });
QUnit.test('uniqueId', function(assert) { test('uniqueId', function() {
var ids = [], i = 0; var ids = [], i = 0;
while (i++ < 100) ids.push(_.uniqueId()); while (i++ < 100) ids.push(_.uniqueId());
assert.equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids'); equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids');
}); });
QUnit.test('times', function(assert) { test('times', function() {
var vals = []; var vals = [];
_.times(3, function(i) { vals.push(i); }); _.times(3, function (i) { vals.push(i); });
assert.deepEqual(vals, [0, 1, 2], 'is 0 indexed'); deepEqual(vals, [0, 1, 2], 'is 0 indexed');
// //
vals = []; vals = [];
_(3).times(function(i) { vals.push(i); }); _(3).times(function(i) { vals.push(i); });
assert.deepEqual(vals, [0, 1, 2], 'works as a wrapper'); deepEqual(vals, [0, 1, 2], 'works as a wrapper');
// collects return values // collects return values
assert.deepEqual([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');
assert.deepEqual(_.times(0, _.identity), []); deepEqual(_.times(0, _.identity), []);
assert.deepEqual(_.times(-1, _.identity), []); deepEqual(_.times(-1, _.identity), []);
assert.deepEqual(_.times(parseFloat('-Infinity'), _.identity), []); deepEqual(_.times(parseFloat('-Infinity'), _.identity), []);
}); });
QUnit.test('mixin', function(assert) { test('mixin', function() {
var ret = _.mixin({ _.mixin({
myReverse: function(string) { myReverse: function(string) {
return string.split('').reverse().join(''); return string.split('').reverse().join('');
} }
}); });
assert.equal(ret, _, 'returns the _ object to facilitate chaining'); equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _');
assert.equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _'); equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper');
assert.equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper');
}); });
QUnit.test('_.escape', function(assert) { test('_.escape', function() {
assert.equal(_.escape(null), ''); equal(_.escape(null), '');
}); });
QUnit.test('_.unescape', function(assert) { test('_.unescape', function() {
var string = 'Curly & Moe'; var string = 'Curly & Moe';
assert.equal(_.unescape(null), ''); equal(_.unescape(null), '');
assert.equal(_.unescape(_.escape(string)), string); equal(_.unescape(_.escape(string)), string);
assert.equal(_.unescape(string), string, 'don\'t unescape unnecessarily'); equal(_.unescape(string), string, 'don\'t unescape unnecessarily');
}); });
// Don't care what they escape them to just that they're escaped and can be unescaped // Don't care what they escape them to just that they're escaped and can be unescaped
QUnit.test('_.escape & unescape', function(assert) { test('_.escape & unescape', function() {
// test & (&amp;) seperately obviously // test & (&amp;) seperately obviously
var escapeCharacters = ['<', '>', '"', '\'', '`']; var escapeCharacters = ['<', '>', '"', '\'', '`'];
_.each(escapeCharacters, function(escapeChar) { _.each(escapeCharacters, function(escapeChar) {
var s = 'a ' + escapeChar + ' string escaped'; var str = 'a ' + escapeChar + ' string escaped';
var e = _.escape(s); var escaped = _.escape(str);
assert.notEqual(s, e, escapeChar + ' is escaped'); notEqual(str, escaped, escapeChar + ' is escaped');
assert.equal(s, _.unescape(e), escapeChar + ' can be unescaped'); equal(str, _.unescape(escaped), escapeChar + ' can be unescaped');
s = 'a ' + escapeChar + escapeChar + escapeChar + 'some more string' + escapeChar; str = 'a ' + escapeChar + escapeChar + escapeChar + 'some more string' + escapeChar;
e = _.escape(s); escaped = _.escape(str);
assert.equal(e.indexOf(escapeChar), -1, 'can escape multiple occurances of ' + escapeChar); equal(escaped.indexOf(escapeChar), -1, 'can escape multiple occurances of ' + escapeChar);
assert.equal(_.unescape(e), s, 'multiple occurrences of ' + escapeChar + ' can be unescaped'); equal(_.unescape(escaped), str, 'multiple occurrences of ' + escapeChar + ' can be unescaped');
}); });
// handles multiple escape characters at once // handles multiple escape characters at once
var joiner = ' other stuff '; var joiner = ' other stuff ';
var allEscaped = escapeCharacters.join(joiner); var allEscaped = escapeCharacters.join(joiner);
allEscaped += allEscaped; allEscaped += allEscaped;
assert.ok(_.every(escapeCharacters, function(escapeChar) { ok(_.every(escapeCharacters, function(escapeChar) {
return allEscaped.indexOf(escapeChar) !== -1; return allEscaped.indexOf(escapeChar) !== -1;
}), 'handles multiple characters'); }), 'handles multiple characters');
assert.ok(allEscaped.indexOf(joiner) >= 0, 'can escape multiple escape characters at the same time'); ok(allEscaped.indexOf(joiner) >= 0, 'can escape multiple escape characters at the same time');
// test & -> &amp; // test & -> &amp;
var str = 'some string & another string & yet another'; var str = 'some string & another string & yet another';
var escaped = _.escape(str); var escaped = _.escape(str);
assert.notStrictEqual(escaped.indexOf('&'), -1, 'handles & aka &amp;'); ok(escaped.indexOf('&') !== -1, 'handles & aka &amp;');
assert.equal(_.unescape(str), str, 'can unescape &amp;'); equal(_.unescape(str), str, 'can unescape &amp;');
}); });
QUnit.test('template', function(assert) { test('template', function() {
var basicTemplate = _.template("<%= thing %> is gettin' on my noives!"); var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");
var result = basicTemplate({thing: 'This'}); var result = basicTemplate({thing : 'This'});
assert.equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation'); equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation');
var sansSemicolonTemplate = _.template('A <% this %> B'); var sansSemicolonTemplate = _.template('A <% this %> B');
assert.equal(sansSemicolonTemplate(), 'A B'); equal(sansSemicolonTemplate(), 'A B');
var backslashTemplate = _.template('<%= thing %> is \\ridanculous'); var backslashTemplate = _.template('<%= thing %> is \\ridanculous');
assert.equal(backslashTemplate({thing: 'This'}), 'This is \\ridanculous'); equal(backslashTemplate({thing: 'This'}), 'This is \\ridanculous');
var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>'); var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>');
assert.equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.'); equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.');
var fancyTemplate = _.template('<ul><% ' + var fancyTemplate = _.template('<ul><% ' +
' for (var key in people) { ' + ' for (var key in people) { ' +
'%><li><%= people[key] %></li><% } %></ul>'); '%><li><%= people[key] %></li><% } %></ul>');
result = fancyTemplate({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}}); result = fancyTemplate({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
assert.equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates'); 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>'); var escapedCharsInJavascriptTemplate = _.template('<ul><% _.each(numbers.split("\\n"), function(item) { %><li><%= item %></li><% }) %></ul>');
result = escapedCharsInJavascriptTemplate({numbers: 'one\ntwo\nthree\nfour'}); result = escapedCharsInJavascriptTemplate({numbers: 'one\ntwo\nthree\nfour'});
assert.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'); 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({ result = namespaceCollisionTemplate({
@@ -226,32 +189,32 @@
3: 'p3-thumbnail.gif' 3: 'p3-thumbnail.gif'
} }
}); });
assert.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(); result = noInterpolateTemplate();
assert.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"); var quoteTemplate = _.template("It's its, not it's");
assert.equal(quoteTemplate({}), "It's its, not it's"); equal(quoteTemplate({}), "It's its, not it's");
var quoteInStatementAndBody = _.template('<% ' + var quoteInStatementAndBody = _.template('<% ' +
" if(foo == 'bar'){ " + " if(foo == 'bar'){ " +
"%>Statement quotes and 'quotes'.<% } %>"); "%>Statement quotes and 'quotes'.<% } %>");
assert.equal(quoteInStatementAndBody({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.'); var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.');
assert.equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.'); equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.');
var template = _.template('<i><%- value %></i>'); var template = _.template('<i><%- value %></i>');
result = template({value: '<script>'}); result = template({value: '<script>'});
assert.equal(result, '<i>&lt;script&gt;</i>'); equal(result, '<i>&lt;script&gt;</i>');
var stooge = { var stooge = {
name: 'Moe', name: 'Moe',
template: _.template("I'm <%= this.name %>") template: _.template("I'm <%= this.name %>")
}; };
assert.equal(stooge.template(), "I'm Moe"); equal(stooge.template(), "I'm Moe");
template = _.template('\n ' + template = _.template('\n ' +
' <%\n ' + ' <%\n ' +
@@ -259,163 +222,159 @@
' if (data) { data += 12345; }; %>\n ' + ' if (data) { data += 12345; }; %>\n ' +
' <li><%= data %></li>\n ' ' <li><%= data %></li>\n '
); );
assert.equal(template({data: 12345}).replace(/\s/g, ''), '<li>24690</li>'); equal(template({data : 12345}).replace(/\s/g, ''), '<li>24690</li>');
_.templateSettings = { _.templateSettings = {
evaluate: /\{\{([\s\S]+?)\}\}/g, evaluate : /\{\{([\s\S]+?)\}\}/g,
interpolate: /\{\{=([\s\S]+?)\}\}/g interpolate : /\{\{=([\s\S]+?)\}\}/g
}; };
var custom = _.template('<ul>{{ for (var key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>'); var custom = _.template('<ul>{{ for (var key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>');
result = custom({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}}); result = custom({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
assert.equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates'); 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"); var customQuote = _.template("It's its, not it's");
assert.equal(customQuote({}), "It's its, not it's"); equal(customQuote({}), "It's its, not it's");
quoteInStatementAndBody = _.template("{{ if(foo == 'bar'){ }}Statement quotes and 'quotes'.{{ } }}"); quoteInStatementAndBody = _.template("{{ if(foo == 'bar'){ }}Statement quotes and 'quotes'.{{ } }}");
assert.equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'."); equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'.");
_.templateSettings = { _.templateSettings = {
evaluate: /<\?([\s\S]+?)\?>/g, evaluate : /<\?([\s\S]+?)\?>/g,
interpolate: /<\?=([\s\S]+?)\?>/g interpolate : /<\?=([\s\S]+?)\?>/g
}; };
var customWithSpecialChars = _.template('<ul><? for (var key in people) { ?><li><?= people[key] ?></li><? } ?></ul>'); var customWithSpecialChars = _.template('<ul><? for (var key in people) { ?><li><?= people[key] ?></li><? } ?></ul>');
result = customWithSpecialChars({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}}); result = customWithSpecialChars({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
assert.equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates'); 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"); var customWithSpecialCharsQuote = _.template("It's its, not it's");
assert.equal(customWithSpecialCharsQuote({}), "It's its, not it's"); equal(customWithSpecialCharsQuote({}), "It's its, not it's");
quoteInStatementAndBody = _.template("<? if(foo == 'bar'){ ?>Statement quotes and 'quotes'.<? } ?>"); quoteInStatementAndBody = _.template("<? if(foo == 'bar'){ ?>Statement quotes and 'quotes'.<? } ?>");
assert.equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'."); equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'.");
_.templateSettings = { _.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g interpolate : /\{\{(.+?)\}\}/g
}; };
var mustache = _.template('Hello {{planet}}!'); var mustache = _.template('Hello {{planet}}!');
assert.equal(mustache({planet: 'World'}), 'Hello World!', 'can mimic mustache.js'); equal(mustache({planet : 'World'}), 'Hello World!', 'can mimic mustache.js');
var templateWithNull = _.template('a null undefined {{planet}}'); var templateWithNull = _.template('a null undefined {{planet}}');
assert.equal(templateWithNull({planet: 'world'}), 'a null undefined world', 'can handle missing escape and evaluate settings'); equal(templateWithNull({planet : 'world'}), 'a null undefined world', 'can handle missing escape and evaluate settings');
}); });
QUnit.test('_.template provides the generated function source, when a SyntaxError occurs', function(assert) { test('_.template provides the generated function source, when a SyntaxError occurs', function() {
var source;
try { try {
_.template('<b><%= if x %></b>'); _.template('<b><%= if x %></b>');
} catch (ex) { } catch (ex) {
source = ex.source; var source = ex.source;
} }
assert.ok(/__p/.test(source)); ok(/__p/.test(source));
}); });
QUnit.test('_.template handles \\u2028 & \\u2029', function(assert) { test('_.template handles \\u2028 & \\u2029', function() {
var tmpl = _.template('<p>\u2028<%= "\\u2028\\u2029" %>\u2029</p>'); var tmpl = _.template('<p>\u2028<%= "\\u2028\\u2029" %>\u2029</p>');
assert.strictEqual(tmpl(), '<p>\u2028\u2028\u2029\u2029</p>'); strictEqual(tmpl(), '<p>\u2028\u2028\u2029\u2029</p>');
}); });
QUnit.test('result calls functions and returns primitives', function(assert) { test('result calls functions and returns primitives', function() {
var obj = {w: '', x: 'x', y: function(){ return this.x; }}; var obj = {w: '', x: 'x', y: function(){ return this.x; }};
assert.strictEqual(_.result(obj, 'w'), ''); strictEqual(_.result(obj, 'w'), '');
assert.strictEqual(_.result(obj, 'x'), 'x'); strictEqual(_.result(obj, 'x'), 'x');
assert.strictEqual(_.result(obj, 'y'), 'x'); strictEqual(_.result(obj, 'y'), 'x');
assert.strictEqual(_.result(obj, 'z'), void 0); strictEqual(_.result(obj, 'z'), undefined);
assert.strictEqual(_.result(null, 'x'), void 0); strictEqual(_.result(null, 'x'), undefined);
}); });
QUnit.test('result returns a default value if object is null or undefined', function(assert) { test('result returns a default value if object is null or undefined', function() {
assert.strictEqual(_.result(null, 'b', 'default'), 'default'); strictEqual(_.result(null, 'b', 'default'), 'default');
assert.strictEqual(_.result(void 0, 'c', 'default'), 'default'); strictEqual(_.result(undefined, 'c', 'default'), 'default');
assert.strictEqual(_.result(''.match('missing'), 1, 'default'), 'default'); strictEqual(_.result(''.match('missing'), 1, 'default'), 'default');
}); });
QUnit.test('result returns a default value if property of object is missing', function(assert) { test('result returns a default value if property of object is missing', function() {
assert.strictEqual(_.result({d: null}, 'd', 'default'), null); strictEqual(_.result({d: null}, 'd', 'default'), null);
assert.strictEqual(_.result({e: false}, 'e', 'default'), false); strictEqual(_.result({e: false}, 'e', 'default'), false);
}); });
QUnit.test('result only returns the default value if the object does not have the property or is undefined', function(assert) { test('result only returns the default value if the object does not have the property or is undefined', function() {
assert.strictEqual(_.result({}, 'b', 'default'), 'default'); strictEqual(_.result({}, 'b', 'default'), 'default');
assert.strictEqual(_.result({d: void 0}, 'd', 'default'), 'default'); strictEqual(_.result({d: undefined}, 'd', 'default'), 'default');
}); });
QUnit.test('result does not return the default if the property of an object is found in the prototype', function(assert) { test('result does not return the default if the property of an object is found in the prototype', function() {
var Foo = function(){}; var Foo = function(){};
Foo.prototype.bar = 1; Foo.prototype.bar = 1;
assert.strictEqual(_.result(new Foo, 'bar', 2), 1); strictEqual(_.result(new Foo, 'bar', 2), 1);
}); });
QUnit.test('result does use the fallback when the result of invoking the property is undefined', function(assert) { test('result does use the fallback when the result of invoking the property is undefined', function() {
var obj = {a: function() {}}; var obj = {a: function() {}};
assert.strictEqual(_.result(obj, 'a', 'failed'), void 0); strictEqual(_.result(obj, 'a', 'failed'), undefined);
}); });
QUnit.test('result fallback can use a function', function(assert) { test('result fallback can use a function', function() {
var obj = {a: [1, 2, 3]}; var obj = {a: [1, 2, 3]};
assert.strictEqual(_.result(obj, 'b', _.constant(5)), 5); strictEqual(_.result(obj, 'b', _.constant(5)), 5);
assert.strictEqual(_.result(obj, 'b', function() { strictEqual(_.result(obj, 'b', function() {
return this.a; return this.a;
}), obj.a, 'called with context'); }), obj.a, 'called with context');
}); });
QUnit.test('_.templateSettings.variable', function(assert) { test('_.templateSettings.variable', function() {
var s = '<%=data.x%>'; var s = '<%=data.x%>';
var data = {x: 'x'}; var data = {x: 'x'};
var tmp = _.template(s, {variable: 'data'}); var tmp = _.template(s, {variable: 'data'});
assert.strictEqual(tmp(data), 'x'); strictEqual(tmp(data), 'x');
_.templateSettings.variable = 'data'; _.templateSettings.variable = 'data';
assert.strictEqual(_.template(s)(data), 'x'); strictEqual(_.template(s)(data), 'x');
}); });
QUnit.test('#547 - _.templateSettings is unchanged by custom settings.', function(assert) { test('#547 - _.templateSettings is unchanged by custom settings.', function() {
assert.notOk(_.templateSettings.variable); ok(!_.templateSettings.variable);
_.template('', {}, {variable: 'x'}); _.template('', {}, {variable: 'x'});
assert.notOk(_.templateSettings.variable); ok(!_.templateSettings.variable);
}); });
QUnit.test('#556 - undefined template variables.', function(assert) { test('#556 - undefined template variables.', function() {
var template = _.template('<%=x%>'); var template = _.template('<%=x%>');
assert.strictEqual(template({x: null}), ''); strictEqual(template({x: null}), '');
assert.strictEqual(template({x: void 0}), ''); strictEqual(template({x: undefined}), '');
var templateEscaped = _.template('<%-x%>'); var templateEscaped = _.template('<%-x%>');
assert.strictEqual(templateEscaped({x: null}), ''); strictEqual(templateEscaped({x: null}), '');
assert.strictEqual(templateEscaped({x: void 0}), ''); strictEqual(templateEscaped({x: undefined}), '');
var templateWithProperty = _.template('<%=x.foo%>'); var templateWithProperty = _.template('<%=x.foo%>');
assert.strictEqual(templateWithProperty({x: {}}), ''); strictEqual(templateWithProperty({x: {}}), '');
assert.strictEqual(templateWithProperty({x: {}}), ''); strictEqual(templateWithProperty({x: {}}), '');
var templateWithPropertyEscaped = _.template('<%-x.foo%>'); var templateWithPropertyEscaped = _.template('<%-x.foo%>');
assert.strictEqual(templateWithPropertyEscaped({x: {}}), ''); strictEqual(templateWithPropertyEscaped({x: {}}), '');
assert.strictEqual(templateWithPropertyEscaped({x: {}}), ''); strictEqual(templateWithPropertyEscaped({x: {}}), '');
}); });
QUnit.test('interpolate evaluates code only once.', function(assert) { test('interpolate evaluates code only once.', 2, function() {
assert.expect(2);
var count = 0; var count = 0;
var template = _.template('<%= f() %>'); var template = _.template('<%= f() %>');
template({f: function(){ assert.notOk(count++); }}); template({f: function(){ ok(!count++); }});
var countEscaped = 0; var countEscaped = 0;
var templateEscaped = _.template('<%- f() %>'); var templateEscaped = _.template('<%- f() %>');
templateEscaped({f: function(){ assert.notOk(countEscaped++); }}); templateEscaped({f: function(){ ok(!countEscaped++); }});
}); });
QUnit.test('#746 - _.template settings are not modified.', function(assert) { test('#746 - _.template settings are not modified.', 1, function() {
assert.expect(1);
var settings = {}; var settings = {};
_.template('', null, settings); _.template('', null, settings);
assert.deepEqual(settings, {}); deepEqual(settings, {});
}); });
QUnit.test('#779 - delimeters are applied to unescaped text.', function(assert) { test('#779 - delimeters are applied to unescaped text.', 1, function() {
assert.expect(1);
var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g}); var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g});
assert.strictEqual(template(), '<<\nx\n>>'); strictEqual(template(), '<<\nx\n>>');
}); });
}()); }());

File diff suppressed because it is too large Load Diff

3346
yarn.lock

File diff suppressed because it is too large Load Diff