Compare commits

..

96 Commits
0.2.0 ... 0.3.1

Author SHA1 Message Date
John-David Dalton
1e2ef542e4 Bump to v0.3.1.
Former-commit-id: 2e1e3b7e47b1f98d2ca20a89a4570a0b958d4323
2012-06-11 00:09:29 -04:00
John-David Dalton
94e8af4d93 Update submodules.
Former-commit-id: 0658ae9b9e49c468f839738f34c9f6361b90897e
2012-06-10 23:58:43 -04:00
John-David Dalton
250a0ab5eb Add _.shuffle benchmark.
Former-commit-id: 13a0a7392108571d4ebced5e6e6ff66048091983
2012-06-10 13:46:45 -04:00
John-David Dalton
2da05d88a0 Add another code example to _.invoke documentation.
Former-commit-id: 0bea74a470771ebc5cf2110243b38db3698cde52
2012-06-10 12:59:42 -04:00
John-David Dalton
7faa849a89 Cleanup README.md.
Former-commit-id: 1cc58476c5737624b97801aabc0dc7368c43c0d3
2012-06-09 03:23:39 -04:00
John-David Dalton
c5bceb8fc8 Update documentation and minified build.
Former-commit-id: edc6264f5721cbdb080c4f7772263848c125b3e2
2012-06-09 03:11:36 -04:00
John-David Dalton
1e94b93ce6 Add Backbone build and correct dependencies for _.bindAll, _.mixin, and _.sortBy.
Former-commit-id: 3d4413d6ab3b41471be6336d138a4b4bfa97fde7
2012-06-09 03:10:57 -04:00
John-David Dalton
3f7bccf2e6 Update Backbone and Underscore submodules.
Former-commit-id: 6f938216d0bb26347ce7fd42169f926e2ae04e0e
2012-06-09 00:31:03 -04:00
John-David Dalton
181b869109 Remove _.map and _.pluck dependency from _.sortBy and simplify method wrappers.
Former-commit-id: 915af96abd41e8da7bba88cd57eb703f8129107f
2012-06-09 00:29:51 -04:00
John-David Dalton
2332245be1 Update minified build and documentation.
Former-commit-id: 6790d25b2164f0df2dcce63d5a5780343f3b5e63
2012-06-07 12:44:53 -04:00
John-David Dalton
3c6999f3a4 Ensure all "Arrays" category methods allow a falsey array argument. [closes #23, #24]
Former-commit-id: 66d09d3c8f3c045daf310c46581afa085daa57de
2012-06-07 12:42:33 -04:00
John-David Dalton
5f2f15b976 Remove _.isArguments fallback from mobile build.
Former-commit-id: d98ac9953e9b403e17bdcef099caafe09873980f
2012-06-07 03:27:01 -04:00
John-David Dalton
47dfb5b6b7 Fix typo in _.values benchmark and tweak how percents are displayed in perf.js.
Former-commit-id: 49be4600561e55e134d3152b00c765e305af98b5
2012-06-07 00:07:33 -04:00
John-David Dalton
c410c1293e Update minified build and documentation.
Former-commit-id: e489b826c65d908b934e13d032ed866d68edd576
2012-06-06 23:48:41 -04:00
John-David Dalton
ca1c732f31 Move _.values to Objects category.
Former-commit-id: e85229b53a7697c11f76eae02aef8a4fce3aec3a
2012-06-06 23:45:30 -04:00
John-David Dalton
5e8c373bf4 Move _.pluck to the Arrays category.
Former-commit-id: a3ba36c1c320c8685c25fcb0bbe16ba2baeb6731
2012-06-06 23:11:25 -04:00
John-David Dalton
51a459fe48 Simplify function checks and cleanup documentation.
Former-commit-id: 460f34725e212ced27831b9aad1e9e7e2fc02cf1
2012-06-06 15:56:40 -04:00
John-David Dalton
03c07abbc3 Update README.md.
Former-commit-id: 64ce8f122be084fd93fd711a6ca207fc4ae6b870
2012-06-06 15:05:52 -04:00
John-David Dalton
5eabe1a172 Add sourceURL support to _.template.
Former-commit-id: 31d40d57f903098fe1678777aa7921e72d1dca9e
2012-06-06 15:05:41 -04:00
John-David Dalton
5b6ea7afb2 Bump to v0.3.0.
Former-commit-id: 2b713b3d926e3dbba80eab6e1e14d080f169bf39
2012-06-06 00:52:57 -04:00
John-David Dalton
7c1c5e70ca Update Backbone and RequireJS submodules.
Former-commit-id: 145455767d22eb1b03a751024e69826e2387fd04
2012-06-06 00:50:31 -04:00
John-David Dalton
d475f8f965 Fix documentation typo.
Former-commit-id: 85e89c893d358d196a3f0f04b95acb10bbca2771
2012-06-05 01:44:50 -04:00
John-David Dalton
fd239076dd Fix minified build for _.forIn.
Former-commit-id: 1d5d41fe63a10ccae8fcf4a91e7e77526a7c0d9c
2012-06-05 01:07:46 -04:00
John-David Dalton
5f786bbe47 Add category build option.
Former-commit-id: 4adea9367949985a1218cff58ff856184fd11db7
2012-06-05 00:41:20 -04:00
John-David Dalton
f66dc6bed8 Fix typo in iteratorTemplate.
Former-commit-id: b787391db088e672c55ca56ca246147557b3694f
2012-06-04 22:49:33 -04:00
John-David Dalton
52c36ac445 Fix documentation typo.
Former-commit-id: defc89d6a8267a4a6626ca6ac7345db1d55cb9b6
2012-06-04 16:54:47 -04:00
John-David Dalton
8f6a78cba5 Update documentation and package.json.
Former-commit-id: 4ab7d954b7abc5f73269eb7c74a39b02fa04970d
2012-06-04 16:38:37 -04:00
John-David Dalton
7053e9113f Add unit test for _.sortedIndex to ensure it supports arrays with high length values.
Former-commit-id: 8956495dfa40c75dcb3c0585e78913607bf92e99
2012-06-04 16:18:23 -04:00
John-David Dalton
89f9ab9940 Bump to v0.3.0-pre.
Former-commit-id: 1e7958b4b1cdffd962a51edf3e3695cea960d8c9
2012-06-04 15:44:54 -04:00
John-David Dalton
240bc40b39 Ensure collection methods treat array-like objects with invalid length properties as regular objects.
Former-commit-id: dd8b382635bc30dc6e417cd9b47c36abfdf5ddcb
2012-06-04 15:36:27 -04:00
John-David Dalton
74649b5f28 Add _.forOwn and _.forIn.
Former-commit-id: f4e94a0fd15318063eec16c464435b07f419fa6a
2012-06-04 14:45:06 -04:00
John-David Dalton
b484d4b2dc Update minified build and documentation.
Former-commit-id: 592319b69487858794529d789383af1b38d55632
2012-06-04 02:23:16 -04:00
John-David Dalton
da1124dd37 Switch to an htmlEscapes object for use in _.escape.
Former-commit-id: bc449b5d6868c846d599840e5c0d90d0314fe4b8
2012-06-04 02:12:41 -04:00
John-David Dalton
210485d0be Update Benchmark.js and UglifyJS submodules.
Former-commit-id: 78611de2f992dc4d6cc4d336bfb761b98b22ce79
2012-06-04 00:08:26 -04:00
John-David Dalton
d9aee5ae60 Update minified build, documentation, and Backbone submodule.
Former-commit-id: cca2cf2f55e2750486d1d32b8da26fbc5576a65b
2012-06-03 21:58:35 -04:00
John-David Dalton
9ac64623fc Added thisArg argument to _.sortedIndex and _.uniq, benchmarks, unit tests, and adjusted related dependencies in build.js.
Former-commit-id: a97aa769d760c7cc4d0df6307cebc860345a0da0
2012-06-03 21:56:36 -04:00
John-David Dalton
6ea4226680 Remove unneeded Closure Compiler export around the template string _.escape(__t) in pre-compile.js.
Former-commit-id: 812bd220cd3baca30a100f07e1d47cd6745a3602
2012-06-03 20:36:31 -04:00
John-David Dalton
c1416bba39 Cleanup console messages in perf.js.
Former-commit-id: b3e669d46f21d39f96873167557b4ede80458beb
2012-06-03 20:35:22 -04:00
John-David Dalton
ddb3ab3238 Tweak indexOf isSorted benchmark.
Former-commit-id: 0183b35929a2c1f7113747a67f55abbc797fab8c
2012-06-03 01:06:12 -04:00
John-David Dalton
5e7c9698c7 Use typeof == 'number' more, and default callback values to docs.
Former-commit-id: 02786903a510d0cc837eeeb7e9f42db2ecd634a4
2012-06-03 01:05:40 -04:00
John-David Dalton
4c66b95516 Make Firebug Lite console fullscreen in more browsers.
Former-commit-id: a42e7d187a582a1caea721860cf3ed4bd0f94368
2012-06-01 07:41:29 -06:00
John-David Dalton
2d03060a0d Make previous build.js regexp simplification non-greedy.
Former-commit-id: e58cfb5e5143e12721bb08445dfd4a6fec119cd1
2012-05-31 23:18:44 -06:00
John-David Dalton
3313b0aa42 Update minified build and docs.
Former-commit-id: 3c0463d77c9091c1e66c7d68240de8b7ab2e499f
2012-05-31 22:54:50 -06:00
John-David Dalton
5d2928d2b3 Simplify regexps in build.js.
Former-commit-id: 7640f90b6aeca0438579c15c9eef270904c2c523
2012-05-31 22:54:37 -06:00
John-David Dalton
f6e2ae41d6 Add more benchmarks.
Former-commit-id: bddb4a26073ecd5aaf622f9726be940b6340cc07
2012-05-31 22:11:07 -06:00
John-David Dalton
7ccb038b6d Add _.isEmpty unit test.
Former-commit-id: 066961a929da280421083d3f9d66b838d3d29dfd
2012-05-31 17:40:47 -06:00
John-David Dalton
7d62bbf74f Optimize _.times.
Former-commit-id: beae48853d0e9be1c3016c11bee86a272964dfa2
2012-05-31 17:37:01 -06:00
John-David Dalton
3d8cc32302 Add fromIndex to _.indexOf and _.lastIndexOf. [closes #20]
Former-commit-id: 3ab67c318a5a7fc2e521a9a2573b694e6920b14d
2012-05-31 17:26:45 -06:00
John-David Dalton
861eea5148 Fix "prototype" iteration bug with _.keys.
Former-commit-id: 1e072b2639e21a5c0a920db0ac27693ade34b009
2012-05-31 10:29:33 -05:00
John-David Dalton
b432721fe5 Optimize this binding in iterator methods and remove _.bind as a dependency for several methods.
Former-commit-id: 60af002cd80758fea81fbff9c2b20b1ccf3ccffd
2012-05-31 10:21:38 -05:00
John-David Dalton
f13a0cc7e0 Format numbers and scroll down results panel in perf.js.
Former-commit-id: 9f80b5534e3b46be7ad9c84ebb7e9ed5afdc35b8
2012-05-30 09:19:58 -04:00
John-David Dalton
1f7e37a1a3 Change performance link in README.md to lodash.com benchmarks.
Former-commit-id: 5c851961fd1b8e46599c28967d782551722a03d4
2012-05-30 04:03:14 -04:00
John-David Dalton
548e9cac26 Update documentation.
Former-commit-id: 6d1aa50111b34e0548f96a55fe3dcca0b7e91b5e
2012-05-30 03:52:59 -04:00
John-David Dalton
0d2a1641c9 Add percent faster than to pref.js results and link to benchmarks in README.md.
Former-commit-id: 1c5fb820fe070599aba780f1765538d408105af3
2012-05-30 03:51:44 -04:00
John-David Dalton
a67281f8e7 Cleanup README.md.
Former-commit-id: b0d0a22ff427b6a5754e2850e2a420e764a1eb39
2012-05-30 01:48:28 -04:00
John-David Dalton
281475e6ef Bump to v0.2.2.
Former-commit-id: c4516d1e2dd2ab4359233121a7f86c356425cebf
2012-05-30 00:21:06 -04:00
John-David Dalton
a5712fc873 Cleanup build.js and fix regression in minified build. [closes #19]
Former-commit-id: 3b455cb277fa8c3fc70efca7b54c6746cde2ea6b
2012-05-29 15:52:02 -04:00
John-David Dalton
205ded45e2 Update submodules, minified build, and documentation.
Former-commit-id: 526a3d4e7b68da2072163a656566ff777b591b2d
2012-05-29 10:18:32 -04:00
John-David Dalton
8ef039b9db Update unit test with _.templateSettings.variable change.
Former-commit-id: e29718c70b0b0bcfeaf54909a32366d12663984d
2012-05-29 10:17:55 -04:00
John-David Dalton
3d2428b278 Merge branch 'master' of github.com:bestiejs/lodash
Former-commit-id: a2b22208dc08b404bd1fbdde9f1d05253c0fc047
2012-05-29 10:14:54 -04:00
John-David Dalton
35d5704e3f Change the default value of _.templateSettings.variable to obj for Underscore.js compatibility. [closes #16]
Former-commit-id: da91e5c881e6b3f9e2108cc231e57c023884b251
2012-05-29 10:14:40 -04:00
Mathias Bynens
c1860d30d6 Optimize escape() by not needlessly escaping the / character
Ref. #18.


Former-commit-id: 82a29019daa15c83cb2159685ca5d575265cd902
2012-05-29 16:11:08 +02:00
Mathias Bynens
e0fba5cb51 Fix typo in build script
Former-commit-id: 1f5327ea167ba88c00c6fcff5bbad3d64be6049b
2012-05-29 14:40:03 +03:00
John-David Dalton
570ba189ed Update docs and minified build.
Former-commit-id: d07b191ef424d6dce31e690e4af5293eb1525313
2012-05-26 03:40:27 -04:00
John-David Dalton
e335e0fd72 Add mobile build support. [closes #14]
Former-commit-id: a73e3ea444f04027e28beeb9d007a19c169c4fa9
2012-05-26 03:40:06 -04:00
John-David Dalton
74a2d8dcb1 Update Backbone and Underscore submodules.
Former-commit-id: 13de1bae42bbbae7ca138bc5d26b83fd66367343
2012-05-26 00:12:43 -04:00
John-David Dalton
43ea0c9072 Reword unit test and add entry to README.md.
Former-commit-id: e5d68317bb8f2688c256de096c58e1b49014a68c
2012-05-26 00:09:41 -04:00
John-David Dalton
dde3eb2e36 Update _.find dependencies.
Former-commit-id: 88e6c8dec2cf62d348bc570c0f3f9bfa23a9dc5c
2012-05-26 00:09:11 -04:00
John-David Dalton
2008bf90af Tweak _.find to avoid using _.identity and add benchmark.
Former-commit-id: a881f90d00828ed6af5b2b0bc80c9ae6e2cb2da8
2012-05-26 00:07:50 -04:00
John-David Dalton
06ffa93bd0 Update minified build and docs.
Former-commit-id: f9c076e5254c563c714bccf7cd5d65b6716cd427
2012-05-25 15:46:29 -04:00
John-David Dalton
5da03cac79 Add pseudo private property in preparation for mobile builds.
Former-commit-id: d5812d968b7694c9778f1be7efa8d05f95789ec8
2012-05-25 15:16:39 -04:00
John-David Dalton
8a5eb89aa8 Ensure _.find returns undefinedwhen a value cannot be found. [closes #15]
Former-commit-id: e6dc89f98a1df81e1b1d67c5e8f5725e4df3bc5a
2012-05-25 15:15:16 -04:00
John-David Dalton
f81ede2fd6 Update changelog with intersect removal.
Former-commit-id: 5902c720c1403b856ac213e293619c31ea6834f5
2012-05-24 18:02:35 -04:00
John-David Dalton
6f7df67ded Cleanup README.md.
Former-commit-id: 6ad747a8ae56f32fd558bd141af6fe95847569ad
2012-05-24 17:50:20 -04:00
John-David Dalton
bb9ad69219 Bump to v0.2.1.
Former-commit-id: d433d39ac7269479f1b9ac3803e62c5021f41e11
2012-05-24 17:08:26 -04:00
John-David Dalton
8f7667a524 Simplify _.max, _.min, and _.bind.
Former-commit-id: 1da0b013d0c47748d757e90248eebe9ed51918ae
2012-05-24 10:02:32 -04:00
John-David Dalton
86e125a6f3 Update minified build and docs.
Former-commit-id: 8c96c3812064f93d404e6d6dda68ab7a865d4228
2012-05-24 02:24:40 -04:00
John-David Dalton
8b3ba13ff0 Cleanup perf.js.
Former-commit-id: 8799b7d384cc48bc1c8ea3289aa12e021be2b97b
2012-05-24 02:23:55 -04:00
John-David Dalton
82f062caf2 Sync with Underscore.
Former-commit-id: 2e3aacd53fef6d22d830dbc2d6c220808aea8739
2012-05-24 02:06:10 -04:00
John-David Dalton
67303eb9fb Update Backbone and Underscore submodules.
Former-commit-id: 43178330e273531286982e34acf96dadf9586f03
2012-05-24 01:43:54 -04:00
John-David Dalton
af3ded68c4 Cleanup _.bind.
Former-commit-id: d974cdfa52c3f6c175e57f0970380bcc9276c35d
2012-05-24 01:40:24 -04:00
John-David Dalton
b94eb44e18 Update minified build and docs.
Former-commit-id: 525d891914a86b1f7167c9dd82b9deaaad453058
2012-05-24 01:30:48 -04:00
John-David Dalton
c62b24b024 Make _.bind follow ES5 spec so it will work with a common Backbone pattern. [closes #11]
Former-commit-id: 8d5e399ca9727a32604601f81fffd9134104c8f4
2012-05-24 01:25:08 -04:00
John-David Dalton
baa37450cc Tweak export order for r.js.
Former-commit-id: 81f8f3feae9228e99978710c0193a9d26bb9b519
2012-05-23 17:06:21 -04:00
John-David Dalton
231fd46cd2 Ensure applet is hidden in perf/index.html.
Former-commit-id: ee23b966eca9148bbecd8d0826d954e755d232fe
2012-05-23 17:00:49 -04:00
John-David Dalton
b2728d9902 Update docs.
Former-commit-id: 462a64eeb8f8afb0951d8449f0f7b766abbcf5cc
2012-05-23 14:52:15 -04:00
John-David Dalton
451a33f526 Add _.difference, _.pick, and _.union benchmarks.
Former-commit-id: 1dd1e577520dfc1a69876eeccadce871f1f05916
2012-05-23 14:30:45 -04:00
John-David Dalton
3670bce918 Add _.flatten test to ensure consistent behavior with sparse arrays.
Former-commit-id: 5505f4d0542596e4c6469aa038fa1bfecaa79800
2012-05-23 14:28:51 -04:00
John-David Dalton
afb041b23c Update docs and minified build.
Former-commit-id: 8ece30dc91c7cd9fe9f936fdf09e6d673566eaef
2012-05-23 02:20:25 -04:00
John-David Dalton
5315058e2d Simplify _.flatten and add benchmarks.
Former-commit-id: f541328bf680a75abea68bce813820def375f4a0
2012-05-23 02:19:35 -04:00
John-David Dalton
26d9cc972e Add unit test to test to ensure _.groupBy only adds elements to own, not inherited, properties of the result object.
Former-commit-id: 61dcdd0f6172db66d62e97873c1bc3053e339342
2012-05-23 01:25:34 -04:00
John-David Dalton
52ae87812e Update docs and minified build.
Former-commit-id: f019b90d5e866bf2a6da1c003001d0e9345bb0b1
2012-05-23 01:01:35 -04:00
John-David Dalton
f8af24b383 Remove unneeded variable references.
Former-commit-id: ab2f5f4408db25dc63b5d85b4adf156f9f978711
2012-05-23 00:52:39 -04:00
John-David Dalton
b38947146e Move _.groupBy and _.size to the "Objects" category and shuffle method order to avoid extra private variables.
Former-commit-id: 8dc89136a3bf2ed94f594f5c1c1f97a0dd7291c4
2012-05-23 00:43:23 -04:00
John-David Dalton
5c48abff4b Add links to relevant sections in the description.
Former-commit-id: da9e65fadae73792cfb2ec885318bc073d4468c3
2012-05-22 13:10:43 -04:00
John-David Dalton
3994c7fc2b Update docdown submodule and README.md.
Former-commit-id: 745eccb03a7eed1f3f2ef696002c57d6fcc44d25
2012-05-22 13:01:14 -04:00
18 changed files with 2446 additions and 1355 deletions

141
README.md
View File

@@ -1,12 +1,18 @@
# Lo-Dash <sup>v0.2.0</sup> # Lo-Dash <sup>v0.3.1</sup>
A drop-in replacement for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), that delivers [performance improvements](http://jsperf.com/lodash-underscore#filterby=family), bug fixes, and additional features. A drop-in replacement for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), that delivers [performance improvements](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#closed-underscorejs-issues), and [additional features](https://github.com/bestiejs/lodash#features).
Lo-Dashs performance is gained by avoiding slower native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls. Lo-Dashs performance is gained by avoiding slower native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls.
## Download
* [Development source](https://raw.github.com/bestiejs/lodash/v0.3.1/lodash.js)
* [Production source](https://raw.github.com/bestiejs/lodash/v0.3.1/lodash.min.js)
* For optimal performance, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need
## Dive in ## Dive in
Weve got [API docs](http://lodash.com/docs) and [unit tests](http://lodash.com/tests). Weve got [API docs](http://lodash.com/docs), [benchmarks](http://lodash.com/benchmarks), and [unit tests](http://lodash.com/tests).
For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/lodash/wiki/Roadmap). For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/lodash/wiki/Roadmap).
@@ -19,35 +25,63 @@ For more information check out these screencasts over Lo-Dash:
## Features ## Features
* AMD loader support * AMD loader support ([RequireJS](http://requirejs.org/), [curl.js](https://github.com/cujojs/curl), etc.)
* [_.bind](http://lodash.com/docs#_bindfunc--arg1-arg2-) supports *"lazy"* binding * [_.bind](http://lodash.com/docs#bind) supports *"lazy"* binding
* [_.debounce](http://lodash.com/docs#_debouncefunc-wait-immediate)ed functions match [_.throttle](http://lodash.com/docs#_throttlefunc-wait)ed functions return value behavior * [_.debounce](http://lodash.com/docs#debounce)ed functions match [_.throttle](http://lodash.com/docs#throttle)ed functions return value behavior
* [_.forEach](http://lodash.com/docs#_foreachcollection-callback--thisarg) is chainable * [_.forEach](http://lodash.com/docs#forEach) is chainable
* [_.groupBy](http://lodash.com/docs#_groupbycollection-callback--thisarg) accepts a third `thisArg` argument * [_.forIn](http://lodash.com/docs#forIn) for iterating over an objects own and inherited properties
* [_.partial](http://lodash.com/docs#_partialfunc--arg1-arg2-) for more functional fun * [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an objects own properties
* [_.size](http://lodash.com/docs#_sizecollection) returns the `length` of string values * [_.groupBy](http://lodash.com/docs#groupBy), [_.sortedIndex](http://lodash.com/docs#sortedIndex), and [_.uniq](http://lodash.com/docs#uniq) accept a `thisArg` argument
* [_.indexOf](http://lodash.com/docs#indexOf) and [_.lastIndexOf](http://lodash.com/docs#lastIndexOf) accept a `fromIndex` argument
* [_.partial](http://lodash.com/docs#partial) for more functional fun
* [_.size](http://lodash.com/docs#size) supports returning the `length` of string values
* [_.template](http://lodash.com/docs#template) utilizes [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier debugging
## Support ## Support
Lo-Dash has been tested in at least Chrome 5-19, Firefox 1.5-12, IE 6-9, Opera 9.25-11.64, Safari 3.0.4-5.1.3, Node.js 0.4.8-0.6.18, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC3. Lo-Dash has been tested in at least Chrome 5-19, Firefox 1.5-13, IE 6-9, Opera 9.25-11.64, Safari 3.0.4-5.1.3, Node.js 0.4.8-0.6.18, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC3.
## Custom builds ## Custom builds
Custom builds make it easy to create lightweight versions of Lo-Dash containing only the methods you need. Custom builds make it easy to create lightweight versions of Lo-Dash containing only the methods you need.
We handle all the method dependency and alias mapping for you. We handle all the method dependency and alias mapping for you.
Custom builds may be created in two ways: * Backbone builds, containing all methods required by Backbone, may be created using the `backbone` modifier argument.
1. Use the`include` argument to pass the names of the methods to include in the build.
~~~ bash ~~~ bash
node build include=each,filter,map,noConflict node build backbone
node build include="each, filter, map, noConflict"
~~~ ~~~
2. Use the `exclude` argument to pass the names of the methods to exclude from the build. * Mobile builds, with IE bug fixes and method compilation removed, may be created using the `mobile` modifier argument.
~~~ bash ~~~ bash
node build exclude=isNaN,isUndefined,union,zip node build mobile
node build exclude="isNaN, isUndefined, union, zip" ~~~
Custom builds may be created in three ways:
1. Use the `category` argument to pass the categories of methods to include in the build.<br>
Valid categories are *"arrays"*, *"chaining"*, *"collections"*, *"functions"*, *"objects"*, and *"utilities"*.
~~~ bash
node build category=collections,functions
node build category="collections, functions"
~~~
2. Use the `include` argument to pass the names of methods to include in the build.
~~~ bash
node build include=each,filter,map
node build include="each, filter, map"
~~~
3. Use the `exclude` argument to pass the names of methods to exclude from the build.
~~~ bash
node build exclude=union,uniq,zip
node build exclude="union, uniq, zip"
~~~
All arguments, except `include` and `exlcude`, may be combined.
~~~ bash
node build backbone mobile category=functions include=pick,uniq
node build backbone mobile category=utilities exclude=first,last
~~~ ~~~
Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`. Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`.
@@ -116,14 +150,21 @@ git submodule update --init
## Closed Underscore.js issues ## Closed Underscore.js issues
* Fix Firefox, IE, Opera, and Safari object iteration bugs [#376](https://github.com/documentcloud/underscore/issues/376) * Allow iteration of objects with a `length` property [[#148](https://github.com/documentcloud/underscore/issues/148), [#154](https://github.com/documentcloud/underscore/issues/154), [#252](https://github.com/documentcloud/underscore/issues/252), [#448](https://github.com/documentcloud/underscore/issues/448), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L266-272)]
* Handle arrays with `undefined` values correctly in IE < 9 [#601](https://github.com/documentcloud/underscore/issues/601) * Ensure "Arrays" category methods allow falsey `array` arguments [[test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L714-748)]
* Methods should work on pages with incorrectly shimmed native methods [#7](https://github.com/documentcloud/underscore/issues/7) * Ensure array-like objects with invalid `length` properties are treated like regular objects [[test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L237-243), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L533-542), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L661-664)]
* Register as AMD module, but still export to global [#431](https://github.com/documentcloud/underscore/pull/431) * Ensure `_(...)` returns passed wrapper instances [[test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L106-109)]
* `_.forEach` should be chainable [#142](https://github.com/documentcloud/underscore/issues/142) * Ensure `_.groupBy` adds values to own, not inherited, properties [[test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L317-324)]
* `_isNaN(new Number(NaN))` should return `true` * Ensure `_.sortedIndex` supports arrays with high `length` values [[test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L586-595)]
* `_.reduceRight` should pass correct callback arguments when iterating objects * Ensure `_.throttle` works when called in tight loops [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L629-639)]
* `_.size` should return the `length` of string values * Fix Firefox, IE, Opera, and Safari object iteration bugs [[#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L175-187), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L277-302), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L379-390), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L398-400), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L418-438), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L554-556)]
* Handle arrays with `undefined` values correctly in IE < 9 [[#601](https://github.com/documentcloud/underscore/issues/601)]
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L88-94)]
* Register as AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L72-86)]
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L232-235)]
* `_isNaN(new Number(NaN))` should return `true` [[test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L408-410)]
* `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L521-531)]
* `_.size` should return the `length` of string values [[test](https://github.com/bestiejs/lodash/blob/801e8a5b3a963157fceaad15075690f59c22de9c/test/test.js#L550-552)]
## Optimized methods <sup>(50+)</sup> ## Optimized methods <sup>(50+)</sup>
@@ -146,7 +187,7 @@ git submodule update --init
* `_.functions`, `_.methods` * `_.functions`, `_.methods`
* `_.groupBy` * `_.groupBy`
* `_.indexOf` * `_.indexOf`
* `_.intersection`, `_.intersect` * `_.intersection`
* `_.invoke` * `_.invoke`
* `_.isEmpty` * `_.isEmpty`
* `_.isEqual` * `_.isEqual`
@@ -171,6 +212,7 @@ git submodule update --init
* `_.sortedIndex` * `_.sortedIndex`
* `_.template` * `_.template`
* `_.throttle` * `_.throttle`
* `_.times`
* `_.toArray` * `_.toArray`
* `_.union` * `_.union`
* `_.uniq`, `_.unique` * `_.uniq`, `_.unique`
@@ -182,6 +224,41 @@ git submodule update --init
## Changelog ## Changelog
### <sup>v0.3.1</sup>
* Added `backbone` build option
* Ensured "Arrays" category methods allow falsey `array` arguments
* Removed `_.isArguments` fallback from the `mobile` build
* Simplified `_.pluck`, `_.values` and `_(...)` method wrappers
### <sup>v0.3.0</sup>
* Added `category` build option
* Added `fromIndex` argument to `_.indexOf` and `_.lastIndexOf`
* Added `//@ sourceURL` support to `_.template`
* Added `thisArg` argument to `_.sortedIndex` and `_.uniq`
* Added `_.forIn` and `_.forOwn` methods
* Ensured array-like objects with invalid `length` properties are treated like regular objects
* Ensured `_.sortedIndex` supports arrays with high `length` values
* Fixed `prototype` property iteration bug in `_.keys` for Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
* Optimized `_.times` and `this` bindings in iterator methods
### <sup>v0.2.2</sup>
* Added `mobile` build option
* Ensured `_.find` returns `undefined` for unmatched values
* Ensured `_.templateSettings.variable` is compatible with Underscore.js
* Optimized `_.escape`
* Reduced dependencies in `_.find`
### <sup>v0.2.1</sup>
* Adjusted the Lo-Dash export order for r.js
* Ensured `_.groupBy` values are added to own, not inherited, properties
* Made `_.bind` follow ES5 spec to support a popular Backbone.js pattern
* Removed the alias `intersect`
* Simplified `_.bind`, `_.flatten`, `_.groupBy`, `_.max`, and `_.min`
### <sup>v0.2.0</sup> ### <sup>v0.2.0</sup>
* Added custom build options * Added custom build options
@@ -189,12 +266,14 @@ git submodule update --init
* Added *"lazy bind"* support to `_.bind` * Added *"lazy bind"* support to `_.bind`
* Added native method overwrite detection to avoid bad native shims * Added native method overwrite detection to avoid bad native shims
* Added support for more AMD build optimizers and aliasing as the *"underscore"* module * Added support for more AMD build optimizers and aliasing as the *"underscore"* module
* Added `thisArg` to `_.groupBy` * Added `thisArg` argument to `_.groupBy`
* Added whitespace to compiled strings * Added whitespace to compiled strings
* Added `_.partial` * Added `_.partial` method
* Commented the `iterationFactory` options object * Commented the `iterationFactory` options object
* Ensured `_(...)` returns passed wrapper instances
* Ensured `_.max` and `_.min` support extremely large arrays * Ensured `_.max` and `_.min` support extremely large arrays
* Fixed IE < 9 `[DontEnum]` bug and Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1s prototype property iteration bug * Ensured `_.throttle` works in tight loops
* Fixed IE < 9 `[DontEnum]` bug and Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1s `prototype` property iteration bug
* Inlined `_.isFunction` calls. * Inlined `_.isFunction` calls.
* Made `_.debounce`ed functions match `_.throttle`ed functions return value behavior * Made `_.debounce`ed functions match `_.throttle`ed functions return value behavior
* Made `_.escape` no longer translate the *">"* character * Made `_.escape` no longer translate the *">"* character

362
build.js
View File

@@ -10,9 +10,6 @@
var lodash = require(path.join(__dirname, 'lodash')), var lodash = require(path.join(__dirname, 'lodash')),
minify = require(path.join(__dirname, 'build', 'minify')); minify = require(path.join(__dirname, 'build', 'minify'));
/** Flag used to specify a custom build */
var isCustom = false;
/** Shortcut used to convert array-like objects to arrays */ /** Shortcut used to convert array-like objects to arrays */
var slice = [].slice; var slice = [].slice;
@@ -31,7 +28,6 @@
'head': 'first', 'head': 'first',
'include': 'contains', 'include': 'contains',
'inject': 'reduce', 'inject': 'reduce',
'intersect': 'intersection',
'methods': 'functions', 'methods': 'functions',
'select': 'filter', 'select': 'filter',
'tail': 'rest', 'tail': 'rest',
@@ -48,7 +44,6 @@
'first': ['head', 'take'], 'first': ['head', 'take'],
'forEach': ['each'], 'forEach': ['each'],
'functions': ['methods'], 'functions': ['methods'],
'intersection': ['intersect'],
'map': ['collect'], 'map': ['collect'],
'reduce': ['foldl', 'inject'], 'reduce': ['foldl', 'inject'],
'reduceRight': ['foldr'], 'reduceRight': ['foldr'],
@@ -57,12 +52,57 @@
'uniq': ['unique'] 'uniq': ['unique']
}; };
/** Used to track Backbone's Lo-Dash dependencies */
var backboneDependencies = [
'bind',
'bindAll',
'clone',
'contains',
'escape',
'every',
'extend',
'filter',
'find',
'first',
'forEach',
'groupBy',
'has',
'indexOf',
'initial',
'invoke',
'isArray',
'isEmpty',
'isEqual',
'isFunction',
'isObject',
'isRegExp',
'keys',
'last',
'lastIndexOf',
'map',
'max',
'min',
'mixin',
'reduce',
'reduceRight',
'reject',
'rest',
'shuffle',
'size',
'some',
'sortBy',
'sortedIndex',
'toArray',
'uniqueId',
'without'
];
/** Used to track function dependencies */ /** Used to track function dependencies */
var dependencyMap = { var dependencyMap = {
'after': [], 'after': [],
'bind': [], 'bind': [],
'bindAll': ['bind'], 'bindAll': ['bind', 'functions'],
'chain': [], 'chain': ['mixin'],
'clone': ['extend', 'isArray'], 'clone': ['extend', 'isArray'],
'compact': [], 'compact': [],
'compose': [], 'compose': [],
@@ -74,15 +114,17 @@
'delay': [], 'delay': [],
'difference': ['indexOf'], 'difference': ['indexOf'],
'escape': [], 'escape': [],
'every': ['bind', 'createIterator', 'identity'], 'every': ['createIterator', 'identity'],
'extend': ['createIterator'], 'extend': ['createIterator'],
'filter': ['bind', 'createIterator', 'identity'], 'filter': ['createIterator', 'identity'],
'find': ['createIterator'], 'find': ['createIterator'],
'first': [], 'first': [],
'flatten': ['isArray'], 'flatten': ['isArray'],
'forEach': ['bind', 'createIterator'], 'forEach': ['createIterator'],
'forIn': ['createIterator'],
'forOwn': ['createIterator'],
'functions': ['createIterator'], 'functions': ['createIterator'],
'groupBy': ['bind', 'createIterator'], 'groupBy': ['createIterator'],
'has': [], 'has': [],
'identity': [], 'identity': [],
'indexOf': ['sortedIndex'], 'indexOf': ['sortedIndex'],
@@ -108,34 +150,34 @@
'keys': ['createIterator'], 'keys': ['createIterator'],
'last': [], 'last': [],
'lastIndexOf': [], 'lastIndexOf': [],
'map': ['bind', 'createIterator', 'identity'], 'map': ['createIterator', 'identity'],
'max': ['bind'], 'max': [],
'memoize': [], 'memoize': [],
'min': ['bind'], 'min': [],
'mixin': ['forEach'], 'mixin': ['forEach', 'functions'],
'noConflict': [], 'noConflict': [],
'once': [], 'once': [],
'partial': [], 'partial': [],
'pick': [], 'pick': [],
'pluck': ['createIterator'], 'pluck': [],
'range': [], 'range': [],
'reduce': ['bind', 'createIterator'], 'reduce': ['createIterator'],
'reduceRight': ['bind', 'keys'], 'reduceRight': ['keys'],
'reject': ['bind', 'createIterator', 'identity'], 'reject': ['createIterator', 'identity'],
'rest': [], 'rest': [],
'result': [], 'result': [],
'shuffle': [], 'shuffle': [],
'size': ['keys'], 'size': ['keys'],
'some': ['bind', 'createIterator', 'identity'], 'some': ['createIterator', 'identity'],
'sortBy': ['bind', 'map', 'pluck'], 'sortBy': [],
'sortedIndex': [], 'sortedIndex': ['identity'],
'tap': [], 'tap': [],
'template': ['escape'], 'template': ['escape'],
'throttle': [], 'throttle': [],
'times': ['bind'], 'times': [],
'toArray': ['values'], 'toArray': ['values'],
'union': ['indexOf'], 'union': ['indexOf'],
'uniq': ['indexOf'], 'uniq': ['identity', 'indexOf'],
'uniqueId': [], 'uniqueId': [],
'values': ['createIterator'], 'values': ['createIterator'],
'without': ['indexOf'], 'without': ['indexOf'],
@@ -143,6 +185,41 @@
'zip': ['max', 'pluck'] 'zip': ['max', 'pluck']
}; };
/** Collections of method names */
var excludeMethods,
includeMethods,
allMethods = Object.keys(dependencyMap);
/** Used to specify whether filtering is for exclusion or inclusion */
var filterType = process.argv.reduce(function(result, value) {
if (result) {
return result;
}
var pair = value.match(/^(exclude|include)=(.*)$/);
if (!pair) {
return result;
}
// remove nonexistent method names
var methodNames = lodash.intersection(allMethods, pair[2].split(/, */).map(getRealName));
if (pair[1] == 'exclude') {
excludeMethods = methodNames;
} else {
includeMethods = methodNames;
}
// return `filterType`
return pair[1];
}, '');
/** Flag used to specify a backbone build */
var isBackbone = process.argv.indexOf('backbone') > -1;
/** Flag used to specify a mobile build */
var isMobile = process.argv.indexOf('mobile') > -1;
/** Flag used to specify a custom build */
var isCustom = filterType || isBackbone || isMobile;
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/** /**
@@ -167,7 +244,7 @@
// iterate over `dependencyMap`, adding the names of functions that // iterate over `dependencyMap`, adding the names of functions that
// have `funcName` as a dependency // have `funcName` as a dependency
return lodash.reduce(dependencyMap, function(result, dependencies, otherName) { return lodash.reduce(dependencyMap, function(result, dependencies, otherName) {
if (dependencies.indexOf(funcName) > -1) { if (lodash.contains(dependencies, funcName)) {
result.push(otherName); result.push(otherName);
} }
return result; return result;
@@ -175,25 +252,26 @@
} }
/** /**
* Gets an array of dependencies for a function of the given `funcName`. * Gets an array of dependencies for a given function name. If passed an array
* of dependencies it will return an array containing the given dependencies
* plus any additional detected sub-dependencies.
* *
* @private * @private
* @param {String} funcName The name of the function to query. * @param {Array|String} funcName A single function name or array of
* dependencies to query.
* @returns {Array} Returns an array of function dependencies. * @returns {Array} Returns an array of function dependencies.
*/ */
function getDependencies(funcName) { function getDependencies(funcName) {
var dependencies = dependencyMap[funcName], var dependencies = Array.isArray(funcName) ? funcName : dependencyMap[funcName];
result = [];
if (!dependencies) { if (!dependencies) {
return result; return [];
} }
// recursively accumulate the dependencies of the `funcName` function, and // recursively accumulate the dependencies of the `funcName` function, and
// the dependencies of its dependencies, and so on. // the dependencies of its dependencies, and so on.
return dependencies.reduce(function(result, otherName) { return lodash.uniq(dependencies.reduce(function(result, otherName) {
result.push.apply(result, getDependencies(otherName).concat(otherName)); result.push.apply(result, getDependencies(otherName).concat(otherName));
return result; return result;
}, result); }, []));
} }
/** /**
@@ -208,7 +286,7 @@
} }
/** /**
* Determines if all functions of the given names have been removed from the `source`. * Determines if all functions of the given names have been removed from `source`.
* *
* @private * @private
* @param {String} source The source to inspect. * @param {String} source The source to inspect.
@@ -222,7 +300,7 @@
} }
/** /**
* Searches the `source` for a `funcName` function declaration, expression, or * Searches `source` for a `funcName` function declaration, expression, or
* assignment and returns the matched snippet. * assignment and returns the matched snippet.
* *
* @private * @private
@@ -239,9 +317,9 @@
// match a function declaration // match a function declaration
'( +)function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' + '( +)function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' +
// match a variable declaration with `createIterator` // match a variable declaration with `createIterator`
' +var ' + funcName + ' *= *(?:[a-zA-Z]+ *\\|\\| *)?createIterator\\((?:{|[a-zA-Z])[\\s\\S]+?\\);|' + ' +var ' + funcName + ' *=.*?createIterator\\((?:{|[a-zA-Z])[\\s\\S]+?\\);|' +
// match a variable declaration with function expression // match a variable declaration with function expression
'( +)var ' + funcName + ' *= *(?:[a-zA-Z]+ *\\|\\| *)?function[\\s\\S]+?\\n\\2};' + '( +)var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\2};' +
// end non-capturing group // end non-capturing group
')\\n' ')\\n'
)); ));
@@ -258,7 +336,7 @@
* @returns {String} Returns the modified source. * @returns {String} Returns the modified source.
*/ */
function removeFromCreateIterator(source, refName) { function removeFromCreateIterator(source, refName) {
var snippet = matchFunction(source, 'createIterator'), var snippet = matchFunction(source, 'createIterator').match(/Function\([\s\S]+$/)[0],
modified = snippet.replace(RegExp('\\b' + refName + '\\b,? *', 'g'), ''); modified = snippet.replace(RegExp('\\b' + refName + '\\b,? *', 'g'), '');
return source.replace(snippet, modified); return source.replace(snippet, modified);
@@ -266,7 +344,7 @@
/** /**
* Removes the `funcName` function declaration, expression, or assignment and * Removes the `funcName` function declaration, expression, or assignment and
* associated code from the `source`. * associated code from `source`.
* *
* @private * @private
* @param {String} source The source to process. * @param {String} source The source to process.
@@ -281,7 +359,6 @@
if (!snippet) { if (!snippet) {
return source; return source;
} }
// remove function // remove function
source = source.replace(matchFunction(source, funcName), ''); source = source.replace(matchFunction(source, funcName), '');
@@ -300,7 +377,18 @@
} }
/** /**
* Removes a given variable from the `source`. * Removes the `_.isArguments` fallback from `source`.
*
* @private
* @param {String} source The source to process.
* @returns {String} Returns the source with the `isArguments` fallback removed.
*/
function removeIsArgumentsFallback(source) {
return source.replace(/(?: *\/\/.*)*\s*if *\(!isArguments[^)]+\)[\s\S]+?};?\s*}\n/, '');
}
/**
* Removes a given variable from `source`.
* *
* @private * @private
* @param {String} source The source to process. * @param {String} source The source to process.
@@ -330,70 +418,96 @@
return removeFromCreateIterator(source, varName); return removeFromCreateIterator(source, varName);
} }
/*--------------------------------------------------------------------------*/ /**
* Removes non-syntax critical whitespace from a string.
// inline `iteratorTemplate` *
(function() { * @private
var iteratorTemplate = lodash._iteratorTemplate, * @param {String} source The source to process.
code = /^function[^{]+{([\s\S]+?)}$/.exec(iteratorTemplate)[1]; * @returns {String} Returns the source with whitespace removed.
*/
// remove whitespace from template function removeWhitespace(source) {
code = code.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |var |\\\\n|\\n|\s+/g, function(match) { return source.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |var |@ |\\\\n|\\n|\s+/g, function(match) {
return match == false || match == '\\n' ? '' : match; return match == false || match == '\\n' ? '' : match;
}); });
}
// remove unnecessary code /*--------------------------------------------------------------------------*/
code = code
.replace(/\|\|\{\}|,__t,__j=Array.prototype.join|function print[^}]+}|\+''/g, '')
.replace(/(\{);|;(\})/g, '$1$2')
.replace(/\(\(__t=\(([^)]+)\)\)==null\?'':__t\)/g, '$1');
// ensure escaped characters are interpreted correctly inside the `Function()` string // Backbone build
code = code.replace(/\\/g, '\\\\'); if (isBackbone) {
// add any additional dependencies
backboneDependencies = getDependencies(backboneDependencies);
// add `code` to `Function()` if (filterType == 'exclude') {
code = '$1Function(\'object\',\n$2 "' + code + '"\n$2);\n'; // remove excluded methods from `backboneDependencies`
includeMethods = lodash.without.apply(lodash, [backboneDependencies].concat(excludeMethods));
}
else if (filterType) {
// merge backbone dependencies into `includeMethods`
includeMethods = lodash.union(includeMethods, backboneDependencies);
}
else {
// include only the Backbone dependencies
includeMethods = backboneDependencies;
}
filterType = 'include';
}
// replace `template()` with `Function()` /*--------------------------------------------------------------------------*/
source = source.replace(/(( +)var iteratorTemplate *= *)([\s\S]+?\n\2.+?);\n/, code);
// remove pseudo private property `_iteratorTemplate` // add category methods
source = source.replace(/(?:\s*\/\/.*)*\s*lodash\._iteratorTemplate\b.+\n/, '\n'); process.argv.some(function(value) {
}()); var categories = value.match(/^category=(.*)$/);
if (!categories) {
return false;
}
// resolve method names belonging to each category
var categoryMethods = categories.reduce(function(result, category) {
return result.concat(allMethods.filter(function(funcName) {
return RegExp('@category ' + category + '\\b', 'i').test(matchFunction(source, funcName));
}));
}, []);
if (filterType == 'exclude') {
// remove excluded methods from `categoryMethods`
includeMethods = lodash.without.apply(lodash, [categoryMethods].concat(excludeMethods));
}
else if (filterType) {
// merge backbone dependencies into `includeMethods`
includeMethods = lodash.union(includeMethods, categoryMethods);
}
else {
// include only the Backbone dependencies
includeMethods = categoryMethods;
}
filterType = 'include';
return true;
});
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
// custom build // custom build
process.argv.some(function(arg) { (function() {
// exit early if not the "exclude" or "include" command option // exit early if "exclude" or "include" options aren't specified
var pair = arg.match(/^(exclude|include)=(.*)$/); if (!filterType) {
if (!pair) { return;
return false;
} }
var filterType = pair[1],
filterNames = lodash.intersection(Object.keys(dependencyMap), pair[2].split(/, */).map(getRealName));
// set custom build flag
isCustom = true;
// remove the specified functions and their dependants
if (filterType == 'exclude') { if (filterType == 'exclude') {
filterNames.forEach(function(funcName) { // remove methods that are named in `excludeMethods` and their dependants
excludeMethods.forEach(function(funcName) {
getDependants(funcName).concat(funcName).forEach(function(otherName) { getDependants(funcName).concat(funcName).forEach(function(otherName) {
source = removeFunction(source, otherName); source = removeFunction(source, otherName);
}); });
}); });
} }
// else remove all but the specified functions and their dependencies
else { else {
filterNames = lodash.uniq(filterNames.reduce(function(result, funcName) { // add dependencies to `includeMethods`
result.push.apply(result, getDependencies(funcName).concat(funcName)); includeMethods = getDependencies(includeMethods);
return result;
}, []));
lodash.each(dependencyMap, function(dependencies, otherName) { // remove methods that aren't named in `includeMethods`
if (filterNames.indexOf(otherName) < 0) { lodash.each(allMethods, function(otherName) {
if (!lodash.contains(includeMethods, otherName)) {
source = removeFunction(source, otherName); source = removeFunction(source, otherName);
} }
}); });
@@ -401,8 +515,7 @@
// remove associated functions, variables and code snippets // remove associated functions, variables and code snippets
if (isRemoved(source, 'isArguments')) { if (isRemoved(source, 'isArguments')) {
// remove `isArguments` if-statement source = removeIsArgumentsFallback(source);
source = source.replace(/(?:\s*\/\/.*)*\s*if *\(!isArguments[^)]+\)[\s\S]+?};?\s*}\n/, '');
} }
if (isRemoved(source, 'mixin')) { if (isRemoved(source, 'mixin')) {
// remove `LoDash` constructor // remove `LoDash` constructor
@@ -416,21 +529,28 @@
// remove `templateSettings` assignment // remove `templateSettings` assignment
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *lodash\.templateSettings[\s\S]+?};\n/, ''); source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *lodash\.templateSettings[\s\S]+?};\n/, '');
} }
if (isRemoved(source, 'max', 'min')) {
source = removeVar(source, 'argsLimit');
// remove `argsLimit` try-catch
source = source.replace(/\n *try\s*\{[\s\S]+?argsLimit *=[\s\S]+?catch[^}]+}\n/, '');
}
if (isRemoved(source, 'isArray', 'isEmpty', 'isEqual', 'size')) { if (isRemoved(source, 'isArray', 'isEmpty', 'isEqual', 'size')) {
source = removeVar(source, 'arrayClass'); source = removeVar(source, 'arrayClass');
} }
if (isRemoved(source, 'bind', 'functions', 'groupBy', 'invoke', 'isEqual', 'isFunction', 'result', 'sortBy', 'toArray')) { if (isRemoved(source, 'bind', 'functions', 'groupBy', 'invoke', 'isEqual', 'isFunction', 'result', 'sortBy', 'toArray')) {
source = removeVar(source, 'funcClass'); source = removeVar(source, 'funcClass');
} }
if (isRemoved(source, 'bind')) {
source = removeVar(source, 'nativeBind');
}
if (isRemoved(source, 'isArray')) {
source = removeVar(source, 'nativeIsArray');
}
if (isRemoved(source, 'keys')) {
source = removeVar(source, 'nativeKeys');
}
if (isRemoved(source, 'clone', 'isObject', 'keys')) { if (isRemoved(source, 'clone', 'isObject', 'keys')) {
source = removeVar(source, 'objectTypes'); source = removeVar(source, 'objectTypes');
source = removeFromCreateIterator(source, 'objectTypes'); source = removeFromCreateIterator(source, 'objectTypes');
} }
if (isRemoved(source, 'bind', 'isArray', 'keys')) {
source = removeVar(source, 'reNative');
}
if (isRemoved(source, 'isEmpty', 'isEqual', 'isString', 'size')) { if (isRemoved(source, 'isEmpty', 'isEqual', 'isString', 'size')) {
source = removeVar(source, 'stringClass'); source = removeVar(source, 'stringClass');
} }
@@ -439,9 +559,63 @@
source = source.replace(/(?:\s*\/\*-+\*\/\s*){2,}/g, function(separators) { source = source.replace(/(?:\s*\/\*-+\*\/\s*){2,}/g, function(separators) {
return separators.match(/^\s*/)[0] + separators.slice(separators.lastIndexOf('/*')); return separators.match(/^\s*/)[0] + separators.slice(separators.lastIndexOf('/*'));
}); });
}());
return true; /*--------------------------------------------------------------------------*/
});
if (isMobile) {
// inline functions defined with `createIterator`
lodash.functions(lodash).forEach(function(funcName) {
// match `funcName` with pseudo private `_` prefixes removed to allow matching `shimKeys`
var reFunc = RegExp('(\\bvar ' + funcName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n');
// skip if not defined with `createIterator`
if (!reFunc.test(source)) {
return;
}
// extract and format the function's code
var code = (lodash[funcName] + '').replace(/\n(?:.*)/g, function(match) {
match = match.slice(1);
return (match == '}' ? '\n ' : '\n ') + match;
});
source = source.replace(reFunc, '$1' + code + ';\n');
});
source = removeIsArgumentsFallback(source);
source = removeVar(source, 'iteratorTemplate');
// remove JScript [[DontEnum]] fix from `isEqual`
source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(result *&& *hasDontEnumBug[\s\S]+?\n\1}\n/, '\n');
// remove IE `shift` and `splice` fix
source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(value.length *=== *0[\s\S]+?\n\1}\n/, '\n');
}
else {
// inline `iteratorTemplate` template
source = source.replace(/(( +)var iteratorTemplate *= *)([\s\S]+?\n\2.+?);\n/, (function() {
// extract `iteratorTemplate` code
var code = /^function[^{]+{([\s\S]+?)}$/.exec(lodash._iteratorTemplate)[1];
code = removeWhitespace(code)
// remove unnecessary code
.replace(/\|\|\{\}|,__t,__j=Array.prototype.join|function print[^}]+}|\+''/g, '')
.replace(/(\{);|;(\})/g, '$1$2')
.replace(/\(\(__t=\(([^)]+)\)\)==null\?'':__t\)/g, '$1')
// ensure escaped characters are interpreted correctly in the string literal
.replace(/\\/g, '\\\\');
// add `code` to `Function()` as a string literal to avoid strict mode
// errors caused by the required with-statement
return '$1Function(\'obj\',\n$2 "' + code + '"\n$2);\n';
}()));
}
/*--------------------------------------------------------------------------*/
// remove pseudo private properties
source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n');
// begin the minification process // begin the minification process
if (isCustom) { if (isCustom) {

View File

@@ -8,33 +8,24 @@
/** Used to minify variables embedded in compiled strings */ /** Used to minify variables embedded in compiled strings */
var compiledVars = [ var compiledVars = [
'accumulator', 'accumulator',
'args',
'array',
'arrayClass', 'arrayClass',
'bind',
'callback', 'callback',
'className', 'className',
'collection', 'collection',
'concat',
'ctor', 'ctor',
'false', 'false',
'funcClass', 'funcClass',
'hasOwnProperty', 'hasOwnProperty',
'identity', 'identity',
'index', 'index',
'indexOf', 'iteratorBind',
'isArray',
'isEmpty',
'isFunc',
'length', 'length',
'object', 'object',
'objectTypes', 'objectTypes',
'noaccum', 'noaccum',
'prop',
'property', 'property',
'result', 'result',
'skipProto', 'skipProto',
'slice',
'source', 'source',
'sourceIndex', 'sourceIndex',
'stringClass', 'stringClass',
@@ -71,9 +62,10 @@
/** Used to minify variables and string values to a single character */ /** Used to minify variables and string values to a single character */
var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
/** Used protect the specified properties from getting minified */ /** Used to protect the specified properties from getting minified */
var propWhitelist = [ var propWhitelist = [
'_', '_',
'_chain',
'_wrapped', '_wrapped',
'after', 'after',
'all', 'all',
@@ -109,6 +101,8 @@
'foldl', 'foldl',
'foldr', 'foldr',
'forEach', 'forEach',
'forIn',
'forOwn',
'functions', 'functions',
'groupBy', 'groupBy',
'has', 'has',
@@ -119,7 +113,6 @@
'initial', 'initial',
'inject', 'inject',
'interpolate', 'interpolate',
'intersect',
'intersection', 'intersection',
'invoke', 'invoke',
'isArguments', 'isArguments',
@@ -177,7 +170,6 @@
'throttle', 'throttle',
'times', 'times',
'toArray', 'toArray',
'toArray',
'union', 'union',
'uniq', 'uniq',
'unique', 'unique',
@@ -203,21 +195,30 @@
// remove copyright to add later in post-compile.js // remove copyright to add later in post-compile.js
source = source.replace(/\/\*![\s\S]+?\*\//, ''); source = source.replace(/\/\*![\s\S]+?\*\//, '');
// correct JSDoc tags for Closure Compiler // remove unrecognized JSDoc tags so Closure Compiler won't complain
source = source.replace(/@(?:alias|category)\b.*/g, ''); source = source.replace(/@(?:alias|category)\b.*/g, '');
// add brackets to whitelisted properties so Closure Compiler won't mung them // add brackets to whitelisted properties so Closure Compiler won't mung them
// http://code.google.com/closure/compiler/docs/api-tutorial3.html#export // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']"); source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']");
// remove brackets from `_.escape(__t)` in `tokenizeEscape`
source = source.replace("_['escape'](__t)", '_.escape(__t)');
// remove whitespace from string literals // remove whitespace from string literals
source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) { source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) {
// avoids removing the '\n' of the `escapes` object // avoids removing the '\n' of the `stringEscapes` object
return string.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |'\\n'|\\\\n|\\n|\s+/g, function(match) { return string.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) {
return match == false || match == '\\n' ? '' : match; return match == false || match == '\\n' ? '' : match;
}); });
}); });
// remove newline from double-quoted string in `_.template`
source = source.replace('"\';\\n"', '"\';"');
// remove debug sourceURL in `_.template`
source = source.replace(/\+(?:\s*\/\/.*)*\s*'\/\/@ sourceURL=[^;]+/, '');
// minify `_.sortBy` internal properties // minify `_.sortBy` internal properties
(function() { (function() {
var properties = ['criteria', 'value'], var properties = ['criteria', 'value'],
@@ -225,9 +226,9 @@
result = snippet; result = snippet;
if (snippet) { if (snippet) {
// minify property strings // minify properties
properties.forEach(function(property, index) { properties.forEach(function(property, index) {
result = result.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'"); result = result.replace(RegExp('\\b' + property + '\\b', 'g'), minNames[index]);
}); });
// replace with modified snippet // replace with modified snippet
source = source.replace(snippet, result); source = source.replace(snippet, result);
@@ -286,7 +287,7 @@
// correct external boolean literals // correct external boolean literals
else if (variable == 'true' || variable == 'false') { else if (variable == 'true' || variable == 'false') {
result = result result = result
.replace(RegExp(': *' + minNames[index] + ',', 'g'), ':' + variable + ',') .replace(RegExp(': *' + minNames[index] + '([,\\n])', 'g'), ':' + variable + '$1')
.replace(RegExp('\\b' + minNames[index] + ';', 'g'), variable + ';'); .replace(RegExp('\\b' + minNames[index] + ';', 'g'), variable + ';');
} }
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -21,8 +21,8 @@
// generate Markdown // generate Markdown
$markdown = docdown(array( $markdown = docdown(array(
'path' => '../' . $file, 'path' => '../' . $file,
'title' => 'Lo-Dash <sup>v0.2.0</sup>', 'title' => 'Lo-Dash <sup>v0.3.1</sup>',
'url' => 'https://github.com/bestiejs/lodash/blob/master/lodash.js' 'url' => 'https://github.com/bestiejs/lodash/blob/v0.3.1/lodash.js'
)); ));
// save to a .md file // save to a .md file

1492
lodash.js

File diff suppressed because it is too large Load Diff

56
lodash.min.js vendored
View File

@@ -1,30 +1,32 @@
/*! /*!
Lo-Dash 0.2.0 lodash.com/license Lo-Dash 0.3.1 lodash.com/license
Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE
*/ */
;(function(u,m){"use strict";function R(a){return"[object Arguments]"==h.call(a)}function c(a){return new p(a)}function p(a){if(a&&a._wrapped)return a;this._wrapped=a}function j(){for(var a,b,d,k=-1,c=arguments.length,f={e:"",f:"",k:"",q:"",c:{m:"++o<t"},o:{}};++k<c;)for(b in a=arguments[k],a)d=(d=a[b])==o?"":d,/d|m|j/.test(b)?("string"==typeof d&&(d={b:d,n:d}),f.c[b]=d.b,f.o[b]=d.n):f[b]=d;a=f.a,b=f.c,d=f.o;var k=/^[^,]+/.exec(a)[0],c=d.m,g=/\S+$/.exec(c||k)[0];f.g=k,f.i=H,f.h="m.call("+g+",o)",f ;(function(e,t){"use strict";function s(e){return"[object Arguments]"==rt.call(e)}function o(e){return new u(e)}function u(e){if(e&&e._wrapped)return e;this._wrapped=e}function a(){for(var e,t,s,o=-1,u=arguments.length,a={e:"",f:"",k:"",q:"",c:{d:"",m:"++k<m"},o:{d:""}};++o<u;)for(t in e=arguments[o],e)s=(s=e[t])==r?"":s,/d|m|j/.test(t)?("string"==typeof s&&(s={b:s,n:s}),a.c[t]=s.b,a.o[t]=s.n):a[t]=s;e=a.a,t=a.c,s=a.o;var o=/^[^,]+/.exec(e)[0],u=s.m,f=/\S+$/.exec(u||o)[0];a.g=o,a.i=M,a.h="i.call("+
.l=g,f.p=ba,f.r=f.r!==r,f.f||(f.f="if("+k+"==null)return z");if("u"==k||!b.j)f.c=o;return c||(d.m="o in "+g),Function("d,e,i,l,m,n,p,q,r,v,B,E,H,I,k,J",'"use strict";return function('+a+"){"+ta(f)+"}")(I,v,D,s,t,ca,w,J,da,S,l,K,h,n,r)}function ua(a,b){return x[b]}function va(a){return"\\"+wa[a]}function xa(a,b){var d=x.length;return x[d]="'+((__t=("+b+"))==null?'':_['escape'](__t))+'",T+d}function ya(a,b){var d=x.length;return x[d]="'+((__t=("+b+"))==null?'':__t)+'",T+d}function za(a,b){var d=x.length f+",k)",a.l=f,a.p=F,a.r=a.r!==i,a.f||(a.f="if(!"+o+")return r");if("n"==o||!t.j)a.c=r;return u||(s.m="k in "+f),Function("b,h,i,j,l,o,v,y,z,g,A",'"use strict";return function('+e+"){"+lt(a)+"}")(W,$,et,L,h,U,Q,rt,n,i)}function f(e,t){return q[t]}function l(e){return"\\"+z[e]}function c(e){return R[e]}function h(e,t){return function(n,r,i){return e.call(t,n,r,i)}}function p(){}function d(e,t){var n=q.length;return q[n]="'+((__t=("+t+"))==null?'':_.escape(__t))+'",I+n}function v(e,t){var n=q.length
;return x[d]="';"+b+";__p+='",T+d}function ea(a,b,d,c){if(!a)return d;var e=a.length,f=3>arguments.length;c&&(b=v(b,c));if(e===+e){for(e&&f&&(d=a[--e]);e--;)d=b(d,a[e],e,a);return d}var g=U(a);for((e=g.length)&&f&&(d=a[g[--e]]);e--;)f=g[e],d=b(d,a[f],f,a);return d}function V(a,b,d){return b==m||d?a[0]:l.call(a,0,b)}function fa(a,b){if(b)return D.apply(z,a);for(var d,c=-1,e=a.length,f=[];++c<e;)d=a[c],J(d)?E.apply(f,fa(d)):f.push(d);return f}function w(a,b,d){var c;if(!a)return-1;if(d)return d=ga( ;return q[n]="'+((__t=("+t+"))==null?'':__t)+'",I+n}function m(e,t){var n=q.length;return q[n]="';"+t+";__p+='",I+n}function g(e,t,n,r){if(!e)return n;var i=e.length,s=3>arguments.length;r&&(t=h(t,r));if(i===i>>>0){for(i&&s&&(n=e[--i]);i--;)n=t(n,e[i],i,e);return n}var o=kt(e);for((i=o.length)&&s&&(n=e[o[--i]]);i--;)s=o[i],n=t(n,e[s],s,e);return n}function y(e,n,r){if(e)return n==t||r?e[0]:nt.call(e,0,n)}function b(e,t){var n=[];if(!e)return n;for(var r,i=-1,s=e.length;++i<s;)r=e[i],Ct(r)?tt.apply
a,b),a[d]===b?d:-1;d=0;for(c=a.length;d<c;d++)if(a[d]===b)return d;return-1}function ha(a){for(var b,d=-1,c=a.length,e=l.call(arguments,1),f=[];++d<c;)b=a[d],0>w(f,b)&&W(e,function(a){return-1<w(a,b)})&&f.push(b);return f}function ia(a,b,d){var c=-Infinity,e=-1,f=a.length,g=c;if(b)d&&(b=v(b,d));else{if(a[0]===+a[0]&&f<=L)try{return Math.max.apply(Math,a)}catch(i){}if(!a.length)return g}for(;++e<f;)d=b?b(a[e],e,a):a[e],d>c&&(c=d,g=a[e]);return g}function ja(a,b,d){return l.call(a,b==m||d?1:b)}function ga (n,t?r:b(r)):n.push(r);return n}function w(e,t,n){if(!e)return-1;var r=-1,i=e.length;if(n){if("number"!=typeof n)return r=T(e,t),e[r]===t?r:-1;r=(0>n?Math.max(0,i+n):n)-1}for(;++r<i;)if(e[r]===t)return r;return-1}function E(e,t,n){var r=-Infinity,i=r;if(!e)return i;var s=-1,o=e.length;if(!t){for(;++s<o;)e[s]>i&&(i=e[s]);return i}for(n&&(t=h(t,n));++s<o;)n=t(e[s],s,e),n>r&&(r=n,i=e[s]);return i}function S(e,t){if(!e)return[];for(var n=-1,r=e.length,i=Array(r);++n<r;)i[n]=e[n][t];return i}function x
(a,b,d){var c,e=0,f=a.length;for(d&&(b=d(b));e<f;)c=e+f>>1,(d?d(a[c]):a[c])<b?e=c+1:f=c;return e}function ka(a,b,d){var c,e=-1,f=a.length,g=[],i=[];for(3>f&&(b=n);++e<f;)if(c=d?d(a[e]):a[e],b?!e||i[i.length-1]!==c:0>w(i,c))i.push(c),g.push(a[e]);return g}function v(a,b){var d,c=h.call(a)==s;if(c){if(B)return a=B.call.apply(B,arguments),function(){return arguments.length?a.apply(m,arguments):a()}}else d=b,b=a;var e=l.call(arguments,2),f=e.length;return function(){var g;return g=arguments,c||(a=b[d (e,n,r){return e?nt.call(e,n==t||r?1:n):[]}function T(e,t,n,r){if(!e)return 0;var i,s=0,o=e.length;if(n)for(t=n.call(r,t);s<o;)i=s+o>>>1,n.call(r,e[i])<t?s=i+1:o=i;else for(;s<o;)i=s+o>>>1,e[i]<t?s=i+1:o=i;return s}function N(e,t,n,r){var s=[];if(!e)return s;var o=-1,u=e.length,a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n?r&&(n=h(n,r)):n=L;++o<u;)if(r=n(e[o],o,e),t?!o||a[a.length-1]!==r:0>w(a,r))a.push(r),s.push(e[o]);return s}function C(e,t){function n(){var u=arguments,a=t;return s||(e=t[i]),
]),f&&(g.length&&(e.length=f,E.apply(e,g)),g=e),g=g.length?a.apply(b,g):a.call(b),e.length=f,g}}function M(a,b,d){d||(d=[]);if(a===b)return 0!==a||1/a==1/b;if(a==m||b==m)return a===b;a.s&&(a=a._wrapped),b.s&&(b=b._wrapped);if(a.isEqual&&h.call(a.isEqual)==s)return a.isEqual(b);if(b.isEqual&&h.call(b.isEqual)==s)return b.isEqual(a);var c=h.call(a);if(c!=h.call(b))return r;switch(c){case K:return a==""+b;case N:return a!=+a?b!=+b:0==a?1/a==1/b:a==+b;case la:case ma:return+a==+b;case na:return a.source== o.length&&(u=u.length?Z.apply(o,u):o),this instanceof n?(p.prototype=e.prototype,a=new p,u=e.apply(a,u),U[typeof u]&&u!==r?u:a):e.apply(a,u)}var i,s=rt.call(e)==$;if(s){if(it)return it.call.apply(it,arguments)}else i=t,t=e;var o=nt.call(arguments,2);return n}function k(e,r,s){s||(s=[]);if(e===r)return 0!==e||1/e==1/r;if(e==t||r==t)return e===r;e._chain&&(e=e._wrapped),r._chain&&(r=r._wrapped);if(e.isEqual&&rt.call(e.isEqual)==$)return e.isEqual(r);if(r.isEqual&&rt.call(r.isEqual)==$)return r.isEqual
b.source&&a.global==b.global&&a.multiline==b.multiline&&a.ignoreCase==b.ignoreCase}if("object"!=typeof a||"object"!=typeof b)return r;for(var e=d.length;e--;)if(d[e]==a)return n;var e=-1,f=n,g=0;d.push(a);if(c==I){if(g=a.length,f=g==b.length)for(;g--&&(f=M(a[g],b[g],d)););}else{if("constructor"in a!="constructor"in b||a.constructor!=b.constructor)return r;for(var i in a)if(t.call(a,i)&&(g++,!(f=t.call(b,i)&&M(a[i],b[i],d))))break;if(f){for(i in b)if(t.call(b,i)&&!(g--))break;f=!g}if(f&&H)for(;7>++ (e);var o=rt.call(e);if(o!=rt.call(r))return i;switch(o){case Q:return e==""+r;case J:return e!=+e?r!=+r:0==e?1/e==1/r:e==+r;case X:case V:return+e==+r;case K:return e.source==r.source&&e.global==r.global&&e.multiline==r.multiline&&e.ignoreCase==r.ignoreCase}if("object"!=typeof e||"object"!=typeof r)return i;for(var u=s.length;u--;)if(s[u]==e)return n;var u=-1,a=n,f=0;s.push(e);if(o==W){if(f=e.length,a=f==r.length)for(;f--&&(a=k(e[f],r[f],s)););}else{if("constructor"in e!="constructor"in r||e.constructor!=
e&&(i=ba[e],!t.call(a,i)||!!(f=t.call(b,i)&&M(a[i],b[i],d))););}return d.pop(),f}function ca(a){return a}function oa(a){F(O(a),function(b){var d=c[b]=a[b];p.prototype[b]=function(){var a=[this._wrapped];return arguments.length&&E.apply(a,arguments),a=1==a.length?d.call(c,a[0]):d.apply(c,a),this.s&&(a=new p(a),a.s=n),a}})}var n=!0,o=null,r=!1,X="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(u=global),exports),L=5e4;try{(function(){L=arguments.length}). r.constructor)return i;for(var l in e)if(et.call(e,l)&&(f++,!(a=et.call(r,l)&&k(e[l],r[l],s))))break;if(a){for(l in r)if(et.call(r,l)&&!(f--))break;a=!f}if(a&&M)for(;7>++u&&(l=F[u],!et.call(e,l)||!!(a=et.call(r,l)&&k(e[l],r[l],s))););}return s.pop(),a}function L(e){return e}function A(e){wt(Nt(e),function(t){var r=o[t]=e[t];u.prototype[t]=function(){var e=[this._wrapped];return arguments.length&&tt.apply(e,arguments),e=r.apply(o,e),this._chain&&(e=new u(e),e._chain=n),e}})}var n=!0,r=null,i=!1,O="object"==typeof
apply(o,Array(L))}catch(Ha){}var wa={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"},H=!{valueOf:0}.propertyIsEnumerable("valueOf"),Aa=0,S={"boolean":r,"function":n,object:n,number:r,string:r,"undefined":r},Ba=u._,A=RegExp("^"+({}.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),Ca=/__token__(\d+)/g,Da=/['\n\r\t\u2028\u2029\\]/g,ba="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf" exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),M=!{valueOf:0}.propertyIsEnumerable("valueOf"),_=0,D=e._,P=RegExp("^"+({}.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),H=/__token__(\d+)/g,B=/[&<"']/g,j=/['\n\r\t\u2028\u2029\\]/g,F="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),I="__token__",q=[],R={"&":"&amp;","<":"&lt;",'"':"&quot;","'":"&#x27;"
.split(" "),T="__token__",x=[],I="[object Array]",la="[object Boolean]",ma="[object Date]",s="[object Function]",N="[object Number]",na="[object RegExp]",K="[object String]",z=Array.prototype,y=Object.prototype,D=z.concat,t=y.hasOwnProperty,E=z.push,l=z.slice,h=y.toString,B=A.test(B=l.bind)&&/\n|Opera/.test(B+h.call(u.opera))&&B,C=A.test(C=Array.isArray)&&C,Ea=u.isFinite,Y=A.test(Y=Object.keys)&&Y,Fa=u.clearTimeout,P=u.setTimeout,ta=Function("u","var __p;with(u){__p='var o,z';if(k){__p+='='+k};__p+=';'+f+';'+q+';';if(c){__p+='var t='+g+'.length;o=-1;';if(o){__p+='if(t===+t){'};__p+=''+c['d']+';while('+c['m']+'){'+c['j']+'}';if(o){__p+='}'}}if(o){if(c){__p+='else{'}if(!i){__p+='var A=typeof '+l+'==\\'function\\';'};__p+=''+o['d']+';for('+o['m']+'){';if(i){if(r){__p+='if('+h+'){'};__p+=''+o['j']+';';if(r){__p+='}'}}else{__p+='if(!(A&&o==\\'prototype\\')';if(r){__p+='&&'+h};__p+='){'+o['j']+'}'};__p+='}';if(i){__p+='var j='+l+'.constructor;';for(var k=0;k<7;k++){__p+='o=\\''+p[k]+'\\';if(';if(p[k]=='constructor'){__p+='!(j&&j.prototype==='+l+')&&'};__p+=''+h+'){'+o['j']+'}'}}if(c){__p+='}'}};__p+=''+e+';return z'}return __p" },U={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i},z={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"},W="[object Array]",X="[object Boolean]",V="[object Date]",$="[object Function]",J="[object Number]",K="[object RegExp]",Q="[object String]",G=Array.prototype,Y=Object.prototype,Z=G.concat,et=Y.hasOwnProperty,tt=G.push,nt=G.slice,rt=Y.toString,it=P.test(it=nt.bind)&&/\n|Opera/.test(it+rt.call(e.opera))&&it,st=P.test(st=Array.isArray)&&st,ot=e.isFinite
),q={a:"h,f,G",k:"h",q:"if(!f){f=n}else if(G){f=e(f,G)}",j:"f(h[o],o,h)"},Z={k:"I",j:"if(!f(h[o],o,h))return!z"},A={a:"u",k:"u",q:"for(var C,D=1,t=arguments.length;D<t;D++){C=arguments[D];"+(H?"if(C){":""),m:"o in C",r:r,j:"u[o]=C[o]",e:(H?"}":"")+"}"},G={k:"[]",j:"f(h[o],o,h)&&z.push(h[o])"},y={k:"",f:"if(!h)return[]",d:{b:"z=Array(t)",n:"z=[]"},j:{b:"z[o]=f(h[o],o,h)",n:"z.push(f(h[o],o,h))"}},J=C||function(a){return h.call(a)==I},da=j({a:"K",k:"I",q:"var g=H.call(K);if(g==d||g==E)return!K.length" ,ut=P.test(ut=Object.keys)&&ut,at=e.clearTimeout,ft=e.setTimeout;o.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:"obj"};var lt=Function("obj","var __p;with(obj){__p='var k,r';if(k){__p+='='+k};__p+=';'+f+';'+q+';';if(c){__p+='var m='+g+'.length;k=-1;';if(o){__p+='if(m===m>>>0){'};__p+=''+c['d']+';while('+c['m']+'){'+c['j']+'}';if(o){__p+='}'}}if(o){if(c){__p+='else{'}if(!i){__p+='var s=typeof '+l+'==\\'function\\';'};__p+=''+o['d']+';for('+o['m']+'){';if(i){if(r){__p+='if('+h+'){'};__p+=''+o['j']+';';if(r){__p+='}'}}else{__p+='if(!(s&&k==\\'prototype\\')';if(r){__p+='&&'+h};__p+='){'+o['j']+'}'};__p+='}';if(i){__p+='var f='+l+'.constructor;';for(var k=0;k<7;k++){__p+='k=\\''+p[k]+'\\';if(';if(p[k]=='constructor'){__p+='!(f&&f.prototype==='+l+')&&'};__p+=''+h+'){'+o['j']+'}'}}if(c){__p+='}'}};__p+=''+e+';return r'}return __p"
,j:{n:"return k"}}),C=j({a:"h,F",k:"k",j:"if(h[o]===F)return I"}),W=j(q,Z),pa=j(q,G),qa=j(q,{j:"if(f(h[o],o,h))return h[o]"}),F=j(q,{q:"if(G)f=e(f,G)"}),Ga=j(q,{k:"{}",q:"var x,s=H.call(f)==l;if(s&&G)f=e(f,G)",j:"x=s?f(h[o],o,h):h[o][f];(z[x]||(z[x]=[])).push(h[o])"}),$=j(q,y),Q=j(y,{a:"h,y",j:{b:"z[o]=h[o][y]",n:"z.push(h[o][y])"}}),aa=j({a:"h,f,a,G",k:"a",q:"var w=arguments.length<3;if(G)f=e(f,G)",d:{b:"if(w)z=h[++o]"},j:{b:"z=f(z,h[o],o,h)",n:"z=w?(w=k,h[o]):f(z,h[o],o,h)"}}),G=j(q,G,{j:"!"+G. ),ct={a:"e,c,x",k:"e",q:"if(!c){c=j}else if(x){c=l(c,x)}",j:"c(e[k],k,e)"},ht={k:"z",j:"if(!c(e[k],k,e))return!r"},pt={a:"n",k:"n",q:"for(var t,u=1,m=arguments.length;u<m;u++){t=arguments[u];"+(M?"if(t){":""),m:"k in t",r:i,j:"n[k]=t[k]",e:(M?"}":"")+"}"},dt={k:"[]",j:"c(e[k],k,e)&&r.push(e[k])"},vt={q:"if(x)c=l(c,x)"},mt={j:{n:ct.j}},gt=a({a:"n",f:"if(!o[typeof n]||n===null)throw TypeError()",k:"[]",j:"r.push(k)"}),P=a({a:"e,w",k:"g",j:"if(e[k]===w)return z"}),yt=a(ct,ht),Y=a(ct,dt),bt=a(ct,vt,{
j}),q=j(q,Z,{k:"k",j:Z.j.replace("!","")}),ra=j(y,{a:"h",j:{b:"z[o]=h[o]",n:"z.push(h[o])"}}),y=j(A,{j:"if(u[o]==J)"+A.j}),sa=j(A),O=j({a:"u",k:"[]",r:r,j:"if(H.call(u[o])==l)z.push(o)",e:"z.sort()"});R(arguments)||(R=function(a){return!!a&&!!t.call(a,"callee")});var U=Y||j({a:"u",f:"if(!v[typeof u]||u===null)throw TypeError()",k:"[]",j:"z.push(o)"});c.VERSION="0.2.0",c.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:"object"},c.after= k:"",j:"if(c(e[k],k,e))return e[k]"}),wt=a(ct,vt),Et=a(ct,{k:"",f:"if(!e)return[]",d:{b:"r=Array(m)",n:"r=[]"},j:{b:"r[k]=c(e[k],k,e)",n:"r.push(c(e[k],k,e))"}}),St=a({a:"e,c,a,x",k:"a",q:"var p=arguments.length<3;if(x)c=l(c,x)",d:{b:"if(p)r=e[++k]"},j:{b:"r=c(r,e[k],k,e)",n:"r=p?(p=g,e[k]):c(r,e[k],k,e)"}}),dt=a(ct,dt,{j:"!"+dt.j}),ht=a(ct,ht,{k:"g",j:ht.j.replace("!","")}),xt=a(pt,{j:"if(n[k]==A)"+pt.j}),Tt=a(pt),pt=a(ct,vt,mt,{r:i}),ct=a(ct,vt,mt),Nt=a({a:"n",k:"[]",r:i,j:"if(y.call(n[k])==h)r.push(k)"
function(a,b){return 1>a?b():function(){if(1>--a)return b.apply(this,arguments)}},c.bind=v,c.bindAll=function(a){var b=arguments,d=1;1==b.length&&(d=0,b=O(a));for(var c=b.length;d<c;d++)a[b[d]]=v(a[b[d]],a);return a},c.chain=function(a){return a=new p(a),a.s=n,a},c.clone=function(a){return S[typeof a]&&a!==o?J(a)?a.slice():sa({},a):a},c.compact=function(a){for(var b=-1,d=a.length,c=[];++b<d;)a[b]&&c.push(a[b]);return c},c.compose=function(){var a=arguments;return function(){for(var b=arguments,d= ,e:"r.sort()"});s(arguments)||(s=function(e){return!!e&&!!et.call(e,"callee")});var Ct=st||function(e){return rt.call(e)==W},st=a({a:"B",k:"z",q:"var d=y.call(B);if(d==b||d==v)return!B.length",j:{n:"return g"}}),kt=ut?function(e){return"function"==typeof e?gt(e):ut(e)}:gt,Lt=a({a:"n",k:"[]",j:"r.push(n[k])"});o.VERSION="0.3.1",o.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this,arguments)}},o.bind=C,o.bindAll=function(e){var t=arguments,n=1;1==t.length&&(n=0,t=Nt(e));for(
a.length;d--;)b=[a[d].apply(this,b)];return b[0]}},c.contains=C,c.debounce=function(a,b,d){function c(){i=m,d||a.apply(g,e)}var e,f,g,i;return function(){var h=d&&!i;return e=arguments,g=this,Fa(i),i=P(c,b),h&&(f=a.apply(g,e)),f}},c.defaults=y,c.defer=function(a){var b=l.call(arguments,1);return P(function(){return a.apply(m,b)},1)},c.delay=function(a,b){var d=l.call(arguments,2);return P(function(){return a.apply(m,d)},b)},c.difference=function(a){for(var b=-1,d=a.length,c=[],e=D.apply(c,l.call( var r=t.length;n<r;n++)e[t[n]]=C(e[t[n]],e);return e},o.chain=function(e){return e=new u(e),e._chain=n,e},o.clone=function(e){return U[typeof e]&&e!==r?Ct(e)?e.slice():Tt({},e):e},o.compact=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length;++n<r;)e[n]&&t.push(e[n]);return t},o.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},o.contains=P,o.debounce=function(e,n,r){function i(){a=t,r||e.apply(u,s)}var s,o,u,a;return function(
arguments,1));++b<d;)0>w(e,a[b])&&c.push(a[b]);return c},c.escape=function(a){return(a+"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")},c.every=W,c.extend=sa,c.filter=pa,c.find=qa,c.first=V,c.flatten=fa,c.forEach=F,c.functions=O,c.groupBy=Ga,c.has=function(a,b){return t.call(a,b)},c.identity=ca,c.indexOf=w,c.initial=function(a,b,d){return l.call(a,0,-(b==m||d?1:b))},c.intersection=ha,c.invoke=function(a,b){for(var d=l.call(arguments ){var t=r&&!a;return s=arguments,u=this,at(a),a=ft(i,n),t&&(o=e.apply(u,s)),o}},o.defaults=xt,o.defer=function(e){var n=nt.call(arguments,1);return ft(function(){return e.apply(t,n)},1)},o.delay=function(e,n){var r=nt.call(arguments,2);return ft(function(){return e.apply(t,r)},n)},o.difference=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length,i=Z.apply(t,nt.call(arguments,1));++n<r;)0>w(i,e[n])&&t.push(e[n]);return t},o.escape=function(e){return(e+"").replace(B,c)},o.every=yt,o.extend=Tt
,2),c=-1,e=a.length,f=h.call(b)==s,g=[];++c<e;)g[c]=(f?b:a[c][b]).apply(a[c],d);return g},c.isArguments=R,c.isArray=J,c.isBoolean=function(a){return a===n||a===r||h.call(a)==la},c.isDate=function(a){return h.call(a)==ma},c.isElement=function(a){return!!a&&1==a.nodeType},c.isEmpty=da,c.isEqual=M,c.isFinite=function(a){return Ea(a)&&h.call(a)==N},c.isFunction=function(a){return h.call(a)==s},c.isNaN=function(a){return h.call(a)==N&&a!=+a},c.isNull=function(a){return a===o},c.isNumber=function(a){return h ,o.filter=Y,o.find=bt,o.first=y,o.flatten=b,o.forEach=wt,o.forIn=pt,o.forOwn=ct,o.functions=Nt,o.groupBy=function(e,t,n){var r={};if(!e)return r;var i,s=-1,o="function"==typeof t,u=e.length;for(o&&n&&(t=h(t,n));++s<u;)i=e[s],n=o?t(i,s,e):i[t],(et.call(r,n)?r[n]:r[n]=[]).push(i);return r},o.has=function(e,t){return et.call(e,t)},o.identity=L,o.indexOf=w,o.initial=function(e,n,r){return e?nt.call(e,0,-(n==t||r?1:n)):[]},o.intersection=function(e){var t=[];if(!e)return t;for(var n,r=-1,i=e.length,s=
.call(a)==N},c.isObject=function(a){return S[typeof a]&&a!==o},c.isRegExp=function(a){return h.call(a)==na},c.isString=function(a){return h.call(a)==K},c.isUndefined=function(a){return a===m},c.keys=U,c.last=function(a,b,d){var c=a.length;return b==m||d?a[c-1]:l.call(a,-b||c)},c.lastIndexOf=function(a,b){if(!a)return-1;for(var d=a.length;d--;)if(a[d]===b)return d;return-1},c.map=$,c.max=ia,c.memoize=function(a,b){var d={};return function(){var c=b?b.apply(this,arguments):arguments[0];return t.call nt.call(arguments,1);++r<i;)n=e[r],0>w(t,n)&&yt(s,function(e){return-1<w(e,n)})&&t.push(n);return t},o.invoke=function(e,t){var n=[];if(!e)return n;for(var r=nt.call(arguments,2),i=-1,s=e.length,o="function"==typeof t;++i<s;)n[i]=(o?t:e[i][t]).apply(e[i],r);return n},o.isArguments=s,o.isArray=Ct,o.isBoolean=function(e){return e===n||e===i||rt.call(e)==X},o.isDate=function(e){return rt.call(e)==V},o.isElement=function(e){return!!e&&1==e.nodeType},o.isEmpty=st,o.isEqual=k,o.isFinite=function(e){return ot
(d,c)?d[c]:d[c]=a.apply(this,arguments)}},c.min=function(a,b,d){var c=Infinity,e=-1,f=a.length,g=c;if(b)d&&(b=v(b,d));else{if(a[0]===+a[0]&&f<=L)try{return Math.min.apply(Math,a)}catch(i){}if(!a.length)return g}for(;++e<f;)d=b?b(a[e],e,a):a[e],d<c&&(c=d,g=a[e]);return g},c.mixin=oa,c.noConflict=function(){return u._=Ba,this},c.once=function(a){var b,d=r;return function(){return d?b:(d=n,b=a.apply(this,arguments))}},c.partial=function(a){var b=l.call(arguments,1),d=b.length;return function(){var c (e)&&rt.call(e)==J},o.isFunction=function(e){return rt.call(e)==$},o.isNaN=function(e){return rt.call(e)==J&&e!=+e},o.isNull=function(e){return e===r},o.isNumber=function(e){return rt.call(e)==J},o.isObject=function(e){return U[typeof e]&&e!==r},o.isRegExp=function(e){return rt.call(e)==K},o.isString=function(e){return rt.call(e)==Q},o.isUndefined=function(e){return e===t},o.keys=kt,o.last=function(e,n,r){if(e){var i=e.length;return n==t||r?e[i-1]:nt.call(e,-n||i)}},o.lastIndexOf=function(e,t,n){
;return c=arguments,c.length&&(b.length=d,E.apply(b,c)),c=1==b.length?a.call(this,b[0]):a.apply(this,b),b.length=d,c}},c.pick=function(a){for(var b,d=0,c=D.apply(z,arguments),e=c.length,f={};++d<e;)b=c[d],b in a&&(f[b]=a[b]);return f},c.pluck=Q,c.range=function(a,b,d){d||(d=1),2>arguments.length&&(b=a||0,a=0);for(var c=-1,e=Math.max(Math.ceil((b-a)/d),0),f=Array(e);++c<e;)f[c]=a,a+=d;return f},c.reduce=aa,c.reduceRight=ea,c.reject=G,c.rest=ja,c.result=function(a,b){if(!a)return o;var d=a[b];return h if(!e)return-1;var r=e.length;for(n&&"number"==typeof n&&(r=(0>n?Math.max(0,r+n):Math.min(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},o.map=Et,o.max=E,o.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return et.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},o.min=function(e,t,n){var r=Infinity,i=r;if(!e)return i;var s=-1,o=e.length;if(!t){for(;++s<o;)e[s]<i&&(i=e[s]);return i}for(n&&(t=h(t,n));++s<o;)n=t(e[s],s,e),n<r&&(r=n,i=e[s]);return i},o.mixin=
.call(d)==s?a[b]():d},c.shuffle=function(a){for(var b,d=-1,c=a.length,e=Array(c);++d<c;)b=Math.floor(Math.random()*(d+1)),e[d]=e[b],e[b]=a[d];return e},c.size=function(a){var b=h.call(a);return b==I||b==K?a.length:U(a).length},c.some=q,c.sortBy=function(a,b,d){if(h.call(b)!=s)var c=b,b=function(a){return a[c]};else d&&(b=v(b,d));return Q($(a,function(d,c){return{a:b(d,c,a),b:d}}).sort(function(a,b){var d=a.a,c=b.a;return d===m?1:c===m?-1:d<c?-1:d>c?1:0}),"b")},c.sortedIndex=ga,c.tap=function(a,b) A,o.noConflict=function(){return e._=D,this},o.once=function(e){var t,r=i;return function(){return r?t:(r=n,t=e.apply(this,arguments))}},o.partial=function(e){var t=nt.call(arguments,1),n=t.length;return function(){var r;return r=arguments,r.length&&(t.length=n,tt.apply(t,r)),r=1==t.length?e.call(this,t[0]):e.apply(this,t),t.length=n,r}},o.pick=function(e){for(var t,n=0,r=Z.apply(G,arguments),i=r.length,s={};++n<i;)t=r[n],t in e&&(s[t]=e[t]);return s},o.pluck=S,o.range=function(e,t,n){n||(n=1),2>
{return b(a),a},c.template=function(a,b,d){d||(d={});var k;k=c.templateSettings||{};var e=d.escape,f=d.evaluate,g=d.interpolate,d=d.variable;return e==o&&(e=k.escape),f==o&&(f=k.evaluate),g==o&&(g=k.interpolate),e&&(a=a.replace(e,xa)),g&&(a=a.replace(g,ya)),f&&(a=a.replace(f,za)),a="__p='"+a.replace(Da,va).replace(Ca,ua)+"';\n",x.length=0,d||(d=k.variable||"object",a="with("+d+"||{}){"+a+"}"),a="function("+d+"){var __p,__t,__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+a+"return __p}" arguments.length&&(t=e||0,e=0);for(var r=-1,i=Math.max(Math.ceil((t-e)/n),0),s=Array(i);++r<i;)s[r]=e,e+=n;return s},o.reduce=St,o.reduceRight=g,o.reject=dt,o.rest=x,o.result=function(e,t){if(!e)return r;var n=e[t];return rt.call(n)==$?e[t]():n},o.shuffle=function(e){if(!e)return[];for(var t,n=-1,r=e.length,i=Array(r);++n<r;)t=Math.floor(Math.random()*(n+1)),i[n]=i[t],i[t]=e[n];return i},o.size=function(e){var t=rt.call(e);return t==W||t==Q?e.length:kt(e).length},o.some=ht,o.sortBy=function(e,n,r
,k=Function("_","return "+a)(c),b?k(b):(k.source=a,k)},c.throttle=function(a,b){function d(){i=new Date,g=m,a.apply(f,c)}var c,e,f,g,i=0;return function(){var h=new Date,j=b-(h-i);return c=arguments,f=this,0>=j?(i=h,e=a.apply(f,c)):g||(g=P(d,j)),e}},c.times=function(a,b,d){d&&(b=v(b,d));for(d=0;d<a;d++)b(d)},c.toArray=function(a){if(!a)return[];if(h.call(a.toArray)==s)return a.toArray();var b=a.length;return b===+b?l.call(a):ra(a)},c.union=function(){for(var a=-1,b=[],d=D.apply(b,arguments),c=d.length ){if(!e)return[];if("string"==typeof n)var i=n,n=function(e){return e[i]};else r&&(n=h(n,r));for(var r=-1,s=e.length,o=Array(s);++r<s;)o[r]={a:n(e[r],r,e),b:e[r]};for(o.sort(function(e,n){var r=e.a,i=n.a;return r===t?1:i===t?-1:r<i?-1:r>i?1:0});s--;)o[s]=o[s].b;return o},o.sortedIndex=T,o.tap=function(e,t){return t(e),e},o.template=function(e,t,n){n||(n={});var i;i=o.templateSettings;var s=n.escape,u=n.evaluate,a=n.interpolate,n=n.variable;return s==r&&(s=i.escape),u==r&&(u=i.evaluate),a==r&&(a=i
;++a<c;)0>w(b,d[a])&&b.push(d[a]);return b},c.uniq=ka,c.uniqueId=function(a){var b=Aa++;return a?a+b:b},c.values=ra,c.without=function(a){for(var b=l.call(arguments,1),d=-1,c=a.length,e=[];++d<c;)0>w(b,a[d])&&e.push(a[d]);return e},c.wrap=function(a,b){return function(){var c=[a];return arguments.length&&E.apply(c,arguments),b.apply(this,c)}},c.zip=function(){for(var a=-1,b=ia(Q(arguments,"length")),c=Array(b);++a<b;)c[a]=Q(arguments,a);return c},c.all=W,c.any=q,c.collect=$,c.detect=qa,c.each=F,c .interpolate),s&&(e=e.replace(s,d)),a&&(e=e.replace(a,v)),u&&(e=e.replace(u,m)),e="__p='"+e.replace(j,l).replace(H,f)+"';",q.length=0,n||(n=i.variable,e="with("+n+"||{}){"+e+"}"),e="function("+n+"){var __p,__t,__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+e+"return __p}",i=Function("_","return "+e)(o),t?i(t):(i.source=e,i)},o.throttle=function(e,n){function r(){a=new Date,u=t,e.apply(o,i)}var i,s,o,u,a=0;return function(){var t=new Date,f=n-(t-a);return i=arguments,o=this
.foldl=aa,c.foldr=ea,c.head=V,c.include=C,c.inject=aa,c.intersect=ha,c.methods=O,c.select=pa,c.tail=ja,c.take=V,c.unique=ka,p.prototype=c.prototype,oa(c),p.prototype.chain=function(){return this.s=n,this},p.prototype.value=function(){return this._wrapped},F("pop push reverse shift sort splice unshift".split(" "),function(a){var b=z[a];p.prototype[a]=function(){var a=this._wrapped;return arguments.length?b.apply(a,arguments):b.call(a),a.length===0&&delete a[0],this.s&&(a=new p(a),a.s=n),a}}),F(["concat" ,0>=f?(a=t,s=e.apply(o,i)):u||(u=ft(r,f)),s}},o.times=function(e,t,n){var r=-1;if(n)for(;++r<e;)t.call(n,r);else for(;++r<e;)t(r)},o.toArray=function(e){if(!e)return[];if(rt.call(e.toArray)==$)return e.toArray();var t=e.length;return t===t>>>0?nt.call(e):Lt(e)},o.union=function(){for(var e=-1,t=[],n=Z.apply(t,arguments),r=n.length;++e<r;)0>w(t,n[e])&&t.push(n[e]);return t},o.uniq=N,o.uniqueId=function(e){var t=_++;return e?e+t:t},o.values=Lt,o.without=function(e){var t=[];if(!e)return t;for(var n=
,"join","slice"],function(a){var b=z[a];p.prototype[a]=function(){var a=this._wrapped,a=arguments.length?b.apply(a,arguments):b.call(a);return this.s&&(a=new p(a),a.s=n),a}}),X?"object"==typeof module&&module&&module.t==X?(module.t=c)._=c:X._=c:(u._=c,typeof define=="function"&&typeof define.amd=="object"&&define.amd&&define(function(){return c}))})(this); nt.call(arguments,1),r=-1,i=e.length;++r<i;)0>w(n,e[r])&&t.push(e[r]);return t},o.wrap=function(e,t){return function(){var n=[e];return arguments.length&&tt.apply(n,arguments),t.apply(this,n)}},o.zip=function(e){if(!e)return[];for(var t=-1,n=E(S(arguments,"length")),r=Array(n);++t<n;)r[t]=S(arguments,t);return r},o.all=yt,o.any=ht,o.collect=Et,o.detect=bt,o.each=wt,o.foldl=St,o.foldr=g,o.head=y,o.include=P,o.inject=St,o.methods=Nt,o.select=Y,o.tail=x,o.take=y,o.unique=N,u.prototype=o.prototype,A(
o),u.prototype.chain=function(){return this._chain=n,this},u.prototype.value=function(){return this._wrapped},wt("pop push reverse shift sort splice unshift".split(" "),function(e){var t=G[e];u.prototype[e]=function(){var e=this._wrapped;return t.apply(e,arguments),e.length===0&&delete e[0],this._chain&&(e=new u(e),e._chain=n),e}}),wt(["concat","join","slice"],function(e){var t=G[e];u.prototype[e]=function(){var e=t.apply(this._wrapped,arguments);return this._chain&&(e=new u(e),e._chain=n),e}}),typeof
define=="function"&&typeof define.amd=="object"&&define.amd?(e._=o,define(function(){return o})):O?"object"==typeof module&&module&&module.s==O?(module.s=o)._=o:O._=o:e._=o})(this);

