Compare commits

...

38 Commits
0.8.0 ... 0.8.2

Author SHA1 Message Date
John-David Dalton
219138ade6 Bump to v0.8.2.
Former-commit-id: edbb9d995a63ec8fd5a3b1a47ccda7b30c353b35
2012-10-10 00:03:39 -07:00
John-David Dalton
9086d189b9 Update vendors.
Former-commit-id: e88301bddf23f177a2d14f2c729877eaede022e5
2012-10-09 20:11:57 -07:00
Kit Cambridge
d1178defe0 Add a note about npm link. See #88.
Former-commit-id: 11c4a9bce02e5f143b09d0edff80362e2e824b10
2012-10-09 15:22:26 -07:00
John-David Dalton
691a561a95 Merge pull request #87 from danheberden/typo_fix
Fix typo in `_.indexOf` docs.

Former-commit-id: 25305344f272cb875a612e37a93ae252a53e1b4b
2012-10-09 13:56:59 -07:00
Dan Heberden
aaaac93bd0 fix tiny baby super small almost didn't need to worry about fixing typo from isSorted to fromIndex for indexOf method
Former-commit-id: 6f2a7b3e11c4830ec47c174f24badca3ef2e6530
2012-10-09 16:53:56 -04:00
John-David Dalton
fd790566b2 Ensure _.throttle clears the timeout when func is called. [closes #86]
Former-commit-id: 6f3b777aa247f059d97f965c02323d4ee6ab8464
2012-10-09 02:15:06 -07:00
John-David Dalton
db3b429784 Update _.min, _.max, _.shuffle build dependencies.
Former-commit-id: 21c4c99f8ead92b90b46c299fee59098131758b1
2012-10-09 01:43:24 -07:00
John-David Dalton
40ed3278d4 Rebuild minified files and docs.
Former-commit-id: b14af8d9fcb9046c2faf4374fe2e6e83c4f4f835
2012-10-09 01:02:14 -07:00
John-David Dalton
d174b13111 Add object iteration unit tests for _.max, _.min, _.shuffle.
Former-commit-id: 45129100fbbfa14610cacb055c1fa393ae6ce153
2012-10-09 00:59:55 -07:00
John-David Dalton
1708663b32 Move _.max, _.min, _.shuffle back to "Collections" methods for compat but still optimized for arrays.
Former-commit-id: 28cd9298915ad123445400a5d061ac8e9432eb6b
2012-10-09 00:48:02 -07:00
John-David Dalton
6fdce4ad0d Re-optimize _.max, _.min, and _.sortedIndex.
Former-commit-id: 7f449a4fde6777f14a1def0d767f2926bdea07c9
2012-10-09 00:17:10 -07:00
John-David Dalton
fff8d5f07d Cleanup var names in lodash.js and continue to optimize for gzip.
Former-commit-id: 00d76bd7ab8b35d2b45237224662849e42d00bac
2012-10-07 22:26:23 -07:00
John-David Dalton
9c8e1f4706 Reduce _.compact and revert _.random use in _.shuffle.
Former-commit-id: 17d153cb09c262830f1497f93c0f3d9b279c8f8a
2012-10-07 19:32:56 -07:00
John-David Dalton
0a1036c78f Add unit tests to check "Collections" methods return values.
Former-commit-id: 6ac6cd97414035f74a102a51e913099e744d9a93
2012-10-07 18:18:20 -07:00
John-David Dalton
0e881a7972 Simplify _.shuffle and iterator options.
Former-commit-id: 341fd577d65725d47b26172d25b46dec2ac8e67f
2012-10-07 17:43:38 -07:00
John-David Dalton
839e52ba30 Organize docs by category. [closes #84]
Former-commit-id: f4ebda7c32a0ce9c5a86cdb0fd1e689f76557e42
2012-10-07 12:21:01 -07:00
John-David Dalton
8f7d5dcb4d Reduce lodash file size.
Former-commit-id: c6c309cbbc5f93bffb852726e831ba9f90c332a0
2012-10-06 23:39:41 -07:00
John-David Dalton
1104b28bc1 Update README.md to remove fixed Underscore issue.
Former-commit-id: 16fc177c33c2f2522fd9080c0974091ef8e97850
2012-10-06 23:38:25 -07:00
John-David Dalton
48521cb1e4 Update DocDown and Underscore.
Former-commit-id: 7744ef274a9d8b47975dc9f3e3283bd778bc5403
2012-10-06 22:31:08 -07:00
John-David Dalton
17e113dafb Update _.map to return an empty array when falsey values are passed.
Former-commit-id: 2f091fbeb140cbc0b8f3bd2df7a449a06239be0b
2012-10-06 21:17:50 -07:00
John-David Dalton
c33825a904 Reduce Underscore build and update Underscore version number.
Former-commit-id: fd631cd5525fa287c2af493bfe4a93668678977d
2012-10-06 20:58:21 -07:00
John-David Dalton
b07ef98c8f Update Backbone/Underscore vendor folders.
Former-commit-id: 3317d501fe535d91eefab8a5dcb3a88a791e20ac
2012-10-06 20:56:42 -07:00
John-David Dalton
b3d68893df Reduce deep _.clone array iteration and add _.each dependency.
Former-commit-id: 3cb599d294a693974483b892748e6f60186d0c50
2012-10-06 18:15:30 -07:00
John-David Dalton
1329599987 Simplify how deep _.clone handles booleans.
Former-commit-id: adf1d03677336131da2f62bd2fb6e2900c9889a4
2012-10-06 17:32:18 -07:00
John-David Dalton
2adf3f364c Add _.isPlainObject to the list of features in README.md. [ci skip]
Former-commit-id: ec81cdc9e7fef775871cc1c4a497e4d17e7716aa
2012-10-06 15:45:48 -07:00
John-David Dalton
436ee34a02 Simplify createIterator.
Former-commit-id: 0530a9db49488900843c6312cc0d30b1dc641120
2012-10-06 14:43:34 -07:00
John-David Dalton
4a6e17b214 Reduce lodash builds and cleanup README.md.
Former-commit-id: 3c6bbc236a35687c843a8cb27c29f71ed89d0ab0
2012-10-04 23:35:36 -07:00
John-David Dalton
6e9cbccde6 Bump to v0.8.1.
Former-commit-id: 1b63f03d4a7ca0cdc66e44cd987fddecaf88f9ce
2012-10-04 01:40:17 -07:00
John-David Dalton
a0cb8ec124 Cleanup lodash.js.
Former-commit-id: 7a2443719a96b36ae53b2f7d0fe2a1867d650f02
2012-10-04 00:28:45 -07:00
John-David Dalton
21217dfda3 Reduce createIterator.
Former-commit-id: 8c27ca8e4d1f71b2727dd988bc62194510a850dc
2012-10-04 00:02:43 -07:00
John-David Dalton
25ba18e570 Update vendors.
Former-commit-id: 94bb6b8541c223d3ef6eb8aad5fb5925f2d3be48
2012-10-03 23:21:51 -07:00
John-David Dalton
a210377f35 Add unit tests for passing falsey values to _.initial and _.rest.
Former-commit-id: 9d5d4960c175a3dd90af977b605ce309bc6446d3
2012-10-03 20:12:03 -07:00
John-David Dalton
07b9ca457f Cleanup build.js regexes.
Former-commit-id: 0d23053cd8ae20fa2268ba24b15db72c6cd7a85e
2012-10-03 09:09:40 -07:00
John-David Dalton
5f1372d39c Rebuild minified files and docs.
Former-commit-id: d8d8453fa79ab026be0acd44a1af967bdb0bc4cc
2012-10-03 09:09:20 -07:00
John-David Dalton
01b84c79f0 Revert removing falsey guards.
Former-commit-id: b5eeb5d4a0896eb030f20e7e91e54bf101535abc
2012-10-03 09:08:51 -07:00
John-David Dalton
4017443b1e Allow deep clone if requested via include or plus with the underscore build.
Former-commit-id: e86dba41f7265700330e57346a112b578873b390
2012-10-02 21:39:18 -07:00
John-David Dalton
fd2a17d244 Reduce lodash.underscore.min.js.
Former-commit-id: a5032bc542e1166fab6acfd7313c305dd8236d36
2012-10-02 01:43:49 -07:00
John-David Dalton
126804f7c3 Cleanup _.difference, _.intersecton, _.without.
Former-commit-id: 1ca8edb52a1c403fc2d8a8e1b3fd113ced9ff39e
2012-10-02 01:43:30 -07:00
28 changed files with 3883 additions and 3429 deletions

View File

@@ -1,4 +1,4 @@
# Lo-Dash <sup>v0.8.0</sup> # Lo-Dash <sup>v0.8.2</sup>
[![build status](https://secure.travis-ci.org/bestiejs/lodash.png)](http://travis-ci.org/bestiejs/lodash) [![build status](https://secure.travis-ci.org/bestiejs/lodash.png)](http://travis-ci.org/bestiejs/lodash)
A drop-in replacement<sup>[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer)</sup> for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues), and [additional features](http://lodash.com/#features). A drop-in replacement<sup>[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer)</sup> for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues), and [additional features](http://lodash.com/#features).
@@ -7,10 +7,10 @@ Lo-Dashs performance is gained by avoiding slower native methods, instead opt
## Download ## Download
* [Development build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.js) * [Development build](https://raw.github.com/bestiejs/lodash/v0.8.2/lodash.js)
* [Production build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.min.js) * [Production build](https://raw.github.com/bestiejs/lodash/v0.8.2/lodash.min.js)
* [Underscore build](https://raw.github.com/bestiejs/lodash/v0.8.0/lodash.underscore.min.js) tailored for projects already using Underscore * [Underscore build](https://raw.github.com/bestiejs/lodash/v0.8.2/lodash.underscore.min.js) tailored for projects already using Underscore
* CDN copies of ≤ [v0.8.0](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.8.0/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/) * CDN copies of ≤ [v0.8.2](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.8.2/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/)
* For optimal file size, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need * For optimal file size, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need
## Dive in ## Dive in
@@ -38,6 +38,7 @@ For more information check out these screencasts over Lo-Dash:
* [_.forEach](http://lodash.com/docs#forEach) is chainable and supports exiting iteration early * [_.forEach](http://lodash.com/docs#forEach) is chainable and supports exiting iteration early
* [_.forIn](http://lodash.com/docs#forIn) for iterating over an objects own and inherited properties * [_.forIn](http://lodash.com/docs#forIn) for iterating over an objects own and inherited properties
* [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an objects own properties * [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an objects own properties
* [_.isPlainObject](http://lodash.com/docs#isPlainObject) checks if values are created by the `Object` constructor
* [_.lateBind](http://lodash.com/docs#lateBind) for late binding * [_.lateBind](http://lodash.com/docs#lateBind) for late binding
* [_.merge](http://lodash.com/docs#merge) for a *“deep”* [_.extend](http://lodash.com/docs#extend) * [_.merge](http://lodash.com/docs#merge) for a *“deep”* [_.extend](http://lodash.com/docs#extend)
* [_.partial](http://lodash.com/docs#partial) for partial application without `this` binding * [_.partial](http://lodash.com/docs#partial) for partial application without `this` binding
@@ -48,7 +49,7 @@ For more information check out these screencasts over Lo-Dash:
## Support ## Support
Lo-Dash has been tested in at least Chrome 5-22, Firefox 1-15, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.8.11, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5. Lo-Dash has been tested in at least Chrome 5~22, Firefox 1~16, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.8.11, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5.
## Custom builds ## Custom builds
@@ -161,7 +162,9 @@ Using [npm](http://npmjs.org/):
```bash ```bash
npm install lodash npm install lodash
npm install -g lodash npm install -g lodash
npm link lodash
``` ```
In [Node.js](http://nodejs.org/) and [RingoJS v0.8.0+](http://ringojs.org/): In [Node.js](http://nodejs.org/) and [RingoJS v0.8.0+](http://ringojs.org/):
@@ -170,6 +173,8 @@ In [Node.js](http://nodejs.org/) and [RingoJS v0.8.0+](http://ringojs.org/):
var _ = require('lodash'); var _ = require('lodash');
``` ```
**Note:** If Lo-Dash is installed globally, [run `npm link lodash`](http://blog.nodejs.org/2011/03/23/npm-1-0-global-vs-local-installation/) in your projects root directory before attempting to `require` it.
In [RingoJS v0.7.0-](http://ringojs.org/): In [RingoJS v0.7.0-](http://ringojs.org/):
```js ```js
@@ -197,21 +202,20 @@ require({
## Resolved Underscore.js issues ## Resolved Underscore.js issues
* Add AMD loader support [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L118-140)] * Add AMD loader support [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L118-140)]
* Allow iteration of objects with a `length` property [[#799](https://github.com/documentcloud/underscore/pull/799), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L510-516)] * Allow iteration of objects with a `length` property [[#799](https://github.com/documentcloud/underscore/pull/799), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L510-516)]
* Ensure *“Collections”* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L470-487)] * Ensure *“Collections”* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L470-487)]
* Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L526-546)] * Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L523-547)]
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [#742](https://github.com/documentcloud/underscore/issues/742), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L142-148)] * Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [#742](https://github.com/documentcloud/underscore/issues/742), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L142-148)]
* `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L215-224)] * `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L214-225)]
* `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L267-276)] * `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L267-276)]
* `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [#718](https://github.com/documentcloud/underscore/issues/718), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L946-968)] * `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [#718](https://github.com/documentcloud/underscore/issues/718), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L968-990)]
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L465-468)] * `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L465-468)]
* `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L556-570)] * `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L553-571)]
* `_.isEmpty` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L703-708)] * `_.isEmpty` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L712-717)]
* `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L763-775)] * `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L772-784)]
* `_.keys` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L856-858)] * `_.keys` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L865-867)]
* `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L1222-1225)] * `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.8.2/test/test.js#L1243-1246)]
* `_.throttle` should work when called in a loop [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/v0.8.0/test/test.js#L1525-1535)]
## Optimized methods <sup>(50+)</sup> ## Optimized methods <sup>(50+)</sup>
@@ -274,25 +278,13 @@ require({
## Release Notes ## Release Notes
### <sup>v0.8.0</sup> ### <sup>v0.8.2</sup>
#### Compatibility Warnings #### * Ensured `_.map` returns an array when passed a falsey collection
* Ensured `_.throttle` clears its timeout when `func` is called
* Made `_.random` return `0` or `1` when no arguments are passed * Made `_.max`, `_.min`, `_.shuffle` support iterating objects
* Moved late bind functionality from `_.bind` to [_.lateBind](http://lodash.com/docs#lateBind) * Reduced `createIterator`, `_.clone`, and `_.compact`
* Removed first argument falsey checks from methods * Re-optimized `_.max`, `_.min`, and `_.sortedIndex`
* Removed support for custom `clone`, `isEqual`, `toArray` methods from<br>
`_.clone`, `_.isEqual`, and `_.toArray`
#### Changes ####
* Added `-d`/`--debug`, `-m/--minify`, `minus`, `plus`, `settings`, and `template` build options
* Added `_.isPlainObject` and `_.lateBind`
* Allowed `_.sortedIndex` to accept a property name as the `callback` argument
* Ensured methods accept a `thisArg` of `null`
* Fixed the `iife` build option to accept more values
* Made `_.times` return an array of `callback` results
* Simplified `_.max`, `_.min`, and `_.reduceRight`
The full changelog is available [here](https://github.com/bestiejs/lodash/wiki/Changelog). The full changelog is available [here](https://github.com/bestiejs/lodash/wiki/Changelog).

148
build.js
View File

@@ -67,7 +67,7 @@
'bind': ['isFunction'], 'bind': ['isFunction'],
'bindAll': ['bind', 'isFunction'], 'bindAll': ['bind', 'isFunction'],
'chain': ['mixin'], 'chain': ['mixin'],
'clone': ['extend', 'forOwn', 'isArguments', 'isPlainObject'], 'clone': ['extend', 'forEach', 'forOwn', 'isArguments', 'isPlainObject'],
'compact': [], 'compact': [],
'compose': [], 'compose': [],
'contains': [], 'contains': [],
@@ -118,10 +118,10 @@
'lastIndexOf': [], 'lastIndexOf': [],
'lateBind': ['isFunction'], 'lateBind': ['isFunction'],
'map': ['identity'], 'map': ['identity'],
'max': ['identity'], 'max': ['forEach'],
'memoize': [], 'memoize': [],
'merge': ['isArray', 'isPlainObject'], 'merge': ['isArray', 'isPlainObject'],
'min': ['identity'], 'min': ['forEach'],
'mixin': ['forEach', 'functions'], 'mixin': ['forEach', 'functions'],
'noConflict': [], 'noConflict': [],
'object': [], 'object': [],
@@ -138,7 +138,7 @@
'reject': ['identity'], 'reject': ['identity'],
'rest': [], 'rest': [],
'result': ['isFunction'], 'result': ['isFunction'],
'shuffle': [], 'shuffle': ['forEach'],
'size': ['keys'], 'size': ['keys'],
'some': ['identity'], 'some': ['identity'],
'sortBy': ['identity'], 'sortBy': ['identity'],
@@ -542,7 +542,7 @@
function matchFunction(source, funcName) { function matchFunction(source, funcName) {
var result = source.match(RegExp( var result = source.match(RegExp(
// match multi-line comment block (could be on a single line) // match multi-line comment block (could be on a single line)
'\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/\\n' + '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/\\n)?' +
// begin non-capturing group // begin non-capturing group
'(?:' + '(?:' +
// match a function declaration // match a function declaration
@@ -684,7 +684,7 @@
// remove `isKeysFast` from `inLoop.object` of `mapIteratorOptions`, `invoke`, `pairs`, `pluck`, and `sortBy` // remove `isKeysFast` from `inLoop.object` of `mapIteratorOptions`, `invoke`, `pairs`, `pluck`, and `sortBy`
.replace(/'\s*\+\s*\(isKeysFast[^)]+?\)\s*\+\s*'/g, '.push') .replace(/'\s*\+\s*\(isKeysFast[^)]+?\)\s*\+\s*'/g, '.push')
// remove data object property assignment in `createIterator` // remove data object property assignment in `createIterator`
.replace(/\s*.+?\.isKeysFast *=.+/, ''); .replace(/ *'isKeysFast':.+\n/, '');
} }
/** /**
@@ -733,16 +733,12 @@
source = source.replace(RegExp('(var ' + varName + ' *=)[\\s\\S]+?(true;\\n)'), '$1$2'); source = source.replace(RegExp('(var ' + varName + ' *=)[\\s\\S]+?(true;\\n)'), '$1$2');
} }
source = source.replace(RegExp( source = source.replace(RegExp(
// begin non-capturing group
'(?:' +
// match multi-line comment block // match multi-line comment block
'(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' + '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' +
// match a variable declaration that's not part of a declaration list // match a variable declaration that's not part of a declaration list
'( +)var ' + varName + ' *= *(?:.+?(?:;|&&\\n[^;]+;)|(?:\\w+\\(|{)[\\s\\S]+?\\n\\1.+?;)\\n|' + '( +)var ' + varName + ' *= *(?:.+?(?:;|&&\\n[^;]+;)|(?:\\w+\\(|{)[\\s\\S]+?\\n\\1.+?;)\\n|' +
// match a variable in a declaration list // match a variable in a declaration list
'\\n +' + varName + ' *=.+?,' + '\\n +' + varName + ' *=.+?,'
// end non-capturing group
')'
), ''); ), '');
// remove a varaible at the start of a variable declaration list // remove a varaible at the start of a variable declaration list
@@ -799,10 +795,8 @@
.replace(/(?: *\/\/.*\n)*(\s*)' *<% *if *\(useStrict\).+/, value ? "$1'\\'use strict\\';\\n' +" : '') .replace(/(?: *\/\/.*\n)*(\s*)' *<% *if *\(useStrict\).+/, value ? "$1'\\'use strict\\';\\n' +" : '')
// remove `useStrict` from iterator options // remove `useStrict` from iterator options
.replace(/ *'useStrict': *false,\n/g, '') .replace(/ *'useStrict': *false,\n/g, '')
// remove `useStrict` variable assignment in `createIterator`
.replace(/,\s*useStrict *=[^;]+/, '')
// remove `useStrict` data object property assignment in `createIterator` // remove `useStrict` data object property assignment in `createIterator`
.replace(/\s*.+?\.useStrict *=.+/, ''); .replace(/ *'useStrict':.+\n/, '');
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -954,6 +948,9 @@
// flag used to specify if the build should include the "use strict" directive // flag used to specify if the build should include the "use strict" directive
var useStrict = isStrict || !(isLegacy || isMobile); var useStrict = isStrict || !(isLegacy || isMobile);
// flag used to specify replacing Lo-Dash's `_.clone` with Underscore's
var useUnderscoreClone = isUnderscore;
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
// names of methods to include in the build // names of methods to include in the build
@@ -978,6 +975,11 @@
(result = getDependencies(optionToMethodsArray(source, value))); (result = getDependencies(optionToMethodsArray(source, value)));
}); });
// use Lo-Dash's clone if explicitly requested
if (result && result.indexOf('clone') > -1) {
useUnderscoreClone = false;
}
// add method names required by Backbone and Underscore builds // add method names required by Backbone and Underscore builds
if (isBackbone && !result) { if (isBackbone && !result) {
result = getDependencies(backboneDependencies); result = getDependencies(backboneDependencies);
@@ -1033,7 +1035,7 @@
} }
} }
if (isLegacy) { if (isLegacy) {
_.each(['isBindFast', 'isKeysFast', 'isStrictFast', 'nativeBind', 'nativeGetPrototypeOf', 'nativeIsArray', 'nativeKeys'], function(varName) { _.each(['getPrototypeOf', 'isBindFast', 'isKeysFast', 'isStrictFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'], function(varName) {
source = replaceVar(source, varName, 'false'); source = replaceVar(source, varName, 'false');
}); });
@@ -1042,7 +1044,6 @@
} }
else if (isUnderscore) { else if (isUnderscore) {
// update dependencies // update dependencies
dependencyMap.clone = ['extend', 'isArray'];
dependencyMap.isEqual = ['isArray', 'isFunction']; dependencyMap.isEqual = ['isArray', 'isFunction'];
dependencyMap.isEmpty = ['isArray']; dependencyMap.isEmpty = ['isArray'];
@@ -1050,17 +1051,79 @@
source = removeVar(source, 'arrayLikeClasses'); source = removeVar(source, 'arrayLikeClasses');
source = removeVar(source, 'cloneableClasses'); source = removeVar(source, 'cloneableClasses');
// remove large array optimizations from `cachedContains` // remove large array optimizations
source = source.replace(/( +)function cachedContains[\s\S]+?\n\1}/, [ source = removeFunction(source, 'cachedContains');
' function cachedContains(array, fromIndex) {', source = removeVar(source, 'largeArraySize');
' return function(value) {',
' return indexOf(array, value, fromIndex || 0) > -1;', // replace `_.clone`
' };', if (useUnderscoreClone) {
dependencyMap.clone = ['extend', 'isArray'];
source = source.replace(/^( +)function clone[\s\S]+?\n\1}/m, [
' function clone(value) {',
' return value && objectTypes[typeof value]',
' ? (isArray(value) ? slice.call(value) : extend({}, value))',
' : value',
' }'
].join('\n'));
}
// replace `_.difference`
source = source.replace(/^( +)function difference[\s\S]+?\n\1}/m, [
' function difference(array) {',
' var index = -1,',
' length = array.length,',
' flattened = concat.apply(ArrayProto, arguments),',
' result = [];',
'',
' while (++index < length) {',
' var value = array[index]',
' if (indexOf(flattened, value, length) < 0) {',
' result.push(value);',
' }',
' }',
' return result',
' }' ' }'
].join('\n')); ].join('\n'));
// reduce the number of arguments passed to `cachedContains` from 3 to 2 // replace `_.intersection`
source = source.replace(/(cachedContains\(\w+, *\w+), *\w+/g, '$1'); source = source.replace(/^( +)function intersection[\s\S]+?\n\1}/m, [
' function intersection(array) {',
' var argsLength = arguments.length,',
' index = -1,',
' length = array.length,',
' result = [];',
'',
' array: while (++index < length) {',
' var value = array[index]',
' if (indexOf(result, value) < 0) {',
' for (var argsIndex = 1; argsIndex < argsLength; argsIndex++) {',
' if (indexOf(arguments[argsIndex], value) < 0) {',
' continue array;',
' }',
' }',
' result.push(value);',
' }',
' }',
' return result',
' }'
].join('\n'));
// replace `_.without`
source = source.replace(/^( +)function without[\s\S]+?\n\1}/m, [
' function without(array) {',
' var index = -1,',
' length = array.length,',
' result = [];',
'',
' while (++index < length) {',
' var value = array[index]',
' if (indexOf(arguments, value, 1) < 0) {',
' result.push(value);',
' }',
' }',
' return result',
' }'
].join('\n'));
// replace `arrayLikeClasses` in `_.isEmpty` // replace `arrayLikeClasses` in `_.isEmpty`
source = source.replace(/'if *\(arrayLikeClasses[\s\S]+?' \|\|\\n/, "'if (isArray(value) || className == stringClass ||"); source = source.replace(/'if *\(arrayLikeClasses[\s\S]+?' \|\|\\n/, "'if (isArray(value) || className == stringClass ||");
@@ -1069,19 +1132,10 @@
source = source.replace(/(?: *\/\/.*\n)*( +)var isArr *= *arrayLikeClasses[^}]+}/, '$1var isArr = isArray(a);'); source = source.replace(/(?: *\/\/.*\n)*( +)var isArr *= *arrayLikeClasses[^}]+}/, '$1var isArr = isArray(a);');
// remove "exit early" feature from `_.each` // remove "exit early" feature from `_.each`
source = source.replace(/( )+var baseIteratorOptions *=[\s\S]+?\n\1.+?;/, function(match) { source = source.replace(/( +)var baseIteratorOptions *=[\s\S]+?\n\1.+?;/, function(match) {
return match.replace(/if *\(callback[^']+/, 'callback(value, index, collection)'); return match.replace(/if *\(callback[^']+/, 'callback(value, index, collection)');
}); });
// remove `deep` clone functionality
source = source.replace(/( +)function clone[\s\S]+?\n\1}/, [
' function clone(value) {',
' return value && objectTypes[typeof value]',
' ? (isArray(value) ? slice.call(value) : extend({}, value))',
' : value',
' }'
].join('\n'));
// remove unused features from `createBound` // remove unused features from `createBound`
if (buildMethods.indexOf('partial') == -1) { if (buildMethods.indexOf('partial') == -1) {
source = source.replace(matchFunction(source, 'createBound'), function(match) { source = source.replace(matchFunction(source, 'createBound'), function(match) {
@@ -1180,6 +1234,8 @@
source = removeFromCreateIterator(source, 'nativeKeys'); source = removeFromCreateIterator(source, 'nativeKeys');
} }
/*----------------------------------------------------------------------*/
if (isMobile) { if (isMobile) {
// inline all functions defined with `createIterator` // inline all functions defined with `createIterator`
_.functions(lodash).forEach(function(methodName) { _.functions(lodash).forEach(function(methodName) {
@@ -1200,8 +1256,14 @@
}); });
if (isUnderscore) { if (isUnderscore) {
// remove "compiled template cleanup" from `_.template`
source = source.replace(/(?:\s*\/\/.*)*\n *source *=.+?isEvaluating.+?reEmptyStringLeading[\s\S]+?\);/, '');
source = removeVar(source, 'reEmptyStringLeading');
source = removeVar(source, 'reEmptyStringMiddle');
source = removeVar(source, 'reEmptyStringTrailing');
// replace `isArguments` and its fallback
(function() { (function() {
// replace `isArguments` and its fallback
var snippet = matchFunction(source, 'isArguments') var snippet = matchFunction(source, 'isArguments')
.replace(/function isArguments/, 'lodash.isArguments = function'); .replace(/function isArguments/, 'lodash.isArguments = function');
@@ -1216,10 +1278,13 @@
} }
else { else {
source = removeIsArgumentsFallback(source); source = removeIsArgumentsFallback(source);
}
// remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, `noArgsEnum` assignment // remove `hasDontEnumBug`, `hasObjectSpliceBug`, `iteratesOwnLast`, `noArgsEnum` assignment
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b[\s\S]+?}\(1\)\);\n/, ''); source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b[\s\S]+?}\(1\)\);\n/, '');
// remove `hasObjectSpliceBug` fix from the mutator Array functions mixin
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasObjectSpliceBug[\s\S]+?\n\1}/, '');
}
// remove `iteratesOwnLast` from `isPlainObject` // remove `iteratesOwnLast` from `isPlainObject`
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(iteratesOwnLast[\s\S]+?\n\1}/, ''); source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(iteratesOwnLast[\s\S]+?\n\1}/, '');
@@ -1227,9 +1292,6 @@
// remove JScript [[DontEnum]] fix from `_.isEqual` // remove JScript [[DontEnum]] fix from `_.isEqual`
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasDontEnumBug[\s\S]+?\n\1}/, ''); source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasDontEnumBug[\s\S]+?\n\1}/, '');
// remove `hasObjectSpliceBug` fix from the mutator Array functions mixin
source = source.replace(/(?:\s*\/\/.*)*\n( +)if *\(hasObjectSpliceBug[\s\S]+?\n\1}/, '');
// remove `noArraySliceOnStrings` from `_.toArray` // remove `noArraySliceOnStrings` from `_.toArray`
source = source.replace(/noArraySliceOnStrings *\?[^:]+: *([^)]+)/g, '$1'); source = source.replace(/noArraySliceOnStrings *\?[^:]+: *([^)]+)/g, '$1');
@@ -1262,7 +1324,7 @@
.replace(/__p *\+= *' *';/g, '') .replace(/__p *\+= *' *';/g, '')
.replace(/(__p *\+= *)' *' *\+/g, '$1') .replace(/(__p *\+= *)' *' *\+/g, '$1')
.replace(/(\{) *;|; *(\})/g, '$1$2') .replace(/(\{) *;|; *(\})/g, '$1$2')
.replace(/\(\(__t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__t\)/g, '$1'); .replace(/\(\(__t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__t\)/g, '($1)');
// remove the with-statement // remove the with-statement
snippet = snippet.replace(/ *with *\(.+?\) *{/, '\n').replace(/}([^}]*}[^}]*$)/, '$1'); snippet = snippet.replace(/ *with *\(.+?\) *{/, '\n').replace(/}([^}]*}[^}]*$)/, '$1');
@@ -1366,7 +1428,7 @@
source = removeVar(source, 'nativeIsArray'); source = removeVar(source, 'nativeIsArray');
} }
if (isRemoved(source, 'isPlainObject')) { if (isRemoved(source, 'isPlainObject')) {
source = removeVar(source, 'nativeGetPrototypeOf'); source = removeVar(source, 'getPrototypeOf');
} }
if (isRemoved(source, 'keys')) { if (isRemoved(source, 'keys')) {
source = removeFunction(source, 'shimKeys'); source = removeFunction(source, 'shimKeys');

View File

@@ -10,7 +10,7 @@
'lodash': 'lodash':
'/*!\n' + '/*!\n' +
' Lo-Dash @VERSION lodash.com/license\n' + ' Lo-Dash @VERSION lodash.com/license\n' +
' Underscore.js 1.4.0 underscorejs.org/LICENSE\n' + ' Underscore.js 1.4.2 underscorejs.org/LICENSE\n' +
'*/', '*/',
'underscore': 'underscore':
'/*! Underscore.js @VERSION underscorejs.org/LICENSE */' '/*! Underscore.js @VERSION underscorejs.org/LICENSE */'

View File

@@ -15,7 +15,6 @@
'createCallback', 'createCallback',
'ctor', 'ctor',
'hasOwnProperty', 'hasOwnProperty',
'identity',
'index', 'index',
'iteratee', 'iteratee',
'length', 'length',

File diff suppressed because it is too large Load Diff

View File

@@ -20,9 +20,10 @@
// generate Markdown // generate Markdown
$markdown = docdown(array( $markdown = docdown(array(
'path' => '../' . $file, 'path' => '../' . $file,
'title' => 'Lo-Dash <sup>v0.8.0</sup>', 'title' => 'Lo-Dash <sup>v0.8.2</sup>',
'url' => 'https://github.com/bestiejs/lodash/blob/master/lodash.js' 'toc' => 'categories',
'url' => 'https://github.com/bestiejs/lodash/blob/master/lodash.js'
)); ));
// save to a .md file // save to a .md file

517
lodash.js
View File

@@ -1,7 +1,7 @@
/*! /*!
* Lo-Dash v0.8.0 <http://lodash.com> * Lo-Dash v0.8.2 <http://lodash.com>
* (c) 2012 John-David Dalton <http://allyoucanleet.com/> * (c) 2012 John-David Dalton <http://allyoucanleet.com/>
* Based on Underscore.js 1.4.0 <http://underscorejs.org> * Based on Underscore.js 1.4.2 <http://underscorejs.org>
* (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
* Available under MIT license <http://lodash.com/license> * Available under MIT license <http://lodash.com/license>
*/ */
@@ -71,7 +71,10 @@
var templateCounter = 0; var templateCounter = 0;
/** Native method shortcuts */ /** Native method shortcuts */
var concat = ArrayProto.concat, var ceil = Math.ceil,
concat = ArrayProto.concat,
floor = Math.floor,
getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
hasOwnProperty = ObjectProto.hasOwnProperty, hasOwnProperty = ObjectProto.hasOwnProperty,
push = ArrayProto.push, push = ArrayProto.push,
propertyIsEnumerable = ObjectProto.propertyIsEnumerable, propertyIsEnumerable = ObjectProto.propertyIsEnumerable,
@@ -80,8 +83,6 @@
/* Native method shortcuts for methods with the same name as other `lodash` methods */ /* Native method shortcuts for methods with the same name as other `lodash` methods */
var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind, var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind,
nativeFloor = Math.floor,
nativeGetPrototypeOf = reNative.test(nativeGetPrototypeOf = Object.getPrototypeOf) && nativeGetPrototypeOf,
nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
nativeIsFinite = window.isFinite, nativeIsFinite = window.isFinite,
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys, nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
@@ -235,6 +236,7 @@
* *
* @name _ * @name _
* @constructor * @constructor
* @category Chaining
* @param {Mixed} value The value to wrap in a `lodash` instance. * @param {Mixed} value The value to wrap in a `lodash` instance.
* @returns {Object} Returns a `lodash` instance. * @returns {Object} Returns a `lodash` instance.
*/ */
@@ -314,7 +316,9 @@
// the `iteratee` may be reassigned by the `top` snippet // the `iteratee` may be reassigned by the `top` snippet
'var index, value, iteratee = <%= firstArg %>, ' + 'var index, value, iteratee = <%= firstArg %>, ' +
// assign the `result` variable an initial value // assign the `result` variable an initial value
'result<% if (init) { %> = <%= init %><% } %>;\n' + 'result = <%= init || firstArg %>;\n' +
// exit early if the first argument is falsey
'if (!<%= firstArg %>) return result;\n' +
// add code before the iteration branches // add code before the iteration branches
'<%= top %>;\n' + '<%= top %>;\n' +
@@ -427,7 +431,6 @@
*/ */
var baseIteratorOptions = { var baseIteratorOptions = {
'args': 'collection, callback, thisArg', 'args': 'collection, callback, thisArg',
'init': 'collection',
'top': 'callback = createCallback(callback, thisArg)', 'top': 'callback = createCallback(callback, thisArg)',
'inLoop': 'if (callback(value, index, collection) === false) return result' 'inLoop': 'if (callback(value, index, collection) === false) return result'
}; };
@@ -452,7 +455,6 @@
'useHas': false, 'useHas': false,
'useStrict': false, 'useStrict': false,
'args': 'object', 'args': 'object',
'init': 'object',
'top': 'top':
'for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {\n' + 'for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {\n' +
' if (iteratee = arguments[argsIndex]) {', ' if (iteratee = arguments[argsIndex]) {',
@@ -480,7 +482,7 @@
/** Reusable iterator options for `invoke`, `map`, `pluck`, and `sortBy` */ /** Reusable iterator options for `invoke`, `map`, `pluck`, and `sortBy` */
var mapIteratorOptions = { var mapIteratorOptions = {
'init': '', 'init': 'collection || []',
'beforeLoop': { 'beforeLoop': {
'array': 'result = Array(length)', 'array': 'result = Array(length)',
'object': 'result = ' + (isKeysFast ? 'Array(length)' : '[]') 'object': 'result = ' + (isKeysFast ? 'Array(length)' : '[]')
@@ -529,13 +531,11 @@
if (isLarge) { if (isLarge) {
// init value cache // init value cache
var key, var index = fromIndex - 1;
index = fromIndex - 1;
while (++index < length) { while (++index < length) {
// manually coerce `value` to string because `hasOwnProperty`, in some // manually coerce `value` to string because `hasOwnProperty`, in some
// older versions of Firefox, coerces objects incorrectly // older versions of Firefox, coerces objects incorrectly
key = array[index] + ''; var key = array[index] + '';
(hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = [])).push(array[index]); (hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = [])).push(array[index]);
} }
} }
@@ -664,14 +664,11 @@
* @private * @private
* @param {Object} [options1, options2, ...] The compile options objects. * @param {Object} [options1, options2, ...] The compile options objects.
* *
* useHas - A boolean to specify whether or not to use `hasOwnProperty` checks * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop.
* in the object loop.
* *
* useStrict - A boolean to specify whether or not to include the ES5 * useStrict - A boolean to specify including the "use strict" directive.
* "use strict" directive.
* *
* args - A string of comma separated arguments the iteration function will * args - A string of comma separated arguments the iteration function will accept.
* accept.
* *
* init - A string to specify the initial value of the `result` variable. * init - A string to specify the initial value of the `result` variable.
* *
@@ -689,61 +686,49 @@
* @returns {Function} Returns the compiled function. * @returns {Function} Returns the compiled function.
*/ */
function createIterator() { function createIterator() {
var object,
prop,
value,
index = -1,
length = arguments.length;
// merge options into a template data object
var data = { var data = {
'bottom': '', 'bottom': '',
'hasDontEnumBug': hasDontEnumBug,
'init': '',
'isKeysFast': isKeysFast,
'noArgsEnum': noArgsEnum,
'noCharByIndex': noCharByIndex,
'shadowed': shadowed,
'top': '', 'top': '',
'useHas': true,
'useStrict': isStrictFast,
'arrayBranch': { 'beforeLoop': '' }, 'arrayBranch': { 'beforeLoop': '' },
'objectBranch': { 'beforeLoop': '' } 'objectBranch': { 'beforeLoop': '' }
}; };
while (++index < length) { var object,
object = arguments[index]; index = -1;
for (prop in object) {
value = (value = object[prop]) == null ? '' : value; // merge options into a template data object
while (object = arguments[++index]) {
for (var prop in object) {
var value = object[prop];
// keep this regexp explicit for the build pre-process // keep this regexp explicit for the build pre-process
if (/beforeLoop|inLoop/.test(prop)) { if (/beforeLoop|inLoop/.test(prop)) {
if (typeof value == 'string') { if (typeof value == 'string') {
value = { 'array': value, 'object': value }; value = { 'array': value, 'object': value };
} }
data.arrayBranch[prop] = value.array || ''; data.arrayBranch[prop] = value.array;
data.objectBranch[prop] = value.object || ''; data.objectBranch[prop] = value.object;
} else { } else {
data[prop] = value; data[prop] = value;
} }
} }
} }
// set additional template `data` values // set additional template `data` properties
var args = data.args, var args = data.args;
firstArg = /^[^,]+/.exec(args)[0], if ((data.firstArg = /^[^,]+/.exec(args)[0]) != 'collection' || !data.arrayBranch.inLoop) {
init = data.init,
useStrict = data.useStrict;
data.firstArg = firstArg;
data.hasDontEnumBug = hasDontEnumBug;
data.init = init == null ? firstArg : init;
data.isKeysFast = isKeysFast;
data.noArgsEnum = noArgsEnum;
data.shadowed = shadowed;
data.useHas = data.useHas !== false;
data.useStrict = useStrict == null ? isStrictFast : useStrict;
if (data.noCharByIndex == null) {
data.noCharByIndex = noCharByIndex;
}
if (firstArg != 'collection' || !data.arrayBranch.inLoop) {
data.arrayBranch = null; data.arrayBranch = null;
} }
// create the function factory // create the function factory
var factory = Function( var factory = Function(
'arrayLikeClasses, ArrayProto, bind, compareAscending, concat, createCallback, ' + 'arrayLikeClasses, ArrayProto, bind, compareAscending, concat, createCallback, ' +
'forIn, hasOwnProperty, identity, indexOf, isArguments, isArray, isFunction, ' + 'forIn, hasOwnProperty, indexOf, isArguments, isArray, isFunction, ' +
'isPlainObject, objectClass, objectTypes, nativeKeys, propertyIsEnumerable, ' + 'isPlainObject, objectClass, objectTypes, nativeKeys, propertyIsEnumerable, ' +
'slice, stringClass, toString, undefined', 'slice, stringClass, toString, undefined',
'var callee = function(' + args + ') {\n' + iteratorTemplate(data) + '\n};\n' + 'var callee = function(' + args + ') {\n' + iteratorTemplate(data) + '\n};\n' +
@@ -752,7 +737,7 @@
// return the compiled function // return the compiled function
return factory( return factory(
arrayLikeClasses, ArrayProto, bind, compareAscending, concat, createCallback, arrayLikeClasses, ArrayProto, bind, compareAscending, concat, createCallback,
forIn, hasOwnProperty, identity, indexOf, isArguments, isArray, isFunction, forIn, hasOwnProperty, indexOf, isArguments, isArray, isFunction,
isPlainObject, objectClass, objectTypes, nativeKeys, propertyIsEnumerable, isPlainObject, objectClass, objectTypes, nativeKeys, propertyIsEnumerable,
slice, stringClass, toString slice, stringClass, toString
); );
@@ -844,7 +829,7 @@
// fallback for browsers that can't detect `arguments` objects by [[Class]] // fallback for browsers that can't detect `arguments` objects by [[Class]]
if (noArgsClass) { if (noArgsClass) {
isArguments = function(value) { isArguments = function(value) {
return !!(value && hasOwnProperty.call(value, 'callee')); return value ? hasOwnProperty.call(value, 'callee') : false;
}; };
} }
@@ -915,15 +900,15 @@
* _.isPlainObject({ 'name': 'moe', 'age': 40 }); * _.isPlainObject({ 'name': 'moe', 'age': 40 });
* // => true * // => true
*/ */
var isPlainObject = !nativeGetPrototypeOf ? isPlainFallback : function(value) { var isPlainObject = !getPrototypeOf ? isPlainFallback : function(value) {
if (!(value && typeof value == 'object')) { if (!(value && typeof value == 'object')) {
return false; return false;
} }
var valueOf = value.valueOf, var valueOf = value.valueOf,
objProto = typeof valueOf == 'function' && (objProto = nativeGetPrototypeOf(valueOf)) && nativeGetPrototypeOf(objProto); objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
return objProto return objProto
? value == objProto || (nativeGetPrototypeOf(value) == objProto && !isArguments(value)) ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value))
: isPlainFallback(value); : isPlainFallback(value);
}; };
@@ -981,7 +966,6 @@
var shimKeys = createIterator({ var shimKeys = createIterator({
'args': 'object', 'args': 'object',
'init': '[]', 'init': '[]',
'top': 'if (!(object && objectTypes[typeof object])) throw TypeError()',
'inLoop': 'result.push(index)' 'inLoop': 'result.push(index)'
}); });
@@ -1071,8 +1055,6 @@
var ctor = value.constructor; var ctor = value.constructor;
switch (className) { switch (className) {
case boolClass: case boolClass:
return new ctor(value == true);
case dateClass: case dateClass:
return new ctor(+value); return new ctor(+value);
@@ -1083,7 +1065,6 @@
case regexpClass: case regexpClass:
return ctor(value.source, reFlags.exec(value)); return ctor(value.source, reFlags.exec(value));
} }
// check for circular references and return corresponding clone // check for circular references and return corresponding clone
stackA || (stackA = []); stackA || (stackA = []);
stackB || (stackB = []); stackB || (stackB = []);
@@ -1094,9 +1075,8 @@
return stackB[length]; return stackB[length];
} }
} }
// init cloned object // init cloned object
var result = isArr ? ctor(length = value.length) : {}; var result = isArr ? ctor(value.length) : {};
// add the source value to the stack of traversed objects // add the source value to the stack of traversed objects
// and associate it with its clone // and associate it with its clone
@@ -1104,16 +1084,10 @@
stackB.push(result); stackB.push(result);
// recursively populate clone (susceptible to call stack limits) // recursively populate clone (susceptible to call stack limits)
if (isArr) { (isArr ? forEach : forOwn)(value, function(objValue, key) {
var index = -1; result[key] = clone(objValue, deep, null, stackA, stackB);
while (++index < length) { });
result[index] = clone(value[index], deep, null, stackA, stackB);
}
} else {
forOwn(value, function(objValue, key) {
result[key] = clone(objValue, deep, null, stackA, stackB);
});
}
return result; return result;
} }
@@ -1230,7 +1204,7 @@
'useHas': false, 'useHas': false,
'args': 'object', 'args': 'object',
'init': '[]', 'init': '[]',
'inLoop': 'if (isFunction(value)) result.push(index)', 'inLoop': 'isFunction(value) && result.push(index)',
'bottom': 'result.sort()' 'bottom': 'result.sort()'
}); });
@@ -1250,7 +1224,7 @@
* // => true * // => true
*/ */
function has(object, property) { function has(object, property) {
return hasOwnProperty.call(object, property); return object ? hasOwnProperty.call(object, property) : false;
} }
/** /**
@@ -1329,7 +1303,6 @@
'args': 'value', 'args': 'value',
'init': 'true', 'init': 'true',
'top': 'top':
'if (!value) return result;\n' +
'var className = toString.call(value),\n' + 'var className = toString.call(value),\n' +
' length = value.length;\n' + ' length = value.length;\n' +
'if (arrayLikeClasses[className]' + 'if (arrayLikeClasses[className]' +
@@ -1690,10 +1663,15 @@
* // => ['one', 'two', 'three'] (order is not guaranteed) * // => ['one', 'two', 'three'] (order is not guaranteed)
*/ */
var keys = !nativeKeys ? shimKeys : function(object) { var keys = !nativeKeys ? shimKeys : function(object) {
var type = typeof object;
// avoid iterating over the `prototype` property // avoid iterating over the `prototype` property
return typeof object == 'function' && propertyIsEnumerable.call(object, 'prototype') if (type == 'function' && propertyIsEnumerable.call(object, 'prototype')) {
? shimKeys(object) return shimKeys(object);
: nativeKeys(object); }
return object && objectTypes[type]
? nativeKeys(object)
: [];
}; };
/** /**
@@ -1748,7 +1726,7 @@
' result[index] = stackB[stackLength]\n' + ' result[index] = stackB[stackLength]\n' +
' } else {\n' + ' } else {\n' +
' stackA.push(source);\n' + ' stackA.push(source);\n' +
' stackB.push(value = (value = result[index]) && isArr\n' + ' stackB.push(value = (value = result[index], isArr)\n' +
' ? (isArray(value) ? value : [])\n' + ' ? (isArray(value) ? value : [])\n' +
' : (isPlainObject(value) ? value : {})\n' + ' : (isPlainObject(value) ? value : {})\n' +
' );\n' + ' );\n' +
@@ -1834,11 +1812,11 @@
var pick = createIterator(omitIteratorOptions, { var pick = createIterator(omitIteratorOptions, {
'top': 'top':
'if (typeof callback != \'function\') {\n' + 'if (typeof callback != \'function\') {\n' +
' var prop,\n' + ' var index = 0,\n' +
' props = concat.apply(ArrayProto, arguments),\n' + ' props = concat.apply(ArrayProto, arguments),\n' +
' length = props.length;\n' + ' length = props.length;\n' +
' for (index = 1; index < length; index++) {\n' + ' while (++index < length) {\n' +
' prop = props[index];\n' + ' var prop = props[index];\n' +
' if (prop in object) result[prop] = object[prop]\n' + ' if (prop in object) result[prop] = object[prop]\n' +
' }\n' + ' }\n' +
'} else {\n' + '} else {\n' +
@@ -1991,7 +1969,7 @@
* // => 2 * // => 2
*/ */
var find = createIterator(baseIteratorOptions, forEachIteratorOptions, { var find = createIterator(baseIteratorOptions, forEachIteratorOptions, {
'init': '', 'init': 'undefined',
'inLoop': 'if (callback(value, index, collection)) return value' 'inLoop': 'if (callback(value, index, collection)) return value'
}); });
@@ -2110,6 +2088,98 @@
*/ */
var map = createIterator(baseIteratorOptions, mapIteratorOptions); var map = createIterator(baseIteratorOptions, mapIteratorOptions);
/**
* Retrieves the maximum value of an `array`. If `callback` is passed,
* it will be executed for each value in the `array` to generate the
* criterion by which the value is ranked. The `callback` is bound to
* `thisArg` and invoked with three arguments; (value, index, collection).
*
* @static
* @memberOf _
* @category Collections
* @param {Array} collection The collection to iterate over.
* @param {Function} [callback] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the maximum value.
* @example
*
* var stooges = [
* { 'name': 'moe', 'age': 40 },
* { 'name': 'larry', 'age': 50 },
* { 'name': 'curly', 'age': 60 }
* ];
*
* _.max(stooges, function(stooge) { return stooge.age; });
* // => { 'name': 'curly', 'age': 60 };
*/
function max(collection, callback, thisArg) {
var computed = -Infinity,
index = -1,
length = collection ? collection.length : 0,
result = computed;
if (callback || length !== +length) {
callback = createCallback(callback, thisArg);
forEach(collection, function(value, index, collection) {
var current = callback(value, index, collection);
if (current > computed) {
computed = current;
result = value;
}
});
} else {
while (++index < length) {
if (collection[index] > result) {
result = collection[index];
}
}
}
return result;
}
/**
* Retrieves the minimum value of an `array`. If `callback` is passed,
* it will be executed for each value in the `array` to generate the
* criterion by which the value is ranked. The `callback` is bound to `thisArg`
* and invoked with three arguments; (value, index, collection).
*
* @static
* @memberOf _
* @category Collections
* @param {Array} collection The collection to iterate over.
* @param {Function} [callback] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the minimum value.
* @example
*
* _.min([10, 5, 100, 2, 1000]);
* // => 2
*/
function min(collection, callback, thisArg) {
var computed = Infinity,
index = -1,
length = collection ? collection.length : 0,
result = computed;
if (callback || length !== +length) {
callback = createCallback(callback, thisArg);
forEach(collection, function(value, index, collection) {
var current = callback(value, index, collection);
if (current < computed) {
computed = current;
result = value;
}
});
} else {
while (++index < length) {
if (collection[index] < result) {
result = collection[index];
}
}
}
return result;
}
/** /**
* Retrieves the value of a specified property from all elements in * Retrieves the value of a specified property from all elements in
* the `collection`. * the `collection`.
@@ -2198,7 +2268,7 @@
*/ */
function reduceRight(collection, callback, accumulator, thisArg) { function reduceRight(collection, callback, accumulator, thisArg) {
var iteratee = collection, var iteratee = collection,
length = collection.length, length = collection ? collection.length : 0,
noaccum = arguments.length < 3; noaccum = arguments.length < 3;
if (length !== +length) { if (length !== +length) {
@@ -2237,6 +2307,32 @@
'inLoop': '!' + filterIteratorOptions.inLoop 'inLoop': '!' + filterIteratorOptions.inLoop
}); });
/**
* Creates an array of shuffled `array` values, using a version of the
* Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
*
* @static
* @memberOf _
* @category Collections
* @param {Array} collection The collection to shuffle.
* @returns {Array} Returns a new shuffled collection.
* @example
*
* _.shuffle([1, 2, 3, 4, 5, 6]);
* // => [4, 1, 6, 3, 5, 2]
*/
function shuffle(collection) {
var index = -1,
result = Array(collection ? collection.length : 0);
forEach(collection, function(value) {
var rand = floor(nativeRandom() * (++index + 1));
result[index] = result[rand];
result[rand] = value;
});
return result;
}
/** /**
* Gets the size of the `collection` by returning `collection.length` for arrays * Gets the size of the `collection` by returning `collection.length` for arrays
* and array-like objects or the number of own enumerable properties for objects. * and array-like objects or the number of own enumerable properties for objects.
@@ -2349,7 +2445,10 @@
* // => [2, 3, 4] * // => [2, 3, 4]
*/ */
function toArray(collection) { function toArray(collection) {
var length = collection ? collection.length : 0; if (!collection) {
return [];
}
var length = collection.length;
if (length === +length) { if (length === +length) {
return (noArraySliceOnStrings ? toString.call(collection) == stringClass : typeof collection == 'string') return (noArraySliceOnStrings ? toString.call(collection) == stringClass : typeof collection == 'string')
? collection.split('') ? collection.split('')
@@ -2386,8 +2485,8 @@
'forIn(properties, function(value, prop) { props.push(prop) });\n' + 'forIn(properties, function(value, prop) { props.push(prop) });\n' +
'var propsLength = props.length', 'var propsLength = props.length',
'inLoop': 'inLoop':
'for (var prop, pass = true, propIndex = 0; propIndex < propsLength; propIndex++) {\n' + 'for (var pass = true, propIndex = 0; propIndex < propsLength; propIndex++) {\n' +
' prop = props[propIndex];\n' + ' var prop = props[propIndex];\n' +
' if (!(pass = value[prop] === properties[prop])) break\n' + ' if (!(pass = value[prop] === properties[prop])) break\n' +
'}\n' + '}\n' +
'pass && result.push(value)' 'pass && result.push(value)'
@@ -2411,12 +2510,13 @@
*/ */
function compact(array) { function compact(array) {
var index = -1, var index = -1,
length = array.length, length = array ? array.length : 0,
result = []; result = [];
while (++index < length) { while (++index < length) {
if (array[index]) { var value = array[index];
result.push(array[index]); if (value) {
result.push(value);
} }
} }
return result; return result;
@@ -2439,15 +2539,19 @@
* // => [1, 3, 4] * // => [1, 3, 4]
*/ */
function difference(array) { function difference(array) {
var result = [];
if (!array) {
return result;
}
var index = -1, var index = -1,
length = array.length, length = array.length,
flattened = concat.apply(ArrayProto, arguments), flattened = concat.apply(ArrayProto, arguments),
contains = cachedContains(flattened, length), contains = cachedContains(flattened, length);
result = [];
while (++index < length) { while (++index < length) {
if (!contains(array[index])) { var value = array[index];
result.push(array[index]); if (!contains(value)) {
result.push(value);
} }
} }
return result; return result;
@@ -2473,7 +2577,9 @@
* // => 5 * // => 5
*/ */
function first(array, n, guard) { function first(array, n, guard) {
return (n == null || guard) ? array[0] : slice.call(array, 0, n); if (array) {
return (n == null || guard) ? array[0] : slice.call(array, 0, n);
}
} }
/** /**
@@ -2495,13 +2601,12 @@
* // => [1, 2, 3, [[4]]]; * // => [1, 2, 3, [[4]]];
*/ */
function flatten(array, shallow) { function flatten(array, shallow) {
var value, var index = -1,
index = -1, length = array ? array.length : 0,
length = array.length,
result = []; result = [];
while (++index < length) { while (++index < length) {
value = array[index]; var value = array[index];
// recursively flatten arrays (susceptible to call stack limits) // recursively flatten arrays (susceptible to call stack limits)
if (isArray(value)) { if (isArray(value)) {
@@ -2516,7 +2621,7 @@
/** /**
* Gets the index at which the first occurrence of `value` is found using * Gets the index at which the first occurrence of `value` is found using
* strict equality for comparisons, i.e. `===`. If the `array` is already * strict equality for comparisons, i.e. `===`. If the `array` is already
* sorted, passing `true` for `isSorted` will run a faster binary search. * sorted, passing `true` for `fromIndex` will run a faster binary search.
* *
* @static * @static
* @memberOf _ * @memberOf _
@@ -2539,15 +2644,13 @@
*/ */
function indexOf(array, value, fromIndex) { function indexOf(array, value, fromIndex) {
var index = -1, var index = -1,
length = array.length; length = array ? array.length : 0;
if (fromIndex) { if (typeof fromIndex == 'number') {
if (typeof fromIndex == 'number') { index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1;
index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) - 1; } else if (fromIndex) {
} else { index = sortedIndex(array, value);
index = sortedIndex(array, value); return array[index] === value ? index : -1;
return array[index] === value ? index : -1;
}
} }
while (++index < length) { while (++index < length) {
if (array[index] === value) { if (array[index] === value) {
@@ -2575,7 +2678,9 @@
* // => [3, 2] * // => [3, 2]
*/ */
function initial(array, n, guard) { function initial(array, n, guard) {
return slice.call(array, 0, -((n == null || guard) ? 1 : n)); return array
? slice.call(array, 0, -((n == null || guard) ? 1 : n))
: [];
} }
/** /**
@@ -2594,15 +2699,14 @@
* // => [1, 2] * // => [1, 2]
*/ */
function intersection(array) { function intersection(array) {
var value, var argsLength = arguments.length,
argsLength = arguments.length,
cache = [], cache = [],
index = -1, index = -1,
length = array.length, length = array ? array.length : 0,
result = []; result = [];
array: while (++index < length) { array: while (++index < length) {
value = array[index]; var value = array[index];
if (indexOf(result, value) < 0) { if (indexOf(result, value) < 0) {
for (var argsIndex = 1; argsIndex < argsLength; argsIndex++) { for (var argsIndex = 1; argsIndex < argsLength; argsIndex++) {
if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(arguments[argsIndex])))(value)) { if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(arguments[argsIndex])))(value)) {
@@ -2634,8 +2738,10 @@
* // => 1 * // => 1
*/ */
function last(array, n, guard) { function last(array, n, guard) {
var length = array.length; if (array) {
return (n == null || guard) ? array[length - 1] : slice.call(array, -n || length); var length = array.length;
return (n == null || guard) ? array[length - 1] : slice.call(array, -n || length);
}
} }
/** /**
@@ -2658,8 +2764,8 @@
* // => 1 * // => 1
*/ */
function lastIndexOf(array, value, fromIndex) { function lastIndexOf(array, value, fromIndex) {
var index = array.length; var index = array ? array.length : 0;
if (fromIndex && typeof fromIndex == 'number') { if (typeof fromIndex == 'number') {
index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
} }
while (index--) { while (index--) {
@@ -2670,84 +2776,6 @@
return -1; return -1;
} }
/**
* Retrieves the maximum value of an `array`. If `callback` is passed,
* it will be executed for each value in the `array` to generate the
* criterion by which the value is ranked. The `callback` is bound to
* `thisArg` and invoked with three arguments; (value, index, array).
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to iterate over.
* @param {Function} [callback] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the maximum value.
* @example
*
* var stooges = [
* { 'name': 'moe', 'age': 40 },
* { 'name': 'larry', 'age': 50 },
* { 'name': 'curly', 'age': 60 }
* ];
*
* _.max(stooges, function(stooge) { return stooge.age; });
* // => { 'name': 'curly', 'age': 60 };
*/
function max(array, callback, thisArg) {
var current,
computed = -Infinity,
index = -1,
length = array ? array.length : 0,
result = computed;
callback = createCallback(callback, thisArg);
while (++index < length) {
current = callback(array[index], index, array);
if (current > computed) {
computed = current;
result = array[index];
}
}
return result;
}
/**
* Retrieves the minimum value of an `array`. If `callback` is passed,
* it will be executed for each value in the `array` to generate the
* criterion by which the value is ranked. The `callback` is bound to `thisArg`
* and invoked with three arguments; (value, index, array).
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to iterate over.
* @param {Function} [callback] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the minimum value.
* @example
*
* _.min([10, 5, 100, 2, 1000]);
* // => 2
*/
function min(array, callback, thisArg) {
var current,
computed = Infinity,
index = -1,
length = array ? array.length : 0,
result = computed;
callback = createCallback(callback, thisArg);
while (++index < length) {
current = callback(array[index], index, array);
if (current < computed) {
computed = current;
result = array[index];
}
}
return result;
}
/** /**
* Creates an object composed from arrays of `keys` and `values`. Pass either * Creates an object composed from arrays of `keys` and `values`. Pass either
* a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or * a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or
@@ -2767,14 +2795,15 @@
*/ */
function object(keys, values) { function object(keys, values) {
var index = -1, var index = -1,
length = keys.length, length = keys ? keys.length : 0,
result = {}; result = {};
while (++index < length) { while (++index < length) {
var key = keys[index];
if (values) { if (values) {
result[keys[index]] = values[index]; result[key] = values[index];
} else { } else {
result[keys[index][0]] = keys[index][1]; result[key[0]] = key[1];
} }
} }
return result; return result;
@@ -2820,7 +2849,7 @@
// use `Array(length)` so V8 will avoid the slower "dictionary" mode // use `Array(length)` so V8 will avoid the slower "dictionary" mode
// http://www.youtube.com/watch?v=XAqIpGU8ZZk#t=16m27s // http://www.youtube.com/watch?v=XAqIpGU8ZZk#t=16m27s
var index = -1, var index = -1,
length = nativeMax(0, Math.ceil((end - start) / step)), length = nativeMax(0, ceil((end - start) / step)),
result = Array(length); result = Array(length);
while (++index < length) { while (++index < length) {
@@ -2849,35 +2878,9 @@
* // => [2, 1] * // => [2, 1]
*/ */
function rest(array, n, guard) { function rest(array, n, guard) {
return slice.call(array, (n == null || guard) ? 1 : n); return array
} ? slice.call(array, (n == null || guard) ? 1 : n)
: [];
/**
* Creates an array of shuffled `array` values, using a version of the
* Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to shuffle.
* @returns {Array} Returns a new shuffled array.
* @example
*
* _.shuffle([1, 2, 3, 4, 5, 6]);
* // => [4, 1, 6, 3, 5, 2]
*/
function shuffle(array) {
var rand,
index = -1,
length = array.length,
result = Array(length);
while (++index < length) {
rand = nativeFloor(nativeRandom() * (index + 1));
result[index] = result[rand];
result[rand] = array[index];
}
return result;
} }
/** /**
@@ -2921,15 +2924,21 @@
* // => 2 * // => 2
*/ */
function sortedIndex(array, value, callback, thisArg) { function sortedIndex(array, value, callback, thisArg) {
var mid, var low = 0,
low = 0, high = array ? array.length : low;
high = array.length;
callback = createCallback(callback, thisArg); if (callback) {
value = callback(value); callback = createCallback(callback, thisArg);
while (low < high) { value = callback(value);
mid = (low + high) >>> 1; while (low < high) {
callback(array[mid]) < value ? low = mid + 1 : high = mid; var mid = (low + high) >>> 1;
callback(array[mid]) < value ? low = mid + 1 : high = mid;
}
} else {
while (low < high) {
var mid = (low + high) >>> 1;
array[mid] < value ? low = mid + 1 : high = mid;
}
} }
return low; return low;
} }
@@ -2956,8 +2965,9 @@
result = []; result = [];
while (++index < length) { while (++index < length) {
if (indexOf(result, flattened[index]) < 0) { var value = flattened[index];
result.push(flattened[index]); if (indexOf(result, value) < 0) {
result.push(value);
} }
} }
return result; return result;
@@ -2994,9 +3004,8 @@
* // => [1, 2, 3] * // => [1, 2, 3]
*/ */
function uniq(array, isSorted, callback, thisArg) { function uniq(array, isSorted, callback, thisArg) {
var computed, var index = -1,
index = -1, length = array ? array.length : 0,
length = array.length,
result = [], result = [],
seen = []; seen = [];
@@ -3008,7 +3017,7 @@
} }
callback = createCallback(callback, thisArg); callback = createCallback(callback, thisArg);
while (++index < length) { while (++index < length) {
computed = callback(array[index], index, array); var computed = callback(array[index], index, array);
if (isSorted if (isSorted
? !index || seen[seen.length - 1] !== computed ? !index || seen[seen.length - 1] !== computed
: indexOf(seen, computed) < 0 : indexOf(seen, computed) < 0
@@ -3037,13 +3046,14 @@
*/ */
function without(array) { function without(array) {
var index = -1, var index = -1,
length = array.length, length = array ? array.length : 0,
contains = cachedContains(arguments, 1, 20), contains = cachedContains(arguments, 1, 20),
result = []; result = [];
while (++index < length) { while (++index < length) {
if (!contains(array[index])) { var value = array[index];
result.push(array[index]); if (!contains(value)) {
result.push(value);
} }
} }
return result; return result;
@@ -3067,7 +3077,7 @@
*/ */
function zip(array) { function zip(array) {
var index = -1, var index = -1,
length = max(pluck(arguments, 'length')), length = array ? max(pluck(arguments, 'length')) : 0,
result = Array(length); result = Array(length);
while (++index < length) { while (++index < length) {
@@ -3166,17 +3176,16 @@
'args': 'object', 'args': 'object',
'top': 'top':
'var funcs = arguments,\n' + 'var funcs = arguments,\n' +
' index = 0,\n' +
' length = funcs.length;\n' + ' length = funcs.length;\n' +
'if (length > 1) {\n' + 'if (length > 1) {\n' +
' for (var index = 1; index < length; index++) {\n' + ' while (++index < length) {\n' +
' result[funcs[index]] = bind(result[funcs[index]], result)\n' + ' result[funcs[index]] = bind(result[funcs[index]], result)\n' +
' }\n' + ' }\n' +
' return result\n' + ' return result\n' +
'}', '}',
'inLoop': 'inLoop':
'if (isFunction(result[index])) {\n' + 'if (isFunction(value)) result[index] = bind(value, result)'
' result[index] = bind(result[index], result)\n' +
'}'
}); });
/** /**
@@ -3459,6 +3468,7 @@
thisArg = this; thisArg = this;
if (remain <= 0) { if (remain <= 0) {
clearTimeout(timeoutId);
lastCalled = now; lastCalled = now;
result = func.apply(thisArg, args); result = func.apply(thisArg, args);
} }
@@ -3624,7 +3634,7 @@
max = min; max = min;
min = 0; min = 0;
} }
return min + nativeFloor(nativeRandom() * ((+max || 0) - min + 1)); return min + floor(nativeRandom() * ((+max || 0) - min + 1));
} }
/** /**
@@ -3729,6 +3739,7 @@
// http://ejohn.org/blog/javascript-micro-templating/ // http://ejohn.org/blog/javascript-micro-templating/
// and Laura Doktorova's doT.js // and Laura Doktorova's doT.js
// https://github.com/olado/doT // https://github.com/olado/doT
text || (text = '');
options || (options = {}); options || (options = {});
var isEvaluating, var isEvaluating,
@@ -3990,7 +4001,7 @@
* @memberOf _ * @memberOf _
* @type String * @type String
*/ */
lodash.VERSION = '0.8.0'; lodash.VERSION = '0.8.2';
// assign static methods // assign static methods
lodash.after = after; lodash.after = after;

74
lodash.min.js vendored
View File

@@ -1,39 +1,39 @@
/*! /*!
Lo-Dash 0.8.0 lodash.com/license Lo-Dash 0.8.2 lodash.com/license
Underscore.js 1.4.0 underscorejs.org/LICENSE Underscore.js 1.4.2 underscorejs.org/LICENSE
*/ */
;(function(e,t){function s(e){if(e&&e.__wrapped__)return e;if(!(this instanceof s))return new s(e);this.__wrapped__=e}function o(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||H),s=i?{}:e;if(i)for(var o=t-1;++o<r;)n=e[o]+"",(Q.call(s,n)?s[n]:s[n]=[]).push(e[o]);return function(e){if(i){var n=e+"";return Q.call(s,n)&&-1<x(s[n],e)}return-1<x(s,e,t)}}function u(e,n){var r=e.b,i=n.b,e=e.a,n=n.a;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<i?-1:1}function a(e,t,n){function r(){var u=arguments ;(function(e,t){function s(e){if(e&&e.__wrapped__)return e;if(!(this instanceof s))return new s(e);this.__wrapped__=e}function o(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||H),s=i?{}:e;if(i)for(n=t-1;++n<r;){var o=e[n]+"";(Z.call(s,o)?s[o]:s[o]=[]).push(e[n])}return function(e){if(i){var n=e+"";return Z.call(s,n)&&-1<T(s[n],e)}return-1<T(s,e,t)}}function u(e,n){var r=e.b,i=n.b,e=e.a,n=n.a;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<i?-1:1}function a(e,t,n){function r(){var u=arguments
,a=s?this:t;return i||(e=t[o]),n.length&&(u=u.length?n.concat(Z.call(u)):n),this instanceof r?(p.prototype=e.prototype,a=new p,(u=e.apply(a,u))&&Pt[typeof u]?u:a):e.apply(a,u)}var i=m(e),s=!n,o=e;return s&&(n=t),r}function f(e,n){return e?"function"!=typeof e?function(t){return t[e]}:n!==t?function(t,r,i){return e.call(n,t,r,i)}:e:A}function l(){for(var e,t,n,s=-1,o=arguments.length,a={e:"",p:"",c:{d:""},l:{d:""}};++s<o;)for(t in e=arguments[s],e)n=(n=e[t])==r?"":n,/d|h/.test(t)?("string"==typeof ,a=s?this:t;return i||(e=t[o]),n.length&&(u=u.length?n.concat(nt.call(u)):n),this instanceof r?(p.prototype=e.prototype,a=new p,(u=e.apply(a,u))&&Ht[typeof u]?u:a):e.apply(a,u)}var i=m(e),s=!n,o=e;return s&&(n=t),r}function f(e,n){return e?"function"!=typeof e?function(t){return t[e]}:n!==t?function(t,r,i){return e.call(n,t,r,i)}:e:A}function l(){for(var e={e:"",g:Et,i:"",j:Mt,m:Tt,n:kt,o:J,p:"",q:n,r:_t,c:{d:""},l:{d:""}},t,i=-1;t=arguments[++i];)for(var s in t){var o=t[s];/d|h/.test(s)?("string"==typeof
n&&(n={b:n,k:n}),a.c[t]=n.b||"",a.l[t]=n.k||""):a[t]=n;e=a.a,t=/^[^,]+/.exec(e)[0],n=a.i,s=a.r,a.f=t,a.g=wt,a.i=n==r?t:n,a.j=Ot,a.m=xt,a.o=J,a.q=a.q!==i,a.r=s==r?Mt:s,a.n==r&&(a.n=Ct);if("d"!=t||!a.c.h)a.c=r;t="",a.r&&(t+="'use strict';"),t+="var j,B,k="+a.f+",u",a.i&&(t+="="+a.i),t+=";"+a.p+";",a.c&&(t+="var l=k.length;j=-1;",a.l&&(t+="if(l===+l){"),a.n&&(t+="if(z.call(k)==x){k=k.split('')}"),t+=a.c.d+";while(++j<l){B=k[j];"+a.c.h+"}",a.l&&(t+="}"));if(a.l){a.c?t+="else {":a.m&&(t+="var l=k.length;j=-1;if(l&&P(k)){while(++j<l){B=k[j+=''];"+ o&&(o={b:o,k:o}),e.c[s]=o.b,e.l[s]=o.k):e[s]=o}t=e.a;if("d"!=(e.f=/^[^,]+/.exec(t)[0])||!e.c.h)e.c=r;i="",e.r&&(i+="'use strict';"),i+="var i,A,j="+e.f+",t="+(e.i||e.f)+";if(!"+e.f+")return t;"+e.p+";",e.c&&(i+="var k=j.length;i=-1;",e.l&&(i+="if(k===+k){"),e.n&&(i+="if(y.call(j)==w){j=j.split('')}"),i+=e.c.d+";while(++i<k){A=j[i];"+e.c.h+"}",e.l&&(i+="}"));if(e.l){e.c?i+="else {":e.m&&(i+="var k=j.length;i=-1;if(k&&O(j)){while(++i<k){A=j[i+=''];"+e.l.h+"}}else {"),e.g||(i+="var u=typeof j=='function'&&q.call(j,'prototype');"
a.l.h+"}}else {"),a.g||(t+="var v=typeof k=='function'&&r.call(k,'prototype');");if(a.j&&a.q)t+="var o=-1,p=Z[typeof k]?m(k):[],l=p.length;"+a.l.d+";while(++o<l){j=p[o];",a.g||(t+="if(!(v&&j=='prototype')){"),t+="B=k[j];"+a.l.h+"",a.g||(t+="}");else{t+=a.l.d+";for(j in k){";if(!a.g||a.q)t+="if(",a.g||(t+="!(v&&j=='prototype')"),!a.g&&a.q&&(t+="&&"),a.q&&(t+="h.call(k,j)"),t+="){";t+="B=k[j];"+a.l.h+";";if(!a.g||a.q)t+="}"}t+="}";if(a.g){t+="var g=k.constructor;";for(n=0;7>n;n++)t+="j='"+a.o[n]+"';if(" );if(e.j&&e.q)i+="var n=-1,o=Y[typeof j]?l(j):[],k=o.length;"+e.l.d+";while(++n<k){i=o[n];",e.g||(i+="if(!(u&&i=='prototype')){"),i+="A=j[i];"+e.l.h+"",e.g||(i+="}");else{i+=e.l.d+";for(i in j){";if(!e.g||e.q)i+="if(",e.g||(i+="!(u&&i=='prototype')"),!e.g&&e.q&&(i+="&&"),e.q&&(i+="h.call(j,i)"),i+="){";i+="A=j[i];"+e.l.h+";";if(!e.g||e.q)i+="}"}i+="}";if(e.g){i+="var g=j.constructor;";for(s=0;7>s;s++)i+="i='"+e.o[s]+"';if(","constructor"==e.o[s]&&(i+="!(g&&g.prototype===j)&&"),i+="h.call(j,i)){A=j[i];"+
,"constructor"==a.o[n]&&(t+="!(g&&g.prototype===k)&&"),t+="h.call(k,j)){B=k[j];"+a.l.h+"}"}if(a.c||a.m)t+="}"}return t+=a.e+";return u",Function("E,F,G,J,e,f,K,h,i,N,P,R,T,U,Y,Z,m,r,w,x,z,A","var H=function("+e+"){"+t+"};return H")(_t,_,L,u,K,f,Zt,Q,A,x,v,Vt,m,$t,vt,Pt,ot,Y,Z,gt,et)}function c(e){return"\\"+Ht[e]}function h(e){return Kt[e]}function p(){}function d(e){return Qt[e]}function v(e){return et.call(e)==lt}function m(e){return"function"==typeof e}function g(e){var t=i;if(!e||"object"!=typeof e.l.h+"}"}if(e.c||e.m)i+="}"}return i+=e.e+";return t",Function("D,E,F,I,e,f,J,h,M,O,Q,S,T,X,Y,l,q,v,w,y,z","var G=function("+t+"){"+i+"};return G")(Dt,_,L,u,Q,f,en,Z,T,v,$t,m,Jt,mt,Ht,ut,tt,nt,yt,rt)}function c(e){return"\\"+Bt[e]}function h(e){return Qt[e]}function p(){}function d(e){return Gt[e]}function v(e){return rt.call(e)==ct}function m(e){return"function"==typeof e}function g(e){var t=i;if(!e||"object"!=typeof e||v(e))return t;var n=e.constructor;return(!Lt||"function"==typeof e.toString||"string"!=typeof
e||v(e))return t;var n=e.constructor;return(!kt||"function"==typeof e.toString||"string"!=typeof (e+""))&&(!m(n)||n instanceof n)?St?(Zt(e,function(e,n,r){return t=!Q.call(r,n),i}),t===i):(Zt(e,function(e,n){t=n}),t===i||Q.call(e,t)):t}function y(e,t,s,o,u){if(e==r)return e;s&&(t=i);if(s=Pt[typeof e]){var a=et.call(e);if(!Dt[a]||Tt&&v(e))return e;var f=a==ct,s=f||(a==vt?$t(e):s)}if(!s||!t)return s?f?Z.call(e):Yt({},e):e;s=e.constructor;switch(a){case ht:return new s(e==n);case pt:return new s(+e) (e+""))&&(!m(n)||n instanceof n)?xt?(en(e,function(e,n,r){return t=!Z.call(r,n),i}),t===i):(en(e,function(e,n){t=n}),t===i||Z.call(e,t)):t}function y(e,t,n,s,o){if(e==r)return e;n&&(t=i);if(n=Ht[typeof e]){var u=rt.call(e);if(!Pt[u]||Nt&&v(e))return e;var a=u==ht,n=a||(u==mt?Jt(e):n)}if(!n||!t)return n?a?nt.call(e):Zt({},e):e;n=e.constructor;switch(u){case pt:case dt:return new n(+e);case vt:case yt:return new n(e);case gt:return n(e.source,U.exec(e))}s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[
;case dt:case gt:return new s(e);case mt:return s(e.source,U.exec(e))}o||(o=[]),u||(u=[]);for(a=o.length;a--;)if(o[a]==e)return u[a];var l=f?s(a=e.length):{};o.push(e),u.push(l);if(f)for(f=-1;++f<a;)l[f]=y(e[f],t,r,o,u);else en(e,function(e,n){l[n]=y(e,t,r,o,u)});return l}function b(e,t,s,o){if(e==r||t==r)return e===t;if(e===t)return 0!==e||1/e==1/t;if(Pt[typeof e]||Pt[typeof t])e=e.__wrapped__||e,t=t.__wrapped__||t;var u=et.call(e);if(u!=et.call(t))return i;switch(u){case ht:case pt:return+e==+t u]==e)return o[u];var f=a?n(e.length):{};return s.push(e),o.push(f),(a?mn:tn)(e,function(e,n){f[n]=y(e,t,r,s,o)}),f}function b(e,t,s,o){if(e==r||t==r)return e===t;if(e===t)return 0!==e||1/e==1/t;if(Ht[typeof e]||Ht[typeof t])e=e.__wrapped__||e,t=t.__wrapped__||t;var u=rt.call(e);if(u!=rt.call(t))return i;switch(u){case pt:case dt:return+e==+t;case vt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case gt:case yt:return e==t+""}var a=Dt[u];if(Nt&&!a&&(a=v(e))&&!v(t)||!a&&(u!=mt||Lt&&("function"!=typeof e.
;case dt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case mt:case gt:return e==t+""}var a=_t[u];if(Tt&&!a&&(a=v(e))&&!v(t)||!a&&(u!=vt||kt&&("function"!=typeof e.toString&&"string"==typeof (e+"")||"function"!=typeof t.toString&&"string"==typeof (t+""))))return i;s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var u=-1,f=n,l=0;s.push(e),o.push(t);if(a){l=e.length;if(f=l==t.length)for(;l--&&(f=b(e[l],t[l],s,o)););return f}a=e.constructor,f=t.constructor;if(a!=f&&(!m(a)||!(a instanceof toString&&"string"==typeof (e+"")||"function"!=typeof t.toString&&"string"==typeof (t+""))))return i;s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var u=-1,f=n,l=0;s.push(e),o.push(t);if(a){l=e.length;if(f=l==t.length)for(;l--&&(f=b(e[l],t[l],s,o)););return f}a=e.constructor,f=t.constructor;if(a!=f&&(!m(a)||!(a instanceof a&&m(f)&&f instanceof f)))return i;for(var c in e)if(Z.call(e,c)&&(l++,!Z.call(t,c)||!b(e[c],t[c],s,o)))return i;for(c in t)if(Z.call(t,c)&&!(l--))return i;if(
a&&m(f)&&f instanceof f)))return i;for(var c in e)if(Q.call(e,c)&&(l++,!Q.call(t,c)||!b(e[c],t[c],s,o)))return i;for(c in t)if(Q.call(t,c)&&!(l--))return i;if(wt)for(;7>++u;)if(c=J[u],Q.call(e,c)&&(!Q.call(t,c)||!b(e[c],t[c],s,o)))return i;return n}function w(e,t,n,r){var s=e,o=e.length,u=3>arguments.length;if(o!==+o)var a=rn(e),o=a.length;else Ct&&et.call(e)==gt&&(s=e.split(""));return vn(e,function(e,f,l){f=a?a[--o]:--o,n=u?(u=i,s[f]):t.call(r,n,s[f],f,l)}),n}function E(e,t,n){return t==r||n?e[0 Et)for(;7>++u;)if(c=J[u],Z.call(e,c)&&(!Z.call(t,c)||!b(e[c],t[c],s,o)))return i;return n}function w(e,t,n){var r=-Infinity,i=-1,s=e?e.length:0,o=r;if(t||s!==+s)t=f(t,n),mn(e,function(e,n,i){n=t(e,n,i),n>r&&(r=n,o=e)});else for(;++i<s;)e[i]>o&&(o=e[i]);return o}function E(e,t,n,r){var s=e,o=e?e.length:0,u=3>arguments.length;if(o!==+o)var a=sn(e),o=a.length;else kt&&rt.call(e)==yt&&(s=e.split(""));return mn(e,function(e,f,l){f=a?a[--o]:--o,n=u?(u=i,s[f]):t.call(r,n,s[f],f,l)}),n}function S(e,t,n){
]:Z.call(e,0,t)}function S(e,t){for(var n,r=-1,i=e.length,s=[];++r<i;)n=e[r],Vt(n)?G.apply(s,t?n:S(n)):s.push(n);return s}function x(e,t,n){var r=-1,i=e.length;if(n){if("number"!=typeof n)return r=C(e,t),e[r]===t?r:-1;r=(0>n?ut(0,i+n):n)-1}for(;++r<i;)if(e[r]===t)return r;return-1}function T(e,t,n){for(var r=-Infinity,i=-1,s=e?e.length:0,o=r,t=f(t,n);++i<s;)n=t(e[i],i,e),n>r&&(r=n,o=e[i]);return o}function N(e,t,n){return Z.call(e,t==r||n?1:t)}function C(e,t,n,r){for(var i=0,s=e.length,n=f(n,r),t= if(e)return t==r||n?e[0]:nt.call(e,0,t)}function x(e,t){for(var n=-1,r=e?e.length:0,i=[];++n<r;){var s=e[n];$t(s)?et.apply(i,t?s:x(s)):i.push(s)}return i}function T(e,t,n){var r=-1,i=e?e.length:0;if("number"==typeof n)r=(0>n?at(0,i+n):n||0)-1;else if(n)return r=C(e,t),e[r]===t?r:-1;for(;++r<i;)if(e[r]===t)return r;return-1}function N(e,t,n){return e?nt.call(e,t==r||n?1:t):[]}function C(e,t,n,r){var i=0,s=e?e.length:i;if(n){n=f(n,r);for(t=n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r}else for(;i<s;)r=i+
n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r;return i}function k(e,t,n,r){var s=-1,o=e.length,u=[],a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n=f(n,r);++s<o;)if(r=n(e[s],s,e),t?!s||a[a.length-1]!==r:0>x(a,r))a.push(r),u.push(e[s]);return u}function L(e,t){return At||tt&&2<arguments.length?tt.call.apply(tt,arguments):a(e,t,Z.call(arguments,2))}function A(e){return e}function O(e){vn(tn(e),function(t){var r=s[t]=e[t];s.prototype[t]=function(){var e=[this.__wrapped__];return arguments.length&&G.apply(e s>>>1,e[r]<t?i=r+1:s=r;return i}function k(e,t,n,r){var s=-1,o=e?e.length:0,u=[],a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n=f(n,r);++s<o;)if(r=n(e[s],s,e),t?!s||a[a.length-1]!==r:0>T(a,r))a.push(r),u.push(e[s]);return u}function L(e,t){return Ot||it&&2<arguments.length?it.call.apply(it,arguments):a(e,t,nt.call(arguments,2))}function A(e){return e}function O(e){mn(nn(e),function(t){var r=s[t]=e[t];s.prototype[t]=function(){var e=[this.__wrapped__];return arguments.length&&et.apply(e,arguments)
,arguments),e=r.apply(s,e),this.__chain__&&(e=new s(e),e.__chain__=n),e}})}var n=!0,r=null,i=!1,M="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),_=Array.prototype,D=Object.prototype,P=0,H=30,B=e._,j=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,F=/&(?:amp|lt|gt|quot|#x27);/g,I=/\b__p\+='';/g,q=/\b(__p\+=)''\+/g,R=/(__e\(.*?\)|\b__t\))\+'';/g,U=/\w*$/,z=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,W=RegExp("^"+(D ,e=r.apply(s,e),this.__chain__&&(e=new s(e),e.__chain__=n),e}})}var n=!0,r=null,i=!1,M="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),_=Array.prototype,D=Object.prototype,P=0,H=30,B=e._,j=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,F=/&(?:amp|lt|gt|quot|#x27);/g,I=/\b__p\+='';/g,q=/\b(__p\+=)''\+/g,R=/(__e\(.*?\)|\b__t\))\+'';/g,U=/\w*$/,z=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,W=RegExp("^"+(D.valueOf+""
.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),X=/($^)/,V=/[&<>"']/g,$=/['\n\r\t\u2028\u2029\\]/g,J="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),K=_.concat,Q=D.hasOwnProperty,G=_.push,Y=D.propertyIsEnumerable,Z=_.slice,et=D.toString,tt=W.test(tt=Z.bind)&&tt,nt=Math.floor,rt=W.test(rt=Object.getPrototypeOf)&&rt,it=W.test(it=Array.isArray)&&it,st=e.isFinite,ot=W.test(ot=Object.keys)&&ot, ).replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),X=/($^)/,V=/[&<>"']/g,$=/['\n\r\t\u2028\u2029\\]/g,J="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),K=Math.ceil,Q=_.concat,G=Math.floor,Y=W.test(Y=Object.getPrototypeOf)&&Y,Z=D.hasOwnProperty,et=_.push,tt=D.propertyIsEnumerable,nt=_.slice,rt=D.toString,it=W.test(it=nt.bind)&&it,st=W.test(st=Array.isArray)&&st,ot=e.isFinite,ut=W.test(ut=Object.keys)&&ut
ut=Math.max,at=Math.min,ft=Math.random,lt="[object Arguments]",ct="[object Array]",ht="[object Boolean]",pt="[object Date]",dt="[object Number]",vt="[object Object]",mt="[object RegExp]",gt="[object String]",yt=e.clearTimeout,bt=e.setTimeout,wt,Et,St,xt=n;(function(){function e(){this.x=1}var t={0:1,length:1},n=[];e.prototype={valueOf:1,y:1};for(var r in new e)n.push(r);for(r in arguments)xt=!r;wt=4>(n+"").length,St="x"!=n[0],Et=(n.splice.call(t,0,1),t[0])})(1);var Tt=!v(arguments),Nt="x"!=Z.call("x" ,at=Math.max,ft=Math.min,lt=Math.random,ct="[object Arguments]",ht="[object Array]",pt="[object Boolean]",dt="[object Date]",vt="[object Number]",mt="[object Object]",gt="[object RegExp]",yt="[object String]",bt=e.clearTimeout,wt=e.setTimeout,Et,St,xt,Tt=n;(function(){function e(){this.x=1}var t={0:1,length:1},n=[];e.prototype={valueOf:1,y:1};for(var r in new e)n.push(r);for(r in arguments)Tt=!r;Et=4>(n+"").length,xt="x"!=n[0],St=(n.splice.call(t,0,1),t[0])})(1);var Nt=!v(arguments),Ct="x"!=nt.call("x"
)[0],Ct="xx"!="x"[0]+Object("x")[0];try{var kt=("[object Object]",et.call(e.document||0)==vt)}catch(Lt){}var At=tt&&/\n|Opera/.test(tt+et.call(e.opera)),Ot=ot&&/^.+$|true/.test(ot+!!e.attachEvent),Mt=!At,_t={};_t[ht]=_t[pt]=_t["[object Function]"]=_t[dt]=_t[vt]=_t[mt]=i,_t[lt]=_t[ct]=_t[gt]=n;var Dt={};Dt[lt]=Dt["[object Function]"]=i,Dt[ct]=Dt[ht]=Dt[pt]=Dt[dt]=Dt[vt]=Dt[mt]=Dt[gt]=n;var Pt={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},Ht={"\\":"\\","'":"'","\n":"n" )[0],kt="xx"!="x"[0]+Object("x")[0];try{var Lt=("[object Object]",rt.call(e.document||0)==mt)}catch(At){}var Ot=it&&/\n|Opera/.test(it+rt.call(e.opera)),Mt=ut&&/^.+$|true/.test(ut+!!e.attachEvent),_t=!Ot,Dt={};Dt[pt]=Dt[dt]=Dt["[object Function]"]=Dt[vt]=Dt[mt]=Dt[gt]=i,Dt[ct]=Dt[ht]=Dt[yt]=n;var Pt={};Pt[ct]=Pt["[object Function]"]=i,Pt[ht]=Pt[pt]=Pt[dt]=Pt[vt]=Pt[mt]=Pt[gt]=Pt[yt]=n;var Ht={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},Bt={"\\":"\\","'":"'","\n":"n"
,"\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};s.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""};var Bt={a:"d,c,y",i:"d",p:"c=f(c,y)",h:"if(c(B,j,d)===false)return u"},jt={i:"{}",p:"c=f(c,y)",h:"var q=c(B,j,d);(h.call(u,q)?u[q]++:u[q]=1)"},Ft={i:"true",h:"if(!c(B,j,d))return!u"},It={q:i,r:i,a:"n",i:"n",p:"for(var a=1,b=arguments.length;a<b;a++){if(k=arguments[a]){",h:"u[j]=B",e:"}}"},qt={i:"[]",h:"c(B,j,d)&&u.push(B)"},Rt={p ,"\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};s.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""};var jt={a:"d,c,x",p:"c=f(c,x)",h:"if(c(A,i,d)===false)return t"},Ft={i:"{}",p:"c=f(c,x)",h:"var p=c(A,i,d);(h.call(t,p)?t[p]++:t[p]=1)"},It={i:"true",h:"if(!c(A,i,d))return!t"},qt={q:i,r:i,a:"m",p:"for(var a=1,b=arguments.length;a<b;a++){if(j=arguments[a]){",h:"t[i]=A",e:"}}"},Rt={i:"[]",h:"c(A,i,d)&&t.push(A)"},Ut={p:"c=f(c,x)"}
:"c=f(c,y)"},Ut={h:{k:Bt.h}},zt={i:"",d:{b:"u=Array(l)",k:"u="+(Ot?"Array(l)":"[]")},h:{b:"u[j]=c(B,j,d)",k:"u"+(Ot?"[o]=":".push")+"(c(B,j,d))"}},Wt={q:i,a:"n,c,y",i:"{}",p:"var S=typeof c=='function';if(S)c=f(c,y);else var t=e.apply(F,arguments)",h:"if(S?!c(B,j,n):N(t,j)<0)u[j]=B"},Xt=l({a:"n",i:"{}",h:"u[B]=j"});Tt&&(v=function(e){return!!e&&!!Q.call(e,"callee")});var Vt=it||function(e){return et.call(e)==ct};m(/x/)&&(m=function(e){return"[object Function]"==et.call(e)});var $t=rt?function(e){ ,zt={h:{k:jt.h}},Wt={i:"d||[]",d:{b:"t=Array(k)",k:"t="+(Mt?"Array(k)":"[]")},h:{b:"t[i]=c(A,i,d)",k:"t"+(Mt?"[n]=":".push")+"(c(A,i,d))"}},Xt={q:i,a:"m,c,x",i:"{}",p:"var R=typeof c=='function';if(R)c=f(c,x);else var s=e.apply(E,arguments)",h:"if(R?!c(A,i,m):M(s,i)<0)t[i]=A"},Vt=l({a:"m",i:"{}",h:"t[A]=i"});Nt&&(v=function(e){return e?Z.call(e,"callee"):i});var $t=st||function(e){return rt.call(e)==ht};m(/x/)&&(m=function(e){return"[object Function]"==rt.call(e)});var Jt=Y?function(e){if(!e||"object"!=typeof
if(!e||"object"!=typeof e)return i;var t=e.valueOf,n="function"==typeof t&&(n=rt(t))&&rt(n);return n?e==n||rt(e)==n&&!v(e):g(e)}:g,Jt=l({a:"n",i:"[]",p:"if(!(n&&Z[typeof n]))throw TypeError()",h:"u.push(j)"}),Kt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"},Qt=Xt(Kt),Gt=l(It,{h:"if(u[j]==null)"+It.h}),Yt=l(It),Zt=l(Bt,Rt,Ut,{q:i}),en=l(Bt,Rt,Ut),tn=l({q:i,a:"n",i:"[]",h:"if(T(B))u.push(j)",e:"u.sort()"}),nn=l({a:"B",i:"true",p:"if(!B)return u;var I=z.call(B),l=B.length;if(E[I]"+(Tt?"||P(B)" e)return i;var t=e.valueOf,n="function"==typeof t&&(n=Y(t))&&Y(n);return n?e==n||Y(e)==n&&!v(e):g(e)}:g,Kt=l({a:"m",i:"[]",h:"t.push(i)"}),Qt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"},Gt=Vt(Qt),Yt=l(qt,{h:"if(t[i]==null)"+qt.h}),Zt=l(qt),en=l(jt,Ut,zt,{q:i}),tn=l(jt,Ut,zt),nn=l({q:i,a:"m",i:"[]",h:"S(A)&&t.push(i)",e:"t.sort()"}),rn=l({a:"A",i:"true",p:"var H=y.call(A),k=A.length;if(D[H]"+(Nt?"||O(A)":"")+"||(H==X&&k===+k&&S(A.splice)))return!k",h:{k:"return false"}}),sn=ut?function(
:"")+"||(I==Y&&l===+l&&T(B.splice)))return!l",h:{k:"return false"}}),rn=ot?function(e){return"function"==typeof e&&Y.call(e,"prototype")?Jt(e):ot(e)}:Jt,sn=l(It,{a:"n,ee,O",p:"var Q,D=arguments,a=0;if(O==J){var b=2,ff=D[3],gg=D[4]}else var b=D.length,ff=[],gg=[];while(++a<b){if(k=D[a]){",h:"if((ee=B)&&((Q=R(ee))||U(ee))){var L=false,hh=ff.length;while(hh--)if(L=ff[hh]==ee)break;if(L){u[j]=gg[hh]}else {ff.push(ee);gg.push(B=(B=u[j])&&Q?(R(B)?B:[]):(U(B)?B:{}));u[j]=H(B,ee,J,ff,gg)}}else if(ee!=null)u[j]=ee" e){var t=typeof e;return"function"==t&&tt.call(e,"prototype")?Kt(e):e&&Ht[t]?ut(e):[]}:Kt,on=l(qt,{a:"m,dd,N",p:"var P,C=arguments,a=0;if(N==I){var b=2,ee=C[3],ff=C[4]}else var b=C.length,ee=[],ff=[];while(++a<b){if(j=C[a]){",h:"if((dd=A)&&((P=Q(dd))||T(dd))){var K=false,gg=ee.length;while(gg--)if(K=ee[gg]==dd)break;if(K){t[i]=ff[gg]}else {ee.push(dd);ff.push(A=(A=t[i],P)?(Q(A)?A:[]):(T(A)?A:{}));t[i]=G(A,dd,I,ee,ff)}}else if(dd!=null)t[i]=dd"}),un=l(Xt),an=l({a:"m",i:"[]",h:"t"+(Mt?"[n]=":".push"
}),on=l(Wt),un=l({a:"n",i:"[]",h:"u"+(Ot?"[o]=":".push")+"([j,B])"}),an=l(Wt,{p:"if(typeof c!='function'){var q,t=e.apply(F,arguments),l=t.length;for(j=1;j<l;j++){q=t[j];if(q in n)u[q]=n[q]}}else {c=f(c,y)",h:"if(c(B,j,n))u[j]=B",e:"}"}),fn=l({a:"n",i:"[]",h:"u.push(B)"}),ln=l({a:"d,ii",i:"false",n:i,d:{b:"if(z.call(d)==x)return d.indexOf(ii)>-1"},h:"if(B===ii)return true"}),cn=l(Bt,jt),hn=l(Bt,Ft),pn=l(Bt,qt),dn=l(Bt,Rt,{i:"",h:"if(c(B,j,d))return B"}),vn=l(Bt,Rt),mn=l(Bt,jt,{h:"var q=c(B,j,d);(h.call(u,q)?u[q]:u[q]=[]).push(B)" )+"([i,A])"}),fn=l(Xt,{p:"if(typeof c!='function'){var i=0,s=e.apply(E,arguments),k=s.length;while(++i<k){var p=s[i];if(p in m)t[p]=m[p]}}else {c=f(c,x)",h:"if(c(A,i,m))t[i]=A",e:"}"}),ln=l({a:"m",i:"[]",h:"t.push(A)"}),cn=l({a:"d,hh",i:"false",n:i,d:{b:"if(y.call(d)==w)return d.indexOf(hh)>-1"},h:"if(A===hh)return true"}),hn=l(jt,Ft),pn=l(jt,It),dn=l(jt,Rt),vn=l(jt,Ut,{i:"z",h:"if(c(A,i,d))return A"}),mn=l(jt,Ut),gn=l(jt,Ft,{h:"var p=c(A,i,d);(h.call(t,p)?t[p]:t[p]=[]).push(A)"}),yn=l(Wt,{a:"d,U"
}),gn=l(zt,{a:"d,V",p:"var D=w.call(arguments,2),S=typeof V=='function'",h:{b:"u[j]=(S?V:B[V]).apply(B,D)",k:"u"+(Ot?"[o]=":".push")+"((S?V:B[V]).apply(B,D))"}}),yn=l(Bt,zt),bn=l(zt,{a:"d,cc",h:{b:"u[j]=B[cc]",k:"u"+(Ot?"[o]=":".push")+"(B[cc])"}}),wn=l({a:"d,c,C,y",i:"C",p:"var W=arguments.length<3;c=f(c,y)",d:{b:"if(W)u=k[++j]"},h:{b:"u=c(u,B,j,d)",k:"u=W?(W=false,B):c(u,B,j,d)"}}),En=l(Bt,qt,{h:"!"+qt.h}),Sn=l(Bt,Ft,{i:"false",h:Ft.h.replace("!","")}),xn=l(Bt,jt,zt,{h:{b:"u[j]={a:c(B,j,d),b:j,c:B}" ,p:"var C=v.call(arguments,2),R=typeof U=='function'",h:{b:"t[i]=(R?U:A[U]).apply(A,C)",k:"t"+(Mt?"[n]=":".push")+"((R?U:A[U]).apply(A,C))"}}),bn=l(jt,Wt),wn=l(Wt,{a:"d,bb",h:{b:"t[i]=A[bb]",k:"t"+(Mt?"[n]=":".push")+"(A[bb])"}}),En=l({a:"d,c,B,x",i:"B",p:"var V=arguments.length<3;c=f(c,x)",d:{b:"if(V)t=j[++i]"},h:{b:"t=c(t,A,i,d)",k:"t=V?(V=false,A):c(t,A,i,d)"}}),Sn=l(jt,Rt,{h:"!"+Rt.h}),xn=l(jt,It,{i:"false",h:It.h.replace("!","")}),Tn=l(jt,Ft,Wt,{h:{b:"t[i]={a:c(A,i,d),b:i,c:A}",k:"t"+(Mt?"[n]="
,k:"u"+(Ot?"[o]=":".push")+"({a:c(B,j,d),b:j,c:B})"},e:"u.sort(J);l=u.length;while(l--)u[l]=u[l].c"}),Tn=l(qt,{a:"d,bb",p:"var t=[];K(bb,function(B,q){t.push(q)});var dd=t.length",h:"for(var q,aa=true,s=0;s<dd;s++){q=t[s];if(!(aa=B[q]===bb[q]))break}aa&&u.push(B)"}),Nn=l({q:i,r:i,a:"n",p:"var M=arguments,l=M.length;if(l>1){for(var j=1;j<l;j++)u[M[j]]=G(u[M[j]],u);return u}",h:"if(T(u[j]))u[j]=G(u[j],u)"});s.VERSION="0.8.0",s.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this :".push")+"({a:c(A,i,d),b:i,c:A})"},e:"t.sort(I);k=t.length;while(k--)t[k]=t[k].c"}),Nn=l(Rt,{a:"d,aa",p:"var s=[];J(aa,function(A,p){s.push(p)});var cc=s.length",h:"for(var Z=true,r=0;r<cc;r++){var p=s[r];if(!(Z=A[p]===aa[p]))break}Z&&t.push(A)"}),Cn=l({q:i,r:i,a:"m",p:"var L=arguments,i=0,k=L.length;if(k>1){while(++i<k)t[L[i]]=F(t[L[i]],t);return t}",h:"if(S(A))t[i]=F(A,t)"});s.VERSION="0.8.2",s.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this,arguments)}},s.bind=L,s.bindAll=
,arguments)}},s.bind=L,s.bindAll=Nn,s.chain=function(e){return e=new s(e),e.__chain__=n,e},s.clone=y,s.compact=function(e){for(var t=-1,n=e.length,r=[];++t<n;)e[t]&&r.push(e[t]);return r},s.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},s.contains=ln,s.countBy=cn,s.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,yt(a),a=bt(i,t),r&&(o=e.apply Cn,s.chain=function(e){return e=new s(e),e.__chain__=n,e},s.clone=y,s.compact=function(e){for(var t=-1,n=e?e.length:0,r=[];++t<n;){var i=e[t];i&&r.push(i)}return r},s.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},s.contains=cn,s.countBy=hn,s.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,bt(a),a=wt(i,t),r&&(o=e.apply(u,s)),o}},s.defaults=
(u,s)),o}},s.defaults=Gt,s.defer=function(e){var n=Z.call(arguments,1);return bt(function(){return e.apply(t,n)},1)},s.delay=function(e,n){var r=Z.call(arguments,2);return bt(function(){return e.apply(t,r)},n)},s.difference=function(e){for(var t=-1,n=e.length,r=K.apply(_,arguments),r=o(r,n),i=[];++t<n;)r(e[t])||i.push(e[t]);return i},s.escape=function(e){return e==r?"":(e+"").replace(V,h)},s.every=hn,s.extend=Yt,s.filter=pn,s.find=dn,s.first=E,s.flatten=S,s.forEach=vn,s.forIn=Zt,s.forOwn=en,s.functions= Yt,s.defer=function(e){var n=nt.call(arguments,1);return wt(function(){return e.apply(t,n)},1)},s.delay=function(e,n){var r=nt.call(arguments,2);return wt(function(){return e.apply(t,r)},n)},s.difference=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length,i=Q.apply(_,arguments),i=o(i,r);++n<r;){var s=e[n];i(s)||t.push(s)}return t},s.escape=function(e){return e==r?"":(e+"").replace(V,h)},s.every=pn,s.extend=Zt,s.filter=dn,s.find=vn,s.first=S,s.flatten=x,s.forEach=mn,s.forIn=en,s.forOwn=tn,
tn,s.groupBy=mn,s.has=function(e,t){return Q.call(e,t)},s.identity=A,s.indexOf=x,s.initial=function(e,t,n){return Z.call(e,0,-(t==r||n?1:t))},s.intersection=function(e){var t,n=arguments.length,r=[],i=-1,s=e.length,u=[];e:for(;++i<s;)if(t=e[i],0>x(u,t)){for(var a=1;a<n;a++)if(!(r[a]||(r[a]=o(arguments[a])))(t))continue e;u.push(t)}return u},s.invert=Xt,s.invoke=gn,s.isArguments=v,s.isArray=Vt,s.isBoolean=function(e){return e===n||e===i||et.call(e)==ht},s.isDate=function(e){return et.call(e)==pt}, s.functions=nn,s.groupBy=gn,s.has=function(e,t){return e?Z.call(e,t):i},s.identity=A,s.indexOf=T,s.initial=function(e,t,n){return e?nt.call(e,0,-(t==r||n?1:t)):[]},s.intersection=function(e){var t=arguments.length,n=[],r=-1,i=e?e.length:0,s=[];e:for(;++r<i;){var u=e[r];if(0>T(s,u)){for(var a=1;a<t;a++)if(!(n[a]||(n[a]=o(arguments[a])))(u))continue e;s.push(u)}}return s},s.invert=Vt,s.invoke=yn,s.isArguments=v,s.isArray=$t,s.isBoolean=function(e){return e===n||e===i||rt.call(e)==pt},s.isDate=function(
s.isElement=function(e){return e?1===e.nodeType:i},s.isEmpty=nn,s.isEqual=b,s.isFinite=function(e){return st(e)&&et.call(e)==dt},s.isFunction=m,s.isNaN=function(e){return et.call(e)==dt&&e!=+e},s.isNull=function(e){return e===r},s.isNumber=function(e){return et.call(e)==dt},s.isObject=function(e){return e?Pt[typeof e]:i},s.isPlainObject=$t,s.isRegExp=function(e){return et.call(e)==mt},s.isString=function(e){return et.call(e)==gt},s.isUndefined=function(e){return e===t},s.keys=rn,s.last=function(e e){return rt.call(e)==dt},s.isElement=function(e){return e?1===e.nodeType:i},s.isEmpty=rn,s.isEqual=b,s.isFinite=function(e){return ot(e)&&rt.call(e)==vt},s.isFunction=m,s.isNaN=function(e){return rt.call(e)==vt&&e!=+e},s.isNull=function(e){return e===r},s.isNumber=function(e){return rt.call(e)==vt},s.isObject=function(e){return e?Ht[typeof e]:i},s.isPlainObject=Jt,s.isRegExp=function(e){return rt.call(e)==gt},s.isString=function(e){return rt.call(e)==yt},s.isUndefined=function(e){return e===t},s
,t,n){var i=e.length;return t==r||n?e[i-1]:Z.call(e,-t||i)},s.lastIndexOf=function(e,t,n){var r=e.length;for(n&&"number"==typeof n&&(r=(0>n?ut(0,r+n):at(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},s.lateBind=function(e,t){return a(t,e,Z.call(arguments,2))},s.map=yn,s.max=T,s.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return Q.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},s.merge=sn,s.min=function(e,t,n){for(var r=Infinity,i=-1,s=e?e.length:0,o= .keys=sn,s.last=function(e,t,n){if(e){var i=e.length;return t==r||n?e[i-1]:nt.call(e,-t||i)}},s.lastIndexOf=function(e,t,n){var r=e?e.length:0;for("number"==typeof n&&(r=(0>n?at(0,r+n):ft(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},s.lateBind=function(e,t){return a(t,e,nt.call(arguments,2))},s.map=bn,s.max=w,s.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return Z.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},s.merge=on,s.min=function(e,t,n){var r=
r,t=f(t,n);++i<s;)n=t(e[i],i,e),n<r&&(r=n,o=e[i]);return o},s.mixin=O,s.noConflict=function(){return e._=B,this},s.object=function(e,t){for(var n=-1,r=e.length,i={};++n<r;)t?i[e[n]]=t[n]:i[e[n][0]]=e[n][1];return i},s.omit=on,s.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},s.pairs=un,s.partial=function(e){return a(e,Z.call(arguments,1))},s.pick=an,s.pluck=bn,s.random=function(e,t){return e==r&&t==r&&(t=1),e=+e||0,t==r&&(t=e,e=0),e+nt(ft()*((+t||0)- Infinity,i=-1,s=e?e.length:0,o=r;if(t||s!==+s)t=f(t,n),mn(e,function(e,n,i){n=t(e,n,i),n<r&&(r=n,o=e)});else for(;++i<s;)e[i]<o&&(o=e[i]);return o},s.mixin=O,s.noConflict=function(){return e._=B,this},s.object=function(e,t){for(var n=-1,r=e?e.length:0,i={};++n<r;){var s=e[n];t?i[s]=t[n]:i[s[0]]=s[1]}return i},s.omit=un,s.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},s.pairs=an,s.partial=function(e){return a(e,nt.call(arguments,1))},s.pick=fn,s.pluck=
e+1))},s.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=ut(0,Math.ceil((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},s.reduce=wn,s.reduceRight=w,s.reject=En,s.rest=N,s.result=function(e,t){var n=e?e[t]:r;return m(n)?e[t]():n},s.shuffle=function(e){for(var t,n=-1,r=e.length,i=Array(r);++n<r;)t=nt(ft()*(n+1)),i[n]=i[t],i[t]=e[n];return i},s.size=function(e){var t=e?e.length:0;return t===+t?t:rn(e).length},s.some=Sn,s.sortBy=xn,s.sortedIndex=C,s.tap=function(e,t){return t(e wn,s.random=function(e,t){return e==r&&t==r&&(t=1),e=+e||0,t==r&&(t=e,e=0),e+G(lt()*((+t||0)-e+1))},s.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=at(0,K((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},s.reduce=En,s.reduceRight=E,s.reject=Sn,s.rest=N,s.result=function(e,t){var n=e?e[t]:r;return m(n)?e[t]():n},s.shuffle=function(e){var t=-1,n=Array(e?e.length:0);return mn(e,function(e){var r=G(lt()*(++t+1));n[t]=n[r],n[r]=e}),n},s.size=function(e){var t=e?e.length:0;return t===+
),e},s.template=function(e,t,n){n||(n={});var r,i,o=0,u=s.templateSettings,a="__p += '",f=n.variable||u.variable,l=f;e.replace(RegExp((n.escape||u.escape||X).source+"|"+(n.interpolate||u.interpolate||X).source+"|"+(n.evaluate||u.evaluate||X).source+"|$","g"),function(t,n,i,s,u){a+=e.slice(o,u).replace($,c),a+=n?"'+__e("+n+")+'":s?"';"+s+";__p+='":i?"'+((__t=("+i+"))==null?'':__t)+'":"",r||(r=s||j.test(n||i)),o=u+t.length}),a+="';",l||(f="obj",r?a="with("+f+"){"+a+"}":(n=RegExp("(\\(\\s*)"+f+"\\."+ t?t:sn(e).length},s.some=xn,s.sortBy=Tn,s.sortedIndex=C,s.tap=function(e,t){return t(e),e},s.template=function(e,t,n){e||(e=""),n||(n={});var r,i,o=0,u=s.templateSettings,a="__p += '",f=n.variable||u.variable,l=f;e.replace(RegExp((n.escape||u.escape||X).source+"|"+(n.interpolate||u.interpolate||X).source+"|"+(n.evaluate||u.evaluate||X).source+"|$","g"),function(t,n,i,s,u){a+=e.slice(o,u).replace($,c),a+=n?"'+__e("+n+")+'":s?"';"+s+";__p+='":i?"'+((__t=("+i+"))==null?'':__t)+'":"",r||(r=s||j.test(
f+"\\b","g"),a=a.replace(z,"$&"+f+".").replace(n,"$1__d"))),a=(r?a.replace(I,""):a).replace(q,"$1").replace(R,"$1;"),a="function("+f+"){"+(l?"":f+"||("+f+"={});")+"var __t,__p='',__e=_.escape"+(r?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(l?"":",__d="+f+"."+f+"||"+f)+";")+a+"return __p}";try{i=Function("_","return "+a)(s)}catch(h){throw h.source=a,h}return t?i(t):(i.source=a,i)},s.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function( n||i)),o=u+t.length}),a+="';",l||(f="obj",r?a="with("+f+"){"+a+"}":(n=RegExp("(\\(\\s*)"+f+"\\."+f+"\\b","g"),a=a.replace(z,"$&"+f+".").replace(n,"$1__d"))),a=(r?a.replace(I,""):a).replace(q,"$1").replace(R,"$1;"),a="function("+f+"){"+(l?"":f+"||("+f+"={});")+"var __t,__p='',__e=_.escape"+(r?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(l?"":",__d="+f+"."+f+"||"+f)+";")+a+"return __p}";try{i=Function("_","return "+a)(s)}catch(h){throw h.source=a,h}return t?i(t):(i.source=
){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(a=r,s=e.apply(o,i)):u||(u=bt(n,f)),s}},s.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r<e;)i[r]=t.call(n,r);return i},s.toArray=function(e){var t=e?e.length:0;return t===+t?(Nt?et.call(e)==gt:"string"==typeof e)?e.split(""):Z.call(e):fn(e)},s.unescape=function(e){return e==r?"":(e+"").replace(F,d)},s.union=function(){for(var e=-1,t=K.apply(_,arguments),n=t.length,r=[];++e<n;)0>x(r,t[e])&&r.push(t[e]);return r},s.uniq=k,s.uniqueId= a,i)},s.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function(){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(bt(u),a=r,s=e.apply(o,i)):u||(u=wt(n,f)),s}},s.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r<e;)i[r]=t.call(n,r);return i},s.toArray=function(e){if(!e)return[];var t=e.length;return t===+t?(Ct?rt.call(e)==yt:"string"==typeof e)?e.split(""):nt.call(e):ln(e)},s.unescape=function(e){return e==r?"":(e+"").replace(F,d)},s.union=
function(e){var t=P++;return e?e+t:t},s.values=fn,s.where=Tn,s.without=function(e){for(var t=-1,n=e.length,r=o(arguments,1,20),i=[];++t<n;)r(e[t])||i.push(e[t]);return i},s.wrap=function(e,t){return function(){var n=[e];return arguments.length&&G.apply(n,arguments),t.apply(this,n)}},s.zip=function(e){for(var t=-1,n=T(bn(arguments,"length")),r=Array(n);++t<n;)r[t]=bn(arguments,t);return r},s.all=hn,s.any=Sn,s.collect=yn,s.detect=dn,s.drop=N,s.each=vn,s.foldl=wn,s.foldr=w,s.head=E,s.include=ln,s.inject= function(){for(var e=-1,t=Q.apply(_,arguments),n=t.length,r=[];++e<n;){var i=t[e];0>T(r,i)&&r.push(i)}return r},s.uniq=k,s.uniqueId=function(e){var t=P++;return e?e+t:t},s.values=ln,s.where=Nn,s.without=function(e){for(var t=-1,n=e?e.length:0,r=o(arguments,1,20),i=[];++t<n;){var s=e[t];r(s)||i.push(s)}return i},s.wrap=function(e,t){return function(){var n=[e];return arguments.length&&et.apply(n,arguments),t.apply(this,n)}},s.zip=function(e){for(var t=-1,n=e?w(wn(arguments,"length")):0,r=Array(n);++
wn,s.methods=tn,s.select=pn,s.tail=N,s.take=E,s.unique=k,O(s),s.prototype.chain=function(){return this.__chain__=n,this},s.prototype.value=function(){return this.__wrapped__},vn("pop push reverse shift sort splice unshift".split(" "),function(e){var t=_[e];s.prototype[e]=function(){var e=this.__wrapped__;return t.apply(e,arguments),Et&&e.length===0&&delete e[0],this.__chain__&&(e=new s(e),e.__chain__=n),e}}),vn(["concat","join","slice"],function(e){var t=_[e];s.prototype[e]=function(){var e=t.apply t<n;)r[t]=wn(arguments,t);return r},s.all=pn,s.any=xn,s.collect=bn,s.detect=vn,s.drop=N,s.each=mn,s.foldl=En,s.foldr=E,s.head=S,s.include=cn,s.inject=En,s.methods=nn,s.select=dn,s.tail=N,s.take=S,s.unique=k,O(s),s.prototype.chain=function(){return this.__chain__=n,this},s.prototype.value=function(){return this.__wrapped__},mn("pop push reverse shift sort splice unshift".split(" "),function(e){var t=_[e];s.prototype[e]=function(){var e=this.__wrapped__;return t.apply(e,arguments),St&&e.length===0&&delete
(this.__wrapped__,arguments);return this.__chain__&&(e=new s(e),e.__chain__=n),e}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(e._=s,define(function(){return s})):M?"object"==typeof module&&module&&module.exports==M?(module.exports=s)._=s:M._=s:e._=s})(this); e[0],this.__chain__&&(e=new s(e),e.__chain__=n),e}}),mn(["concat","join","slice"],function(e){var t=_[e];s.prototype[e]=function(){var e=t.apply(this.__wrapped__,arguments);return this.__chain__&&(e=new s(e),e.__chain__=n),e}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(e._=s,define(function(){return s})):M?"object"==typeof module&&module&&module.exports==M?(module.exports=s)._=s:M._=s:e._=s})(this);

View File

@@ -1,35 +1,36 @@
/*! /*!
Lo-Dash 0.8.0 lodash.com/license Lo-Dash 0.8.2 lodash.com/license
Underscore.js 1.4.0 underscorejs.org/LICENSE Underscore.js 1.4.2 underscorejs.org/LICENSE
*/ */
;(function(e,t){function s(e,t,r){var s,t=T(t,r),o=e.length,r=-1;if(o===+o){for(;++r<o;)if(s=e[r],t(s,r,e))return n}else for(r in e)if(st.call(e,r)&&(s=e[r],t(s,r,e)))return n;return i}function o(e,t,n,r){var s,o,u=n,a=3>arguments.length,t=T(t,r),f=e.length;s=-1;if(f===+f)for(a&&(u=e[++s]);++s<f;)o=e[s],u=t(u,o,s,e);else for(s in e)st.call(e,s)&&(o=e[s],u=a?(a=i,o):t(u,o,s,e));return u}function u(e,t){var n,r,i,s=e.length;n=-1;if(s===+s)for(i=Array(s);++n<s;)r=e[n],i[n]=r[t];else for(n in i=[],e)st ;(function(e,t){function s(e,t,r){var s;if(!e)return i;var t=x(t,r),o=e.length,r=-1;if(o===+o){for(;++r<o;)if(s=e[r],t(s,r,e))return n}else for(r in e)if(it.call(e,r)&&(s=e[r],t(s,r,e)))return n;return i}function o(e,t,n,r){var s,o,u=n;if(!e)return u;var a=3>arguments.length,t=x(t,r),f=e.length;s=-1;if(f===+f)for(a&&(u=e[++s]);++s<f;)o=e[s],u=t(u,o,s,e);else for(s in e)it.call(e,s)&&(o=e[s],u=a?(a=i,o):t(u,o,s,e));return u}function u(e,t){var n,r,i=e||[];if(!e)return i;var s=e.length;n=-1;if(s===+
.call(e,n)&&(r=e[n],i.push(r[t]));return i}function a(e,t,n){var r,i,t=T(t,n),s=e.length,n=-1;if(s===+s)for(i=Array(s);++n<s;)r=e[n],i[n]=t(r,n,e);else for(n in i=[],e)st.call(e,n)&&(r=e[n],i.push(t(r,n,e)));return i}function f(e,t,n){var r,t=T(t,n),i=e.length,n=-1;if(i===+i)for(;++n<i;)r=e[n],t(r,n,e);else for(n in e)st.call(e,n)&&(r=e[n],t(r,n,e));return e}function l(e,t,n){var r,t=T(t,n),i=e.length,n=-1;if(i===+i){for(;++n<i;)if(r=e[n],t(r,n,e))return r}else for(n in e)if(st.call(e,n)&&(r=e[n] s)for(i=Array(s);++n<s;)r=e[n],i[n]=r[t];else for(n in i=[],e)it.call(e,n)&&(r=e[n],i.push(r[t]));return i}function a(e,t,n){var r,i=e||[];if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(i=Array(s);++n<s;)r=e[n],i[n]=t(r,n,e);else for(n in i=[],e)it.call(e,n)&&(r=e[n],i.push(t(r,n,e)));return i}function f(e,t,n){var r;if(!e)return e;var t=x(t,n),i=e.length,n=-1;if(i===+i)for(;++n<i;)r=e[n],t(r,n,e);else for(n in e)it.call(e,n)&&(r=e[n],t(r,n,e));return e}function l(e,n,r){var i,s=t;if(!
,t(r,n,e)))return r}function c(e,t,n){var r,i=[],t=T(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],t(r,n,e)&&i.push(r);else for(n in e)st.call(e,n)&&(r=e[n],t(r,n,e)&&i.push(r));return i}function h(e,t,r){var s,t=T(t,r),o=e.length,r=-1;if(o===+o){for(;++r<o;)if(s=e[r],!t(s,r,e))return i}else for(r in e)if(st.call(e,r)&&(s=e[r],!t(s,r,e)))return i;return n}function p(e,t){var r,s,o=e.length;r=-1;if(o===+o){if(ft.call(e)==Tt)return-1<e.indexOf(t);for(;++r<o;)if(s=e[r],s===t)return n}else for(r in e)return s;var n=x(n,r),o=e.length,r=-1;if(o===+o){for(;++r<o;)if(i=e[r],n(i,r,e))return i}else for(r in e)if(it.call(e,r)&&(i=e[r],n(i,r,e)))return i;return s}function c(e,t,n){var r,i=[];if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],t(r,n,e)&&i.push(r);else for(n in e)it.call(e,n)&&(r=e[n],t(r,n,e)&&i.push(r));return i}function h(e,t,r){var s;if(!e)return n;var t=x(t,r),o=e.length,r=-1;if(o===+o){for(;++r<o;)if(s=e[r],!t(s,r,e))return i}else for(r in e)if(it.call(e,r)&&
e)if(st.call(e,r)&&(s=e[r],s===t))return n;return i}function d(e){var t,n,r=[];for(t in e)st.call(e,t)&&(n=e[t],r.push(n));return r}function v(e){var t,n,r=[];for(t in e)n=e[t],A(n)&&r.push(t);return r.sort(),r}function m(e,t,n){var r,t=T(t,n);for(r in e)n=e[r],t(n,r,e);return e}function g(e){for(var t,n,r=e,i=1,s=arguments.length;i<s;i++)if(r=arguments[i])for(t in r)n=r[t],e[t]=n;return e}function y(e){var t,n=[];if(!e||!Lt[typeof e])throw TypeError();for(t in e)st.call(e,t)&&n.push(t);return n} (s=e[r],!t(s,r,e)))return i;return n}function p(e,t){var r,s;if(!e)return i;var o=e.length;r=-1;if(o===+o){if(ut.call(e)==wt)return-1<e.indexOf(t);for(;++r<o;)if(s=e[r],s===t)return n}else for(r in e)if(it.call(e,r)&&(s=e[r],s===t))return n;return i}function d(e){var t,n,r=[];if(!e)return r;for(t in e)it.call(e,t)&&(n=e[t],r.push(n));return r}function v(e){var t,n,r=[];if(!e)return r;for(t in e)n=e[t],L(n)&&r.push(t);return r.sort(),r}function m(e,t,n){var r;if(!e)return e;t=x(t,n);for(r in e)n=e
function b(e){var t,n,r={};for(t in e)st.call(e,t)&&(n=e[t],r[n]=t);return r}function w(e){if(e&&e.__wrapped__)return e;if(!(this instanceof w))return new w(e);this.__wrapped__=e}function E(e,t){return function(n){return-1<H(e,n,t||0)}}function S(e,n){var r=e.b,i=n.b,e=e.a,n=n.a;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<i?-1:1}function x(e,t,n){function r(){var i=arguments,s=t;return n.length&&(i=i.length?n.concat(at.call(i)):n),this instanceof r?(k.prototype=e.prototype,s=new [r],t(n,r,e);return e}function g(e){var t,n,r=e;if(!e)return e;for(var i=1,s=arguments.length;i<s;i++)if(r=arguments[i])for(t in r)n=r[t],e[t]=n;return e}function y(e){var t,n=[];if(!e)return n;for(t in e)it.call(e,t)&&n.push(t);return n}function b(e){var t,n,r={};if(!e)return r;for(t in e)it.call(e,t)&&(n=e[t],r[n]=t);return r}function w(e){if(e&&e.__wrapped__)return e;if(!(this instanceof w))return new w(e);this.__wrapped__=e}function E(e,n){var r=e.b,i=n.b,e=e.a,n=n.a;if(e!==n){if(e>n||e===t)return 1
k,(i=e.apply(s,i))&&Lt[typeof i]?i:s):e.apply(s,i)}return r}function T(e,n){return e?"function"!=typeof e?function(t){return t[e]}:n!==t?function(t,r,i){return e.call(n,t,r,i)}:e:R}function N(e){return"\\"+At[e]}function C(e){return Mt[e]}function k(){}function L(e){return _t[e]}function A(e){return"function"==typeof e}function O(e){var t=i;if(!e||"object"!=typeof e||isArguments(e))return t;var n=e.constructor;return!A(n)||n instanceof n?(m(e,function(e,n){t=n}),t===i||st.call(e,t)):t}function M( ;if(e<n||n===t)return-1}return r<i?-1:1}function S(e,t,n){function r(){var i=arguments,s=t;return n.length&&(i=i.length?n.concat(ot.call(i)):n),this instanceof r?(C.prototype=e.prototype,s=new C,(i=e.apply(s,i))&&Tt[typeof i]?i:s):e.apply(s,i)}return r}function x(e,n){return e?"function"!=typeof e?function(t){return t[e]}:n!==t?function(t,r,i){return e.call(n,t,r,i)}:e:q}function T(e){return"\\"+Nt[e]}function N(e){return kt[e]}function C(){}function k(e){return Lt[e]}function L(e){return"function"==typeof
e,t,s,o){if(e==r||t==r)return e===t;if(e===t)return 0!==e||1/e==1/t;if(Lt[typeof e]||Lt[typeof t])e=e.__wrapped__||e,t=t.__wrapped__||t;var u=ft.call(e);if(u!=ft.call(t))return i;switch(u){case bt:case wt:return+e==+t;case Et:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case xt:case Tt:return e==t+""}var a=Ot(e);if(!a&&u!=St)return i;s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var f=n,u=0;s.push(e),o.push(t);if(a){u=e.length;if(f=u==t.length)for(;u--&&(f=M(e[u],t[u],s,o)););return f e}function A(e){var t=i;if(!e||"object"!=typeof e||isArguments(e))return t;var n=e.constructor;return!L(n)||n instanceof n?(m(e,function(e,n){t=n}),t===i||it.call(e,t)):t}function O(e,t,s,o){if(e==r||t==r)return e===t;if(e===t)return 0!==e||1/e==1/t;if(Tt[typeof e]||Tt[typeof t])e=e.__wrapped__||e,t=t.__wrapped__||t;var u=ut.call(e);if(u!=ut.call(t))return i;switch(u){case vt:case mt:return+e==+t;case gt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case bt:case wt:return e==t+""}var a=Ct(e);if(!a&&u!=yt
}a=e.constructor,f=t.constructor;if(a!=f&&(!A(a)||!(a instanceof a&&A(f)&&f instanceof f)))return i;for(var l in e)if(st.call(e,l)&&(u++,!st.call(t,l)||!M(e[l],t[l],s,o)))return i;for(l in t)if(st.call(t,l)&&!(u--))return i;return n}function _(e,t,n,r){var s=e.length,o=3>arguments.length;if(s!==+s)var u=Dt(e),s=u.length;return f(e,function(a,f,l){f=u?u[--s]:--s,n=o?(o=i,e[f]):t.call(r,n,e[f],f,l)}),n}function D(e,t,n){return t==r||n?e[0]:at.call(e,0,t)}function P(e,t){for(var n,r=-1,i=e.length,s= )return i;s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var f=n,u=0;s.push(e),o.push(t);if(a){u=e.length;if(f=u==t.length)for(;u--&&(f=O(e[u],t[u],s,o)););return f}a=e.constructor,f=t.constructor;if(a!=f&&(!L(a)||!(a instanceof a&&L(f)&&f instanceof f)))return i;for(var l in e)if(it.call(e,l)&&(u++,!it.call(t,l)||!O(e[l],t[l],s,o)))return i;for(l in t)if(it.call(t,l)&&!(u--))return i;return n}function M(e,t,n){var r=-Infinity,i=-1,s=e?e.length:0,o=r;if(t||s!==+s)t=x(t,n),f(e,function(
[];++r<i;)n=e[r],Ot(n)?ot.apply(s,t?n:P(n)):s.push(n);return s}function H(e,t,n){var r=-1,i=e.length;if(n){if("number"!=typeof n)return r=F(e,t),e[r]===t?r:-1;r=(0>n?mt(0,i+n):n)-1}for(;++r<i;)if(e[r]===t)return r;return-1}function B(e,t,n){for(var r=-Infinity,i=-1,s=e?e.length:0,o=r,t=T(t,n);++i<s;)n=t(e[i],i,e),n>r&&(r=n,o=e[i]);return o}function j(e,t,n){return at.call(e,t==r||n?1:t)}function F(e,t,n,r){for(var i=0,s=e.length,n=T(n,r),t=n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r;return i}function I e,n,i){n=t(e,n,i),n>r&&(r=n,o=e)});else for(;++i<s;)e[i]>o&&(o=e[i]);return o}function _(e,t,n,r){var s=e?e.length:0,o=3>arguments.length;if(s!==+s)var u=At(e),s=u.length;return f(e,function(a,f,l){f=u?u[--s]:--s,n=o?(o=i,e[f]):t.call(r,n,e[f],f,l)}),n}function D(e,t,n){if(e)return t==r||n?e[0]:ot.call(e,0,t)}function P(e,t){for(var n=-1,r=e?e.length:0,i=[];++n<r;){var s=e[n];Ct(s)?st.apply(i,t?s:P(s)):i.push(s)}return i}function H(e,t,n){var r=-1,i=e?e.length:0;if("number"==typeof n)r=(0>n?ht(0,
(e,t,n,r){var s=-1,o=e.length,u=[],a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n=T(n,r);++s<o;)if(r=n(e[s],s,e),t?!s||a[a.length-1]!==r:0>H(a,r))a.push(r),u.push(e[s]);return u}function q(e,t){return kt||lt&&2<arguments.length?lt.call.apply(lt,arguments):x(e,t,at.call(arguments,2))}function R(e){return e}function U(e){f(v(e),function(t){var r=w[t]=e[t];w.prototype[t]=function(){var e=[this.__wrapped__];return arguments.length&&ot.apply(e,arguments),e=r.apply(w,e),this.__chain__&&(e=new w(e),e.__chain__= i+n):n||0)-1;else if(n)return r=j(e,t),e[r]===t?r:-1;for(;++r<i;)if(e[r]===t)return r;return-1}function B(e,t,n){return e?ot.call(e,t==r||n?1:t):[]}function j(e,t,n,r){var i=0,s=e?e.length:i;if(n){n=x(n,r);for(t=n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r}else for(;i<s;)r=i+s>>>1,e[r]<t?i=r+1:s=r;return i}function F(e,t,n,r){var s=-1,o=e?e.length:0,u=[],a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n=x(n,r);++s<o;)if(r=n(e[s],s,e),t?!s||a[a.length-1]!==r:0>H(a,r))a.push(r),u.push(e[s]);return u}function I
n),e}})}var n=!0,r=null,i=!1,z="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),W=Array.prototype,X=Object.prototype,V=0,$=e._,J=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,K=/&(?:amp|lt|gt|quot|#x27);/g,Q=/\b__p\+='';/g,G=/\b(__p\+=)''\+/g,Y=/(__e\(.*?\)|\b__t\))\+'';/g,Z=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,et=RegExp("^"+(X.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g (e,t){return xt||at&&2<arguments.length?at.call.apply(at,arguments):S(e,t,ot.call(arguments,2))}function q(e){return e}function R(e){f(v(e),function(t){var r=w[t]=e[t];w.prototype[t]=function(){var e=[this.__wrapped__];return arguments.length&&st.apply(e,arguments),e=r.apply(w,e),this.__chain__&&(e=new w(e),e.__chain__=n),e}})}var n=!0,r=null,i=!1,U="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),z=Array.prototype,W=Object.prototype,
,".+?")+"$"),tt=/($^)/,nt=/[&<>"']/g,rt=/['\n\r\t\u2028\u2029\\]/g,it=W.concat,st=X.hasOwnProperty,ot=W.push,ut=X.propertyIsEnumerable,at=W.slice,ft=X.toString,lt=et.test(lt=at.bind)&&lt,ct=Math.floor,ht=et.test(ht=Object.getPrototypeOf)&&ht,pt=et.test(pt=Array.isArray)&&pt,dt=e.isFinite,vt=et.test(vt=Object.keys)&&vt,mt=Math.max,gt=Math.min,yt=Math.random,bt="[object Boolean]",wt="[object Date]",Et="[object Number]",St="[object Object]",xt="[object RegExp]",Tt="[object String]",Nt=e.clearTimeout X=0,V=e._,$=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,J=/&(?:amp|lt|gt|quot|#x27);/g,K=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,Q=RegExp("^"+(W.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),G=/($^)/,Y=/[&<>"']/g,Z=/['\n\r\t\u2028\u2029\\]/g,et=Math.ceil,tt=z.concat,nt=Math.floor,rt=Q.test(rt=Object.getPrototypeOf)&&rt,it=W.hasOwnProperty,st=z.push,ot=z.slice,ut=W.toString,at=Q.test(at=ot.bind)&&at,ft=Q.test(ft=Array.isArray
,Ct=e.setTimeout,kt=lt&&/\n|Opera/.test(lt+ft.call(e.opera)),Lt={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},At={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};w.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""},w.isArguments=function(e){return"[object Arguments]"==ft.call(e)},w.isArguments(arguments)||(w.isArguments=function(e){return!!e&&!!st.call(e,"callee")});var Ot= )&&ft,lt=e.isFinite,ct=Q.test(ct=Object.keys)&&ct,ht=Math.max,pt=Math.min,dt=Math.random,vt="[object Boolean]",mt="[object Date]",gt="[object Number]",yt="[object Object]",bt="[object RegExp]",wt="[object String]",Et=e.clearTimeout,St=e.setTimeout,xt=at&&/\n|Opera/.test(at+ut.call(e.opera)),Tt={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},Nt={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};w.templateSettings={escape:/<%-([\s\S]+?)%>/g
pt||function(e){return"[object Array]"==ft.call(e)};A(/x/)&&(A=function(e){return"[object Function]"==ft.call(e)});var X=ht?function(e){if(!e||"object"!=typeof e)return i;var t=e.valueOf,n="function"==typeof t&&(n=ht(t))&&ht(n);return n?e==n||ht(e)==n&&!isArguments(e):O(e)}:O,Mt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"},_t=b(Mt),Dt=vt?function(e){return"function"==typeof e&&ut.call(e,"prototype")?y(e):vt(e)}:y;w.VERSION="0.8.0",w.after=function(e,t){return 1>e?t():function(){if(1>-- ,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""},w.isArguments=function(e){return"[object Arguments]"==ut.call(e)},w.isArguments(arguments)||(w.isArguments=function(e){return e?it.call(e,"callee"):i});var Ct=ft||function(e){return"[object Array]"==ut.call(e)};L(/x/)&&(L=function(e){return"[object Function]"==ut.call(e)});var W=rt?function(e){if(!e||"object"!=typeof e)return i;var t=e.valueOf,n="function"==typeof t&&(n=rt(t))&&rt(n);return n?e==n||rt(e)==n&&!isArguments(e):A
e)return t.apply(this,arguments)}},w.bind=q,w.bindAll=function(e){var t,n=e,r=e,i=arguments,s=i.length;if(1<s){for(t=1;t<s;t++)r[i[t]]=q(r[i[t]],r);return r}for(t in n)A(r[t])&&(r[t]=q(r[t],r));return r},w.chain=function(e){return e=new w(e),e.__chain__=n,e},w.clone=function(e){return e&&Lt[typeof e]?Ot(e)?at.call(e):g({},e):e},w.compact=function(e){for(var t=-1,n=e.length,r=[];++t<n;)e[t]&&r.push(e[t]);return r},w.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length (e)}:A,kt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"},Lt=b(kt),At=ct?function(e){return e&&Tt[typeof e]?ct(e):[]}:y;w.VERSION="0.8.2",w.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this,arguments)}},w.bind=I,w.bindAll=function(e){var t,n,r=e,i=e;if(!e)return i;n=arguments,t=0;var s=n.length;if(1<s){for(;++t<s;)i[n[t]]=I(i[n[t]],i);return i}for(t in r)n=r[t],L(n)&&(i[t]=I(n,i));return i},w.chain=function(e){return e=new w(e),e.__chain__=n,e},w.clone=function(
;n--;)t=[e[n].apply(this,t)];return t[0]}},w.contains=p,w.countBy=function(e,t,n){var r,i={},t=T(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],r=t(r,n,e),st.call(i,r)?i[r]++:i[r]=1;else for(n in e)st.call(e,n)&&(r=e[n],r=t(r,n,e),st.call(i,r)?i[r]++:i[r]=1);return i},w.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,Nt(a),a=Ct(i,t),r&&(o=e.apply(u,s)),o}},w.defaults=function(e){for(var t,n,i=e,s=1,o=arguments.length e){return e&&Tt[typeof e]?Ct(e)?ot.call(e):g({},e):e},w.compact=function(e){for(var t=-1,n=e?e.length:0,r=[];++t<n;){var i=e[t];i&&r.push(i)}return r},w.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},w.contains=p,w.countBy=function(e,t,n){var r,i={};if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],r=t(r,n,e),it.call(i,r)?i[r]++:i[r]=1;else for(n in e)it.call(e,n)&&(r=e[n],r=t(r,n,e),it.call(i,r)?
;s<o;s++)if(i=arguments[s])for(t in i)n=i[t],e[t]==r&&(e[t]=n);return e},w.defer=function(e){var n=at.call(arguments,1);return Ct(function(){return e.apply(t,n)},1)},w.delay=function(e,n){var r=at.call(arguments,2);return Ct(function(){return e.apply(t,r)},n)},w.difference=function(e){for(var t=-1,n=e.length,r=it.apply(W,arguments),r=E(r,n),i=[];++t<n;)r(e[t])||i.push(e[t]);return i},w.escape=function(e){return e==r?"":(e+"").replace(nt,C)},w.every=h,w.extend=g,w.filter=c,w.find=l,w.first=D,w.flatten= i[r]++:i[r]=1);return i},w.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,Et(a),a=St(i,t),r&&(o=e.apply(u,s)),o}},w.defaults=function(e){var t,n,i=e;if(!e)return e;for(var s=1,o=arguments.length;s<o;s++)if(i=arguments[s])for(t in i)n=i[t],e[t]==r&&(e[t]=n);return e},w.defer=function(e){var n=ot.call(arguments,1);return St(function(){return e.apply(t,n)},1)},w.delay=function(e,n){var r=ot.call(arguments,2);return St
P,w.forEach=f,w.forIn=m,w.forOwn=function(e,t,n){var r,t=T(t,n);for(r in e)st.call(e,r)&&(n=e[r],t(n,r,e));return e},w.functions=v,w.groupBy=function(e,t,n){var r,i={},t=T(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;){r=e[n];var o=t(r,n,e);(st.call(i,o)?i[o]:i[o]=[]).push(r)}else for(n in e)st.call(e,n)&&(r=e[n],o=t(r,n,e),(st.call(i,o)?i[o]:i[o]=[]).push(r));return i},w.has=function(e,t){return st.call(e,t)},w.identity=R,w.indexOf=H,w.initial=function(e,t,n){return at.call(e,0,-(t==r||n?1:t))},w.intersection= (function(){return e.apply(t,r)},n)},w.difference=function(e){for(var t=-1,n=e.length,r=tt.apply(z,arguments),i=[];++t<n;){var s=e[t];0>H(r,s,n)&&i.push(s)}return i},w.escape=function(e){return e==r?"":(e+"").replace(Y,N)},w.every=h,w.extend=g,w.filter=c,w.find=l,w.first=D,w.flatten=P,w.forEach=f,w.forIn=m,w.forOwn=function(e,t,n){var r;if(!e)return e;t=x(t,n);for(r in e)it.call(e,r)&&(n=e[r],t(n,r,e));return e},w.functions=v,w.groupBy=function(e,t,n){var r,i={};if(!e)return i;var t=x(t,n),s=e.length
function(e){var t,n=arguments.length,r=[],i=-1,s=e.length,o=[];e:for(;++i<s;)if(t=e[i],0>H(o,t)){for(var u=1;u<n;u++)if(!(r[u]||(r[u]=E(arguments[u])))(t))continue e;o.push(t)}return o},w.invert=b,w.invoke=function(e,t){var n,r,i=e,s,o=at.call(arguments,2),u="function"==typeof t,a=i.length;n=-1;if(a===+a)for(s=Array(a);++n<a;)r=i[n],s[n]=(u?t:r[t]).apply(r,o);else for(n in s=[],i)st.call(i,n)&&(r=i[n],s.push((u?t:r[t]).apply(r,o)));return s},w.isArray=Ot,w.isBoolean=function(e){return e===n||e=== ,n=-1;if(s===+s)for(;++n<s;){r=e[n];var o=t(r,n,e);(it.call(i,o)?i[o]:i[o]=[]).push(r)}else for(n in e)it.call(e,n)&&(r=e[n],o=t(r,n,e),(it.call(i,o)?i[o]:i[o]=[]).push(r));return i},w.has=function(e,t){return e?it.call(e,t):i},w.identity=q,w.indexOf=H,w.initial=function(e,t,n){return e?ot.call(e,0,-(t==r||n?1:t)):[]},w.intersection=function(e){var t=arguments.length,n=-1,r=e.length,i=[];e:for(;++n<r;){var s=e[n];if(0>H(i,s)){for(var o=1;o<t;o++)if(0>H(arguments[o],s))continue e;i.push(s)}}return i
i||ft.call(e)==bt},w.isDate=function(e){return ft.call(e)==wt},w.isElement=function(e){return e?1===e.nodeType:i},w.isEmpty=function(e){var t;if(!e)return n;var r=ft.call(e),s=e.length;if(Ot(e)||r==Tt||r==St&&s===+s&&A(e.splice))return!s;for(t in e)if(st.call(e,t))return i;return n},w.isEqual=M,w.isFinite=function(e){return dt(e)&&ft.call(e)==Et},w.isFunction=A,w.isNaN=function(e){return ft.call(e)==Et&&e!=+e},w.isNull=function(e){return e===r},w.isNumber=function(e){return ft.call(e)==Et},w.isObject= },w.invert=b,w.invoke=function(e,t){var n,r,i=e,s=e||[];if(!e)return s;var o=ot.call(arguments,2),u="function"==typeof t,a=i.length;n=-1;if(a===+a)for(s=Array(a);++n<a;)r=i[n],s[n]=(u?t:r[t]).apply(r,o);else for(n in s=[],i)it.call(i,n)&&(r=i[n],s.push((u?t:r[t]).apply(r,o)));return s},w.isArray=Ct,w.isBoolean=function(e){return e===n||e===i||ut.call(e)==vt},w.isDate=function(e){return ut.call(e)==mt},w.isElement=function(e){return e?1===e.nodeType:i},w.isEmpty=function(e){var t;if(!e)return n;var r=
function(e){return e?Lt[typeof e]:i},w.isPlainObject=X,w.isRegExp=function(e){return ft.call(e)==xt},w.isString=function(e){return ft.call(e)==Tt},w.isUndefined=function(e){return e===t},w.keys=Dt,w.last=function(e,t,n){var i=e.length;return t==r||n?e[i-1]:at.call(e,-t||i)},w.lastIndexOf=function(e,t,n){var r=e.length;for(n&&"number"==typeof n&&(r=(0>n?mt(0,r+n):gt(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},w.map=a,w.max=B,w.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this ut.call(e),s=e.length;if(Ct(e)||r==wt||r==yt&&s===+s&&L(e.splice))return!s;for(t in e)if(it.call(e,t))return i;return n},w.isEqual=O,w.isFinite=function(e){return lt(e)&&ut.call(e)==gt},w.isFunction=L,w.isNaN=function(e){return ut.call(e)==gt&&e!=+e},w.isNull=function(e){return e===r},w.isNumber=function(e){return ut.call(e)==gt},w.isObject=function(e){return e?Tt[typeof e]:i},w.isPlainObject=W,w.isRegExp=function(e){return ut.call(e)==bt},w.isString=function(e){return ut.call(e)==wt},w.isUndefined=
,arguments):arguments[0];return st.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},w.min=function(e,t,n){for(var r=Infinity,i=-1,s=e?e.length:0,o=r,t=T(t,n);++i<s;)n=t(e[i],i,e),n<r&&(r=n,o=e[i]);return o},w.mixin=U,w.noConflict=function(){return e._=$,this},w.object=function(e,t){for(var n=-1,r=e.length,i={};++n<r;)t?i[e[n]]=t[n]:i[e[n][0]]=e[n][1];return i},w.omit=function(e,t,n){var r,i,s=e,o={},u="function"==typeof t;if(u)t=T(t,n);else var a=it.apply(W,arguments);for(r in s)if(i=s[r],u?!t(i,r,e function(e){return e===t},w.keys=At,w.last=function(e,t,n){if(e){var i=e.length;return t==r||n?e[i-1]:ot.call(e,-t||i)}},w.lastIndexOf=function(e,t,n){var r=e?e.length:0;for("number"==typeof n&&(r=(0>n?ht(0,r+n):pt(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},w.map=a,w.max=M,w.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return it.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},w.min=function(e,t,n){var r=Infinity,i=-1,s=e?e.length:0,o=r;if(t||s!==+
):0>H(a,r))o[r]=i;return o},w.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},w.pairs=function(e){var t,n,r=[];for(t in e)st.call(e,t)&&(n=e[t],r.push([t,n]));return r},w.pick=function(e,t,n){var r,i,s=e,o={};if("function"!=typeof t){var s=it.apply(W,arguments),u=s.length;for(r=1;r<u;r++)i=s[r],i in e&&(o[i]=e[i])}else for(r in t=T(t,n),s)i=s[r],t(i,r,e)&&(o[r]=i);return o},w.pluck=u,w.random=function(e,t){return e==r&&t==r&&(t=1),e=+e||0,t==r&&(t=e s)t=x(t,n),f(e,function(e,n,i){n=t(e,n,i),n<r&&(r=n,o=e)});else for(;++i<s;)e[i]<o&&(o=e[i]);return o},w.mixin=R,w.noConflict=function(){return e._=V,this},w.object=function(e,t){for(var n=-1,r=e?e.length:0,i={};++n<r;){var s=e[n];t?i[s]=t[n]:i[s[0]]=s[1]}return i},w.omit=function(e,t,n){var r,i,s=e,o={};if(!e)return o;var u="function"==typeof t;if(u)t=x(t,n);else var a=tt.apply(z,arguments);for(r in s)if(i=s[r],u?!t(i,r,e):0>H(a,r))o[r]=i;return o},w.once=function(e){var t,s=i;return function(){
,e=0),e+ct(yt()*((+t||0)-e+1))},w.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=mt(0,Math.ceil((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},w.reduce=o,w.reduceRight=_,w.reject=function(e,t,n){var r,i=[],t=T(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],!t(r,n,e)&&i.push(r);else for(n in e)st.call(e,n)&&(r=e[n],!t(r,n,e)&&i.push(r));return i},w.rest=j,w.result=function(e,t){var n=e?e[t]:r;return A(n)?e[t]():n},w.shuffle=function(e){for(var t,n=-1,r=e.length,i=Array( return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},w.pairs=function(e){var t,n,r=[];if(!e)return r;for(t in e)it.call(e,t)&&(n=e[t],r.push([t,n]));return r},w.pick=function(e,t,n){var r,i,s=e,o={};if(!e)return o;if("function"!=typeof t){r=0,i=tt.apply(z,arguments);for(s=i.length;++r<s;){var u=i[r];u in e&&(o[u]=e[u])}}else for(r in t=x(t,n),s)i=s[r],t(i,r,e)&&(o[r]=i);return o},w.pluck=u,w.random=function(e,t){return e==r&&t==r&&(t=1),e=+e||0,t==r&&(t=e,e=0),e+nt(dt()*((+t||0)-e+1))},w.range=function(
r);++n<r;)t=ct(yt()*(n+1)),i[n]=i[t],i[t]=e[n];return i},w.size=function(e){var t=e?e.length:0;return t===+t?t:Dt(e).length},w.some=s,w.sortBy=function(e,t,n){var r,i,t=T(t,n),s=e.length,n=-1;if(s===+s)for(i=Array(s);++n<s;)r=e[n],i[n]={a:t(r,n,e),b:n,c:r};else for(n in i=[],e)st.call(e,n)&&(r=e[n],i.push({a:t(r,n,e),b:n,c:r}));i.sort(S);for(s=i.length;s--;)i[s]=i[s].c;return i},w.sortedIndex=F,w.tap=function(e,t){return t(e),e},w.template=function(e,t,n){n||(n={});var r,i,s=0,o=w.templateSettings e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=ht(0,et((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},w.reduce=o,w.reduceRight=_,w.reject=function(e,t,n){var r,i=[];if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],!t(r,n,e)&&i.push(r);else for(n in e)it.call(e,n)&&(r=e[n],!t(r,n,e)&&i.push(r));return i},w.rest=B,w.result=function(e,t){var n=e?e[t]:r;return L(n)?e[t]():n},w.shuffle=function(e){var t=-1,n=Array(e?e.length:0);return f(e,function(e){var r=nt(dt()*(++
,u="__p += '",a=n.variable||o.variable,f=a;e.replace(RegExp((n.escape||o.escape||tt).source+"|"+(n.interpolate||o.interpolate||tt).source+"|"+(n.evaluate||o.evaluate||tt).source+"|$","g"),function(t,n,i,o,a){u+=e.slice(s,a).replace(rt,N),u+=n?"'+__e("+n+")+'":o?"';"+o+";__p+='":i?"'+((__t=("+i+"))==null?'':__t)+'":"",r||(r=o||J.test(n||i)),s=a+t.length}),u+="';",f||(a="obj",r?u="with("+a+"){"+u+"}":(n=RegExp("(\\(\\s*)"+a+"\\."+a+"\\b","g"),u=u.replace(Z,"$&"+a+".").replace(n,"$1__d"))),u=(r?u.replace t+1));n[t]=n[r],n[r]=e}),n},w.size=function(e){var t=e?e.length:0;return t===+t?t:At(e).length},w.some=s,w.sortBy=function(e,t,n){var r,i=e||[];if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(i=Array(s);++n<s;)r=e[n],i[n]={a:t(r,n,e),b:n,c:r};else for(n in i=[],e)it.call(e,n)&&(r=e[n],i.push({a:t(r,n,e),b:n,c:r}));i.sort(E);for(s=i.length;s--;)i[s]=i[s].c;return i},w.sortedIndex=j,w.tap=function(e,t){return t(e),e},w.template=function(e,t,n){e||(e=""),n||(n={});var r,i,s=0,o=w.templateSettings
(Q,""):u).replace(G,"$1").replace(Y,"$1;"),u="function("+a+"){"+(f?"":a+"||("+a+"={});")+"var __t,__p='',__e=_.escape"+(r?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(f?"":",__d="+a+"."+a+"||"+a)+";")+u+"return __p}";try{i=Function("_","return "+u)(w)}catch(l){throw l.source=u,l}return t?i(t):(i.source=u,i)},w.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function(){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(a= ,u="__p += '",a=n.variable||o.variable,f=a;e.replace(RegExp((n.escape||o.escape||G).source+"|"+(n.interpolate||o.interpolate||G).source+"|"+(n.evaluate||o.evaluate||G).source+"|$","g"),function(t,n,i,o,a){u+=e.slice(s,a).replace(Z,T),u+=n?"'+__e("+n+")+'":o?"';"+o+";__p+='":i?"'+((__t=("+i+"))==null?'':__t)+'":"",r||(r=o||$.test(n||i)),s=a+t.length}),u+="';",f||(a="obj",r?u="with("+a+"){"+u+"}":(n=RegExp("(\\(\\s*)"+a+"\\."+a+"\\b","g"),u=u.replace(K,"$&"+a+".").replace(n,"$1__d"))),u="function("+
r,s=e.apply(o,i)):u||(u=Ct(n,f)),s}},w.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r<e;)i[r]=t.call(n,r);return i},w.toArray=function(e){var t=e?e.length:0;return t===+t?"string"==typeof e?e.split(""):at.call(e):d(e)},w.unescape=function(e){return e==r?"":(e+"").replace(K,L)},w.union=function(){for(var e=-1,t=it.apply(W,arguments),n=t.length,r=[];++e<n;)0>H(r,t[e])&&r.push(t[e]);return r},w.uniq=I,w.uniqueId=function(e){var t=V++;return e?e+t:t},w.values=d,w.where=function(e,t){var r, a+"){"+(f?"":a+"||("+a+"={});")+"var __t,__p='',__e=_.escape"+(r?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(f?"":",__d="+a+"."+a+"||"+a)+";")+u+"return __p}";try{i=Function("_","return "+u)(w)}catch(l){throw l.source=u,l}return t?i(t):(i.source=u,i)},w.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function(){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(Et(u),a=r,s=e.apply(o,i)):u||(u=St(n,f)),s}},w.times=function(
i,s=[],o=[];m(t,function(e,t){o.push(t)});var u=o.length,a=e.length;r=-1;if(a===+a)for(;++r<a;){i=e[r];var f;f=n;for(var l=0;l<u&&(f=o[l],f=i[f]===t[f]);l++);f&&s.push(i)}else for(r in e)if(st.call(e,r)){i=e[r],f=n;for(l=0;l<u&&(f=o[l],f=i[f]===t[f]);l++);f&&s.push(i)}return s},w.without=function(e){for(var t=-1,n=e.length,r=E(arguments,1),i=[];++t<n;)r(e[t])||i.push(e[t]);return i},w.wrap=function(e,t){return function(){var n=[e];return arguments.length&&ot.apply(n,arguments),t.apply(this,n)}},w e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r<e;)i[r]=t.call(n,r);return i},w.toArray=function(e){if(!e)return[];var t=e.length;return t===+t?"string"==typeof e?e.split(""):ot.call(e):d(e)},w.unescape=function(e){return e==r?"":(e+"").replace(J,k)},w.union=function(){for(var e=-1,t=tt.apply(z,arguments),n=t.length,r=[];++e<n;){var i=t[e];0>H(r,i)&&r.push(i)}return r},w.uniq=F,w.uniqueId=function(e){var t=X++;return e?e+t:t},w.values=d,w.where=function(e,t){var r,i,s=[];if(!e)return s;var o=[];m(t,function(
.zip=function(e){for(var t=-1,n=B(u(arguments,"length")),r=Array(n);++t<n;)r[t]=u(arguments,t);return r},w.all=h,w.any=s,w.collect=a,w.detect=l,w.drop=j,w.each=f,w.foldl=o,w.foldr=_,w.head=D,w.include=p,w.inject=o,w.methods=v,w.select=c,w.tail=j,w.take=D,w.unique=I,U(w),w.prototype.chain=function(){return this.__chain__=n,this},w.prototype.value=function(){return this.__wrapped__},f("pop push reverse shift sort splice unshift".split(" "),function(e){var t=W[e];w.prototype[e]=function(){var e=this e,t){o.push(t)});var u=o.length,a=e.length;r=-1;if(a===+a)for(;++r<a;){i=e[r];for(var f=n,l=0;l<u&&(f=o[l],f=i[f]===t[f]);l++);f&&s.push(i)}else for(r in e)if(it.call(e,r)){i=e[r],f=n;for(l=0;l<u&&(f=o[l],f=i[f]===t[f]);l++);f&&s.push(i)}return s},w.without=function(e){for(var t=-1,n=e.length,r=[];++t<n;){var i=e[t];0>H(arguments,i,1)&&r.push(i)}return r},w.wrap=function(e,t){return function(){var n=[e];return arguments.length&&st.apply(n,arguments),t.apply(this,n)}},w.zip=function(e){for(var t=-1
.__wrapped__;return t.apply(e,arguments),this.__chain__&&(e=new w(e),e.__chain__=n),e}}),f(["concat","join","slice"],function(e){var t=W[e];w.prototype[e]=function(){var e=t.apply(this.__wrapped__,arguments);return this.__chain__&&(e=new w(e),e.__chain__=n),e}}),z?"object"==typeof module&&module&&module.exports==z?(module.exports=w)._=w:z._=w:e._=w})(this); ,n=e?M(u(arguments,"length")):0,r=Array(n);++t<n;)r[t]=u(arguments,t);return r},w.all=h,w.any=s,w.collect=a,w.detect=l,w.drop=B,w.each=f,w.foldl=o,w.foldr=_,w.head=D,w.include=p,w.inject=o,w.methods=v,w.select=c,w.tail=B,w.take=D,w.unique=F,R(w),w.prototype.chain=function(){return this.__chain__=n,this},w.prototype.value=function(){return this.__wrapped__},f("pop push reverse shift sort splice unshift".split(" "),function(e){var t=z[e];w.prototype[e]=function(){var e=this.__wrapped__;return t.apply
(e,arguments),this.__chain__&&(e=new w(e),e.__chain__=n),e}}),f(["concat","join","slice"],function(e){var t=z[e];w.prototype[e]=function(){var e=t.apply(this.__wrapped__,arguments);return this.__chain__&&(e=new w(e),e.__chain__=n),e}}),U?"object"==typeof module&&module&&module.exports==U?(module.exports=w)._=w:U._=w:e._=w})(this);

View File

@@ -1,6 +1,6 @@
{ {
"name": "lodash", "name": "lodash",
"version": "0.8.0", "version": "0.8.2",
"description": "A drop-in replacement for Underscore.js delivering performance, bug fixes, and additional features.", "description": "A drop-in replacement for Underscore.js delivering performance, bug fixes, and additional features.",
"homepage": "http://lodash.com", "homepage": "http://lodash.com",
"main": "./lodash", "main": "./lodash",

View File

@@ -69,12 +69,9 @@
'intersection', 'intersection',
'last', 'last',
'lastIndexOf', 'lastIndexOf',
'max',
'min',
'object', 'object',
'range', 'range',
'rest', 'rest',
'shuffle',
'sortedIndex', 'sortedIndex',
'tail', 'tail',
'take', 'take',
@@ -113,11 +110,14 @@
'inject', 'inject',
'invoke', 'invoke',
'map', 'map',
'max',
'min',
'pluck', 'pluck',
'reduce', 'reduce',
'reduceRight', 'reduceRight',
'reject', 'reject',
'select', 'select',
'shuffle',
'size', 'size',
'some', 'some',
'sortBy', 'sortBy',
@@ -633,6 +633,24 @@
start(); start();
}); });
}); });
asyncTest('`lodash underscore plus=clone`', function() {
var start = _.after(2, _.once(QUnit.start));
build(['-s', 'underscore', 'plus=clone'], function(source, filePath) {
var array = [{ 'value': 1 }],
basename = path.basename(filePath, '.js'),
context = createContext();
vm.runInContext(source, context);
var lodash = context._,
clone = lodash.clone(array, true);
deepEqual(array, clone, basename);
notEqual(array, clone, basename);
start();
});
});
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -786,7 +804,7 @@
start = _.once(QUnit.start); start = _.once(QUnit.start);
minify(source, { minify(source, {
'silent': true, 'isSilent': true,
'workingName': 'underscore.min', 'workingName': 'underscore.min',
'onComplete': function(result) { 'onComplete': function(result) {
var context = createContext(); var context = createContext();

View File

@@ -395,7 +395,7 @@
} else { } else {
func(object, { 'a': 1 }); func(object, { 'a': 1 });
} }
} catch(e) {console.log(e); } catch(e) {
pass = false; pass = false;
} }
ok(pass); ok(pass);
@@ -646,6 +646,15 @@
var array = [1, 2, 3]; var array = [1, 2, 3];
deepEqual(_.initial(array, 0), []); deepEqual(_.initial(array, 0), []);
}); });
test('should allow a falsey `array` argument', function() {
_.each(falsey, function(index, value) {
try {
var actual = index ? _.initial(value) : _.initial();
} catch(e) { }
deepEqual(actual, []);
})
});
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -938,6 +947,19 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.max and lodash.min object iteration');
_.each(['max', 'min'], function(methodName) {
var func = _[methodName];
test('lodash.' + methodName + ' should iterate an object', function() {
var actual = func({ 'a': 1, 'b': 2, 'c': 3 });
equal(actual, methodName == 'max' ? 3 : 1);
});
});
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.merge'); QUnit.module('lodash.merge');
(function() { (function() {
@@ -982,7 +1004,6 @@
source.bar.b = source.foo.b; source.bar.b = source.foo.b;
var actual = _.merge(object, source); var actual = _.merge(object, source);
ok(actual.bar.b === actual.foo.b && actual.foo.b.foo.c === actual.foo.b.foo.c.foo.b.foo.c); ok(actual.bar.b === actual.foo.b && actual.foo.b.foo.c === actual.foo.b.foo.c.foo.b.foo.c);
}); });
@@ -1291,6 +1312,32 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.rest');
(function() {
test('should allow a falsey `array` argument', function() {
_.each(falsey, function(index, value) {
try {
var actual = index ? _.rest(value) : _.rest();
} catch(e) { }
deepEqual(actual, []);
})
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.shuffle');
(function() {
test('should shuffle an object', function() {
var actual = _.shuffle({ 'a': 1, 'b': 2, 'c': 3 });
deepEqual(actual.sort(), [1, 2, 3]);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.size'); QUnit.module('lodash.size');
(function() { (function() {
@@ -1550,6 +1597,31 @@
throttled(); throttled();
}); });
asyncTest('should clear timeout when `func` is called', function() {
var now = new Date,
times = [];
var throttled = _.throttle(function() {
times.push(new Date - now);
}, 20);
setTimeout(throttled, 20);
setTimeout(throttled, 20);
setTimeout(throttled, 40);
setTimeout(throttled, 40);
setTimeout(function() {
var actual = _.every(times, function(value, index) {
return index
? (value - times[index - 1]) > 2
: true;
});
ok(actual);
QUnit.start();
}, 120);
});
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -1702,11 +1774,67 @@
QUnit.module('lodash methods'); QUnit.module('lodash methods');
(function() { (function() {
test('should allow falsey arguments', function() {
var returnArrays = [
'filter',
'invoke',
'map',
'pluck',
'reject',
'shuffle',
'sortBy',
'toArray',
'where'
];
var funcs = _.without.apply(_, [_.functions(_)].concat([
'_',
'_iteratorTemplate',
'_shimKeys',
'after',
'bind',
'bindAll',
'compose',
'debounce',
'defer',
'delay',
'functions',
'memoize',
'once',
'partial',
'tap',
'throttle',
'wrap'
]));
_.each(funcs, function(methodName) {
var actual = [],
expected = _.times(falsey.length, function() { return []; }),
func = _[methodName],
pass = true;
_.each(falsey, function(value, index) {
try {
actual.push(index ? func(value) : func());
} catch(e) {
pass = false;
}
});
if (_.indexOf(returnArrays, methodName) > -1) {
deepEqual(actual, expected, '_.' + methodName + ' returns an array');
} else {
skipTest(falsey.length);
}
ok(pass, '_.' + methodName + ' allows falsey arguments');
});
});
test('should handle `null` `thisArg` arguments', function() { test('should handle `null` `thisArg` arguments', function() {
var thisArg, var thisArg,
array = ['a'], array = ['a'],
callback = function() { thisArg = this; }, callback = function() { thisArg = this; },
useStrict = (function() { return this; }).call(null) === null; expected = (function() { return this; }).call(null);
var funcs = [ var funcs = [
'countBy', 'countBy',
@@ -1748,10 +1876,10 @@
func(array, callback, null); func(array, callback, null);
} }
if (useStrict) { if (expected === null) {
deepEqual(thisArg, null, message); deepEqual(thisArg, null, message);
} else { } else {
equal(thisArg, window, message); equal(thisArg, expected, message);
} }
}); });
}); });

View File

@@ -183,22 +183,22 @@
// is automatically generated and assigned for you. // is automatically generated and assigned for you.
var Model = Backbone.Model = function(attributes, options) { var Model = Backbone.Model = function(attributes, options) {
var defaults; var defaults;
attributes || (attributes = {}); var attrs = attributes || {};
if (options && options.collection) this.collection = options.collection; if (options && options.collection) this.collection = options.collection;
if (options && options.parse) attributes = this.parse(attributes); if (options && options.parse) attributes = this.parse(attributes);
if (defaults = _.result(this, 'defaults')) { if (defaults = _.result(this, 'defaults')) {
attributes = _.extend({}, defaults, attributes); attrs = _.extend({}, defaults, attrs);
} }
this.attributes = {}; this.attributes = {};
this._escapedAttributes = {}; this._escapedAttributes = {};
this.cid = _.uniqueId('c'); this.cid = _.uniqueId('c');
this.changed = {}; this.changed = {};
this._silent = {}; this._changes = {};
this._pending = {}; this._pending = {};
this.set(attributes, {silent: true}); this.set(attrs, {silent: true});
// Reset change tracking. // Reset change tracking.
this.changed = {}; this.changed = {};
this._silent = {}; this._changes = {};
this._pending = {}; this._pending = {};
this._previousAttributes = _.clone(this.attributes); this._previousAttributes = _.clone(this.attributes);
this.initialize.apply(this, arguments); this.initialize.apply(this, arguments);
@@ -210,14 +210,18 @@
// A hash of attributes whose current and previous value differ. // A hash of attributes whose current and previous value differ.
changed: null, changed: null,
// A hash of attributes that have silently changed since the last time // A hash of attributes that have changed since the last time `change`
// `change` was called. Will become pending attributes on the next call. // was called.
_silent: null, _changes: null,
// A hash of attributes that have changed since the last `'change'` event // A hash of attributes that have changed since the last `change` event
// began. // began.
_pending: null, _pending: null,
// A hash of attributes with the current model state to determine if
// a `change` should be recorded within a nested `change` block.
_changing : null,
// The default name for the JSON `id` attribute is `"id"`. MongoDB and // The default name for the JSON `id` attribute is `"id"`. MongoDB and
// CouchDB users may want to set this to `"_id"`. // CouchDB users may want to set this to `"_id"`.
idAttribute: 'id', idAttribute: 'id',
@@ -257,23 +261,22 @@
// Set a hash of model attributes on the object, firing `"change"` unless // Set a hash of model attributes on the object, firing `"change"` unless
// you choose to silence it. // you choose to silence it.
set: function(key, value, options) { set: function(attrs, options) {
var attrs, attr, val; var attr, key, val;
if (attrs == null) return this;
// Handle both `"key", value` and `{key: value}` -style arguments. // Handle both `"key", value` and `{key: value}` -style arguments.
if (_.isObject(key) || key == null) { if (!_.isObject(attrs)) {
attrs = key; key = attrs;
options = value; (attrs = {})[key] = options;
} else { options = arguments[2];
attrs = {};
attrs[key] = value;
} }
// Extract attributes and options. // Extract attributes and options.
options || (options = {}); var silent = options && options.silent;
if (!attrs) return this; var unset = options && options.unset;
if (attrs instanceof Model) attrs = attrs.attributes; if (attrs instanceof Model) attrs = attrs.attributes;
if (options.unset) for (attr in attrs) attrs[attr] = void 0; if (unset) for (attr in attrs) attrs[attr] = void 0;
// Run validation. // Run validation.
if (!this._validate(attrs, options)) return false; if (!this._validate(attrs, options)) return false;
@@ -281,7 +284,7 @@
// Check for changes of `id`. // Check for changes of `id`.
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
var changes = options.changes = {}; var changing = this._changing;
var now = this.attributes; var now = this.attributes;
var escaped = this._escapedAttributes; var escaped = this._escapedAttributes;
var prev = this._previousAttributes || {}; var prev = this._previousAttributes || {};
@@ -291,27 +294,30 @@
val = attrs[attr]; val = attrs[attr];
// If the new and current value differ, record the change. // If the new and current value differ, record the change.
if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) { if (!_.isEqual(now[attr], val) || (unset && _.has(now, attr))) {
delete escaped[attr]; delete escaped[attr];
(options.silent ? this._silent : changes)[attr] = true; this._changes[attr] = true;
} }
// Update or delete the current value. // Update or delete the current value.
options.unset ? delete now[attr] : now[attr] = val; unset ? delete now[attr] : now[attr] = val;
// If the new and previous value differ, record the change. If not, // If the new and previous value differ, record the change. If not,
// then remove changes for this attribute. // then remove changes for this attribute.
if (!_.isEqual(prev[attr], val) || (_.has(now, attr) !== _.has(prev, attr))) { if (!_.isEqual(prev[attr], val) || (_.has(now, attr) !== _.has(prev, attr))) {
this.changed[attr] = val; this.changed[attr] = val;
if (!options.silent) this._pending[attr] = true; if (!silent) this._pending[attr] = true;
} else { } else {
delete this.changed[attr]; delete this.changed[attr];
delete this._pending[attr]; delete this._pending[attr];
if (!changing) delete this._changes[attr];
} }
if (changing && _.isEqual(now[attr], changing[attr])) delete this._changes[attr];
} }
// Fire the `"change"` events. // Fire the `"change"` events.
if (!options.silent) this.change(options); if (!silent) this.change(options);
return this; return this;
}, },
@@ -346,16 +352,14 @@
// Set a hash of model attributes, and sync the model to the server. // Set a hash of model attributes, and sync the model to the server.
// If the server returns an attributes hash that differs, the model's // If the server returns an attributes hash that differs, the model's
// state will be `set` again. // state will be `set` again.
save: function(key, value, options) { save: function(attrs, options) {
var attrs, current, done; var key, current, done;
// Handle both `("key", value)` and `({key: value})` -style calls. // Handle both `"key", value` and `{key: value}` -style arguments.
if (_.isObject(key) || key == null) { if (attrs != null && !_.isObject(attrs)) {
attrs = key; key = attrs;
options = value; (attrs = {})[key] = options;
} else { options = arguments[2];
attrs = {};
attrs[key] = value;
} }
options = options ? _.clone(options) : {}; options = options ? _.clone(options) : {};
@@ -372,7 +376,7 @@
} }
// Do not persist invalid models. // Do not persist invalid models.
if (!attrs && !this.isValid()) return false; if (!attrs && !this._validate(null, options)) return false;
// After a successful server-side save, the client is (optionally) // After a successful server-side save, the client is (optionally)
// updated with the server-side state. // updated with the server-side state.
@@ -455,18 +459,25 @@
// a `"change:attribute"` event for each changed attribute. // a `"change:attribute"` event for each changed attribute.
// Calling this will cause all objects observing the model to update. // Calling this will cause all objects observing the model to update.
change: function(options) { change: function(options) {
options || (options = {});
var changing = this._changing; var changing = this._changing;
this._changing = true; var current = this._changing = {};
// Silent changes become pending changes. // Silent changes become pending changes.
for (var attr in this._silent) this._pending[attr] = true; for (var attr in this._changes) this._pending[attr] = true;
// Silent changes are triggered. // Trigger 'change:attr' for any new or silent changes.
var changes = _.extend({}, options.changes, this._silent); var changes = this._changes;
this._silent = {}; this._changes = {};
// Set the correct state for this._changing values
var triggers = [];
for (var attr in changes) { for (var attr in changes) {
this.trigger('change:' + attr, this, this.get(attr), options); current[attr] = this.get(attr);
triggers.push(attr);
}
for (var i=0, l=triggers.length; i < l; i++) {
this.trigger('change:' + triggers[i], this, current[triggers[i]], options);
} }
if (changing) return this; if (changing) return this;
@@ -476,13 +487,13 @@
this.trigger('change', this, options); this.trigger('change', this, options);
// Pending and silent changes still remain. // Pending and silent changes still remain.
for (var attr in this.changed) { for (var attr in this.changed) {
if (this._pending[attr] || this._silent[attr]) continue; if (this._pending[attr] || this._changes[attr]) continue;
delete this.changed[attr]; delete this.changed[attr];
} }
this._previousAttributes = _.clone(this.attributes); this._previousAttributes = _.clone(this.attributes);
} }
this._changing = false; this._changing = null;
return this; return this;
}, },
@@ -532,7 +543,7 @@
// returning `true` if all is well. If a specific `error` callback has // returning `true` if all is well. If a specific `error` callback has
// been passed, call that instead of firing the general `"error"` event. // been passed, call that instead of firing the general `"error"` event.
_validate: function(attrs, options) { _validate: function(attrs, options) {
if (options.silent || !this.validate) return true; if (options && options.silent || !this.validate) return true;
attrs = _.extend({}, this.attributes, attrs); attrs = _.extend({}, this.attributes, attrs);
var error = this.validate(attrs, options); var error = this.validate(attrs, options);
if (!error) return true; if (!error) return true;
@@ -894,9 +905,10 @@
// Cached regular expressions for matching named param parts and splatted // Cached regular expressions for matching named param parts and splatted
// parts of route strings. // parts of route strings.
var optionalParam = /\((.*?)\)/g;
var namedParam = /:\w+/g; var namedParam = /:\w+/g;
var splatParam = /\*\w+/g; var splatParam = /\*\w+/g;
var escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g; var escapeRegExp = /[-{}[\]+?.,\\^$|#\s]/g;
// 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, {
@@ -947,6 +959,7 @@
// against the current location hash. // against the current location hash.
_routeToRegExp: function(route) { _routeToRegExp: function(route) {
route = route.replace(escapeRegExp, '\\$&') route = route.replace(escapeRegExp, '\\$&')
.replace(optionalParam, '(?:$1)?')
.replace(namedParam, '([^\/]+)') .replace(namedParam, '([^\/]+)')
.replace(splatParam, '(.*?)'); .replace(splatParam, '(.*?)');
return new RegExp('^' + route + '$'); return new RegExp('^' + route + '$');
@@ -1059,7 +1072,7 @@
// opened by a non-pushState browser. // opened by a non-pushState browser.
this.fragment = fragment; this.fragment = fragment;
var loc = this.location; var loc = this.location;
var atRoot = (loc.pathname.replace(/[^/]$/, '$&/') === this.root) && !loc.search; var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
// If we've started off with a route from a `pushState`-enabled browser, // 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... // but we're currently in a browser that doesn't support it...
@@ -1073,7 +1086,7 @@
// in a browser where it could be `pushState`-based instead... // in a browser where it could be `pushState`-based instead...
} else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) { } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
this.fragment = this.getHash().replace(routeStripper, ''); this.fragment = this.getHash().replace(routeStripper, '');
this.history.replaceState({}, document.title, this.root + this.fragment); this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
} }
if (!this.options.silent) return this.loadUrl(); if (!this.options.silent) return this.loadUrl();
@@ -1221,8 +1234,8 @@
// memory leaks. // memory leaks.
dispose: function() { dispose: function() {
this.undelegateEvents(); this.undelegateEvents();
if (this.model) this.model.off(null, null, this); if (this.model && this.model.off) this.model.off(null, null, this);
if (this.collection) this.collection.off(null, null, this); if (this.collection && this.collection.off) this.collection.off(null, null, this);
return this; return this;
}, },
@@ -1320,7 +1333,7 @@
if (this.className) attrs['class'] = _.result(this, 'className'); if (this.className) attrs['class'] = _.result(this, 'className');
this.setElement(this.make(_.result(this, 'tagName'), attrs), false); this.setElement(this.make(_.result(this, 'tagName'), attrs), false);
} else { } else {
this.setElement(this.el, false); this.setElement(_.result(this, 'el'), false);
} }
} }
@@ -1435,9 +1448,12 @@
child = function(){ parent.apply(this, arguments); }; child = function(){ parent.apply(this, arguments); };
} }
// Add static properties to the constructor function, if supplied.
_.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. // `parent`'s constructor function.
function Surrogate(){ this.constructor = child; }; var Surrogate = function(){ this.constructor = child; };
Surrogate.prototype = parent.prototype; Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate; child.prototype = new Surrogate;
@@ -1445,9 +1461,6 @@
// if supplied. // if supplied.
if (protoProps) _.extend(child.prototype, protoProps); if (protoProps) _.extend(child.prototype, protoProps);
// Add static properties to the constructor function, if supplied.
_.extend(child, parent, staticProps);
// 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.
child.__super__ = parent.prototype; child.__super__ = parent.prototype;

View File

@@ -740,9 +740,9 @@ $(document).ready(function() {
model.set({b: 2}, {silent: true}); model.set({b: 2}, {silent: true});
}); });
model.set({b: 0}); model.set({b: 0});
deepEqual(changes, [0, 1, 1]); deepEqual(changes, [0, 1]);
model.change(); model.change();
deepEqual(changes, [0, 1, 1, 2, 1]); deepEqual(changes, [0, 1, 2, 1]);
}); });
test("nested set multiple times", 1, function() { test("nested set multiple times", 1, function() {
@@ -816,4 +816,66 @@ $(document).ready(function() {
strictEqual(model.save(), false); strictEqual(model.save(), false);
}); });
test("#1377 - Save without attrs triggers 'error'.", 1, function() {
var Model = Backbone.Model.extend({
url: '/test/',
sync: function(method, model, options){ options.success(); },
validate: function(){ return 'invalid'; }
});
var model = new Model({id: 1});
model.on('error', function(){ ok(true); });
model.save();
});
test("#1545 - `undefined` can be passed to a model constructor without coersion", function() {
var Model = Backbone.Model.extend({
defaults: { one: 1 },
initialize : function(attrs, opts) {
equal(attrs, undefined);
}
});
var emptyattrs = new Model();
var undefinedattrs = new Model(undefined);
});
asyncTest("#1478 - Model `save` does not trigger change on unchanged attributes", 0, function() {
var Model = Backbone.Model.extend({
sync: function(method, model, options) {
setTimeout(function(){
options.success();
start();
}, 0);
}
});
new Model({x: true})
.on('change:x', function(){ ok(false); })
.save(null, {wait: true});
});
test("#1664 - Changing from one value, silently to another, back to original does not trigger change.", 0, function() {
var model = new Backbone.Model({x:1});
model.on('change:x', function() { ok(false); });
model.set({x:2},{silent:true});
model.set({x:3},{silent:true});
model.set({x:1});
});
test("#1664 - multiple silent changes nested inside a change event", 2, function() {
var changes = [];
var model = new Backbone.Model();
model.on('change', function() {
model.set({a:'c'}, {silent:true});
model.set({b:2}, {silent:true});
model.unset('c', {silent:true});
model.set({a:'a'}, {silent:true});
model.set({b:1}, {silent:true});
model.set({c:'item'}, {silent:true});
});
model.on('change:a change:b change:c', function(model, val) { changes.push(val); });
model.set({a:'a', b:1, c:'item'});
deepEqual(changes, ['a',1,'item']);
model.change();
deepEqual(changes, ['a',1,'item']);
});
}); });

View File

@@ -69,6 +69,7 @@ $(document).ready(function() {
"contacts": "contacts", "contacts": "contacts",
"contacts/new": "newContact", "contacts/new": "newContact",
"contacts/:id": "loadContact", "contacts/:id": "loadContact",
"optional(/:item)": "optionalItem",
"splat/*args/end": "splat", "splat/*args/end": "splat",
"*first/complex-:part/*rest": "complex", "*first/complex-:part/*rest": "complex",
":entity?*args": "query", ":entity?*args": "query",
@@ -105,6 +106,10 @@ $(document).ready(function() {
this.contact = 'load'; this.contact = 'load';
}, },
optionalItem: function(arg){
this.arg = arg !== undefined ? arg : null;
},
splat : function(args) { splat : function(args) {
this.args = args; this.args = args;
}, },
@@ -199,6 +204,15 @@ $(document).ready(function() {
equal(router.args, 'long-list/of/splatted_99args'); equal(router.args, 'long-list/of/splatted_99args');
}); });
test("routes (optional)", 2, function() {
location.replace('http://example.com#optional');
Backbone.history.checkUrl();
equal(router.arg, null);
location.replace('http://example.com#optional/thing');
Backbone.history.checkUrl();
equal(router.arg, 'thing');
});
test("routes (complex)", 3, function() { test("routes (complex)", 3, function() {
location.replace('http://example.com#one/two/three/complex-part/four/five/six/seven'); location.replace('http://example.com#one/two/three/complex-part/four/five/six/seven');
Backbone.history.checkUrl(); Backbone.history.checkUrl();
@@ -449,4 +463,22 @@ $(document).ready(function() {
}); });
}); });
test("#1695 - hashChange to pushState with search.", 1, function() {
Backbone.history.stop();
location.replace('http://example.com/root?a=b#x/y');
Backbone.history = _.extend(new Backbone.History, {
location: location,
history: {
pushState: function(){},
replaceState: function(state, title, url){
strictEqual(url, '/root/x/y?a=b');
}
}
});
Backbone.history.start({
root: 'root',
pushState: true
});
});
}); });

View File

@@ -305,6 +305,11 @@ $(document).ready(function() {
view.$el.click(); view.$el.click();
}); });
test("dispose with non Backbone objects", 0, function() {
var view = new Backbone.View({model: {}, collection: {}});
view.dispose();
});
test("view#remove calls dispose.", 1, function() { test("view#remove calls dispose.", 1, function() {
var view = new Backbone.View(); var view = new Backbone.View();
@@ -312,4 +317,15 @@ $(document).ready(function() {
view.remove(); view.remove();
}); });
test("Provide function for el.", 1, function() {
var View = Backbone.View.extend({
el: function() {
return "<p><a></a></p>";
}
});
var view = new View;
ok(view.$el.is('p:has(a)'));
});
}); });

View File

@@ -8,7 +8,7 @@ require(dirname(__FILE__) . '/src/DocDown/Generator.php');
/** /**
* Generates Markdown from JSDoc entries in a given file. * Generates Markdown from JSDoc entries in a given file.
* *
* @param {Array} [$options=array()] The options array. * @param {Array} [$options=array()] The options array.
* @returns {String} The generated Markdown. * @returns {String} The generated Markdown.
* @example * @example

View File

@@ -22,10 +22,11 @@ class Alias {
* @param {String} $name The alias name. * @param {String} $name The alias name.
* @param {Object} $owner The alias owner. * @param {Object} $owner The alias owner.
*/ */
public function __construct($name, $owner) { public function __construct( $name, $owner ) {
$this->owner = $owner; $this->owner = $owner;
$this->_name = $name; $this->_name = $name;
$this->_call = $owner->getCall(); $this->_call = $owner->getCall();
$this->_category = $owner->getCategory();
$this->_desc = $owner->getDesc(); $this->_desc = $owner->getDesc();
$this->_example = $owner->getExample(); $this->_example = $owner->getExample();
$this->_lineNumber = $owner->getLineNumber(); $this->_lineNumber = $owner->getLineNumber();
@@ -65,6 +66,16 @@ class Alias {
return $this->_call; return $this->_call;
} }
/**
* Extracts the owner entry's `category` data.
*
* @memberOf Alias
* @returns {String} The owner entry's `category` data.
*/
public function getCategory() {
return $this->_category;
}
/** /**
* Extracts the owner entry's description. * Extracts the owner entry's description.
* *

View File

@@ -152,6 +152,27 @@ class Entry {
return $this->_call; return $this->_call;
} }
/**
* Extracts the entry's `category` data.
*
* @memberOf Entry
* @returns {String} The entry's `category` data.
*/
public function getCategory() {
if (isset($this->_category)) {
return $this->_category;
}
preg_match('#\* *@category\s+([^\n]+)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1]));
} else {
$result = $this->getType() == 'Function' ? 'Methods' : 'Properties';
}
$this->_category = $result;
return $result;
}
/** /**
* Extracts the entry's description. * Extracts the entry's description.
* *

View File

@@ -7,6 +7,15 @@ require(dirname(__FILE__) . "/Entry.php");
*/ */
class Generator { class Generator {
/**
* The HTML for the close tag.
*
* @static
* @memberOf Generator
* @type String
*/
public $closeTag = "\n<!-- /div -->\n";
/** /**
* An array of JSDoc entries. * An array of JSDoc entries.
* *
@@ -15,6 +24,15 @@ class Generator {
*/ */
public $entries = array(); public $entries = array();
/**
* The HTML for the open tag.
*
* @static
* @memberOf Generator
* @type String
*/
public $openTag = "\n<!-- div -->\n";
/** /**
* An options array used to configure the generator. * An options array used to configure the generator.
* *
@@ -24,7 +42,7 @@ class Generator {
public $options = array(); public $options = array();
/** /**
* The entire file's source code. * The file's source code.
* *
* @memberOf Generator * @memberOf Generator
* @type String * @type String
@@ -65,6 +83,9 @@ class Generator {
if (!isset($options['lang'])) { if (!isset($options['lang'])) {
$options['lang'] = 'js'; $options['lang'] = 'js';
} }
if (!isset($options['toc'])) {
$options['toc'] = 'properties';
}
$this->options = $options; $this->options = $options;
$this->source = str_replace(PHP_EOL, "\n", $options['source']); $this->source = str_replace(PHP_EOL, "\n", $options['source']);
@@ -86,7 +107,7 @@ class Generator {
* @param {String} $string The string to format. * @param {String} $string The string to format.
* @returns {String} The formatted string. * @returns {String} The formatted string.
*/ */
private static function format($string) { private static function format( $string ) {
$counter = 0; $counter = 0;
// tokenize inline code snippets // tokenize inline code snippets
@@ -121,7 +142,7 @@ class Generator {
* @param {Array|Object} $object The template object. * @param {Array|Object} $object The template object.
* @returns {String} The modified string. * @returns {String} The modified string.
*/ */
private static function interpolate($string, $object) { private static function interpolate( $string, $object ) {
preg_match_all('/#\{([^}]+)\}/', $string, $tokens); preg_match_all('/#\{([^}]+)\}/', $string, $tokens);
$tokens = array_unique(array_pop($tokens)); $tokens = array_unique(array_pop($tokens));
@@ -149,6 +170,63 @@ class Generator {
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/**
* Adds the given `$entries` to the `$result` array.
*
* @private
* @memberOf Generator
* @param {Array} $result The result array to modify.
* @param {Array} $entries The entries to add to the `$result`.
*/
private function addEntries( &$result, $entries ) {
foreach ($entries as $entry) {
// skip aliases
if ($entry->isAlias()) {
continue;
}
// name and description
array_push(
$result,
$this->openTag,
Generator::interpolate("### <a id=\"#{hash}\"></a>`#{member}#{separator}#{call}`\n<a href=\"##{hash}\">#</a> [&#x24C8;](#{href} \"View in source\") [&#x24C9;][1]\n\n#{desc}", $entry)
);
// @alias
if (count($aliases = $entry->getAliases())) {
array_push($result, '', '#### Aliases');
foreach ($aliases as $index => $alias) {
$aliases[$index] = $alias->getName();
}
$result[] = '*' . implode(', ', $aliases) . '*';
}
// @param
if (count($params = $entry->getParams())) {
array_push($result, '', '#### Arguments');
foreach ($params as $index => $param) {
$result[] = Generator::interpolate('#{num}. `#{name}` (#{type}): #{desc}', array(
'desc' => $param[2],
'name' => $param[1],
'num' => $index + 1,
'type' => $param[0]
));
}
}
// @returns
if (count($returns = $entry->getReturns())) {
array_push(
$result, '',
'#### Returns',
Generator::interpolate('(#{type}): #{desc}', array('desc' => $returns[1], 'type' => $returns[0]))
);
}
// @example
if ($example = $entry->getExample()) {
array_push($result, '', '#### Example', $example);
}
array_push($result, "\n* * *", $this->closeTag);
}
}
/** /**
* Resolves the entry's hash used to navigate the documentation. * Resolves the entry's hash used to navigate the documentation.
* *
@@ -204,9 +282,11 @@ class Generator {
*/ */
public function generate() { public function generate() {
$api = array(); $api = array();
$byCategory = $this->options['toc'] == 'categories';
$categories = array();
$closeTag = $this->closeTag;
$compiling = false; $compiling = false;
$openTag = "\n<!-- div -->\n"; $openTag = $this->openTag;
$closeTag = "\n<!-- /div -->\n";
$result = array('# ' . $this->options['title']); $result = array('# ' . $this->options['title']);
$toc = 'toc'; $toc = 'toc';
@@ -223,14 +303,14 @@ class Generator {
foreach ($members as $member) { foreach ($members as $member) {
// create api category arrays // create api category arrays
if (!isset($api[$member]) && $member) { if ($member && !isset($api[$member])) {
// create temporary entry to be replaced later // create temporary entry to be replaced later
$api[$member] = new Entry('', '', $entry->lang); $api[$member] = new stdClass;
$api[$member]->static = array(); $api[$member]->static = array();
$api[$member]->plugin = array(); $api[$member]->plugin = array();
} }
// append entry to api category // append entry to api member
if (!$member || $entry->isCtor() || ($entry->getType() == 'Object' && if (!$member || $entry->isCtor() || ($entry->getType() == 'Object' &&
!preg_match('/[=:]\s*(?:null|undefined)\s*[,;]?$/', $entry->entry))) { !preg_match('/[=:]\s*(?:null|undefined)\s*[,;]?$/', $entry->entry))) {
@@ -261,6 +341,26 @@ class Generator {
} }
} }
// add properties to each entry
foreach ($api as $entry) {
$entry->hash = $this->getHash($entry);
$entry->href = $this->getLineUrl($entry);
$member = $entry->getMembers(0);
$member = ($member ? $member . ($entry->isPlugin() ? '.prototype.' : '.') : '') . $entry->getName();
$entry->member = preg_replace('/' . $entry->getName() . '$/', '', $member);
// add properties to static and plugin sub-entries
foreach (array('static', 'plugin') as $kind) {
foreach ($entry->{$kind} as $subentry) {
$subentry->hash = $this->getHash($subentry);
$subentry->href = $this->getLineUrl($subentry);
$subentry->member = $member;
$subentry->separator = $this->getSeparator($subentry);
}
}
}
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
// custom sort for root level entries // custom sort for root level entries
@@ -268,19 +368,19 @@ class Generator {
function sortCompare($a, $b) { function sortCompare($a, $b) {
$score = array( 'a' => 0, 'b' => 0); $score = array( 'a' => 0, 'b' => 0);
foreach (array( 'a' => $a, 'b' => $b) as $key => $value) { foreach (array( 'a' => $a, 'b' => $b) as $key => $value) {
// capitalized keys that represent constructor properties are last // capitalized properties are last
if (preg_match('/[#.][A-Z]/', $value)) { if (preg_match('/[#.][A-Z]/', $value)) {
$score[$key] = 0; $score[$key] = 0;
} }
// lowercase keys with prototype properties are next to last // lowercase prototype properties are next to last
else if (preg_match('/#[a-z]/', $value)) { else if (preg_match('/#[a-z]/', $value)) {
$score[$key] = 1; $score[$key] = 1;
} }
// lowercase keys with static properties next to first // lowercase static properties next to first
else if (preg_match('/\.[a-z]/', $value)) { else if (preg_match('/\.[a-z]/', $value)) {
$score[$key] = 2; $score[$key] = 2;
} }
// lowercase keys with no properties are first // root properties are first
else if (preg_match('/^[^#.]+$/', $value)) { else if (preg_match('/^[^#.]+$/', $value)) {
$score[$key] = 3; $score[$key] = 3;
} }
@@ -310,48 +410,90 @@ class Generator {
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
// add categories
foreach ($api as $entry) {
$categories[$entry->getCategory()][] = $entry;
foreach (array('static', 'plugin') as $kind) {
foreach ($entry->{$kind} as $subentry) {
$categories[$subentry->getCategory()][] = $subentry;
}
}
}
// sort categories
ksort($categories);
foreach(array('Methods', 'Properties') as $category) {
if (isset($categories[$category])) {
$entries = $categories[$category];
unset($categories[$category]);
$categories[$category] = $entries;
}
}
/*------------------------------------------------------------------------*/
// compile TOC // compile TOC
$result[] = $openTag; $result[] = $openTag;
foreach ($api as $key => $entry) { // compile TOC by categories
$entry->hash = $this->getHash($entry); if ($byCategory) {
$entry->href = $this->getLineUrl($entry); foreach ($categories as $category => $entries) {
if ($compiling) {
$member = $entry->getMembers(0); $result[] = $closeTag;
$member = ($member ? $member . ($entry->isPlugin() ? '.prototype.' : '.') : '') . $entry->getName(); } else {
$compiling = true;
$entry->member = preg_replace('/' . $entry->getName() . '$/', '', $member);
$compiling = $compiling ? ($result[] = $closeTag) : true;
// assign TOC hash
if (count($result) == 2) {
$toc = $member;
}
// add root entry
array_push(
$result,
$openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $member . '`',
Generator::interpolate('* [`' . $member . '`](##{hash})', $entry)
);
// add static and plugin sub-entries
foreach (array('static', 'plugin') as $kind) {
if ($kind == 'plugin' && count($entry->plugin)) {
array_push(
$result,
$closeTag,
$openTag,
'## `' . $member . ($entry->isCtor() ? '.prototype`' : '`')
);
} }
foreach ($entry->{$kind} as $subentry) { // assign TOC hash
$subentry->hash = $this->getHash($subentry); if (count($result) == 2) {
$subentry->href = $this->getLineUrl($subentry); $toc = $category;
$subentry->member = $member; }
$subentry->separator = $this->getSeparator($subentry); // add category
$result[] = Generator::interpolate('* [`#{member}#{separator}#{name}`](##{hash})', $subentry); array_push(
$result,
$openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $category . '`'
);
// add entries
foreach ($entries as $entry) {
$result[] = Generator::interpolate('* [`#{member}#{separator}#{name}`](##{hash})', $entry);
}
}
}
// compile TOC by namespace
else {
foreach ($api as $entry) {
if ($compiling) {
$result[] = $closeTag;
} else {
$compiling = true;
}
$member = $entry->member . $entry->getName();
// assign TOC hash
if (count($result) == 2) {
$toc = $member;
}
// add root entry
array_push(
$result,
$openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $member . '`',
Generator::interpolate('* [`' . $member . '`](##{hash})', $entry)
);
// add static and plugin sub-entries
foreach (array('static', 'plugin') as $kind) {
if ($kind == 'plugin' && count($entry->plugin)) {
array_push(
$result,
$closeTag,
$openTag,
'## `' . $member . ($entry->isCtor() ? '.prototype`' : '`')
);
}
foreach ($entry->{$kind} as $subentry) {
$subentry->member = $member;
$result[] = Generator::interpolate('* [`#{member}#{separator}#{name}`](##{hash})', $subentry);
}
} }
} }
} }
@@ -364,81 +506,51 @@ class Generator {
$compiling = false; $compiling = false;
$result[] = $openTag; $result[] = $openTag;
foreach ($api as $entry) { if ($byCategory) {
// skip aliases foreach ($categories as $category => $entries) {
if ($entry->isAlias()) { if ($compiling) {
continue; $result[] = $closeTag;
} } else {
$compiling = true;
// add root entry
$member = $entry->member . $entry->getName();
$compiling = $compiling ? ($result[] = $closeTag) : true;
array_push($result, $openTag, '## `' . $member . '`');
foreach (array($entry, 'static', 'plugin') as $kind) {
$subentries = is_string($kind) ? $entry->{$kind} : array($kind);
// title
if ($kind != 'static' && $entry->getType() != 'Object' &&
count($subentries) && $subentries[0] != $kind) {
if ($kind == 'plugin') {
$result[] = $closeTag;
}
array_push(
$result,
$openTag,
'## `' . $member . ($kind == 'plugin' ? '.prototype`' : '`')
);
} }
if ($category != 'Methods' && $category != 'Properties') {
$category = '“' . $category . '” Methods';
}
array_push($result, $openTag, '## `' . $category . '`');
$this->addEntries($result, $entries);
}
}
else {
foreach ($api as $entry) {
// skip aliases
if ($entry->isAlias()) {
continue;
}
if ($compiling) {
$result[] = $closeTag;
} else {
$compiling = true;
}
// add root entry name
$member = $entry->member . $entry->getName();
array_push($result, $openTag, '## `' . $member . '`');
// body foreach (array($entry, 'static', 'plugin') as $kind) {
foreach ($subentries as $subentry) { $subentries = is_string($kind) ? $entry->{$kind} : array($kind);
// skip aliases
if ($subentry->isAlias()) {
continue;
}
// description // add sub-entry name
array_push( if ($kind != 'static' && $entry->getType() != 'Object' &&
$result, count($subentries) && $subentries[0] != $kind) {
$openTag, if ($kind == 'plugin') {
Generator::interpolate("### <a id=\"#{hash}\"></a>`#{member}#{separator}#{call}`\n<a href=\"##{hash}\">#</a> [&#x24C8;](#{href} \"View in source\") [&#x24C9;][1]\n\n#{desc}", $subentry) $result[] = $closeTag;
);
// @alias
if (count($aliases = $subentry->getAliases())) {
array_push($result, '', '#### Aliases');
foreach ($aliases as $index => $alias) {
$aliases[$index] = $alias->getName();
} }
$result[] = '*' . implode(', ', $aliases) . '*';
}
// @param
if (count($params = $subentry->getParams())) {
array_push($result, '', '#### Arguments');
foreach ($params as $index => $param) {
$result[] = Generator::interpolate('#{num}. `#{name}` (#{type}): #{desc}', array(
'desc' => $param[2],
'name' => $param[1],
'num' => $index + 1,
'type' => $param[0]
));
}
}
// @returns
if (count($returns = $subentry->getReturns())) {
array_push( array_push(
$result, '', $result,
'#### Returns', $openTag,
Generator::interpolate('(#{type}): #{desc}', array('desc' => $returns[1], 'type' => $returns[0])) '## `' . $member . ($kind == 'plugin' ? '.prototype`' : '`')
); );
} }
// @example $this->addEntries($result, $subentries);
if ($example = $subentry->getExample()) {
array_push($result, '', '#### Example', $example);
}
array_push($result, "\n* * *", $closeTag);
} }
} }
} }

View File

@@ -1,4 +1,4 @@
[QUnit](http://qunitjs.com) - A JavaScript Unit Testing framework. [QUnit](http://docs.jquery.com/QUnit) - A JavaScript Unit Testing framework.
================================ ================================
QUnit is a powerful, easy-to-use, JavaScript test suite. It's used by the jQuery QUnit is a powerful, easy-to-use, JavaScript test suite. It's used by the jQuery
@@ -35,8 +35,7 @@ the change, run `grunt` to lint and test it, then commit, push and create a pull
Include some background for the change in the commit message and `Fixes #nnn`, referring Include some background for the change in the commit message and `Fixes #nnn`, referring
to the issue number you're addressing. to the issue number you're addressing.
To run `grunt`, you need `node` and `npm`, then `npm install grunt -g`. That gives you a global To run `grunt`, you need `node` and `npm`, then `npm install grunt -g`.
grunt binary. For additional grunt tasks, also run `npm install`.
Releases Releases
-------- --------
@@ -48,12 +47,3 @@ tag, update them again to the next version, commit and push commits and tags
Put the 'v' in front of the tag, e.g. `v1.8.0`. Clean up the changelog, removing merge commits Put the 'v' in front of the tag, e.g. `v1.8.0`. Clean up the changelog, removing merge commits
or whitespace cleanups. or whitespace cleanups.
To upload to code.jquery.com (replace $version accordingly):
scp -q qunit/qunit.js jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/qunit/qunit-$version.js
scp -q qunit/qunit.css jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/qunit/qunit-$version.css
Then update /var/www/html/code.jquery.com/index.html and purge it with:
curl -s http://code.origin.jquery.com/?reload

View File

@@ -1,11 +1,11 @@
/** /**
* QUnit v1.10.0 - A JavaScript Unit Testing Framework * QUnit v1.9.0 - A JavaScript Unit Testing Framework
* *
* http://qunitjs.com * http://docs.jquery.com/QUnit
* *
* Copyright 2012 jQuery Foundation and other contributors * Copyright (c) 2012 John Resig, Jörn Zaefferer
* Released under the MIT license. * Dual licensed under the MIT (MIT-LICENSE.txt)
* http://jquery.org/license * or GPL (GPL-LICENSE.txt) licenses.
*/ */
/** Font Family and Sizes */ /** Font Family and Sizes */
@@ -20,7 +20,7 @@
/** Resets */ /** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
@@ -67,7 +67,6 @@
padding: 0.5em 0 0.5em 2em; padding: 0.5em 0 0.5em 2em;
color: #5E740B; color: #5E740B;
background-color: #eee; background-color: #eee;
overflow: hidden;
} }
#qunit-userAgent { #qunit-userAgent {
@@ -77,9 +76,6 @@
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
} }
#qunit-modulefilter-container {
float: right;
}
/** Tests: Pass/Fail */ /** Tests: Pass/Fail */

View File

@@ -1,11 +1,11 @@
/** /**
* QUnit v1.10.0 - A JavaScript Unit Testing Framework * QUnit v1.9.0 - A JavaScript Unit Testing Framework
* *
* http://qunitjs.com * http://docs.jquery.com/QUnit
* *
* Copyright 2012 jQuery Foundation and other contributors * Copyright (c) 2012 John Resig, Jörn Zaefferer
* Released under the MIT license. * Dual licensed under the MIT (MIT-LICENSE.txt)
* http://jquery.org/license * or GPL (GPL-LICENSE.txt) licenses.
*/ */
(function( window ) { (function( window ) {
@@ -17,8 +17,6 @@ var QUnit,
fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
toString = Object.prototype.toString, toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty, hasOwn = Object.prototype.hasOwnProperty,
// Keep a local reference to Date (GH-283)
Date = window.Date,
defined = { defined = {
setTimeout: typeof window.setTimeout !== "undefined", setTimeout: typeof window.setTimeout !== "undefined",
sessionStorage: (function() { sessionStorage: (function() {
@@ -306,8 +304,7 @@ QUnit = {
// call on start of module test to prepend name to all tests // call on start of module test to prepend name to all tests
module: function( name, testEnvironment ) { module: function( name, testEnvironment ) {
config.currentModule = name; config.currentModule = name;
config.currentModuleTestEnvironment = testEnvironment; config.currentModuleTestEnviroment = testEnvironment;
config.modules[name] = true;
}, },
asyncTest: function( testName, expected, callback ) { asyncTest: function( testName, expected, callback ) {
@@ -339,7 +336,7 @@ QUnit = {
async: async, async: async,
callback: callback, callback: callback,
module: config.currentModule, module: config.currentModule,
moduleTestEnvironment: config.currentModuleTestEnvironment, moduleTestEnvironment: config.currentModuleTestEnviroment,
stack: sourceFromStacktrace( 2 ) stack: sourceFromStacktrace( 2 )
}); });
@@ -352,11 +349,7 @@ QUnit = {
// Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
expect: function( asserts ) { expect: function( asserts ) {
if (arguments.length === 1) { config.current.expected = asserts;
config.current.expected = asserts;
} else {
return config.current.expected;
}
}, },
start: function( count ) { start: function( count ) {
@@ -422,8 +415,6 @@ QUnit.assert = {
var source, var source,
details = { details = {
module: config.current.module,
name: config.current.testName,
result: result, result: result,
message: msg message: msg
}; };
@@ -609,9 +600,6 @@ config = {
} }
], ],
// Set of all modules.
modules: {},
// logging callback queues // logging callback queues
begin: [], begin: [],
done: [], done: [],
@@ -722,10 +710,17 @@ extend( QUnit, {
}, },
// Resets the test setup. Useful for tests that modify the DOM. // Resets the test setup. Useful for tests that modify the DOM.
// If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
reset: function() { reset: function() {
var fixture = id( "qunit-fixture" ); var fixture;
if ( fixture ) {
fixture.innerHTML = config.fixture; if ( window.jQuery ) {
jQuery( "#qunit-fixture" ).html( config.fixture );
} else {
fixture = id( "qunit-fixture" );
if ( fixture ) {
fixture.innerHTML = config.fixture;
}
} }
}, },
@@ -786,8 +781,6 @@ extend( QUnit, {
var output, source, var output, source,
details = { details = {
module: config.current.module,
name: config.current.testName,
result: result, result: result,
message: message, message: message,
actual: actual, actual: actual,
@@ -833,8 +826,6 @@ extend( QUnit, {
var output, var output,
details = { details = {
module: config.current.module,
name: config.current.testName,
result: false, result: false,
message: message message: message
}; };
@@ -925,9 +916,7 @@ QUnit.load = function() {
runLoggingCallbacks( "begin", QUnit, {} ); runLoggingCallbacks( "begin", QUnit, {} );
// Initialize the config, saving the execution queue // Initialize the config, saving the execution queue
var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes, moduleFilter, var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes,
numModules = 0,
moduleFilterHtml = "",
urlConfigHtml = "", urlConfigHtml = "",
oldconfig = extend( {}, config ); oldconfig = extend( {}, config );
@@ -951,15 +940,6 @@ QUnit.load = function() {
urlConfigHtml += "<input id='qunit-urlconfig-" + val.id + "' name='" + val.id + "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) + " title='" + val.tooltip + "'><label for='qunit-urlconfig-" + val.id + "' title='" + val.tooltip + "'>" + val.label + "</label>"; urlConfigHtml += "<input id='qunit-urlconfig-" + val.id + "' name='" + val.id + "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) + " title='" + val.tooltip + "'><label for='qunit-urlconfig-" + val.id + "' title='" + val.tooltip + "'>" + val.label + "</label>";
} }
moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " + ( config.module === undefined ? "selected" : "" ) + ">< All Modules ></option>";
for ( i in config.modules ) {
if ( config.modules.hasOwnProperty( i ) ) {
numModules += 1;
moduleFilterHtml += "<option value='" + encodeURIComponent(i) + "' " + ( config.module === i ? "selected" : "" ) + ">" + i + "</option>";
}
}
moduleFilterHtml += "</select>";
// `userAgent` initialized at top of scope // `userAgent` initialized at top of scope
userAgent = id( "qunit-userAgent" ); userAgent = id( "qunit-userAgent" );
if ( userAgent ) { if ( userAgent ) {
@@ -1022,19 +1002,6 @@ QUnit.load = function() {
window.location = QUnit.url( params ); window.location = QUnit.url( params );
}); });
toolbar.appendChild( urlConfigCheckboxes ); toolbar.appendChild( urlConfigCheckboxes );
if (numModules > 1) {
moduleFilter = document.createElement( 'span' );
moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
moduleFilter.innerHTML = moduleFilterHtml;
addEvent( moduleFilter, "change", function() {
var selectBox = moduleFilter.getElementsByTagName("select")[0],
selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
});
toolbar.appendChild(moduleFilter);
}
} }
// `main` initialized at top of scope // `main` initialized at top of scope
@@ -1072,9 +1039,9 @@ window.onerror = function ( error, filePath, linerNr ) {
} }
QUnit.pushFailure( error, filePath + ":" + linerNr ); QUnit.pushFailure( error, filePath + ":" + linerNr );
} else { } else {
QUnit.test( "global failure", extend( function() { QUnit.test( "global failure", function() {
QUnit.pushFailure( error, filePath + ":" + linerNr ); QUnit.pushFailure( error, filePath + ":" + linerNr );
}, { validTest: validTest } ) ); });
} }
return false; return false;
} }
@@ -1141,11 +1108,6 @@ function done() {
} }
} }
// scroll back to top to show results
if ( window.scrollTo ) {
window.scrollTo(0, 0);
}
runLoggingCallbacks( "done", QUnit, { runLoggingCallbacks( "done", QUnit, {
failed: config.stats.bad, failed: config.stats.bad,
passed: passed, passed: passed,
@@ -1161,12 +1123,6 @@ function validTest( test ) {
module = config.module && config.module.toLowerCase(), module = config.module && config.module.toLowerCase(),
fullName = (test.module + ": " + test.testName).toLowerCase(); fullName = (test.module + ": " + test.testName).toLowerCase();
// Internally-generated tests are always valid
if ( test.callback && test.callback.validTest === validTest ) {
delete test.callback.validTest;
return true;
}
if ( config.testNumber ) { if ( config.testNumber ) {
return test.testNumber === config.testNumber; return test.testNumber === config.testNumber;
} }
@@ -1448,8 +1404,7 @@ QUnit.equiv = (function() {
a.global === b.global && a.global === b.global &&
// (gmi) ... // (gmi) ...
a.ignoreCase === b.ignoreCase && a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline && a.multiline === b.multiline;
a.sticky === b.sticky;
}, },
// - skip when the property is a method of an instance (OOP) // - skip when the property is a method of an instance (OOP)

View File

@@ -1,5 +1,5 @@
/** vim: et:ts=4:sw=4:sts=4 /** vim: et:ts=4:sw=4:sts=4
* @license RequireJS 2.0.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. * @license RequireJS 2.1.0 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
@@ -12,7 +12,7 @@ var requirejs, require, define;
(function (global) { (function (global) {
var req, s, head, baseElement, dataMain, src, var req, s, head, baseElement, dataMain, src,
interactiveScript, currentlyAddingScript, mainScript, subPath, interactiveScript, currentlyAddingScript, mainScript, subPath,
version = '2.0.6', version = '2.1.0',
commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
jsSuffixRegExp = /\.js$/, jsSuffixRegExp = /\.js$/,
@@ -147,41 +147,6 @@ var requirejs, require, define;
return g; return g;
} }
function makeContextModuleFunc(func, relMap, enableBuildCallback) {
return function () {
//A version of a require function that passes a moduleName
//value for items that may need to
//look up paths relative to the moduleName
var args = aps.call(arguments, 0), lastArg;
if (enableBuildCallback &&
isFunction((lastArg = args[args.length - 1]))) {
lastArg.__requireJsBuild = true;
}
args.push(relMap);
return func.apply(null, args);
};
}
function addRequireMethods(req, context, relMap) {
each([
['toUrl'],
['undef'],
['defined', 'requireDefined'],
['specified', 'requireSpecified']
], function (item) {
var prop = item[1] || item[0];
req[item[0]] = context ? makeContextModuleFunc(context[prop], relMap) :
//If no context, then use default context. Reference from
//contexts instead of early binding to default context, so
//that during builds, the latest instance of the default
//context with its config gets used.
function () {
var ctx = contexts[defContextName];
return ctx[prop].apply(ctx, arguments);
};
});
}
/** /**
* Constructs an error with a pointer to an URL with more information. * Constructs an error with a pointer to an URL with more information.
* @param {String} id the error ID that maps to an ID on a web page. * @param {String} id the error ID that maps to an ID on a web page.
@@ -238,12 +203,7 @@ var requirejs, require, define;
defined = {}, defined = {},
urlFetched = {}, urlFetched = {},
requireCounter = 1, requireCounter = 1,
unnormalizedCounter = 1, unnormalizedCounter = 1;
//Used to track the order in which modules
//should be executed, by the order they
//load. Important for consistent cycle resolution
//behavior.
waitAry = [];
/** /**
* Trims the . and .. from an array of path segments. * Trims the . and .. from an array of path segments.
@@ -405,12 +365,25 @@ var requirejs, require, define;
//Pop off the first array value, since it failed, and //Pop off the first array value, since it failed, and
//retry //retry
pathConfig.shift(); pathConfig.shift();
context.undef(id); context.require.undef(id);
context.require([id]); context.require([id]);
return true; return true;
} }
} }
//Turns a plugin!resource to [plugin, resource]
//with the plugin being undefined if the name
//did not have a plugin prefix.
function splitPrefix(name) {
var prefix,
index = name ? name.indexOf('!') : -1;
if (index > -1) {
prefix = name.substring(0, index);
name = name.substring(index + 1, name.length);
}
return [prefix, name];
}
/** /**
* Creates a module mapping that includes plugin prefix, module * Creates a module mapping that includes plugin prefix, module
* name, and path. If parentModuleMap is provided it will * name, and path. If parentModuleMap is provided it will
@@ -427,8 +400,7 @@ var requirejs, require, define;
* @returns {Object} * @returns {Object}
*/ */
function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
var url, pluginModule, suffix, var url, pluginModule, suffix, nameParts,
index = name ? name.indexOf('!') : -1,
prefix = null, prefix = null,
parentName = parentModuleMap ? parentModuleMap.name : null, parentName = parentModuleMap ? parentModuleMap.name : null,
originalName = name, originalName = name,
@@ -442,10 +414,9 @@ var requirejs, require, define;
name = '_@r' + (requireCounter += 1); name = '_@r' + (requireCounter += 1);
} }
if (index !== -1) { nameParts = splitPrefix(name);
prefix = name.substring(0, index); prefix = nameParts[0];
name = name.substring(index + 1, name.length); name = nameParts[1];
}
if (prefix) { if (prefix) {
prefix = normalize(prefix, parentName, applyMap); prefix = normalize(prefix, parentName, applyMap);
@@ -466,6 +437,15 @@ var requirejs, require, define;
} else { } else {
//A regular module. //A regular module.
normalizedName = normalize(name, parentName, applyMap); normalizedName = normalize(name, parentName, applyMap);
//Normalized name may be a plugin ID due to map config
//application in normalize. The map config values must
//already be normalized, so do not need to redo that part.
nameParts = splitPrefix(normalizedName);
prefix = nameParts[0];
normalizedName = nameParts[1];
isNormalized = true;
url = context.nameToUrl(normalizedName); url = context.nameToUrl(normalizedName);
} }
} }
@@ -557,148 +537,71 @@ var requirejs, require, define;
} }
} }
/**
* Helper function that creates a require function object to give to
* modules that ask for it as a dependency. It needs to be specific
* per module because of the implication of path mappings that may
* need to be relative to the module name.
*/
function makeRequire(mod, enableBuildCallback, altRequire) {
var relMap = mod && mod.map,
modRequire = makeContextModuleFunc(altRequire || context.require,
relMap,
enableBuildCallback);
addRequireMethods(modRequire, context, relMap);
modRequire.isBrowser = isBrowser;
return modRequire;
}
handlers = { handlers = {
'require': function (mod) { 'require': function (mod) {
return makeRequire(mod); if (mod.require) {
return mod.require;
} else {
return (mod.require = context.makeRequire(mod.map));
}
}, },
'exports': function (mod) { 'exports': function (mod) {
mod.usingExports = true; mod.usingExports = true;
if (mod.map.isDefine) { if (mod.map.isDefine) {
return (mod.exports = defined[mod.map.id] = {}); if (mod.exports) {
return mod.exports;
} else {
return (mod.exports = defined[mod.map.id] = {});
}
} }
}, },
'module': function (mod) { 'module': function (mod) {
return (mod.module = { if (mod.module) {
id: mod.map.id, return mod.module;
uri: mod.map.url, } else {
config: function () { return (mod.module = {
return (config.config && config.config[mod.map.id]) || {}; id: mod.map.id,
}, uri: mod.map.url,
exports: defined[mod.map.id] config: function () {
}); return (config.config && config.config[mod.map.id]) || {};
},
exports: defined[mod.map.id]
});
}
} }
}; };
function removeWaiting(id) { function cleanRegistry(id) {
//Clean up machinery used for waiting modules. //Clean up machinery used for waiting modules.
delete registry[id]; delete registry[id];
each(waitAry, function (mod, i) {
if (mod.map.id === id) {
waitAry.splice(i, 1);
if (!mod.defined) {
context.waitCount -= 1;
}
return true;
}
});
} }
function findCycle(mod, traced, processed) { function breakCycle(mod, traced, processed) {
var id = mod.map.id, var id = mod.map.id;
depArray = mod.depMaps,
foundModule;
//Do not bother with unitialized modules or not yet enabled if (mod.error) {
//modules. mod.emit('error', mod.error);
if (!mod.inited) { } else {
return; traced[id] = true;
} each(mod.depMaps, function (depMap, i) {
var depId = depMap.id,
dep = registry[depId];
//Found the cycle. //Only force things that have not completed
if (traced[id]) { //being defined, so still in the registry,
return mod; //and only if it has not been matched up
} //in the module already.
if (dep && !mod.depMatched[i] && !processed[depId]) {
traced[id] = true; if (traced[depId]) {
mod.defineDep(i, defined[depId]);
//Trace through the dependencies. mod.check(); //pass false?
each(depArray, function (depMap) { } else {
var depId = depMap.id, breakCycle(dep, traced, processed);
depMod = registry[depId]; }
if (!depMod || processed[depId] ||
!depMod.inited || !depMod.enabled) {
return;
}
return (foundModule = findCycle(depMod, traced, processed));
});
processed[id] = true;
return foundModule;
}
function forceExec(mod, traced, uninited) {
var id = mod.map.id,
depArray = mod.depMaps;
if (!mod.inited || !mod.map.isDefine) {
return;
}
if (traced[id]) {
return defined[id];
}
traced[id] = mod;
each(depArray, function (depMap) {
var depId = depMap.id,
depMod = registry[depId],
value;
if (handlers[depId]) {
return;
}
if (depMod) {
if (!depMod.inited || !depMod.enabled) {
//Dependency is not inited,
//so this module cannot be
//given a forced value yet.
uninited[id] = true;
return;
} }
});
//Get the value for the current dependency processed[id] = true;
value = forceExec(depMod, traced, uninited); }
//Even with forcing it may not be done,
//in particular if the module is waiting
//on a plugin resource.
if (!uninited[depId]) {
mod.defineDepById(depId, value);
}
}
});
mod.check(true);
return defined[id];
}
function modCheck(mod) {
mod.check();
} }
function checkLoaded() { function checkLoaded() {
@@ -707,6 +610,7 @@ var requirejs, require, define;
//It is possible to disable the wait interval by using waitSeconds of 0. //It is possible to disable the wait interval by using waitSeconds of 0.
expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
noLoads = [], noLoads = [],
reqCalls = [],
stillLoading = false, stillLoading = false,
needCycleCheck = true; needCycleCheck = true;
@@ -727,6 +631,10 @@ var requirejs, require, define;
return; return;
} }
if (!map.isDefine) {
reqCalls.push(mod);
}
if (!mod.error) { if (!mod.error) {
//If the module should be executed, and it has not //If the module should be executed, and it has not
//been inited and time is up, remember it. //been inited and time is up, remember it.
@@ -761,31 +669,9 @@ var requirejs, require, define;
//Not expired, check for a cycle. //Not expired, check for a cycle.
if (needCycleCheck) { if (needCycleCheck) {
each(reqCalls, function (mod) {
each(waitAry, function (mod) { breakCycle(mod, {}, {});
if (mod.defined) {
return;
}
var cycleMod = findCycle(mod, {}, {}),
traced = {};
if (cycleMod) {
forceExec(cycleMod, traced, {});
//traced modules may have been
//removed from the registry, but
//their listeners still need to
//be called.
eachProp(traced, modCheck);
}
}); });
//Now that dependencies have
//been satisfied, trigger the
//completion check that then
//notifies listeners.
eachProp(registry, modCheck);
} }
//If still waiting on loads, and the waiting load is something //If still waiting on loads, and the waiting load is something
@@ -851,7 +737,6 @@ var requirejs, require, define;
//doing a direct modification of the depMaps array //doing a direct modification of the depMaps array
//would affect that config. //would affect that config.
this.depMaps = depMaps && depMaps.slice(0); this.depMaps = depMaps && depMaps.slice(0);
this.depMaps.rjsSkipMap = depMaps.rjsSkipMap;
this.errback = errback; this.errback = errback;
@@ -873,20 +758,6 @@ var requirejs, require, define;
} }
}, },
defineDepById: function (id, depExports) {
var i;
//Find the index for this dependency.
each(this.depMaps, function (map, index) {
if (map.id === id) {
i = index;
return true;
}
});
return this.defineDep(i, depExports);
},
defineDep: function (i, depExports) { defineDep: function (i, depExports) {
//Because of cycles, defined callback for a given //Because of cycles, defined callback for a given
//export can be called more than once. //export can be called more than once.
@@ -910,7 +781,9 @@ var requirejs, require, define;
//If the manager is for a plugin managed resource, //If the manager is for a plugin managed resource,
//ask the plugin to load it now. //ask the plugin to load it now.
if (this.shim) { if (this.shim) {
makeRequire(this, true)(this.shim.deps || [], bind(this, function () { context.makeRequire(this.map, {
enableBuildCallback: true
})(this.shim.deps || [], bind(this, function () {
return map.prefix ? this.callPlugin() : this.load(); return map.prefix ? this.callPlugin() : this.load();
})); }));
} else { } else {
@@ -931,11 +804,9 @@ var requirejs, require, define;
/** /**
* Checks is the module is ready to define itself, and if so, * Checks is the module is ready to define itself, and if so,
* define it. If the silent argument is true, then it will just * define it.
* define, but not notify listeners, and not ask for a context-wide
* check of all loaded modules. That is useful for cycle breaking.
*/ */
check: function (silent) { check: function () {
if (!this.enabled || this.enabling) { if (!this.enabled || this.enabling) {
return; return;
} }
@@ -1013,11 +884,6 @@ var requirejs, require, define;
delete registry[id]; delete registry[id];
this.defined = true; this.defined = true;
context.waitCount -= 1;
if (context.waitCount === 0) {
//Clear the wait array used for cycles.
waitAry = [];
}
} }
//Finished the define stage. Allow calling check again //Finished the define stage. Allow calling check again
@@ -1025,25 +891,33 @@ var requirejs, require, define;
//cycle. //cycle.
this.defining = false; this.defining = false;
if (!silent) { if (this.defined && !this.defineEmitted) {
if (this.defined && !this.defineEmitted) { this.defineEmitted = true;
this.defineEmitted = true; this.emit('defined', this.exports);
this.emit('defined', this.exports); this.defineEmitComplete = true;
this.defineEmitComplete = true;
}
} }
} }
}, },
callPlugin: function () { callPlugin: function () {
var map = this.map, var map = this.map,
id = map.id, id = map.id,
pluginMap = makeModuleMap(map.prefix, null, false, true); //Map already normalized the prefix.
pluginMap = makeModuleMap(map.prefix);
//Mark this as a dependency for this plugin, so it
//can be traced for cycles.
this.depMaps.push(pluginMap);
on(pluginMap, 'defined', bind(this, function (plugin) { on(pluginMap, 'defined', bind(this, function (plugin) {
var load, normalizedMap, normalizedMod, var load, normalizedMap, normalizedMod,
name = this.map.name, name = this.map.name,
parentName = this.map.parentMap ? this.map.parentMap.name : null; parentName = this.map.parentMap ? this.map.parentMap.name : null,
localRequire = context.makeRequire(map.parentMap, {
enableBuildCallback: true,
skipMap: true
});
//If current map is not normalized, wait for that //If current map is not normalized, wait for that
//normalized name to load instead of continuing. //normalized name to load instead of continuing.
@@ -1055,10 +929,10 @@ var requirejs, require, define;
}) || ''; }) || '';
} }
//prefix and name should already be normalized, no need
//for applying map config again either.
normalizedMap = makeModuleMap(map.prefix + '!' + name, normalizedMap = makeModuleMap(map.prefix + '!' + name,
this.map.parentMap, this.map.parentMap);
false,
true);
on(normalizedMap, on(normalizedMap,
'defined', bind(this, function (value) { 'defined', bind(this, function (value) {
this.init([], function () { return value; }, null, { this.init([], function () { return value; }, null, {
@@ -1066,8 +940,13 @@ var requirejs, require, define;
ignore: true ignore: true
}); });
})); }));
normalizedMod = registry[normalizedMap.id]; normalizedMod = registry[normalizedMap.id];
if (normalizedMod) { if (normalizedMod) {
//Mark this as a dependency for this plugin, so it
//can be traced for cycles.
this.depMaps.push(normalizedMap);
if (this.events.error) { if (this.events.error) {
normalizedMod.on('error', bind(this, function (err) { normalizedMod.on('error', bind(this, function (err) {
this.emit('error', err); this.emit('error', err);
@@ -1094,7 +973,7 @@ var requirejs, require, define;
//since they will never be resolved otherwise now. //since they will never be resolved otherwise now.
eachProp(registry, function (mod) { eachProp(registry, function (mod) {
if (mod.map.id.indexOf(id + '_unnormalized') === 0) { if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
removeWaiting(mod.map.id); cleanRegistry(mod.map.id);
} }
}); });
@@ -1103,9 +982,19 @@ var requirejs, require, define;
//Allow plugins to load other code without having to know the //Allow plugins to load other code without having to know the
//context or how to 'complete' the load. //context or how to 'complete' the load.
load.fromText = function (moduleName, text) { load.fromText = bind(this, function (text, textAlt) {
/*jslint evil: true */ /*jslint evil: true */
var hasInteractive = useInteractive; var moduleName = map.name,
moduleMap = makeModuleMap(moduleName),
hasInteractive = useInteractive;
//As of 2.1.0, support just passing the text, to reinforce
//fromText only being called once per resource. Still
//support old style of passing moduleName but discard
//that moduleName in favor of the internal ref.
if (textAlt) {
text = textAlt;
}
//Turn off interactive script matching for IE for any define //Turn off interactive script matching for IE for any define
//calls in the text, then turn it back on at the end. //calls in the text, then turn it back on at the end.
@@ -1115,25 +1004,35 @@ var requirejs, require, define;
//Prime the system by creating a module instance for //Prime the system by creating a module instance for
//it. //it.
getModule(makeModuleMap(moduleName)); getModule(moduleMap);
req.exec(text); try {
req.exec(text);
} catch (e) {
throw new Error('fromText eval for ' + moduleName +
' failed: ' + e);
}
if (hasInteractive) { if (hasInteractive) {
useInteractive = true; useInteractive = true;
} }
//Mark this as a dependency for the plugin
//resource
this.depMaps.push(moduleMap);
//Support anonymous modules. //Support anonymous modules.
context.completeLoad(moduleName); context.completeLoad(moduleName);
};
//Bind the value of that module to the value for this
//resource ID.
localRequire([moduleName], load);
});
//Use parentName here since the plugin's name is not reliable, //Use parentName here since the plugin's name is not reliable,
//could be some weird string with no path that actually wants to //could be some weird string with no path that actually wants to
//reference the parentName's path. //reference the parentName's path.
plugin.load(map.name, makeRequire(map.parentMap, true, function (deps, cb, er) { plugin.load(map.name, localRequire, load, config);
deps.rjsSkipMap = true;
return context.require(deps, cb, er);
}), load, config);
})); }));
context.enable(pluginMap, this); context.enable(pluginMap, this);
@@ -1143,12 +1042,6 @@ var requirejs, require, define;
enable: function () { enable: function () {
this.enabled = true; this.enabled = true;
if (!this.waitPushed) {
waitAry.push(this);
context.waitCount += 1;
this.waitPushed = true;
}
//Set flag mentioning that the module is enabling, //Set flag mentioning that the module is enabling,
//so that immediate calls to the defined callbacks //so that immediate calls to the defined callbacks
//for dependencies do not trigger inadvertent load //for dependencies do not trigger inadvertent load
@@ -1165,7 +1058,7 @@ var requirejs, require, define;
depMap = makeModuleMap(depMap, depMap = makeModuleMap(depMap,
(this.map.isDefine ? this.map : this.map.parentMap), (this.map.isDefine ? this.map : this.map.parentMap),
false, false,
!this.depMaps.rjsSkipMap); !this.skipMap);
this.depMaps[i] = depMap; this.depMaps[i] = depMap;
handler = handlers[depMap.id]; handler = handlers[depMap.id];
@@ -1227,7 +1120,7 @@ var requirejs, require, define;
if (name === 'error') { if (name === 'error') {
//Now that the error handler was triggered, remove //Now that the error handler was triggered, remove
//the listeners, since this broken Module instance //the listeners, since this broken Module instance
//can stay around for a while in the registry/waitAry. //can stay around for a while in the registry.
delete this.events[name]; delete this.events[name];
} }
} }
@@ -1274,16 +1167,16 @@ var requirejs, require, define;
}; };
} }
return (context = { context = {
config: config, config: config,
contextName: contextName, contextName: contextName,
registry: registry, registry: registry,
defined: defined, defined: defined,
urlFetched: urlFetched, urlFetched: urlFetched,
waitCount: 0,
defQueue: defQueue, defQueue: defQueue,
Module: Module, Module: Module,
makeModuleMap: makeModuleMap, makeModuleMap: makeModuleMap,
nextTick: req.nextTick,
/** /**
* Set a configuration for the context. * Set a configuration for the context.
@@ -1325,8 +1218,8 @@ var requirejs, require, define;
deps: value deps: value
}; };
} }
if (value.exports && !value.exports.__buildReady) { if (value.exports && !value.exportsFn) {
value.exports = context.makeShimExports(value.exports); value.exportsFn = context.makeShimExports(value);
} }
shim[id] = value; shim[id] = value;
}); });
@@ -1381,125 +1274,152 @@ var requirejs, require, define;
} }
}, },
makeShimExports: function (exports) { makeShimExports: function (value) {
var func; function fn() {
if (typeof exports === 'string') { var ret;
func = function () { if (value.init) {
return getGlobal(exports); ret = value.init.apply(global, arguments);
}; }
//Save the exports for use in nodefine checking. return ret || getGlobal(value.exports);
func.exports = exports;
return func;
} else {
return function () {
return exports.apply(global, arguments);
};
} }
return fn;
}, },
requireDefined: function (id, relMap) { makeRequire: function (relMap, options) {
return hasProp(defined, makeModuleMap(id, relMap, false, true).id); options = options || {};
},
requireSpecified: function (id, relMap) { function require(deps, callback, errback) {
id = makeModuleMap(id, relMap, false, true).id; var id, map, requireMod, args;
return hasProp(defined, id) || hasProp(registry, id);
},
require: function (deps, callback, errback, relMap) { if (options.enableBuildCallback && callback && isFunction(callback)) {
var moduleName, id, map, requireMod, args; callback.__requireJsBuild = true;
if (typeof deps === 'string') {
if (isFunction(callback)) {
//Invalid call
return onError(makeError('requireargs', 'Invalid require call'), errback);
} }
//Synchronous access to one module. If require.get is if (typeof deps === 'string') {
//available (as in the Node adapter), prefer that. if (isFunction(callback)) {
//In this case deps is the moduleName and callback is //Invalid call
//the relMap return onError(makeError('requireargs', 'Invalid require call'), errback);
if (req.get) { }
return req.get(context, deps, callback);
//If require|exports|module are requested, get the
//value for them from the special handlers. Caveat:
//this only works while module is being defined.
if (relMap && handlers[deps]) {
return handlers[deps](registry[relMap.id]);
}
//Synchronous access to one module. If require.get is
//available (as in the Node adapter), prefer that.
if (req.get) {
return req.get(context, deps, relMap);
}
//Normalize module name, if it contains . or ..
map = makeModuleMap(deps, relMap, false, true);
id = map.id;
if (!hasProp(defined, id)) {
return onError(makeError('notloaded', 'Module name "' +
id +
'" has not been loaded yet for context: ' +
contextName +
(relMap ? '' : '. Use require([])')));
}
return defined[id];
} }
//Just return the module wanted. In this scenario, the //Any defined modules in the global queue, intake them now.
//second arg (if passed) is just the relMap. takeGlobalQueue();
moduleName = deps;
relMap = callback;
//Normalize module name, if it contains . or .. //Make sure any remaining defQueue items get properly processed.
map = makeModuleMap(moduleName, relMap, false, true); while (defQueue.length) {
id = map.id; args = defQueue.shift();
if (args[0] === null) {
if (!hasProp(defined, id)) { return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
return onError(makeError('notloaded', 'Module name "' + } else {
id + //args are id, deps, factory. Should be normalized by the
'" has not been loaded yet for context: ' + //define() function.
contextName)); callGetModule(args);
}
} }
return defined[id];
//Mark all the dependencies as needing to be loaded.
context.nextTick(function () {
requireMod = getModule(makeModuleMap(null, relMap));
//Store if map config should be applied to this require
//call for dependencies.
requireMod.skipMap = options.skipMap;
requireMod.init(deps, callback, errback, {
enabled: true
});
checkLoaded();
});
return require;
} }
//Callback require. Normalize args. if callback or errback is mixin(require, {
//not a function, it means it is a relMap. Test errback first. isBrowser: isBrowser,
if (errback && !isFunction(errback)) {
relMap = errback;
errback = undefined;
}
if (callback && !isFunction(callback)) {
relMap = callback;
callback = undefined;
}
//Any defined modules in the global queue, intake them now. /**
takeGlobalQueue(); * Converts a module name + .extension into an URL path.
* *Requires* the use of a module name. It does not support using
* plain URLs like nameToUrl.
*/
toUrl: function (moduleNamePlusExt) {
var index = moduleNamePlusExt.lastIndexOf('.'),
ext = null;
//Make sure any remaining defQueue items get properly processed. if (index !== -1) {
while (defQueue.length) { ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
args = defQueue.shift(); moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
if (args[0] === null) { }
return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
} else { return context.nameToUrl(normalize(moduleNamePlusExt,
//args are id, deps, factory. Should be normalized by the relMap && relMap.id, true), ext);
//define() function. },
callGetModule(args);
defined: function (id) {
return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
},
specified: function (id) {
id = makeModuleMap(id, relMap, false, true).id;
return hasProp(defined, id) || hasProp(registry, id);
} }
}
//Mark all the dependencies as needing to be loaded.
requireMod = getModule(makeModuleMap(null, relMap));
requireMod.init(deps, callback, errback, {
enabled: true
}); });
checkLoaded(); //Only allow undef on top level require calls
if (!relMap) {
require.undef = function (id) {
//Bind any waiting define() calls to this context,
//fix for #408
takeGlobalQueue();
return context.require; var map = makeModuleMap(id, relMap, true),
}, mod = registry[id];
undef: function (id) { delete defined[id];
//Bind any waiting define() calls to this context, delete urlFetched[map.url];
//fix for #408 delete undefEvents[id];
takeGlobalQueue();
var map = makeModuleMap(id, null, true), if (mod) {
mod = registry[id]; //Hold on to listeners in case the
//module will be attempted to be reloaded
//using a different config.
if (mod.events.defined) {
undefEvents[id] = mod.events;
}
delete defined[id]; cleanRegistry(id);
delete urlFetched[map.url]; }
delete undefEvents[id]; };
if (mod) {
//Hold on to listeners in case the
//module will be attempted to be reloaded
//using a different config.
if (mod.events.defined) {
undefEvents[id] = mod.events;
}
removeWaiting(id);
} }
return require;
}, },
/** /**
@@ -1523,7 +1443,7 @@ var requirejs, require, define;
completeLoad: function (moduleName) { completeLoad: function (moduleName) {
var found, args, mod, var found, args, mod,
shim = config.shim[moduleName] || {}, shim = config.shim[moduleName] || {},
shExports = shim.exports && shim.exports.exports; shExports = shim.exports;
takeGlobalQueue(); takeGlobalQueue();
@@ -1563,31 +1483,13 @@ var requirejs, require, define;
} else { } else {
//A script that does not call define(), so just simulate //A script that does not call define(), so just simulate
//the call for it. //the call for it.
callGetModule([moduleName, (shim.deps || []), shim.exports]); callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
} }
} }
checkLoaded(); checkLoaded();
}, },
/**
* Converts a module name + .extension into an URL path.
* *Requires* the use of a module name. It does not support using
* plain URLs like nameToUrl.
*/
toUrl: function (moduleNamePlusExt, relModuleMap) {
var index = moduleNamePlusExt.lastIndexOf('.'),
ext = null;
if (index !== -1) {
ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
}
return context.nameToUrl(normalize(moduleNamePlusExt, relModuleMap && relModuleMap.id, true),
ext);
},
/** /**
* Converts a module name to a file path. Supports cases where * Converts a module name to a file path. Supports cases where
* moduleName may actually be just an URL. * moduleName may actually be just an URL.
@@ -1701,7 +1603,10 @@ var requirejs, require, define;
return onError(makeError('scripterror', 'Script error', evt, [data.id])); return onError(makeError('scripterror', 'Script error', evt, [data.id]));
} }
} }
}); };
context.require = context.makeRequire();
return context;
} }
/** /**
@@ -1762,6 +1667,16 @@ var requirejs, require, define;
return req(config); return req(config);
}; };
/**
* Execute something after the current tick
* of the event loop. Override for other envs
* that have a better solution than setTimeout.
* @param {Function} fn function to execute later.
*/
req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
setTimeout(fn, 4);
} : function (fn) { fn(); };
/** /**
* Export require as a global, but only if it does not already exist. * Export require as a global, but only if it does not already exist.
*/ */
@@ -1782,9 +1697,21 @@ var requirejs, require, define;
//Create default context. //Create default context.
req({}); req({});
//Exports some context-sensitive methods on global require, using //Exports some context-sensitive methods on global require.
//default context if no context specified. each([
addRequireMethods(req); 'toUrl',
'undef',
'defined',
'specified'
], function (prop) {
//Reference from contexts instead of early binding to default context,
//so that during builds, the latest instance of the default context
//with its config gets used.
req[prop] = function () {
var ctx = contexts[defContextName];
return ctx.require[prop].apply(ctx, arguments);
};
});
if (isBrowser) { if (isBrowser) {
head = s.head = document.getElementsByTagName('head')[0]; head = s.head = document.getElementsByTagName('head')[0];
@@ -1962,7 +1889,7 @@ var requirejs, require, define;
define = function (name, deps, callback) { define = function (name, deps, callback) {
var node, context; var node, context;
//Allow for anonymous functions //Allow for anonymous modules
if (typeof name !== 'string') { if (typeof name !== 'string') {
//Adjust args appropriately //Adjust args appropriately
callback = deps; callback = deps;

View File

@@ -14,6 +14,8 @@ $(document).ready(function() {
equal(result.join(','), '1,1', 'works well with _.map'); equal(result.join(','), '1,1', 'works well with _.map');
result = (function() { return _.take([1,2,3], 2); })(); result = (function() { return _.take([1,2,3], 2); })();
equal(result.join(','), '1,2', 'aliased as take'); equal(result.join(','), '1,2', 'aliased as take');
equal(_.first(null), undefined, 'handles nulls');
}); });
test("rest", function() { test("rest", function() {
@@ -47,6 +49,8 @@ $(document).ready(function() {
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);
equal(result.join(','), '3,3', 'works well with _.map'); equal(result.join(','), '3,3', 'works well with _.map');
equal(_.last(null), undefined, 'handles nulls');
}); });
test("compact", function() { test("compact", function() {
@@ -136,6 +140,8 @@ $(document).ready(function() {
var stooges = {moe: 30, larry: 40, curly: 50}; var stooges = {moe: 30, larry: 40, curly: 50};
ok(_.isEqual(_.object(_.pairs(stooges)), stooges), 'an object converted to pairs and back to an object'); ok(_.isEqual(_.object(_.pairs(stooges)), stooges), 'an object converted to pairs and back to an object');
ok(_.isEqual(_.object(null), {}), 'handles nulls');
}); });
test("indexOf", function() { test("indexOf", function() {
@@ -144,6 +150,7 @@ $(document).ready(function() {
equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function'); equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3); var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
equal(result, 1, 'works on an arguments object'); equal(result, 1, 'works on an arguments object');
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
var numbers = [10, 20, 30, 40, 50], num = 35; var numbers = [10, 20, 30, 40, 50], num = 35;
var index = _.indexOf(numbers, num, true); var index = _.indexOf(numbers, num, true);
@@ -172,6 +179,7 @@ $(document).ready(function() {
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);
equal(result, 5, 'works on an arguments object'); equal(result, 5, 'works on an arguments object');
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
index = _.lastIndexOf(numbers, 2, 2); index = _.lastIndexOf(numbers, 2, 2);

View File

@@ -25,6 +25,10 @@ $(document).ready(function() {
answer = null; answer = null;
_.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; }); _.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; });
ok(answer, 'can reference the original collection from inside the iterator'); ok(answer, 'can reference the original collection from inside the iterator');
answers = 0;
_.each(null, function(){ ++answers; });
equal(answers, 0, 'handles a null properly');
}); });
test('map', function() { test('map', function() {
@@ -50,6 +54,9 @@ $(document).ready(function() {
var ids = _.map(document.images, function(n){ return n.id; }); var ids = _.map(document.images, function(n){ return n.id; });
ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections'); ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections');
var ifnull = _.map(null, function(){});
ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly');
}); });
test('reduce', function() { test('reduce', function() {
@@ -69,6 +76,15 @@ $(document).ready(function() {
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }); var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
equal(sum, 6, 'default initial value'); equal(sum, 6, 'default initial value');
var ifnull;
try {
_.reduce(null, function(){});
} catch (ex) {
ifnull = ex;
}
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case'); equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value'); raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
}); });
@@ -83,9 +99,19 @@ $(document).ready(function() {
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }); var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; });
equal(list, 'bazbarfoo', 'default initial value'); equal(list, 'bazbarfoo', 'default initial value');
var ifnull;
try {
_.reduceRight(null, function(){});
} catch (ex) {
ifnull = ex;
}
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; }); var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; });
equal(sum, 6, 'default initial value on object'); equal(sum, 6, 'default initial value on object');
ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case'); equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value'); raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
@@ -385,6 +411,8 @@ $(document).ready(function() {
equal(func(1, 2, 3, 4), 4, 'can test the size of the arguments object'); equal(func(1, 2, 3, 4), 4, 'can test the size of the arguments object');
equal(_.size('hello'), 5, 'can compute the size of a string'); equal(_.size('hello'), 5, 'can compute the size of a string');
equal(_.size(null), 0, 'handles nulls');
}); });
}); });

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
// Underscore.js 1.4.0 // Underscore.js 1.4.2
// http://underscorejs.org // http://underscorejs.org
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore may be freely distributed under the MIT license. // Underscore may be freely distributed under the MIT license.
@@ -65,7 +65,7 @@
} }
// Current version. // Current version.
_.VERSION = '1.4.0'; _.VERSION = '1.4.2';
// Collection Functions // Collection Functions
// -------------------- // --------------------
@@ -74,6 +74,7 @@
// Handles objects with the built-in `forEach`, arrays, and raw objects. // Handles objects with the built-in `forEach`, arrays, and raw objects.
// Delegates to **ECMAScript 5**'s native `forEach` if available. // Delegates to **ECMAScript 5**'s native `forEach` if available.
var each = _.each = _.forEach = function(obj, iterator, context) { var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return;
if (nativeForEach && obj.forEach === nativeForEach) { if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context); obj.forEach(iterator, context);
} else if (obj.length === +obj.length) { } else if (obj.length === +obj.length) {
@@ -93,6 +94,7 @@
// Delegates to **ECMAScript 5**'s native `map` if available. // Delegates to **ECMAScript 5**'s native `map` if available.
_.map = _.collect = function(obj, iterator, context) { _.map = _.collect = function(obj, iterator, context) {
var results = []; var results = [];
if (obj == null) return results;
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
each(obj, function(value, index, list) { each(obj, function(value, index, list) {
results[results.length] = iterator.call(context, value, index, list); results[results.length] = iterator.call(context, value, index, list);
@@ -104,6 +106,7 @@
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
var initial = arguments.length > 2; var initial = arguments.length > 2;
if (obj == null) obj = [];
if (nativeReduce && obj.reduce === nativeReduce) { if (nativeReduce && obj.reduce === nativeReduce) {
if (context) iterator = _.bind(iterator, context); if (context) iterator = _.bind(iterator, context);
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
@@ -124,6 +127,7 @@
// Delegates to **ECMAScript 5**'s native `reduceRight` if available. // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
_.reduceRight = _.foldr = function(obj, iterator, memo, context) { _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
var initial = arguments.length > 2; var initial = arguments.length > 2;
if (obj == null) obj = [];
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
if (context) iterator = _.bind(iterator, context); if (context) iterator = _.bind(iterator, context);
return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
@@ -163,6 +167,7 @@
// Aliased as `select`. // Aliased as `select`.
_.filter = _.select = function(obj, iterator, context) { _.filter = _.select = function(obj, iterator, context) {
var results = []; var results = [];
if (obj == null) return results;
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
each(obj, function(value, index, list) { each(obj, function(value, index, list) {
if (iterator.call(context, value, index, list)) results[results.length] = value; if (iterator.call(context, value, index, list)) results[results.length] = value;
@@ -173,6 +178,7 @@
// Return all the elements for which a truth test fails. // Return all the elements for which a truth test fails.
_.reject = function(obj, iterator, context) { _.reject = function(obj, iterator, context) {
var results = []; var results = [];
if (obj == null) return results;
each(obj, function(value, index, list) { each(obj, function(value, index, list) {
if (!iterator.call(context, value, index, list)) results[results.length] = value; if (!iterator.call(context, value, index, list)) results[results.length] = value;
}); });
@@ -185,6 +191,7 @@
_.every = _.all = function(obj, iterator, context) { _.every = _.all = function(obj, iterator, context) {
iterator || (iterator = _.identity); iterator || (iterator = _.identity);
var result = true; var result = true;
if (obj == null) return result;
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
each(obj, function(value, index, list) { each(obj, function(value, index, list) {
if (!(result = result && iterator.call(context, value, index, list))) return breaker; if (!(result = result && iterator.call(context, value, index, list))) return breaker;
@@ -198,6 +205,7 @@
var any = _.some = _.any = function(obj, iterator, context) { var any = _.some = _.any = function(obj, iterator, context) {
iterator || (iterator = _.identity); iterator || (iterator = _.identity);
var result = false; var result = false;
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function(value, index, list) { each(obj, function(value, index, list) {
if (result || (result = iterator.call(context, value, index, list))) return breaker; if (result || (result = iterator.call(context, value, index, list))) return breaker;
@@ -209,6 +217,7 @@
// Aliased as `include`. // Aliased as `include`.
_.contains = _.include = function(obj, target) { _.contains = _.include = function(obj, target) {
var found = false; var found = false;
if (obj == null) return found;
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
found = any(obj, function(value) { found = any(obj, function(value) {
return value === target; return value === target;
@@ -360,6 +369,7 @@
// Return the number of elements in an object. // Return the number of elements in an object.
_.size = function(obj) { _.size = function(obj) {
if (obj == null) return 0;
return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
}; };
@@ -370,6 +380,7 @@
// values in the array. Aliased as `head` and `take`. The **guard** check // values in the array. Aliased as `head` and `take`. The **guard** check
// allows it to work with `_.map`. // allows it to work with `_.map`.
_.first = _.head = _.take = function(array, n, guard) { _.first = _.head = _.take = function(array, n, guard) {
if (array == null) return void 0;
return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
}; };
@@ -384,6 +395,7 @@
// Get the last element of an array. Passing **n** will return the last N // Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`. // values in the array. The **guard** check allows it to work with `_.map`.
_.last = function(array, n, guard) { _.last = function(array, n, guard) {
if (array == null) return void 0;
if ((n != null) && !guard) { if ((n != null) && !guard) {
return slice.call(array, Math.max(array.length - n, 0)); return slice.call(array, Math.max(array.length - n, 0));
} else { } else {
@@ -482,6 +494,7 @@
// pairs, or two parallel arrays of the same length -- one of keys, and one of // pairs, or two parallel arrays of the same length -- one of keys, and one of
// the corresponding values. // the corresponding values.
_.object = function(list, values) { _.object = function(list, values) {
if (list == null) return {};
var result = {}; var result = {};
for (var i = 0, l = list.length; i < l; i++) { for (var i = 0, l = list.length; i < l; i++) {
if (values) { if (values) {
@@ -500,6 +513,7 @@
// If the array is large and already in sort order, pass `true` // If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search. // for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) { _.indexOf = function(array, item, isSorted) {
if (array == null) return -1;
var i = 0, l = array.length; var i = 0, l = array.length;
if (isSorted) { if (isSorted) {
if (typeof isSorted == 'number') { if (typeof isSorted == 'number') {
@@ -516,6 +530,7 @@
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
_.lastIndexOf = function(array, item, from) { _.lastIndexOf = function(array, item, from) {
if (array == null) return -1;
var hasIndex = from != null; var hasIndex = from != null;
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
@@ -607,25 +622,25 @@
// Returns a function, that, when invoked, will only be triggered at most once // Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. // during a given window of time.
_.throttle = function(func, wait) { _.throttle = function(func, wait) {
var context, args, timeout, throttling, more, result; var context, args, timeout, result;
var whenDone = _.debounce(function(){ more = throttling = false; }, wait); var previous = 0;
var later = function() {
previous = new Date;
timeout = null;
result = func.apply(context, args);
};
return function() { return function() {
context = this; args = arguments; var now = new Date;
var later = function() { var remaining = wait - (now - previous);
timeout = null; context = this;
if (more) { args = arguments;
result = func.apply(context, args); if (remaining <= 0) {
} clearTimeout(timeout);
whenDone(); previous = now;
};
if (!timeout) timeout = setTimeout(later, wait);
if (throttling) {
more = true;
} else {
throttling = true;
result = func.apply(context, args); result = func.apply(context, args);
} else if (!timeout) {
timeout = setTimeout(later, remaining);
} }
whenDone();
return result; return result;
}; };
}; };