View File

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

View File

@@ -9,14 +9,18 @@
padding: 0; padding: 0;
height: 100%; height: 100%;
} }
applet {
position: absolute;
left: -9999em;
}
</style> </style>
</head> </head>
<body> <body>
<script src="../lodash.min.js"></script> <script src="../lodash.js"></script>
<script> <script>
var lodash = _.noConflict(); var lodash = _.noConflict();
</script> </script>
<script src="../vendor/underscore/underscore-min.js"></script> <script src="../vendor/underscore/underscore.js"></script>
<script src="../vendor/benchmark.js/benchmark.js"></script> <script src="../vendor/benchmark.js/benchmark.js"></script>
<script src="../vendor/firebug-lite/src/firebug-lite-debug.js"></script> <script src="../vendor/firebug-lite/src/firebug-lite-debug.js"></script>
<script> <script>
@@ -30,11 +34,13 @@
}()); }());
window.onload = function() { window.onload = function() {
var sibling = document.getElementsByTagName('script')[0], var fbUI = document.getElementById('FirebugUI'),
fbDoc = (fbDoc = fbUI.contentWindow || fbUI.contentDocument).document || fbDoc,
sibling = document.getElementsByTagName('script')[0],
script = document.createElement('script'); script = document.createElement('script');
document.getElementById('FirebugUI').style.height = '100%'; fbUI.style.height = fbDoc.body.style.height = fbDoc.documentElement.style.height = '100%';
script.src = 'perf.js'; script.src = 'perf.js?t=' + (+new Date);
sibling.parentNode.insertBefore(script, sibling); sibling.parentNode.insertBefore(script, sibling);
}; };
</script> </script>

View File

@@ -13,7 +13,7 @@
/** Load Lo-Dash */ /** Load Lo-Dash */
var lodash = var lodash =
window.lodash || ( window.lodash || (
lodash = load('../lodash.min.js') || window._, lodash = load('../lodash.js') || window._,
lodash = lodash._ || lodash, lodash = lodash._ || lodash,
lodash.noConflict() lodash.noConflict()
); );
@@ -21,10 +21,15 @@
/** Load Underscore */ /** Load Underscore */
var _ = var _ =
window._ || ( window._ || (
_ = load('../vendor/underscore/underscore-min.js') || window._, _ = load('../vendor/underscore/underscore.js') || window._,
_._ || _ _._ || _
); );
/** Used to access the Firebug Lite panel */
var fbPanel = (fbPanel = window.document && document.getElementById('FirebugUI')) &&
(fbPanel = (fbPanel = fbPanel.contentWindow || fbPanel.contentDocument).document || fbPanel) &&
fbPanel.getElementById('fbPanel1');
/** Used to score Lo-Dash and Underscore performance */ /** Used to score Lo-Dash and Underscore performance */
var score = { 'lodash': 0, 'underscore': 0 }; var score = { 'lodash': 0, 'underscore': 0 };
@@ -41,43 +46,112 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/**
* Logs text to the console.
*
* @private
* @param {String} text The text to log.
*/
function log(text) {
console.log(text);
if (fbPanel) {
// scroll the Firebug Lite panel down
fbPanel.scrollTop = fbPanel.scrollHeight;
}
}
/*--------------------------------------------------------------------------*/
lodash.extend(Benchmark.options, { lodash.extend(Benchmark.options, {
'async': true, 'async': true,
'setup': function() { 'setup': function() {
var window = Function('return this || global')(), var window = Function('return this || global')(),
_ = window._, _ = window._,
lodash = window.lodash, lodash = window.lodash;
numbers = [],
object = {};
for (var index = 0; index < 20; index++) { var length = 20,
numbers = [],
object = {},
fourNumbers = [5, 25, 10, 30],
nestedNumbers = [1, [2], [3, [[4]]]],
twoNumbers = [12, 21];
var ctor = function() { },
func = function(greeting) { return greeting + ': ' + this.name; };
var lodashBoundNormal = lodash.bind(func, { 'name': 'moe' }),
lodashBoundCtor = lodash.bind(ctor, { 'name': 'moe' }),
lodashBoundPartial = lodash.bind(func, { 'name': 'moe' }, 'hi');
var _boundNormal = _.bind(func, { 'name': 'moe' }),
_boundCtor = _.bind(ctor, { 'name': 'moe' }),
_boundPartial = _.bind(func, { 'name': 'moe' }, 'hi');
var wordToNumber = {
'one': 1,
'two': 2,
'three': 3,
'four': 4,
'five': 5,
'six': 6,
'seven': 7,
'eight': 8,
'nine': 9,
'ten': 10,
'eleven': 11,
'twelve': 12,
'thirteen': 13,
'fourteen': 14,
'fifteen': 15,
'sixteen': 16,
'seventeen': 17,
'eighteen': 18,
'nineteen': 19,
'twenty': 20,
'twenty-one': 21,
'twenty-two': 22,
'twenty-three': 23,
'twenty-four': 24,
'twenty-five': 25
};
var words = _.keys(wordToNumber).slice(0, length);
for (var index = 0; index < length; index++) {
numbers[index] = index; numbers[index] = index;
object['key' + index] = index; object['key' + index] = index;
} }
var objects = lodash.map(numbers, function(n) { var objects = lodash.map(numbers, function(num) {
return { 'num': n }; return { 'num': num };
}); });
} }
}); });
lodash.extend(Benchmark.Suite.options, { lodash.extend(Benchmark.Suite.options, {
'onStart': function() { 'onStart': function() {
console.log('\n' + this.name + ':'); log('\n' + this.name + ':');
}, },
'onCycle': function(event) { 'onCycle': function(event) {
console.log(event.target + ''); log(event.target + '');
}, },
'onComplete': function() { 'onComplete': function() {
var fastest = this.filter('fastest').pluck('name'), var formatNumber = Benchmark.formatNumber,
fastest = this.filter('fastest'),
slowest = this.filter('slowest'),
lodashHz = 1 / (this[0].stats.mean + this[0].stats.moe), lodashHz = 1 / (this[0].stats.mean + this[0].stats.moe),
underscoreHz = 1 / (this[1].stats.mean + this[1].stats.moe); underscoreHz = 1 / (this[1].stats.mean + this[1].stats.moe);
if (fastest.length > 1) { if (fastest.length > 1) {
console.log('It\'s too close to call.'); log('It\'s too close to call.');
lodashHz = underscoreHz = Math.min(lodashHz, underscoreHz); lodashHz = underscoreHz = Math.min(lodashHz, underscoreHz);
} else { }
console.log(fastest + ' is the fastest.'); else {
var fastestHz = fastest[0] == this[0] ? lodashHz : underscoreHz,
slowestHz = slowest[0] == this[0] ? lodashHz : underscoreHz,
percent = ((fastestHz / slowestHz) - 1) * 100;
log(fastest[0].name + ' is ' + formatNumber(percent < 1 ? percent.toFixed(2) : Math.round(percent)) + '% faster.');
} }
// add score adjusted for margin of error // add score adjusted for margin of error
score.lodash += lodashHz; score.lodash += lodashHz;
@@ -91,11 +165,17 @@
suites[0].run(); suites[0].run();
} }
else { else {
var fastestTotalHz = Math.max(score.lodash, score.underscore),
slowestTotalHz = Math.min(score.lodash, score.underscore),
totalPercent = formatNumber(Math.round(((fastestTotalHz / slowestTotalHz) - 1) * 100)),
totalX = fastestTotalHz / slowestTotalHz,
message = ' is ' + totalPercent + '% ' + (totalX == 1 ? '' : '(' + formatNumber(totalX.toFixed(2)) + 'x) ') + 'faster than ';
// report results // report results
if (score.lodash >= score.underscore) { if (score.lodash >= score.underscore) {
console.log('\nLo-Dash is ' + (score.lodash / score.underscore).toFixed(2) + 'x faster than Underscore.'); log('\nLo-Dash' + message + 'Underscore.');
} else { } else {
console.log('\nUnderscore is ' + (score.underscore / score.lodash).toFixed(2) + 'x faster than Lo-Dash.'); log('\nUnderscore' + message + 'Lo-Dash.');
} }
} }
} }
@@ -103,18 +183,88 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('bind call')
.add('Lo-Dash', function() {
lodash.bind(func, { 'name': 'moe' }, 'hi');
})
.add('Underscore', function() {
_.bind(func, { 'name': 'moe' }, 'hi');
})
);
suites.push(
Benchmark.Suite('bound')
.add('Lo-Dash', function() {
lodashBoundNormal();
})
.add('Underscore', function() {
_boundNormal();
})
);
suites.push(
Benchmark.Suite('bound partial')
.add('Lo-Dash', function() {
lodashBoundPartial();
})
.add('Underscore', function() {
_boundPartial();
})
);
suites.push(
Benchmark.Suite('bound constructor')
.add('Lo-Dash', function() {
new lodashBoundCtor();
})
.add('Underscore', function() {
new _boundCtor();
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('each array') Benchmark.Suite('each array')
.add('Lo-Dash', function() { .add('Lo-Dash', function() {
var timesTwo = []; var result = [];
lodash.each(numbers, function(num) { lodash.each(numbers, function(num) { result.push(num * 2); });
timesTwo.push(num * 2); })
.add('Underscore', function() {
var result = [];
_.each(numbers, function(num) { result.push(num * 2); });
})
);
suites.push(
Benchmark.Suite('each array thisArg')
.add('Lo-Dash', function() {
var result = [];
lodash.each(numbers, function(num, index) {
result.push(num + this['key' + index]);
}, object);
})
.add('Underscore', function() {
var result = [];
_.each(numbers, function(num, index) {
result.push(num + this['key' + index]);
}, object);
})
);
suites.push(
Benchmark.Suite('each object')
.add('Lo-Dash', function() {
var result = [];
lodash.each(object, function(num) {
result.push(num * 2);
}); });
}) })
.add('Underscore', function() { .add('Underscore', function() {
var timesTwo = []; var result = [];
_.each(numbers, function(num) { _.each(object, function(num) {
timesTwo.push(num * 2); result.push(num * 2);
}); });
}) })
); );
@@ -122,23 +272,111 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('each object') Benchmark.Suite('find')
.add('Lo-Dash', function() { .add('Lo-Dash', function() {
var timesTwo = []; lodash.find(numbers, function(num) {
lodash.each(object, function(num) { return num === 19;
timesTwo.push(num * 2);
}); });
}) })
.add('Underscore', function() { .add('Underscore', function() {
var timesTwo = []; _.find(numbers, function(num) {
_.each(object, function(num) { return num === 19;
timesTwo.push(num * 2);
}); });
}) })
); );
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('flatten deep')
.add('Lo-Dash', function() {
lodash.flatten(nestedNumbers);
})
.add('Underscore', function() {
_.flatten(nestedNumbers);
})
);
suites.push(
Benchmark.Suite('flatten shallow')
.add('Lo-Dash', function() {
lodash.flatten(nestedNumbers, true);
})
.add('Underscore', function() {
_.flatten(nestedNumbers, true);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('difference')
.add('Lo-Dash', function() {
lodash.difference(numbers, fourNumbers);
})
.add('Underscore', function() {
_.difference(numbers, fourNumbers);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('groupBy callback')
.add('Lo-Dash', function() {
lodash.groupBy(numbers, function(num) { return num >> 1; });
})
.add('Underscore', function() {
_.groupBy(numbers, function(num) { return num >> 1; });
})
);
suites.push(
Benchmark.Suite('groupBy property name')
.add('Lo-Dash', function() {
lodash.groupBy(words, 'length');
})
.add('Underscore', function() {
_.groupBy(words, 'length');
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('indexOf')
.add('Lo-Dash', function() {
lodash.indexOf(numbers, 9);
})
.add('Underscore', function() {
_.indexOf(numbers, 9);
})
);
suites.push(
Benchmark.Suite('indexOf isSorted')
.add('Lo-Dash', function() {
lodash.indexOf(numbers, 19, true);
})
.add('Underscore', function() {
_.indexOf(numbers, 19, true);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('intersection')
.add('Lo-Dash', function() {
lodash.intersection(numbers, fourNumbers, twoNumbers);
})
.add('Underscore', function() {
_.intersection(numbers, fourNumbers, twoNumbers);
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('keys') Benchmark.Suite('keys')
.add('Lo-Dash', function() { .add('Lo-Dash', function() {
@@ -151,20 +389,82 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('lastIndexOf')
.add('Lo-Dash', function() {
lodash.lastIndexOf(numbers, 9);
})
.add('Underscore', function() {
_.lastIndexOf(numbers, 9);
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('map') Benchmark.Suite('map')
.add('Lo-Dash', function() { .add('Lo-Dash', function() {
lodash.map(objects, function(obj) { lodash.map(objects, function(value) {
return obj.num; return value.num;
}); });
}) })
.add('Underscore', function() { .add('Underscore', function() {
_.map(objects, function(obj) { _.map(objects, function(value) {
return obj.num; return value.num;
}); });
}) })
); );
suites.push(
Benchmark.Suite('map thisArg')
.add('Lo-Dash', function() {
lodash.map(objects, function(value, index) {
return this['key' + index] + value.num;
}, object);
})
.add('Underscore', function() {
_.map(objects, function(value, index) {
return this['key' + index] + value.num;
}, object);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('max')
.add('Lo-Dash', function() {
lodash.max(numbers);
})
.add('Underscore', function() {
_.max(numbers);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('min')
.add('Lo-Dash', function() {
lodash.min(numbers);
})
.add('Underscore', function() {
_.min(numbers);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('pick')
.add('Lo-Dash', function() {
lodash.pick(object, 'key6', 'key13');
})
.add('Underscore', function() {
_.pick(object, 'key6', 'key13');
})
);
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
@@ -180,21 +480,156 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('values') Benchmark.Suite('shuffle')
.add('Lo-Dash', function() { .add('Lo-Dash', function() {
lodash.values(objects); lodash.shuffle(numbers);
}) })
.add('Underscore', function() { .add('Underscore', function() {
_.values(objects); _.shuffle(numbers);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('sortBy callback')
.add('Lo-Dash', function() {
lodash.sortBy(numbers, function(num) { return Math.sin(num); });
})
.add('Underscore', function() {
_.sortBy(numbers, function(num) { return Math.sin(num); });
})
);
suites.push(
Benchmark.Suite('sortBy callback thisArg')
.add('Lo-Dash', function() {
lodash.sortBy(numbers, function(num) { return this.sin(num); }, Math);
})
.add('Underscore', function() {
_.sortBy(numbers, function(num) { return this.sin(num); }, Math);
})
);
suites.push(
Benchmark.Suite('sortBy property name')
.add('Lo-Dash', function() {
lodash.sortBy(words, 'length');
})
.add('Underscore', function() {
_.sortBy(words, 'length');
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('sortedIndex')
.add('Lo-Dash', function() {
lodash.sortedIndex(numbers, 25);
})
.add('Underscore', function() {
_.sortedIndex(numbers, 25);
})
);
suites.push(
Benchmark.Suite('sortedIndex callback')
.add('Lo-Dash', function() {
lodash.sortedIndex(words, 'twenty-five', function(value) {
return wordToNumber[value];
});
})
.add('Underscore', function() {
_.sortedIndex(words, 'twenty-five', function(value) {
return wordToNumber[value];
});
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('times')
.add('Lo-Dash', function() {
var result = [];
lodash.times(length, function(n) { result.push(n); });
})
.add('Underscore', function() {
var result = [];
_.times(length, function(n) { result.push(n); });
})
);
suites.push(
Benchmark.Suite('times thisArg')
.add('Lo-Dash', function() {
var result = [];
lodash.times(length, function(n) { result.push(this.sin(n)); }, Math);
})
.add('Underscore', function() {
var result = [];
_.times(length, function(n) { result.push(this.sin(n)); }, Math);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('union')
.add('Lo-Dash', function() {
lodash.union(numbers, fourNumbers, twoNumbers);
})
.add('Underscore', function() {
_.union(numbers, fourNumbers, twoNumbers);
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('uniq')
.add('Lo-Dash', function() {
lodash.uniq(numbers.concat(fourNumbers, twoNumbers));
})
.add('Underscore', function() {
_.uniq(numbers.concat(fourNumbers, twoNumbers));
})
);
suites.push(
Benchmark.Suite('uniq callback')
.add('Lo-Dash', function() {
lodash.uniq(numbers.concat(fourNumbers, twoNumbers), function(num) {
return num % 2;
});
})
.add('Underscore', function() {
_.uniq(numbers.concat(fourNumbers, twoNumbers), function(num) {
return num % 2;
});
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('values')
.add('Lo-Dash', function() {
lodash.values(object);
})
.add('Underscore', function() {
_.values(object);
}) })
); );
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
if (Benchmark.platform + '') { if (Benchmark.platform + '') {
console.log(Benchmark.platform + ''); log(Benchmark.platform + '');
} }
// start suites // start suites
log('\nSit back and relax, this may take a while.');
suites[0].run(); suites[0].run();
}(typeof global == 'object' && global || this)); }(typeof global == 'object' && global || this));

View File

@@ -37,6 +37,17 @@
'valueOf': 7 'valueOf': 7
}; };
/** Used to check problem JScript properties too */
var shadowedKeys = [
'constructor',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'toLocaleString',
'toString',
'valueOf'
];
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/** /**
@@ -92,7 +103,7 @@
ok(_() instanceof _); ok(_() instanceof _);
}); });
test('should pass through LoDash instances', function() { test('should return passed LoDash instances', function() {
var wrapped = _([]); var wrapped = _([]);
equal(_(wrapped), wrapped); equal(_(wrapped), wrapped);
}); });
@@ -142,6 +153,10 @@
test('should not escape the ">" character', function() { test('should not escape the ">" character', function() {
equal(_.escape('>'), '>'); equal(_.escape('>'), '>');
}); });
test('should not escape the "/" character', function() {
equal(_.escape('/'), '/');
});
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -174,26 +189,120 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.find');
(function() {
var array = [1, 2, 3];
test('should return found `value`', function() {
equal(_.find(array, function(n) { return n > 2; }), 3);
});
test('should return `undefined` if `value` is not found', function() {
equal(_.find(array, function(n) { return n == 4; }), undefined);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.flatten');
(function() {
test('should treat sparse arrays as dense', function() {
var array = [[1, 2, 3], Array(3)],
expected = [1, 2, 3],
actual1 = _.flatten(array),
actual2 = _.flatten(array, true);
expected.push(undefined, undefined, undefined);
deepEqual(actual1, expected);
ok('4' in actual1);
deepEqual(actual2, expected);
ok('4' in actual2);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.forEach'); QUnit.module('lodash.forEach');
(function() { (function() {
test('returns the collection', function() { test('returns the collection', function() {
var collection = [1, 2, 3, 4]; var collection = [1, 2, 3];
equal(_.forEach(collection, Boolean), collection); equal(_.forEach(collection, Boolean), collection);
}); });
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { test('should treat array-like object with invalid `length` as a regular object', function() {
var object = {}; var keys = [],
_.forEach(shadowed, function(value, key) { object = { 'length': -1 };
object[key] = value;
});
deepEqual(object, shadowed); _.forEach(object, function(value, key) { keys.push(key); });
deepEqual(keys, ['length']);
}); });
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.forIn');
(function() {
test('iterates over inherited properties', function() {
function Dog(name) { this.name = name; }
Dog.prototype.bark = function() { /* Woof, woof! */ };
var keys = [];
_.forIn(new Dog('Dagny'), function(value, key) { keys.push(key); });
deepEqual(keys.sort(), ['bark', 'name']);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.forOwn');
(function() {
test('iterates over the `length` property', function() {
var keys = [],
object = { '0': 'zero', '1': 'one', 'length': 2 };
_.forOwn(object, function(value, key) { keys.push(key); });
deepEqual(keys.sort(), ['0', '1', 'length']);
});
}());
/*--------------------------------------------------------------------------*/
_.each(['forEach', 'forIn', 'forOwn'], function(methodName) {
var func = _[methodName];
QUnit.module('lodash.' + methodName + ' iteration bugs');
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
var keys = [];
func(shadowed, function(value, key) { keys.push(key); });
deepEqual(keys.sort(), shadowedKeys);
});
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() {
function Foo() {}
Foo.prototype.a = 1;
var keys = [];
function callback(value, key) { keys.push(key); }
func(Foo, callback);
deepEqual(keys, []);
keys.length = 0;
Foo.prototype = { 'a': 1 };
func(Foo, callback);
deepEqual(keys, []);
});
});
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.groupBy'); QUnit.module('lodash.groupBy');
(function() { (function() {
@@ -204,6 +313,51 @@
deepEqual(actual, { '1': [1.3], '2': [2.1, 2.4] }); deepEqual(actual, { '1': [1.3], '2': [2.1, 2.4] });
}); });
test('should only add elements to own, not inherited, properties', function() {
var actual = _.groupBy([1.3, 2.1, 2.4], function(num) {
return Math.floor(num) > 1 ? 'hasOwnProperty' : 'constructor';
});
deepEqual(actual.constructor, [1.3]);
deepEqual(actual.hasOwnProperty, [2.1, 2.4]);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.indexOf');
(function() {
var array = [1, 2, 3, 1, 2, 3];
test('should work with a positive `fromIndex`', function() {
equal(_.indexOf(array, 1, 2), 3);
});
test('should work with `fromIndex` >= `array.length`', function() {
equal(_.indexOf(array, 1, 6), -1);
equal(_.indexOf(array, undefined, 6), -1);
equal(_.indexOf(array, 1, 8), -1);
equal(_.indexOf(array, undefined, 8), -1);
});
test('should work with a negative `fromIndex`', function() {
equal(_.indexOf(array, 2, -3), 4);
});
test('should work with a negative `fromIndex` <= `-array.length`', function() {
equal(_.indexOf(array, 1, -6), 0);
equal(_.indexOf(array, 2, -8), 1);
});
test('should ignore non-number `fromIndex` values', function() {
equal(_.indexOf([1, 2, 3], 1, '1'), 0);
});
test('should work with `isSorted`', function() {
equal(_.indexOf([1, 2, 3], 1, true), 0);
});
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -212,7 +366,7 @@
(function() { (function() {
test('returns an empty collection for `n` of `0`', function() { test('returns an empty collection for `n` of `0`', function() {
var array = [1, 2, 3, 4]; var array = [1, 2, 3];
deepEqual(_.initial(array, 0), []); deepEqual(_.initial(array, 0), []);
}); });
}()); }());
@@ -225,6 +379,15 @@
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
equal(_.isEmpty(shadowed), false); equal(_.isEmpty(shadowed), false);
}); });
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() {
function Foo() {}
Foo.prototype.a = 1;
equal(_.isEmpty(Foo), true);
Foo.prototype = { 'a': 1 };
equal(_.isEmpty(Foo), true);
});
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -257,30 +420,54 @@
Foo.prototype.a = 1; Foo.prototype.a = 1;
deepEqual(_.keys(Foo.prototype), ['a']); deepEqual(_.keys(Foo.prototype), ['a']);
deepEqual(_.keys(shadowed).sort(), deepEqual(_.keys(shadowed).sort(), shadowedKeys);
'constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf'.split(' ')); });
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() {
function Foo() {}
Foo.prototype.c = 3;
Foo.a = 1;
Foo.b = 2;
var expected = ['a', 'b'];
deepEqual(_.keys(Foo), expected);
Foo.prototype = { 'c': 3 };
deepEqual(_.keys(Foo), expected);
}); });
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.lastIndexOf');
(function() { (function() {
var i = -1, var array = [1, 2, 3, 1, 2, 3];
largeArray = [];
while (++i <= 1e6) { test('should work with a positive `fromIndex`', function() {
largeArray[i] = i; equal(_.lastIndexOf(array, 1, 2), 0);
} });
_.each(['max', 'min'], function(methodName) {
QUnit.module('lodash.' + methodName);
test('does not error when computing the ' + methodName + ' value of massive arrays', function() { test('should work with `fromIndex` >= `array.length`', function() {
try { equal(_.lastIndexOf(array, undefined, 6), -1);
var actual = _[methodName](largeArray); equal(_.lastIndexOf(array, 1, 6), 3);
} catch(e) { } equal(_.lastIndexOf(array, undefined, 8), -1);
equal(_.lastIndexOf(array, 1, 8), 3);
});
equal(actual, methodName == 'max' ? 1e6 : 0); test('should work with a negative `fromIndex`', function() {
}); equal(_.lastIndexOf(array, 2, -3), 1);
});
test('should work with a negative `fromIndex` <= `-array.length`', function() {
equal(_.lastIndexOf(array, 1, -6), 0);
equal(_.lastIndexOf(array, 2, -8), -1);
});
test('should ignore non-number `fromIndex` values', function() {
equal(_.lastIndexOf([1, 2, 3], 3, '1'), 2);
equal(_.lastIndexOf([1, 2, 3], 3, true), 2);
}); });
}()); }());
@@ -342,6 +529,17 @@
deepEqual(args, ['C', 'B', 'b', object]); deepEqual(args, ['C', 'B', 'b', object]);
}); });
test('should treat array-like object with invalid `length` as a regular object', function() {
var args,
object = { 'a': 'A', 'length': -1 };
_.reduceRight(object, function() {
args || (args = slice.call(arguments));
});
deepEqual(args, [-1, 'A', 'a', object]);
});
}()); }());
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@@ -364,11 +562,36 @@
(function() { (function() {
test('supports the `thisArg` argument', function() { test('supports the `thisArg` argument', function() {
var actual = _.sortBy([1, 2, 3, 4], function(num) { var actual = _.sortBy([1, 2, 3], function(num) {
return this.sin(num); return this.sin(num);
}, Math); }, Math);
deepEqual(actual, [4, 3, 1, 2]); deepEqual(actual, [3, 1, 2]);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.sortedIndex');
(function() {
test('supports the `thisArg` argument', function() {
var actual = _.sortedIndex([1, 2, 3], 4, function(num) {
return this.sin(num);
}, Math);
equal(actual, 0);
});
test('supports arrays with lengths larger than `Math.pow(2, 31) - 1`', function() {
var length = Math.pow(2, 32) - 1,
index = length - 1,
array = Array(length),
steps = 0;
array[index] = index;
_.sortedIndex(array, index, function() { steps++; });
equal(steps, 33);
}); });
}()); }());
@@ -378,7 +601,7 @@
(function() { (function() {
test('supports recursive calls', function() { test('supports recursive calls', function() {
var compiled = _.template('<%= a %><% a = _.template(c, object) %><%= a %>'), var compiled = _.template('<%= a %><% a = _.template(c, obj) %><%= a %>'),
data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' }; data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' };
equal(compiled(data), 'AB'); equal(compiled(data), 'AB');
@@ -412,7 +635,7 @@
while ((new Date - start) < limit) { while ((new Date - start) < limit) {
throttled(); throttled();
} }
equal(counter, 3); ok(counter > 1);
}); });
}()); }());
@@ -429,15 +652,34 @@
deepEqual(_.toArray(array), [3, 2, 1]); deepEqual(_.toArray(array), [3, 2, 1]);
}); });
test('should treat array-like-objects like arrays', function() { test('should treat array-like objects like arrays', function() {
var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 }; var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 };
deepEqual(_.toArray(object), ['a', 'b', 'c']); deepEqual(_.toArray(object), ['a', 'b', 'c']);
deepEqual(_.toArray(args), [1, 2, 3]); deepEqual(_.toArray(args), [1, 2, 3]);
}); });
test('should treat array-like object with invalid `length` as a regular object', function() {
var object = { 'length': -1 };
deepEqual(_.toArray(object), [-1]);
});
}(1, 2, 3)); }(1, 2, 3));
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.uniq');
(function() {
test('supports the `thisArg` argument', function() {
var actual = _.uniq([1, 2, 1.5, 3, 2.5], function(num) {
return this.floor(num);
}, Math);
deepEqual(actual, [1, 2, 3]);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash(...).shift'); QUnit.module('lodash(...).shift');
(function() { (function() {
@@ -466,6 +708,82 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash "Arrays" methods');
(function() {
test('should allow a falsey `array` argument', function() {
_.each([
'compact',
'difference',
'first',
'flatten',
'groupBy',
'indexOf',
'initial',
'intersection',
'invoke',
'last',
'lastIndexOf',
'max',
'min',
'pluck',
'range',
'rest',
'shuffle',
'sortBy',
'sortedIndex',
'union',
'uniq',
'without',
'zip'
], function(methodName) {
var pass = true;
try {
_[methodName]();
} catch(e) {
pass = false;
}
ok(pass, methodName + ' allows a falsey `array` argument');
});
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash "Collections" methods');
(function() {
test('should allow a falsey `collection` argument', function() {
_.each([
'contains',
'every',
'filter',
'find',
'forEach',
'map',
'reduce',
'reduceRight',
'reject',
'some',
'toArray'
], function(methodName) {
var pass = true;
try {
if (/^(?:contains|toArray)$/.test(methodName)) {
_[methodName](null);
} else {
_[methodName](null, _.identity);
}
} catch(e) {
pass = false;
}
ok(pass, methodName + ' allows a falsey `collection` argument');
});
});
}());
/*--------------------------------------------------------------------------*/
// explicitly call `QUnit.start()` for Narwhal, Rhino, and RingoJS // explicitly call `QUnit.start()` for Narwhal, Rhino, and RingoJS
QUnit.start(); QUnit.start();

2
vendor/docdown vendored

2
vendor/qunit vendored