Compare commits

...

270 Commits
0.2.1 ... 0.5.0

Author SHA1 Message Date
John-David Dalton
15b14e12e2 Change to triple-backtick code fences.
Former-commit-id: 81d38ed0155734a72d98b2e16425635da907aa01
2012-08-18 00:04:17 -07:00
Mathias Bynens
b328972c4d README: Switch to the triple backtick syntax for highlighted code blocks
Former-commit-id: c4fba0c9cf7e8b0fdfc846260b148ecd327c0a1f
2012-08-17 19:31:03 +02:00
John-David Dalton
da3156047f Update minified build and rebuild documentation.
Former-commit-id: ab353b4c73c47b51144f5a917aeb53682b40552e
2012-08-17 08:17:14 -07:00
John-David Dalton
f9f08ba54f Optimize isPlainObject use in _.clone.
Former-commit-id: 7bb48bc5f9276c730f947b6e75b6fba4588f17c1
2012-08-17 08:16:31 -07:00
John-David Dalton
b43684262f Cleanup _.template documentation.
Former-commit-id: 7b45705bd8a4661dbf824912798ccba15e5ed989
2012-08-17 04:05:50 -07:00
John-David Dalton
2120f78bd7 Fix typos in README.md.
Former-commit-id: fb31a291a3afe799d2e9809f17420eda10888250
2012-08-17 02:54:19 -07:00
John-David Dalton
2d896f22d6 Bump to v0.5.0.
Former-commit-id: f30f4b99104c94fb52df4c90dcda24b8ac51432c
2012-08-17 02:28:42 -07:00
John-David Dalton
9fa0aebfe9 Add check for V8 bug #2291.
Former-commit-id: 245f156a2ce1ee92c8f8f8f34b9891ba4eff0d23
2012-08-17 02:12:17 -07:00
John-David Dalton
2ddc3af5ff Fix jQuery/MooTools DOM collection unit tests in IE6.
Former-commit-id: b9c3dbcffb28b0088018614e21fbe313b0d53713
2012-08-17 00:25:52 -07:00
John-David Dalton
fd80e096ea Remove noArgsClass check from isPlainObject.
Former-commit-id: bab7a68e8eaa21679b33b2ab70a9f8e47758ebc1
2012-08-17 00:10:03 -07:00
John-David Dalton
fab2d69fce Ensure _.sortBy performs a stable sort. [closes #59]
Former-commit-id: 09c5ff85ef0f1d054579ec4260a7f76d9c0da281
2012-08-16 23:24:59 -07:00
John-David Dalton
83d08e3aba Avoid false positives for arguments objects in IE < 9 when using isPlainObject.
Former-commit-id: 19e5a6efed32f26d0c908771eec40e7fb2ecf265
2012-08-16 22:22:08 -07:00
John-David Dalton
bfea6bcacf Maintain up-to-date minified underscore-min.js and use in perf tests.
Former-commit-id: 6317df872bd6136d81763d27a62a444f6e392537
2012-08-16 21:21:48 -07:00
John-David Dalton
feff34b021 Update vendors.
Former-commit-id: 44c2fe9fbfbf50aa64663d46b45d6fd2c778f2b7
2012-08-16 21:20:54 -07:00
John-David Dalton
79fbade92a Minor unit test cleanup.
Former-commit-id: 3243247d9da53f3a12cd19bec822bb43eb7f315e
2012-08-16 21:20:05 -07:00
John-David Dalton
bf508e453e Remove unused funcClass variable from compiled functions.
Former-commit-id: f47b8e412b5151e69a3ab78f03243c461b5ab072
2012-08-16 21:19:47 -07:00
John-David Dalton
47b51c22fa Ensure build tweaks are applied when new lines break up specific patterns.
Former-commit-id: 085a837521750457db9f20f3701984cba24a4f4f
2012-08-14 23:15:04 -07:00
John-David Dalton
ebd16105f2 Detect and remove additional unnecessary brackets from template strings during the build process.
Former-commit-id: 0b9786e7d41497fd1627e31401a5e7e0926eea9c
2012-08-14 00:12:27 -07:00
John-David Dalton
01fb1a5775 Optimize _.isFunction.
Former-commit-id: 0aaaa6d166c7eea94237388d61a11c6d183cbe1f
2012-08-13 23:11:01 -07:00
John-David Dalton
b8c2a05db9 Add strict comparison note to _.intersection and _.union documentation.
Former-commit-id: 47792d96e77fdeb6f00db1e4d30b41a6f1a59dbb
2012-08-13 07:37:26 -07:00
John-David Dalton
4087dc5fe4 Reword unit jQuery/MooTools DOM query collection unit test.
Former-commit-id: c80673f799ce6f1449d043eabf76fd6970a70b77
2012-08-13 00:45:38 -07:00
John-David Dalton
408029e6e0 Don't expose _.forIn or _.forOwn if underscore build modifier is present and include doesn't contain forIn or forOwn.
Former-commit-id: 6ebd0bc61d3ae6e2d0506fe72dd22ed59c601c70
2012-08-13 00:44:37 -07:00
John-David Dalton
23ff403529 Update vendors.
Former-commit-id: b239f365c9d8e012bf20525167e6d1a412ce828e
2012-08-12 22:33:27 -07:00
John-David Dalton
be4f81f584 Remove more unnecessary brackets from template strings during the build process.
Former-commit-id: c8e3dfe7d34f9c61fff75512fb4587a987bdf49f
2012-08-12 21:41:41 -07:00
John-David Dalton
361c91e610 Add support in _.isEmpty and _.size for jQuery/MooTools DOM query collections.
Former-commit-id: dc834256d09d7a3f2797ba65690961aad00717bf
2012-08-12 21:40:46 -07:00
John-David Dalton
2aa2ea9675 Fix edge issue with Opera 10.53-10.60.
Former-commit-id: 60014a8e3855bcbf0e4c6f47461123cacafcf668
2012-08-11 21:47:04 -07:00
John-David Dalton
e084225edf Cleanup .npmignore and ensure perf.js will work in the package.
Former-commit-id: e03213fba34c38af2be9003f5be4837d293198e1
2012-08-11 21:36:14 -07:00
John-David Dalton
9ce342205b Add Jam package support.
Former-commit-id: 399caeea73fc79dd340baa7e34b46179ff2beb86
2012-08-11 21:35:06 -07:00
John-David Dalton
0edf50e00e Update edge links in README.md to v0.5.0-rc.1 tagged links.
Former-commit-id: 1f9fea70c6608d980cc8c8fd7d0a39764cf14fa2
2012-08-09 00:24:53 -07:00
John-David Dalton
1ea19daad9 Clear the func variable in _.once so the function may be garbage collected.
Former-commit-id: 521a9d997cb206a5c468b30e5dfa8e096e1a13d5
2012-08-09 00:16:35 -07:00
John-David Dalton
32b302314e Add doc links to the change log entry in README.md.
Former-commit-id: 3c6c79de33331f14af2d5d2c64d1286c67bfb774
2012-08-07 08:20:00 -07:00
John-David Dalton
ee197e02a2 Updated tested environments and resolved issues in README.md.
Former-commit-id: 7d8cc17bad215d87c8c11210d58e1927c5766145
2012-08-07 08:04:46 -07:00
John-David Dalton
7cd6ffec2a Bump to v0.5.0-rc.1.
Former-commit-id: f5a29fd34de5aced3287413f40a0a36226465c84
2012-08-07 00:47:15 -07:00
John-David Dalton
0077580838 Fix failing unit tests in various browsers.
Former-commit-id: 9b5c6e82e0dfed79c505f41b66030ede81ca9a1c
2012-08-07 00:17:04 -07:00
John-David Dalton
4d85a79fd1 Add note about Chrome extensions to _.template.
Former-commit-id: 97b5220ebc3dbbd30b0e52f6c804b449b8d451ca
2012-08-06 08:03:54 -07:00
John-David Dalton
a35139bb61 Fix typo in test-ui.js.
Former-commit-id: 95057e80cfac9d7d776170d66f2c2bfdd364944f
2012-08-06 02:02:23 -07:00
John-David Dalton
f72b833724 Ensure _.keys works with arguments objets cross-browser.
Former-commit-id: 1238c9efcfc13a420804c26c5edee1e4aa5a4238
2012-08-06 01:51:47 -07:00
John-David Dalton
0e16bac6e2 Rebuild documentation.
Former-commit-id: d24c2fb65a54b018da9ad08aa3a67363a31c1122
2012-08-05 23:38:23 -07:00
John-David Dalton
e17564b362 Add unit tests for exiting early from _.forEach, _.forIn, _.forOwn.
Former-commit-id: 18d55054989d3b55afce1f4d604cd274eb9289c8
2012-08-05 23:09:05 -07:00
John-David Dalton
90b66eddf5 Add _.keys unit test for arguments objects.
Former-commit-id: dd90a9d3dc973a6ea8dce0c10ad511cce82097dd
2012-08-05 22:37:43 -07:00
John-David Dalton
2862a5849f Document how _.each, _.forIn, and _.forOwn may terminate iteration early by explicitly returning false in the callback.
Former-commit-id: e218eae83de880deecf1e45d32ca019efd25b548
2012-08-05 00:29:18 -07:00
John-David Dalton
7e839231ed Add iteratesOwnLast bug check.
Former-commit-id: fcc42a42f08e60acc1252ec06b045cfee17bd020
2012-08-05 00:09:00 -07:00
John-David Dalton
fa56a4bb73 Cleanup build.js and update dependencies for _.clone, _.isEmpty, _.isEqual, _.merge, and _.size.
Former-commit-id: df19990609a3dd8432694798149a5eb5bda142c4
2012-08-05 00:02:33 -07:00
John-David Dalton
dff950748c Fix the build to work with _.merge.
Former-commit-id: cb1d9897b97b357197bb6933c65f4afbecea1aea
2012-08-04 17:13:09 -07:00
John-David Dalton
b7374e3f8e Ensure merge works with sources containing circular references.
Former-commit-id: cb3301868299c4e4d32a3d3608199e4269d951ec
2012-08-04 17:12:25 -07:00
John-David Dalton
4244b92b08 Update minified build and rebuild docs.
Former-commit-id: f80bacba89ab171aae61d5ce7269e8507117bffa
2012-08-02 00:33:39 -07:00
John-David Dalton
4f688028ad Update vendors.
Former-commit-id: d1dd2ecf337cf8cda71e0da2af0647813b8de24a
2012-08-02 00:32:15 -07:00
John-David Dalton
5a9a18501d Add _.merge.
Former-commit-id: e393655b1fa41c8eb6ae1b925f456aa05231078a
2012-08-02 00:28:19 -07:00
John-David Dalton
896b8f7cf1 Remove noNodeClass from "mobile" and "csp" builds.
Former-commit-id: 0773f7b1c1ea637d0d519a3015d1534863a9be11
2012-07-29 23:54:52 -07:00
John-David Dalton
95bd1b014f Rework the noNodeClass inference to detect the JScript quirk too.
Former-commit-id: 3a6b73509490d7e87d2322fe1c09890f5f6b57ea
2012-07-29 23:48:07 -07:00
John-David Dalton
dbdf8642bb Rebuild documentation and update the minified build.
Former-commit-id: c4d4281f16250f50ea4d5337a53acceedd2ce660
2012-07-29 14:18:05 -07:00
John-David Dalton
c3cd9007d2 Add unit tests for _.where.
Former-commit-id: 5247bba20d7aa772867e29def99221faea376db1
2012-07-29 14:17:34 -07:00
John-David Dalton
8079fb5bc5 Reorganize and cleanup code for _.where.
Former-commit-id: 769dfafc1701c5ebc2d351abeb729ca6fcfa12e9
2012-07-29 13:49:23 -07:00
John-David Dalton
80d0b5d4ed Add _.where. [closes #22].
Former-commit-id: dec7a9d0df4158a395ec84fb9e774ed20205d421
2012-07-29 13:48:21 -07:00
John-David Dalton
86bd847bf9 Ensure _.isEqual works correctly for objects from another document and add _.clone benchmark.
Former-commit-id: b1ef745ec6c24e8ea0c8fae304ead80c60dfd5aa
2012-07-29 00:58:23 -07:00
John-David Dalton
943004844a Ensure the callback of _.filter can't modify the resulting value.
Former-commit-id: 6652dc5926390e8418b524c7ffd2347c2fa65c82
2012-07-26 23:24:17 -07:00
John-David Dalton
4ff12e0426 Fix recent typo in isEqual.
Former-commit-id: 84cdf90de59c8184a0ac1f78704f61dcc88c91f1
2012-07-25 01:35:56 -07:00
John-David Dalton
0d7bdb6fa8 Make _.range coerce arguments to numbers.
Former-commit-id: 5408800fef0bc8a418c298a112049232b6d85e78
2012-07-25 01:32:28 -07:00
John-David Dalton
6d488b6a81 Update minified build and rebuild documentation.
Former-commit-id: 5f0ea311b51723c225774d735f67fc58f55a4d6e
2012-07-24 02:15:20 -07:00
John-David Dalton
f1d0263ffa Add csp Content Security Policy build.
Former-commit-id: f922046de5150c098eb7f6d3b6901552117631e7
2012-07-24 02:13:31 -07:00
John-David Dalton
24035caadb Keep objects in the stack array of _.isEqual in case a cyclical object is used in a sibling property.
Former-commit-id: 33ffcec837322f4d479f64f9ec6b14184bf5f7a2
2012-07-24 02:13:07 -07:00
John-David Dalton
ed89a3e0f8 Check for custom isEqual methods in _.isEqual before other comparisons and add cross-browser support for arguments objects.
Former-commit-id: 56e40f670309aeb0dcda7868c8aa84b5909db1f1
2012-07-24 01:45:34 -07:00
John-David Dalton
7088ab89f1 Add deep clone support via the deep argument to _.clone.
Former-commit-id: d4fad45364489efb957d29e201846e8c1875b9ed
2012-07-24 01:41:38 -07:00
John-David Dalton
d4688bd76b Adjust _.wrap docs and rebuild/update the minified build/docs.
Former-commit-id: b33c4489bde49c98e7e161d0f831e07388a9da22
2012-07-20 03:22:13 -04:00
John-David Dalton
befe0fccaf Cleanup _.isEqual comments and ensure _.isEmpty/_.size detect arguments objects correctly.
Former-commit-id: 75b044d27b990d55393bf27234aad6ce369f6abe
2012-07-20 02:06:13 -04:00
John-David Dalton
a192410498 Remove Narwhal link from README.md.
Former-commit-id: b8bd53c9a19ef18480db14cfa82545aa872416b1
2012-07-19 09:15:04 -04:00
John-David Dalton
d43ede3a11 Update vendor/underscore and backbone.
Former-commit-id: 614926653b0b1669f8a5533666adb0aecbd46c03
2012-07-19 01:32:47 -04:00
John-David Dalton
9848ffb77f Add _.countBy and related unit tests, benchmarks, and documentation.
Former-commit-id: 915eaf414883a1dc344a558b08c7a1337ab5a225
2012-07-19 01:29:51 -04:00
John-David Dalton
7487497d1f Update minified build and rebuild documentation.
Former-commit-id: e674d7a30c1e5745b0acf90e38aa5757b15a3423
2012-07-18 04:52:13 -04:00
John-David Dalton
be11c848f4 Add "underscore" build.
Former-commit-id: 44e9f4543631cbf342ae7571cf540214623352db
2012-07-18 04:51:08 -04:00
John-David Dalton
9836b274b9 Add _.drop, unit tests, and cleanup documentation for _.extend, _.defaults, and _.pick.
Former-commit-id: a45b0c45d52fdbe5f71984412d631f3dfe87965b
2012-07-18 03:55:16 -04:00
John-David Dalton
a96d14566f Add Underscore ticket reference to Fix cross-browser object iteration bugs bullet in README.md.
Former-commit-id: 9814daf6b81f1c60b3c6681c10c1fc7b94ac61b8
2012-07-18 02:15:16 -04:00
John-David Dalton
1c8cd8c168 Ensure reEvaluateDelimiter is assigned an initial value if evaluateDelimiter is undefined by default. [closes #52]
Former-commit-id: 6cefeeca164901e611009ce1413e5080027592c9
2012-07-18 01:53:15 -04:00
John-David Dalton
5f5806a98e Update CDN link and rebuild documentation.
Former-commit-id: 32210baffaed31b7fb4daed58a0c0a4f22daf4f0
2012-07-17 01:41:21 -04:00
John-David Dalton
624b045ac0 Add unit tests and code comments for the conditional compilation patch.
Former-commit-id: 557aa43dc7c8db738452a9f3afb8ff2aadf8061a
2012-07-17 01:39:51 -04:00
Jay Phelps
0f8bae950e Ensure running in IE if concated with other files that enable conditional compilation /*@cc_on @/`.
Former-commit-id: cf2d9c01ce92b8b85149116d48145bc4342471a4
2012-07-16 20:07:55 -04:00
John-David Dalton
fcede42903 Add Unit testing video link to README and minor cleanup to build.js help text.
Former-commit-id: 504b69acede1bb4759ba942d01dfd0b899715f00
2012-07-16 18:28:34 -04:00
John-David Dalton
5defe7d975 Bump to v0.4.2.
Former-commit-id: 48638d63970b9d4300661620b881ea34854d24d2
2012-07-16 14:34:48 -04:00
John-David Dalton
7e79903fe8 Update tests to work around QUnit 1.9.0 bug in Narwhal/older-Firefox and add platform.js to test/index.html.
Former-commit-id: eed8246c795735558ba9f499b86f08ed3970ccaf
2012-07-16 13:58:36 -04:00
John-David Dalton
a2fa52504c Ensure stringClass isn't stripped out when needed for certain builds and update dependencies for arrayClass, funcClass, objectTypes, and reNative.
Former-commit-id: 334973dcab4660733e1d081efe3602a167c452d9
2012-07-15 07:01:44 -04:00
John-David Dalton
2629f85e73 Update minified build and rebuild documentation.
Former-commit-id: 5b434ca8c22a44d1603dcc1e92bf4caea6fe00a1
2012-07-15 03:52:22 -04:00
John-David Dalton
8577816234 Add optimizations for large arrays to _.difference, _.intersection, and _.without.
Former-commit-id: 26d55a6a3340e77b5269b2003d20def3fe77bca9
2012-07-15 03:51:28 -04:00
John-David Dalton
e58d47a3b2 Add "strict" build.
Former-commit-id: fcdd8d36c9e0c6d698059541b97915ae1b28650e
2012-07-14 08:59:50 -04:00
John-David Dalton
c9c83ee7e6 Add _.invoke benchmark to perf.js and a link to the compatibility changes wiki entry in README.md.
Former-commit-id: 51296709ea8d9dd6e951530b9874b90af3c764a2
2012-07-14 06:21:59 -04:00
John-David Dalton
139693dce6 Optimize benchmark setups, cleanup perf/index.html, and add platform.js.
Former-commit-id: 228b7b6fd230638f9ec8c79eafa56506fc84b79a
2012-07-14 04:51:50 -04:00
John-David Dalton
f98193d822 Poll until Firebug-lite is loaded.
Former-commit-id: c568ed963fc5716c2c84d63aba45a8ef258c1e7b
2012-07-13 14:41:21 -04:00
John-David Dalton
8052f1ac9d Revert unstable Closure Compiler.
Former-commit-id: 81716f0c269ac8a5befbf584c0dc964777cc1e1a
2012-07-13 04:33:50 -04:00
John-David Dalton
4f78a06993 Add _.isEqual benchmarks.
Former-commit-id: 5b3ee06ea3f31f10e8fac96da8766cc1c4c2d3bb
2012-07-13 04:17:38 -04:00
John-David Dalton
6c4b4b392b Avoid expensive test setup in perf.js.
Former-commit-id: f1c1ed41cb86c83aba2c3f7da1dedf6a280221ad
2012-07-12 18:19:23 -04:00
John-David Dalton
268fe34238 Update Closure Compiler.
Former-commit-id: bfdbe43546f3861cbeaaa99644af68e95f2175d5
2012-07-12 16:54:17 -04:00
John-David Dalton
cc620205d6 Control "use strict" directive use in builds.
Former-commit-id: 66a9bdee5cc61710d7d42d685feba616ec855322
2012-07-12 16:25:30 -04:00
John-David Dalton
f0d7c97b7b Update test-ui.js to better integrate with QUnit 1.9.0.
Former-commit-id: 7e6083ebb54fde0ebaa9f4f4551bb190e602a370
2012-07-12 15:48:52 -04:00
John-David Dalton
660a6e9e4c Update minified build and rebuild documentation.
Former-commit-id: 6e747961d3d756d016a27b530bf961841a93bd00
2012-07-12 15:27:25 -04:00
John-David Dalton
3386c2a7a5 Avoid enforcing strict mode in _.defaults, _.extend, and _.bindAll and add benchmarks for _.bindAll and _.functions. [closes #45]
Former-commit-id: 1bb0b5155d3ae46052b4a06cb538dff307e8ec5e
2012-07-12 15:25:18 -04:00
John-David Dalton
9530efb4d4 Update vendor folder.
Former-commit-id: 363508c8d79afa1ec8c1aba48b5be58a8a572367
2012-07-12 13:32:48 -04:00
John-David Dalton
4293515b3d Add help and version options to build.js.
Former-commit-id: 95a9fdaa7a00550922e71ce01a3f742b845d082c
2012-07-12 13:31:42 -04:00
John-David Dalton
61105e0679 Cleanup inline documentation.
Former-commit-id: 1fa95d45c2c3d1fe50f5827f4743aad3c8b75f95
2012-07-12 03:27:15 -04:00
John-David Dalton
79a289c7e2 Update CDN copy link.
Former-commit-id: 4d0d26292eef227f343f6b482856482f8f554a43
2012-07-12 02:06:55 -04:00
John-David Dalton
46781e7614 Bump to v0.4.1.
Former-commit-id: ef73c95edc22d59412affba898d9820251c06b5b
2012-07-12 00:47:24 -04:00
John-David Dalton
1f3546a9f6 Cleanup pre-compile.js and build.js removing more unused vars missed by minifiers.
Former-commit-id: 198715b39ced1a33bd55109099af462ae96a7188
2012-07-11 23:37:12 -04:00
John-David Dalton
0dc88bb412 Fix template regressions. [Closes #44]
Former-commit-id: 15e98d86c290fea74780822b49b5d71e54064e01
2012-07-11 22:46:16 -04:00
John-David Dalton
971a26c123 Remove noArraySliceOnStrings from the mobile build.
Former-commit-id: 943f907672f211be4f3d1c2e8fe8d5769a0a569e
2012-07-11 12:48:37 -04:00
John-David Dalton
0976a3b721 Bump version to 0.4.0.
Former-commit-id: e3606a629e44711ad9174ac7c6690f2a53f088b9
2012-07-11 11:59:04 -04:00
John-David Dalton
d496361555 Fix failing unit test in Opera < 10.52 and add _.toArray benchmarks.
Former-commit-id: 0ed6d5c52b2486be4ccc212da7bbc7cb6d67cf7f
2012-07-11 11:29:44 -04:00
John-David Dalton
60ed65a73a Add utf8 encoding to the generated minified file in minify.js.
Former-commit-id: 2765e28a177ae2703d3b1a6328a35cf5c92fa6ef
2012-07-11 05:54:19 -04:00
John-David Dalton
d1407b3bd0 Add unneeded vendor folders to .npmignore.
Former-commit-id: 7be56b8081be64d41cc66914dce577695d9d0747
2012-07-11 05:40:25 -04:00
John-David Dalton
5ca2da76df Make build.js work as a npm executable.
Former-commit-id: fff327957854aa85a5abfe80994b59f3d0d24370
2012-07-11 05:39:30 -04:00
John-David Dalton
2ac887ff74 Make compiled templates more debuggable.
Former-commit-id: aba1aa3efcea6695632aae0eb61148aa3174debd
2012-07-11 01:52:50 -04:00
John-David Dalton
cbdc9c0be1 Make _.contains work with strings similar ES6 draft String#contains.
Former-commit-id: 3cfffdcddec3e1e8175da95043ec86ac3c6a85fe
2012-07-11 01:11:25 -04:00
John-David Dalton
b9bade8d5a Remove unused UglifyJS file.
Former-commit-id: cfefdb6796583cc55a16ce02533541e6395e4356
2012-07-10 23:22:01 -04:00
John-David Dalton
eb43786641 Cleanup unit tests.
Former-commit-id: 460ffc3bd38c98dd86fc8c74d4720eed5d50433d
2012-07-10 22:04:40 -04:00
John-David Dalton
0515db3d7c Add more false values unit tests for _.size and "Arrays"/"Collections" methods.
Former-commit-id: 475941321404ceec4eabb56fb9ee10855a653e12
2012-07-10 21:41:38 -04:00
John-David Dalton
db257778c0 Update vendor folder.
Former-commit-id: dde7c53eee254e2f50608e65540893764ab8d9cb
2012-07-10 18:14:15 -04:00
John-David Dalton
3b37d7489f Add legacy build info to README.md and rebuild minified file and documentation.
Former-commit-id: 83560976f173a3c797128b08fb184cc7c1e77319
2012-07-10 01:27:07 -04:00
John-David Dalton
329c7e8e05 Add custom-debug build to unit test runners and add unit tests for passing strings to "Collections" methods.
Former-commit-id: cb6c66d01a9f30908a27e689f8ffba5fa9f04299
2012-07-10 01:06:06 -04:00
John-David Dalton
fad9b4fa72 Add support for strings in "Collections" methods.
Former-commit-id: 1abb252101d20c9a01291f4cef19db8a7eeda743
2012-07-10 01:05:22 -04:00
John-David Dalton
c1a81279ed Rename test/ui.js to test/test-ui.js and add to .npmignore. [closes #40]
Former-commit-id: 80165ec342e8b833a28bbe66f59e074c8f4f5185
2012-07-09 07:54:35 -04:00
John-David Dalton
8bb35a17d2 Allow different builds to be tested more easily with a dropdown menu.
Former-commit-id: a692bda9708523aa0443acb35dd8fcc5a342ef3f
2012-07-09 03:56:43 -04:00
John-David Dalton
36415054ea Update minified build and documentation.
Former-commit-id: fc680301b9ae378139e5174e48eb8e4708fddba0
2012-07-08 18:10:10 -04:00
John-David Dalton
3e84cbae69 Add removeKeysOptimization function to build.js.
Former-commit-id: ce13e7b7a1f12199cdddcccbf0b7e0d98d6438ec
2012-07-08 18:08:41 -04:00
John-David Dalton
f5f2bf7f46 Cleanup iteratorTemplate and optimize methods that use mapIteratorOptions.
Former-commit-id: a0f876250a1c7875745e9080bf75546e16fbf6e7
2012-07-08 10:05:04 -04:00
John-David Dalton
acb6656958 Update minified build and documentation.
Former-commit-id: 19462dc946eca093f4265620b8e063b8c162c27d
2012-07-08 03:40:51 -04:00
John-David Dalton
9d70d7c27e Fix _.sortBy in the mobile build attempt two.
Former-commit-id: 8f54b16a901acc4ce91f071c5b36c632334f7dde
2012-07-08 03:39:38 -04:00
John-David Dalton
648a6afb25 Add object iteration benchmarks for _.filter, _.find, _.groupBy, and _.map to perf.js.
Former-commit-id: dc30e2c0e4f88b2a0164f02bf3bf92fd40a87012
2012-07-08 03:31:40 -04:00
John-David Dalton
57ae1925b1 Fix _.sortBy in the mobile build.
Former-commit-id: 0af3778e89e61effbe60347d6f0bcb33d8c37a2e
2012-07-08 03:30:16 -04:00
John-David Dalton
d49318582f Adjust how "mobile" build is created and add first pass at "legacy" build.
Former-commit-id: 740cc40c21d33353f34796ae6da3bc8ce015ab6c
2012-07-08 03:28:18 -04:00
John-David Dalton
83e3f830e6 Rename useNativeBind and useNativeKeys to isBindFast and isKeysFast.
Former-commit-id: 9f001b030dc49146b177678443406720c436ac0b
2012-07-08 02:47:01 -04:00
John-David Dalton
04d4353c0f Optimize object iteration using Object.keys where faster than for-in loops.
Former-commit-id: 8826f75cf6eaf4233758684e3aae2ccdc3c9f262
2012-07-08 02:04:57 -04:00
John-David Dalton
6d217fc097 Add propertyIsEnumerable check to _.keys.
Former-commit-id: 1dcd532d29b3e99ce54a18f4489c766652d56d83
2012-07-06 14:14:44 -04:00
John-David Dalton
9d7136c63c Add more checks to the reComplexDelimiter regexp.
Former-commit-id: 87fba2813619882d388261a1226e75503ec9b8d0
2012-07-05 15:04:09 -04:00
John-David Dalton
51a679d60a Add _.template unit test to ensure complex "interpolate" delimiters work.
Former-commit-id: bdfdbf00b1a1838e104919214012a9cfb39dda19
2012-07-05 13:19:45 -04:00
John-David Dalton
7d4d28614a Remove more unnecessary code from custom builds.
Former-commit-id: 7df2ebc805072456b9f0565a0a33fc1bcf2a4049
2012-07-05 11:51:40 -04:00
John-David Dalton
c75cfaf692 Update minified build and documentation.
Former-commit-id: 401c87b9755301440d2c86f7bfe618cc68db7e1e
2012-07-05 11:29:28 -04:00
John-David Dalton
fe6aa8a6fc Further optimize _.template by controlling how the with-statement is inserted.
Former-commit-id: a62331e771302f9390d5aca04f878b839fe11b69
2012-07-05 11:28:41 -04:00
John-David Dalton
a5fe1eb5fb Optimize how with-statements are inserted into compiled templates.
Former-commit-id: aabb0b1f8c6e910532464b7a007767801c00a640
2012-07-04 20:07:25 -04:00
John-David Dalton
5afd37c92c Update package.json and .npmignore to allow build.js.
Former-commit-id: 782a448163baa27275ca87da209db53441bdcb08
2012-07-04 20:06:35 -04:00
John-David Dalton
293d0409c6 Remove Cloning this repo from the README.md.
Former-commit-id: 4f95f8b9a6781b5b6207a95082415f97e4d4236b
2012-07-03 12:06:14 -04:00
John-David Dalton
4352f18dd3 Cleanup perf.js.
Former-commit-id: 53285a24dcb27857a05b07aa7a6a8840026f8c42
2012-07-02 17:59:09 -04:00
John-David Dalton
0ae7fe9df5 Add non-submodule vendor directory.
Former-commit-id: 392cdade55487e774e959013d8d25ae0b1dfe93b
2012-07-02 15:35:36 -04:00
John-David Dalton
5048f0422d Delete vendor directory.
Former-commit-id: 3d866435290966ec2f0d00561dcd99d0dfad29e0
2012-07-02 15:31:27 -04:00
John-David Dalton
c46a36f8ed Remove submodules and cleanup repo.
Former-commit-id: f3950601f2001ceb4f36db2a7f2efa28acc8472d
2012-07-02 15:22:48 -04:00
John-David Dalton
90e2bd0372 Correct variable declaration order.
Former-commit-id: 5f5a36057b065799dcc05b0054a2c88f00fad8c0
2012-07-02 03:43:01 -04:00
John-David Dalton
10fbc8a04b Update minified build and documentation.
Former-commit-id: 03b6f5fdf71ab1dab48f3fb06d60b6ec8a8e494c
2012-07-02 03:01:03 -04:00
John-David Dalton
fb818f3775 Cleanup lodash.js.
Former-commit-id: a1b7dc187dbd562b62d3446ce731674e0bb539d9
2012-07-02 03:00:01 -04:00
John-David Dalton
434e23c209 Add _.template benchmarks.
Former-commit-id: 97c5a90825d6a9a0b876d8c9f90e621f00389766
2012-07-02 02:59:33 -04:00
John-David Dalton
fe53bd6475 Fix build for _.bind.
Former-commit-id: 59ef841bca271bed05555c4b40e32b85ee1a4d37
2012-07-02 00:26:16 -04:00
John-David Dalton
268ce91c65 Add _.bind and _.size benchmarks.
Former-commit-id: bb3517e9517db81de56e3794abc256cd2dac59b5
2012-07-02 00:07:55 -04:00
John-David Dalton
3b4074bfc7 Optimize _.template when no evaluate delimiters are used and optimize _.bind when partially applied in V8.
Former-commit-id: 25489d41ba3cac7ac3f1414e09f1971a11a779be
2012-07-02 00:07:22 -04:00
John-David Dalton
6af4652161 Optimize inlining the iteratorTemplate for builds.
Former-commit-id: 8b7ac4622e51dbe5c0364f3c6781aa474dcfa96e
2012-06-30 03:06:21 -04:00
John-David Dalton
3717d30188 Update Backbone and Underscore submodules.
Former-commit-id: 0cdf988c89269ff95eb0d7fbd0bc51cbe95d3524
2012-06-29 20:41:51 -04:00
John-David Dalton
4cf2e83418 Add _.zipObject.
Former-commit-id: 0fe17adc359fbc608025dced32f6dd509d019413
2012-06-29 20:41:12 -04:00
John-David Dalton
1228639103 Cleanup build.js.
Former-commit-id: 01f5488ddba9f51344561c8df493d4f1bc6b0ef9
2012-06-29 19:33:36 -04:00
John-David Dalton
e12d67de94 Update minified build and documentation.
Former-commit-id: f4c5987a37d5c22f9705495e3a49a497f009d01c
2012-06-29 19:09:13 -04:00
John-David Dalton
10bcb37ca5 Inline more functionality into _.sortBy.
Former-commit-id: 6549e86881b7a93d96854a9ac1b04f0f5a5db0f1
2012-06-29 19:07:05 -04:00
John-David Dalton
e973598bff DRY out isType methods and simplify templates during the build process.
Former-commit-id: cd982282a5de63fddc36d1dc4759c8982e1c5ad4
2012-06-29 19:05:30 -04:00
John-David Dalton
3a5129694d Update documentation and minified build.
Former-commit-id: 193568c6f99736971ef93f9c4d63bc72195b8b2b
2012-06-29 04:03:02 -04:00
John-David Dalton
a1e0fbea8b Add issue reference to README.md.
Former-commit-id: 09ed4e386b55f657d8710f40c14fb3b283d66b7c
2012-06-29 04:01:58 -04:00
John-David Dalton
0bf374454e Add scripts entry to package.json.
Former-commit-id: 9ab2b915ea8aa6c3b8c28b5d14eaa32613db7ed0
2012-06-29 04:00:35 -04:00
John-David Dalton
5e592fbf29 Merge branch 'master' of github.com:bestiejs/lodash
Former-commit-id: a4de2b320b871d2bfd689890fc526605215091bf
2012-06-29 03:58:54 -04:00
John-David Dalton
ad4101bc99 Optimize _.sortBy and remove the _.map dependency from _.sortBy.
Former-commit-id: f6a133f0d27e7a00cb54e2e8478066dcfbe05659
2012-06-29 03:11:31 -04:00
John-David Dalton
2d057d92cf Merge pull request #38 from davidmurdoch/00d1cc9bf84355f35268d24201e02feaec6a00b1 [formerly d387147685f95cf88a437e678c873181cbcb907f]
Use `null` when comparing `null`/`undefined`.

Former-commit-id: 16c513648279e37a72eb433bd9b5fbe840854376
2012-06-28 22:21:18 -07:00
David Murdoch
00d1cc9bf8 Use null when comparing null/undefined
for non-strict equals. Saves 2 gzipped bytes.


Former-commit-id: d387147685f95cf88a437e678c873181cbcb907f
2012-06-28 09:56:10 -04:00
David Murdoch
2c1ec5fe75 Save 2 gzipped bytes by flipping args in math.max
Also, remove some stray whitespace.


Former-commit-id: 98b4711bc7d978ef66a693593d6be108f6bcfd8d
2012-06-28 09:45:14 -04:00
John-David Dalton
81b28d005d Remove arguments object from _.range.
Former-commit-id: d3da531e33bcd00a00ff80986f56196ac1b6f2c5
2012-06-27 13:51:46 -04:00
John-David Dalton
6a90616b99 Cleanup README.md.
Former-commit-id: 1a07361430f1d20382beb277db17e94967fd791d
2012-06-26 04:08:11 -04:00
John-David Dalton
d5be43695a Merge pull request #35 from tomByrer/master
Add CDN and jsPerf links to README.md.

Former-commit-id: b2ba93fb493536060c9abb13f406db9fd84d0ea4
2012-06-26 00:31:43 -07:00
John-David Dalton
0a93b81ae7 Update minified build and documentation.
Former-commit-id: 3b2d6cbd0c91933043c64b6f15a4c990a5c400c5
2012-06-26 03:28:08 -04:00
John-David Dalton
65f8da1654 Make _.size work consistently cross-browser with arguments objects and avoid erroring when falsey values are passed.
Former-commit-id: 76dc852a4e1fd84218f9c57f44c93e483a3680d9
2012-06-26 03:23:53 -04:00
John-David Dalton
911014db95 Avoid compiling unnecessary _.template code.
Former-commit-id: 74006fd2df2b5d2ba8a222baf21574f729f34bcb
2012-06-26 02:32:43 -04:00
John-David Dalton
313ee13f18 Move _.groupBy and _.sortBy back to the "Collections" category. [closes #34]
Former-commit-id: ce0f7f906758ce13cc2ea927520ac401e6bba9f6
2012-06-26 02:18:44 -04:00
tomByrer
addad04c44 Update master
Former-commit-id: c61735bdbf4dbad6dfd15a03660901fca9043327
2012-06-19 20:34:28 -06:00
tomByrer
e3789e5b64 merged tests with Dive in section
Former-commit-id: 1b32a93390d9b806bd66a298d558e68588ba7574
2012-06-19 20:32:49 -06:00
tomByrer
410315ce35 + CDN usage link
+ testing links

Former-commit-id: 79740ec7b2ac8c088545ca585ab5d3d94c804e2a
2012-06-19 20:23:58 -06:00
tomByrer
90998da308 + cdn js' hosting
Former-commit-id: 4276796f0fa31602060860da9c45c43dce34e8c4
2012-06-19 19:53:50 -06:00
John-David Dalton
6fa5b13e10 Add comment explaining a V8 optimization.
Former-commit-id: 733f0985509467291287e1e0a95fcd22114cdbcf
2012-06-19 11:42:27 +02:00
John-David Dalton
93067c2d52 Update documentation and minified build.
Former-commit-id: 156cdcff42eb4fef4a982e5b3016030246ba9f63
2012-06-19 10:56:05 +02:00
John-David Dalton
b2079b7007 Leverage _.indexOf's fromIndex in _.difference and _.without.
Former-commit-id: 0fd092d2ee109b99a50791899e7f2d690b3852af
2012-06-19 10:54:23 +02:00
John-David Dalton
b643dd074c Clarify benchmark descriptions.
Former-commit-id: 79c71d7d2c034ebe31f20f5d10251a8ba175cfd8
2012-06-16 20:35:55 -04:00
John-David Dalton
a3932c75e1 Move screencast links to Vimeo.
Former-commit-id: d9f48294d88ff50889c0859b3c1956d0e49a3bd4
2012-06-16 09:34:36 -04:00
John-David Dalton
1cd3b9ec47 Add 3rd screencast link to README.md.
Former-commit-id: c714180beab13c911f9d1676cb65117186a9524a
2012-06-15 17:21:45 -04:00
John-David Dalton
0c77f42080 Fix documentation typo, s/uiq/uniq. [closes #32] [cheeaun]
Former-commit-id: 343ff0d9a7238ab7eec6d5cc75b5c7dff3de1925
2012-06-15 09:12:03 -04:00
John-David Dalton
cea122db38 Update submodules.
Former-commit-id: 53394993a20cacf965de52e382ff72399d2b89ad
2012-06-15 00:12:06 -04:00
John-David Dalton
966f9fcd07 Update unit test link in README.md.
Former-commit-id: 0c11e69795cd0a28f0b370c40b7a6197fe712d0a
2012-06-14 15:30:37 -04:00
John-David Dalton
6ce9df8504 Bump to v0.3.2.
Former-commit-id: ff3cac0ce890b46a45c8738d559f68ac63b80caf
2012-06-14 15:19:09 -04:00
John-David Dalton
2a0b223896 Simplify dependencies in build.js.
Former-commit-id: 2d154d1dfb4d639aa32c5e9aeaeea6942965aee7
2012-06-14 02:17:09 -04:00
John-David Dalton
c2db180829 Tweak _.sortedIndex for Chrome optimizations.
Former-commit-id: d1d9f1bd1ecfd3bcde98aa51423e05e128f6ffd4
2012-06-14 01:06:08 -04:00
John-David Dalton
3223e4ffa5 Update documentation and minified build.
Former-commit-id: 5472dccceb33c3575c538190472dde0e82bcfcde
2012-06-14 00:29:14 -04:00
John-David Dalton
24c9b6e211 Move _.pluck and _.invoke back to the "Collections" category and optimize _.sortedIndex when a callback is passed.
Former-commit-id: d16763e7d35660d8ba9ea976c8b2a4dc20f1211f
2012-06-14 00:28:36 -04:00
John-David Dalton
e5555dd26a Move _.tap to the "Chaining" category, and deprecate _(…).chain, _.isNull, _.isUndefined, _.result, and _.size.
Former-commit-id: 64ee67758b8730fd70cbb28af4230bb336b91214
2012-06-13 15:26:46 -04:00
John-David Dalton
ee2d0ddf8a Ensure custom builds generate lodash.custom files.
Former-commit-id: c89ee640688f6f598bb2d3834f714f0edc4ce7a4
2012-06-13 15:15:20 -04:00
John-David Dalton
aef130b396 Update submodules.
Former-commit-id: 801d3c7413cb5906b4a517639098a6a32d015cba
2012-06-13 00:21:03 -04:00
John-David Dalton
fbdadec5e5 Add _.throttle unit test for recursive calls.
Former-commit-id: 7208516b56905c83df73aef6b02cee0101602349
2012-06-12 23:53:03 -04:00
John-David Dalton
a068339079 Indicate slow paths in perf.js.
Former-commit-id: 561e4f0957934b25422f7f515678705be4af726f
2012-06-12 23:44:21 -04:00
John-David Dalton
3f07d3ec55 Remove the useSourceURL variable from the minified build.
Former-commit-id: c0f02e7e87c533220a99ebe99c9ee08516fb9deb
2012-06-12 20:15:52 -04:00
John-David Dalton
62e7da9d8a Update docs and minified build.
Former-commit-id: d0673323dc850f4e7936f00374905cd29c5d6e24
2012-06-12 19:29:01 -04:00
John-David Dalton
b60d43e5f6 Ensure sourceURL support doesn't cause errors in Adobe's JS engine.
Former-commit-id: 2ad1214e6a58832c732499b272ebfc434953213b
2012-06-12 19:28:47 -04:00
John-David Dalton
a5873a3158 Add comments, documentation, and update the minified build.
Former-commit-id: c65665063f254b1ba9dab9c6948fedf29f1e795f
2012-06-11 22:49:24 -04:00
John-David Dalton
3a698eb0ed Make _.escape match _.template's escape delimiter results for null and undefined values.
Former-commit-id: b6717c6debf3bc308cf12b778916f5a46dbb954d
2012-06-11 22:37:54 -04:00
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
81 changed files with 50897 additions and 2364 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
*.custom.*
.DS_Store
dist/
node_modules/
node_modules/

24
.gitmodules vendored
View File

@@ -1,24 +0,0 @@
[submodule "vendor/benchmark.js"]
path = vendor/benchmark.js
url = git://github.com/bestiejs/benchmark.js.git
[submodule "vendor/docdown"]
path = vendor/docdown
url = git://github.com/jdalton/docdown.git
[submodule "vendor/qunit"]
path = vendor/qunit
url = git://github.com/jquery/qunit.git
[submodule "vendor/qunit-clib"]
path = vendor/qunit-clib
url = git://github.com/jdalton/qunit-clib.git
[submodule "vendor/requirejs"]
path = vendor/requirejs
url = git://github.com/jrburke/requirejs.git
[submodule "vendor/uglifyjs"]
path = vendor/uglifyjs
url = git://github.com/mishoo/UglifyJS.git
[submodule "vendor/underscore"]
path = vendor/underscore
url = git://github.com/documentcloud/underscore.git
[submodule "vendor/backbone"]
path = vendor/backbone
url = git://github.com/documentcloud/backbone.git

7
.jamignore Normal file
View File

@@ -0,0 +1,7 @@
*.custom.*
.*
dist/
doc/*.php
node_modules/
perf/*.sh
test/*.sh

View File

@@ -1,19 +1,16 @@
*.custom.*
*.min.*
.*
build.*
build/
dist/
doc/*.php
node_modules/
perf/*.html
perf/*.sh
test/*.html
test/*-ui.js
test/*.sh
vendor/backbone/
vendor/closure-compiler/
vendor/docdown/
vendor/firebug-lite/
vendor/qunit/qunit/*.css
vendor/requirejs/
vendor/uglifyjs/
vendor/underscore/
vendor/underscore/test/

260
README.md
View File

@@ -1,12 +1,21 @@
# Lo-Dash <sup>v0.2.1</sup>
# Lo-Dash <sup>v0.5.0</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](https://github.com/bestiejs/lodash#closed-underscorejs-issues), and [additional features](https://github.com/bestiejs/lodash#features).
A drop-in replacement<sup>[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer)</sup> for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues-20), 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.
## Download
* [Development source](https://raw.github.com/bestiejs/lodash/v0.5.0/lodash.js)
* [Production source](https://raw.github.com/bestiejs/lodash/v0.5.0/lodash.min.js)
* CDN copies of ≤ [v0.4.2](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.4.2/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/)
* For optimal performance, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need
## 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).
Create your own benchmarks at [jsPerf](http://jsperf.com), or [search](http://jsperf.com/search?q=lodash) for existing ones.
For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/lodash/wiki/Roadmap).
@@ -14,41 +23,100 @@ For a list of upcoming features, check out our [roadmap](https://github.com/best
For more information check out these screencasts over Lo-Dash:
* [Introducing Lo-Dash](http://dl.dropbox.com/u/513327/allyoucanleet/post/20/file/screencast.mp4)
* [Optimizations and custom builds](http://dl.dropbox.com/u/513327/allyoucanleet/post/21/file/screencast.mp4)
* [Introducing Lo-Dash](https://vimeo.com/44154599)
* [Lo-Dash optimizations and custom builds](https://vimeo.com/44154601)
* [Lo-Dashs origin and why its a better utility belt](https://vimeo.com/44154600)
* [Unit testing in Lo-Dash](https://vimeo.com/45865290)
## Features
* AMD loader support
* [_.bind](http://lodash.com/docs#_bindfunc--arg1-arg2-) 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
* [_.forEach](http://lodash.com/docs#_foreachcollection-callback--thisarg) is chainable
* [_.groupBy](http://lodash.com/docs#_groupbycollection-callback--thisarg) accepts a third, `thisArg`, argument
* [_.partial](http://lodash.com/docs#_partialfunc--arg1-arg2-) for more functional fun
* [_.size](http://lodash.com/docs#_sizecollection) supports returning the `length` of string values
* AMD loader support ([RequireJS](http://requirejs.org/), [curl.js](https://github.com/cujojs/curl), etc.)
* [_.bind](http://lodash.com/docs#bind) supports *"lazy"* binding
* [_.clone](http://lodash.com/docs#clone) supports *"deep"* cloning
* [_.countBy](http://lodash.com/docs#countBy) as a compainion function for [_.groupBy](http://lodash.com/docs#groupBy) and [_.sortBy](http://lodash.com/docs#sortBy)
* [_.debounce](http://lodash.com/docs#debounce)ed functions match [_.throttle](http://lodash.com/docs#throttle)ed functions return value behavior
* [_.drop](http://lodash.com/docs#drop) for the inverse functionality of [_.pick](http://lodash.com/docs#pick)
* [_.forEach](http://lodash.com/docs#forEach) is chainable and supports exiting iteration early
* [_.forIn](http://lodash.com/docs#forIn) for iterating over an objects own and inherited properties
* [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an objects own properties
* [_.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
* [_.merge](http://lodash.com/docs#merge) for a *"deep"* [_.extend](http://lodash.com/docs#extend)
* [_.partial](http://lodash.com/docs#partial) for partial application without `this` binding
* [_.template](http://lodash.com/docs#template) utilizes [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier debugging
* [_.where](http://lodash.com/docs#where) for filtering collections by contained properties
* [_.zipObject](http://lodash.com/docs#zipObject) for composing objects
* [_.contains](http://lodash.com/docs#contains), [_.size](http://lodash.com/docs#size), [_.toArray](http://lodash.com/docs#toArray),
[and more…](http://lodash.com/docs "_.every, _.filter, _.find, _.forEach, _.groupBy, _.invoke, _.map, _.pluck, _.reduce, _.reduceRight, _.reject, _.some, _sortBy") accept strings
## 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-21, Firefox 1.5-13, IE 6-9, Opera 9.25-12.01, Safari 3-6, Node.js 0.4.8-0.8.7, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5.
## Custom builds
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.
Custom builds may be created in two ways:
* Backbone builds, containing all methods required by Backbone, may be created using the `backbone` modifier argument.
```bash
lodash backbone
```
1. Use the`include` argument to pass the names of the methods to include in the build.
~~~ bash
node build include=each,filter,map,noConflict
node build include="each, filter, map, noConflict"
~~~
* CSP builds, supporting default Content Security Policy restrictions, may be created using the `csp` modifier argument.
```bash
lodash csp
```
2. Use the `exclude` argument to pass the names of the methods to exclude from the build.
~~~ bash
node build exclude=isNaN,isUndefined,union,zip
node build exclude="isNaN, isUndefined, union, zip"
~~~
* Legacy builds, tailored for older browsers without [ES5 support](http://es5.github.com/), may be created using the `legacy` modifier argument.
```bash
lodash legacy
```
* Mobile builds, with IE < 9 bug fixes and method compilation removed, may be created using the `mobile` modifier argument.
```bash
lodash mobile
```
* Strict builds, with `_.bindAll`, `_.defaults`, and `_.extend` in [strict mode](http://es5.github.com/#C), may be created using the `strict` modifier argument.
```bash
lodash strict
```
* Underscore builds, containing only methods included in Underscore, may be created using the `underscore` modifier argument.
```bash
lodash underscore
```
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
lodash category=collections,functions
lodash category="collections, functions"
```
2. Use the `exclude` argument to pass the names of methods to exclude from the build.
```bash
lodash exclude=union,uniq,zip
lodash exclude="union, uniq, zip"
```
3. Use the `include` argument to pass the names of methods to include in the build.
```bash
lodash include=each,filter,map
lodash include="each, filter, map"
```
All arguments, except `backbone` with `underscore`, `exclude` with `include`, and `legacy` with `csp`/`mobile`, may be combined.
```bash
lodash backbone legacy category=utilities exclude=first,last
lodash underscore mobile strict category=functions include=pick,uniq
```
The `lodash` command-line utility is available when Lo-Dash is installed as a global package (i.e. `npm install -g lodash`).
Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`.
@@ -56,37 +124,38 @@ Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`.
In browsers:
~~~ html
```html
<script src="lodash.js"></script>
~~~
```
Using [npm](http://npmjs.org/):
~~~ bash
```bash
npm install lodash
~~~
npm install -g lodash
```
In [Node.js](http://nodejs.org/) and [RingoJS v0.8.0+](http://ringojs.org/):
~~~ js
```js
var _ = require('lodash');
~~~
```
In [Narwhal](http://narwhaljs.org/) and [RingoJS v0.7.0-](http://ringojs.org/):
In [RingoJS v0.7.0-](http://ringojs.org/):
~~~ js
```js
var _ = require('lodash')._;
~~~
```
In [Rhino](http://www.mozilla.org/rhino/):
~~~ js
```js
load('lodash.js');
~~~
```
In an AMD loader like [RequireJS](http://requirejs.org/):
~~~ js
```js
require({
'paths': {
'underscore': 'path/to/lodash'
@@ -95,37 +164,41 @@ require({
['underscore'], function(_) {
console.log(_.VERSION);
});
~~~
```
## Cloning this repo
## Resolved Underscore.js issues <sup>(20+)</sup>
To clone this repository including all submodules, using Git 1.6.5 or later:
~~~ bash
git clone --recursive https://github.com/bestiejs/lodash.git
cd lodash.js
~~~
For older Git versions, just use:
~~~ bash
git clone https://github.com/bestiejs/lodash.git
cd lodash
git submodule update --init
~~~
## Closed Underscore.js issues
* Ensure `_.groupBy` adds values to own, not inherited, properties [[test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L229-236)]
* Ensure `_.throttle` works when called in tight loops [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L436-446)]
* Fix Firefox, IE, Opera, and Safari object iteration bugs [[#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L152-172), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L206-213), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L255-257), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L265-267), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L285-292), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L386-388)]
* 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), [#659](https://github.com/documentcloud/underscore/issues/659), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L544-550)]
* Ensure array-like objects with invalid `length` properties are treated like regular objects [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L491-501)]
* Ensure *"Arrays"* methods allow falsey `array` arguments [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1487-1525)]
* Ensure *"Collections"* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L503-521)]
* Ensure templates compiled with errors are inspectable [[#666](https://github.com/documentcloud/underscore/issues/666), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1232-1235)]
* Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L555-580)]
* 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/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L77-83)]
* Register as AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L61-75)]
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L74-77)]
* `_isNaN(new Number(NaN))` should return `true` [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L95-99)]
* `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L106-116)]
* `_.size` should return the `length` of string values [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L121-127)]
* 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/v0.5.0/test/test.js#L117-123)]
* Register as an AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L101-115)]
* `_(…)` should return passed wrapper instances [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L135-138)]
* `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L197-212)]
* `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L267-276)]
* `_.escape` should return an empty string when passed `null` or `undefined` [[#427](https://github.com/documentcloud/underscore/issues/427), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L367-370)]
* `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L882-955)]
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L486-489)]
* `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L582-601)]
* `_.groupBy` should add values to own, not inherited, properties [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L616-623)]
* `_.isEmpty` and `_.size` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L716-721)]
* `_.isEqual` should return `true` for like-objects from different documents [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L757-777)]
* `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L785-797)]
* `_.isNaN(new Number(NaN))` should return `true` [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L805-807)]
* `_.keys` and `_.size` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [#653](https://github.com/documentcloud/underscore/issues/653), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L817-819)]
* `_.once` should free the given function for garbage collection [[#693](https://github.com/documentcloud/underscore/pull/693)]
* `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1042-1045)]
* `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1053-1067)]
* `_.size` should return the `length` of string values [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1112-1114)]
* `_.size` shouldnt error on falsey values [[#650](https://github.com/documentcloud/underscore/pull/650), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1116-1123)]
* `_.sortedIndex` should support arrays with high `length` values [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1202-1211)]
* `_.template` should not augment the `options` object [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1226-1230)]
* `_.throttle` should work when called in a loop [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1322-1332)]
* `_.zipObject` should accept less than two arguments [[test](https://github.com/bestiejs/lodash/blob/v0.5.0/test/test.js#L1449-1451)]
## Optimized methods <sup>(50+)</sup>
@@ -150,10 +223,14 @@ git submodule update --init
* `_.indexOf`
* `_.intersection`
* `_.invoke`
* `_.isArguments`
* `_.isDate`
* `_.isEmpty`
* `_.isEqual`
* `_.isFinite`
* `_.isFunction`
* `_.isObject`
* `_.isNumber`
* `_.isRegExp`
* `_.isString`
* `_.keys`
* `_.lastIndexOf`
@@ -173,6 +250,7 @@ git submodule update --init
* `_.sortedIndex`
* `_.template`
* `_.throttle`
* `_.times`
* `_.toArray`
* `_.union`
* `_.uniq`, `_.unique`
@@ -180,42 +258,30 @@ git submodule update --init
* `_.without`
* `_.wrap`
* `_.zip`
* plus all `_(...)` method wrappers
* plus all `_()` method wrappers
## Changelog
## Release Notes
### <sup>v0.2.1</sup>
### <sup>v0.5.0</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`
* Added [_.countBy](http://lodash.com/docs#countBy), [_.drop](http://lodash.com/docs#drop), [_.merge](http://lodash.com/docs#merge), and [_.where](http://lodash.com/docs#where)
* Added `csp` *(Content Security Policy)* and `underscore` build options
* Added `deep` cloning support to `_.clone`
* Added [Jam](http://jamjs.org/) package support
* Added support for exiting `_.forEach`, `_.forIn`, and `_.forOwn` early by returning `false` in the `callback`
* Added support for jQuery/MooTools DOM query collections to `_.isEmpty` and `_.size`
* Ensured development build works with IE conditional compilation enabled
* Ensured `_.clone` doesn't clone functions, DOM nodes, `arguments` objects, and objects created by constructors other than `Object`
* Ensured `_.filter`s `callback` can't modify result values
* Ensured `_.isEmpty`, `_.isEquals`, and `_.size` support `arguments` objects
* Ensured `_.isEqual` doesn't inspect DOM nodes, works with objects from other documents, and calls custom `isEqual` methods before checking strict equality
* Ensured `_.once` frees the given function for garbage collection
* Ensured `_.sortBy` performs a stable sort
* Ensured `reEvaluateDelimiter` is assigned when `_.templateSettings.evaluate` is undefined
* Made `_.range` coerce arguments to numbers
* Optimized `_.isFunction`
### <sup>v0.2.0</sup>
* Added custom build options
* Added default `_.templateSettings.variable` value
* Added *"lazy bind"* support to `_.bind`
* Added native method overwrite detection to avoid bad native shims
* Added support for more AMD build optimizers and aliasing as the *"underscore"* module
* Added `thisArg` argument to `_.groupBy`
* Added whitespace to compiled strings
* Added `_.partial` method
* Commented the `iterationFactory` options object
* Ensured `_.max` and `_.min` support extremely large arrays
* 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.
* Made `_.debounce`ed functions match `_.throttle`ed functions return value behavior
* Made `_.escape` no longer translate the *">"* character
* Fixed `clearTimeout` typo
* Simplified all methods in the *"Arrays"* category
* Optimized `_.debounce`, `_.escape`, `_.flatten`, `_.forEach`, `_.groupBy`, `_.intersection`, `_.invoke`, `_.isObject`, `_.max`, `_.min`, `_.pick`, `_.shuffle`, `_.sortedIndex`, `_.template`, `_.throttle`, `_.union`, `_.uniq`
### <sup>v0.1.0</sup>
* Initial release
The full changelog is available [here](https://github.com/bestiejs/lodash/wiki/Changelog).
## BestieJS

946
build.js

File diff suppressed because it is too large Load Diff

View File

@@ -35,8 +35,8 @@
/*--------------------------------------------------------------------------*/
/**
* The exposed `minify` function minifies a given `source` and invokes the
* `onComplete` callback when finished.
* The exposed `minify` function minifies a given Lo-Dash `source` and invokes
* the `onComplete` callback when finished.
*
* @param {String} source The source to minify.
* @param {String} workingName The name to give temporary files creates during the minification process.
@@ -58,7 +58,10 @@
function Minify(source, workingName, onComplete) {
// create the destination directory if it doesn't exist
if (!fs.existsSync(distPath)) {
fs.mkdirSync(distPath);
// avoid errors when called as a npm executable
try {
fs.mkdirSync(distPath);
} catch(e) { }
}
this.compiled = {};
@@ -291,17 +294,20 @@
name = this.workingName,
uglified = this.uglified;
// save the Closure Compiled version to disk
fs.writeFileSync(path.join(distPath, name + '.compiler.js'), compiled.source);
fs.writeFileSync(path.join(distPath, name + '.compiler.js.gz'), compiled.gzip);
// avoid errors when called as a npm executable
try {
// save the Closure Compiled version to disk
fs.writeFileSync(path.join(distPath, name + '.compiler.js'), compiled.source);
fs.writeFileSync(path.join(distPath, name + '.compiler.js.gz'), compiled.gzip);
// save the Uglified version to disk
fs.writeFileSync(path.join(distPath, name + '.uglify.js'), uglified.source);
fs.writeFileSync(path.join(distPath, name + '.uglify.js.gz'), uglified.gzip);
// save the Uglified version to disk
fs.writeFileSync(path.join(distPath, name + '.uglify.js'), uglified.source);
fs.writeFileSync(path.join(distPath, name + '.uglify.js.gz'), uglified.gzip);
// save the hybrid minified version to disk
fs.writeFileSync(path.join(distPath, name + '.hybrid.js'), hybrid.source);
fs.writeFileSync(path.join(distPath, name + '.hybrid.js.gz'), hybrid.gzip);
// save the hybrid minified version to disk
fs.writeFileSync(path.join(distPath, name + '.hybrid.js'), hybrid.source);
fs.writeFileSync(path.join(distPath, name + '.hybrid.js.gz'), hybrid.gzip);
} catch(e) { }
// select the smallest gzipped file and use its minified counterpart as the
// official minified release (ties go to Closure Compiler)
@@ -324,9 +330,9 @@
module.exports = minify;
}
else {
// read the JavaScript source file from the first argument if the script
// read the Lo-Dash source file from the first argument if the script
// was invoked directly (e.g. `node minify.js source.js`) and write to
// the same file
// `<filename>.min.js`
(function() {
var filePath = process.argv[2],
dirPath = path.dirname(filePath),
@@ -334,7 +340,7 @@
workingName = path.basename(filePath, '.js') + '.min';
minify(source, workingName, function(result) {
fs.writeFileSync(path.join(dirPath, workingName + '.js'), result);
fs.writeFileSync(path.join(dirPath, workingName + '.js'), result, 'utf8');
});
}());
}

View File

@@ -15,7 +15,7 @@
/*--------------------------------------------------------------------------*/
/**
* Post-process a given minified JavaScript `source`, preparing it for
* Post-process a given minified Lo-Dash `source`, preparing it for
* deployment.
*
* @param {String} source The source to process.
@@ -34,14 +34,11 @@
// move vars exposed by Closure Compiler into the IIFE
source = source.replace(/^([^(\n]+)\s*(\(function[^)]+\){)/, '$2$1');
// use double quotes consistently
source = source.replace(/'use strict'/, '"use strict"');
// unescape properties (i.e. foo["bar"] => foo.bar)
source = source.replace(/(\w)\["([^."]+)"\]/g, '$1.$2');
// correct AMD module definition for AMD build optimizers
source = source.replace(/("function")==(typeof define)&&\(?("object")==(typeof define\.amd)(&&define\.amd)\)?/, '$2==$1&&$4==$3$5');
source = source.replace(/("function")\s*==\s*(typeof define)\s*&&\s*\(?\s*("object")\s*==\s*(typeof define\.amd)\s*&&\s*(define\.amd)\s*\)?/, '$2==$1&&$4==$3&&$5');
// add license
source = license + '\n;' + source;
@@ -56,7 +53,7 @@
if (module != require.main) {
module.exports = postprocess;
} else {
// read the JavaScript source file from the first argument if the script
// read the Lo-Dash source file from the first argument if the script
// was invoked directly (e.g. `node post-compile.js source.js`) and write to
// the same file
(function() {

View File

@@ -7,34 +7,69 @@
/** Used to minify variables embedded in compiled strings */
var compiledVars = [
'accumulator',
'arrayClass',
'bind',
'callback',
'className',
'collection',
'concat',
'ctor',
'false',
'funcClass',
'hasOwnProperty',
'identity',
'index',
'iteratee',
'iteratorBind',
'length',
'nativeKeys',
'object',
'objectTypes',
'noaccum',
'property',
'ownIndex',
'ownProps',
'prop',
'propertyIsEnumerable',
'propIndex',
'props',
'result',
'skipProto',
'source',
'sourceIndex',
'slice',
'stringClass',
'target',
'thisArg',
'toString',
'true',
'undefined',
'value'
'value',
// lesser used variables
'accumulator',
'args',
'argsIndex',
'argsLength',
'arrayLikeClasses',
'ArrayProto',
'bind',
'callee',
'className',
'compareAscending',
'destValue',
'forIn',
'found',
'funcs',
'indexOf',
'indicator',
'isArguments',
'isArr',
'isArray',
'isFunc',
'isFunction',
'isPlainObject',
'methodName',
'noaccum',
'objectClass',
'objectTypes',
'pass',
'properties',
'property',
'propsLength',
'recursive',
'source',
'stack',
'stackLength',
'target',
'valueProp'
];
/** Used to minify `compileIterator` option properties */
@@ -46,30 +81,36 @@
'bottom',
'exit',
'firstArg',
'hasExp',
'hasDontEnumBug',
'inLoop',
'init',
'iteratedObject',
'loopExp',
'isKeysFast',
'object',
'objectBranch',
'noArgsEnum',
'noCharByIndex',
'shadowed',
'top',
'useHas'
'useHas',
'useStrict'
];
/** Used to minify variables and string values to a single character */
var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
minNames.push.apply(minNames, minNames.map(function(value) {
return value + value;
}));
/** Used protect the specified properties from getting minified */
/** Used to protect the specified properties from getting minified */
var propWhitelist = [
'_',
'_chain',
'_wrapped',
'after',
'all',
'amd',
'any',
'attachEvent',
'bind',
'bindAll',
'chain',
@@ -79,6 +120,7 @@
'compact',
'compose',
'contains',
'countBy',
'criteria',
'debounce',
'defaults',
@@ -86,6 +128,7 @@
'delay',
'detect',
'difference',
'drop',
'each',
'environment',
'escape',
@@ -100,12 +143,15 @@
'foldl',
'foldr',
'forEach',
'forIn',
'forOwn',
'functions',
'groupBy',
'has',
'head',
'identity',
'include',
'index',
'indexOf',
'initial',
'inject',
@@ -136,6 +182,7 @@
'map',
'max',
'memoize',
'merge',
'methods',
'min',
'mixin',
@@ -175,15 +222,17 @@
'values',
'variable',
'VERSION',
'where',
'without',
'wrap',
'zip'
'zip',
'zipObject'
];
/*--------------------------------------------------------------------------*/
/**
* Pre-process a given JavaScript `source`, preparing it for minification.
* Pre-process a given Lo-Dash `source`, preparing it for minification.
*
* @param {String} source The source to process.
* @returns {String} Returns the processed source.
@@ -192,48 +241,132 @@
// remove copyright to add later in post-compile.js
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, '');
// manually convert `arrayLikeClasses` property assignments because
// Closure Compiler errors trying to minify them
source = source.replace(/(arrayLikeClasses =)[\s\S]+?= *true/,
"$1{'[object Arguments]': true, '[object Array]': true, '[object Boolean]': false, " +
"'[object Date]': false, '[object Function]': false, '[object Number]': false, " +
"'[object Object]': false, '[object RegExp]': false, '[object String]': true }"
);
// manually convert `cloneableClasses` property assignments because
// Closure Compiler errors trying to minify them
source = source.replace(/(cloneableClasses =)[\s\S]+?= *true/,
"$1{'[object Arguments]': false, '[object Array]': true, '[object Boolean]': true, " +
"'[object Date]': true, '[object Function]': false, '[object Number]': true, " +
"'[object Object]': true, '[object RegExp]': true, '[object String]': true }"
);
// add brackets to whitelisted properties so Closure Compiler won't mung them
// http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']");
// remove brackets from `_.escape()` in `tokenizeEscape`
source = source.replace(/_\['escape']\("/, '_.escape("');
// remove brackets from `_.escape()` in `_.template`
source = source.replace(/__e *= *_\['escape']/, '__e=_.escape');
// remove brackets from `collection.indexOf` in `_.contains`
source = source.replace("collection['indexOf'](target)", 'collection.indexOf(target)');
// remove brackets from `result[length].value` in `_.sortBy`
source = source.replace("result[length]['value']", 'result[length].value');
// remove whitespace from string literals
source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) {
// avoids removing the '\n' of the `escapes` object
return string.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |'\\n'|\\\\n|\\n|\s+/g, function(match) {
// 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 match == false || match == '\\n' ? '' : match;
});
});
// minify `_.sortBy` internal properties
(function() {
var properties = ['criteria', 'value'],
snippet = (source.match(/( +)function sortBy\b[\s\S]+?\n\1}/) || 0)[0],
result = snippet;
// remove whitespace from `_.template` related regexes
source = source.replace(/(?:reDelimiterCode\w+|reEmptyString\w+|reInsertVariable) *=.+/g, function(match) {
return match.replace(/ |\\n/g, '');
});
if (snippet) {
// minify property strings
properties.forEach(function(property, index) {
result = result.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'");
});
// replace with modified snippet
source = source.replace(snippet, result);
// remove newline from double-quoted strings in `_.template`
source = source
.replace('"\';\\n__with ("', '"\';__with("')
.replace('"\\n}__\\n__p += \'"', '"}____p+=\'"')
.replace('"__p = \'"', '"__p=\'"')
.replace('"\';\\n"', '"\';"')
.replace("') {\\n'", "'){'")
// remove `useSourceURL` variable
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *try *\{(?:\s*\/\/.*)*\n *var useSourceURL[\s\S]+?catch[^}]+}\n/, '');
// remove debug sourceURL use in `_.template`
source = source.replace(/(?:\s*\/\/.*\n)* *if *\(useSourceURL[^}]+}/, '');
// minify internal properties used by 'compareAscending', `_.clone`, `_.merge`, and `_.sortBy`
(function() {
var properties = ['criteria', 'index', 'source', 'value'],
snippets = source.match(/( +)(?:function clone|function compareAscending|var merge|var sortBy)\b[\s\S]+?\n\1}/g);
if (!snippets) {
return;
}
snippets.forEach(function(snippet) {
var modified = snippet,
isCompilable = /(?:var merge|var sortBy)\b/.test(modified),
isInlined = !/\bcreateIterator\b/.test(modified);
// minify properties
properties.forEach(function(property, index) {
var reBracketProp = RegExp("\\['(" + property + ")'\\]", 'g'),
reDotProp = RegExp('\\.' + property + '\\b', 'g'),
rePropColon = RegExp("(')?\\b" + property + "\\1 *:", 'g');
if (isCompilable) {
// add quotes around properties in the inlined `_.merge` and `_.sortBy`
// of the mobile build so Closure Compiler won't mung them
if (isInlined) {
modified = modified
.replace(reBracketProp, "['" + minNames[index] + "']")
.replace(reDotProp, "['" + minNames[index] + "']")
.replace(rePropColon, "'" + minNames[index] + "':");
}
else {
modified = modified
.replace(reBracketProp, '.' + minNames[index])
.replace(reDotProp, '.' + minNames[index])
.replace(rePropColon, minNames[index] + ':');
}
}
else {
modified = modified
.replace(reBracketProp, "['" + minNames[index] + "']")
.replace(reDotProp, '.' + minNames[index])
.replace(rePropColon, "'" + minNames[index] + "':")
// correct `value.source` in regexp branch of `_.clone`
if (property == 'source') {
modified = modified.replace("value['" + minNames[index] + "']", "value['source']");
}
}
});
// replace with modified snippet
source = source.replace(snippet, modified);
});
}());
// minify all compilable snippets
var snippets = source.match(
RegExp([
// match the `iteratorTemplate`
'var iteratorTemplate\\b[\\s\\S]+?\\);\\n',
'( +)var iteratorTemplate\\b[\\s\\S]+?\\n\\1}',
// match methods created by `createIterator` calls
'createIterator\\((?:{|[a-zA-Z]+)[\\s\\S]+?\\);\\n',
// match variables storing `createIterator` options
'( +)var [a-zA-Z]+IteratorOptions\\b[\\s\\S]+?\\n\\1}',
'( +)var [a-zA-Z]+IteratorOptions\\b[\\s\\S]+?\\n\\2}',
// match the the `createIterator` function
'( +)function createIterator\\b[\\s\\S]+?\\n\\2}'
'( +)function createIterator\\b[\\s\\S]+?\\n\\3}'
].join('|'), 'g')
);
@@ -245,38 +378,26 @@
snippets.forEach(function(snippet, index) {
var isCreateIterator = /function createIterator\b/.test(snippet),
isIteratorTemplate = /var iteratorTemplate\b/.test(snippet),
result = snippet;
modified = snippet;
// add brackets to whitelisted properties so Closure Compiler won't mung them
result = result.replace(RegExp('\\.(' + iteratorOptions.join('|') + ')\\b', 'g'), "['$1']");
modified = modified.replace(RegExp('\\.(' + iteratorOptions.join('|') + ')\\b', 'g'), "['$1']");
if (isCreateIterator) {
// add `true` and `false` arguments to be minified
result = result
.replace(/(Function\(\s*'[\s\S]+?)undefined/, '$1true,false,undefined')
.replace(/factory\([^)]+/, '$&,true,false');
// replace with modified snippet early and clip snippet so other arguments
// aren't minified
source = source.replace(snippet, result);
snippet = result = result.replace(/factory\([\s\S]+$/, '');
// replace with modified snippet early and clip snippet to the `factory`
// call so other arguments aren't minified
source = source.replace(snippet, modified);
snippet = modified = modified.replace(/factory\([\s\S]+$/, '');
}
// minify snippet variables / arguments
compiledVars.forEach(function(variable, index) {
// ensure properties in compiled strings aren't minified
result = result.replace(RegExp('([^.]\\b)' + variable + '\\b(?!\' *[\\]:])', 'g'), '$1' + minNames[index]);
modified = modified.replace(RegExp('([^.]\\b)' + variable + '\\b(?!\' *[\\]:])', 'g'), '$1' + minNames[index]);
// correct `typeof x == 'object'`
if (variable == 'object') {
result = result.replace(RegExp("(typeof [^']+')" + minNames[index] + "'", 'g'), "$1object'");
}
// correct external boolean literals
else if (variable == 'true' || variable == 'false') {
result = result
.replace(RegExp(': *' + minNames[index] + ',', 'g'), ':' + variable + ',')
.replace(RegExp('\\b' + minNames[index] + ';', 'g'), variable + ';');
modified = modified.replace(RegExp("(typeof [^']+')" + minNames[index] + "'", 'g'), "$1object'");
}
});
@@ -284,26 +405,26 @@
iteratorOptions.forEach(function(property, index) {
if (isIteratorTemplate) {
// minify property names as interpolated template variables
result = result.replace(RegExp('\\b' + property + '\\b', 'g'), minNames[index]);
modified = modified.replace(RegExp('\\b' + property + '\\b', 'g'), minNames[index]);
}
else {
if (property == 'array' || property == 'object') {
// minify "array" and "object" sub property names
result = result.replace(RegExp("'" + property + "'( *[\\]:])", 'g'), "'" + minNames[index] + "'$1");
modified = modified.replace(RegExp("'" + property + "'( *[\\]:])", 'g'), "'" + minNames[index] + "'$1");
}
else {
// minify property name strings
result = result.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'");
// minify property names in regexps and accessors
modified = modified.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'");
// minify property names in regexes and accessors
if (isCreateIterator) {
result = result.replace(RegExp('([\\.|/])' + property + '\\b' , 'g'), '$1' + minNames[index]);
modified = modified.replace(RegExp('([\\.|/])' + property + '\\b' , 'g'), '$1' + minNames[index]);
}
}
}
});
// replace with modified snippet
source = source.replace(snippet, result);
source = source.replace(snippet, modified);
});
return source;
@@ -316,7 +437,7 @@
module.exports = preprocess;
}
else {
// read the JavaScript source file from the first argument if the script
// read the Lo-Dash source file from the first argument if the script
// was invoked directly (e.g. `node pre-compile.js source.js`) and write to
// the same file
(function() {

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@
// generate Markdown
$markdown = docdown(array(
'path' => '../' . $file,
'title' => 'Lo-Dash <sup>v0.2.1</sup>',
'title' => 'Lo-Dash <sup>v0.5.0</sup>',
'url' => 'https://github.com/bestiejs/lodash/blob/master/lodash.js'
));

3547
lodash.js

File diff suppressed because it is too large Load Diff

64
lodash.min.js vendored
View File

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

View File

@@ -1,7 +1,7 @@
{
"name": "lodash",
"version": "0.2.1",
"description": "A drop-in replacement for Underscore.js that delivers performance improvements, bug fixes, and additional features.",
"version": "0.5.0",
"description": "A drop-in replacement for Underscore.js delivering performance, bug fixes, and additional features.",
"homepage": "http://lodash.com",
"main": "lodash",
"keywords": [
@@ -21,7 +21,7 @@
],
"author": {
"name": "John-David Dalton",
"email": "john@fusejs.com",
"email": "john.david.dalton@gmail.com",
"web": "http://allyoucanleet.com/"
},
"bugs": {
@@ -31,12 +31,22 @@
"type": "git",
"url": "https://github.com/bestiejs/lodash.git"
},
"bin": {
"lodash": "./build.js"
},
"directories": {
"doc": "./doc",
"test": "./test"
},
"engines": [
"node",
"rhino"
],
"directories": {
"doc": "./doc",
"test": "./test"
"jam": {
"main": "lodash.min.js"
},
"scripts": {
"build": "node build",
"test": "node test/test"
}
}
}

View File

@@ -16,31 +16,42 @@
</style>
</head>
<body>
<script src="../lodash.js"></script>
<script src="../lodash.min.js"></script>
<script>
var lodash = _.noConflict();
</script>
<script src="../vendor/underscore/underscore.js"></script>
<script src="../vendor/underscore/underscore-min.js"></script>
<script src="../vendor/platform.js/platform.js"></script>
<script src="../vendor/benchmark.js/benchmark.js"></script>
<script src="../vendor/firebug-lite/src/firebug-lite-debug.js"></script>
<script src="perf.js"></script>
<script>
(function() {
if (!/[?&]nojava=true(?:&|$)/.test(location.search)) {
var useApplet = !/[?&]nojava=true(?:&|$)/.test(location.search);
function init() {
var fbUI = document.getElementById('FirebugUI'),
fbDoc = fbUI && (fbDoc = fbUI.contentWindow || fbUI.contentDocument).document || fbDoc,
fbCommandLine = fbDoc && fbDoc.getElementById('fbCommandLine');
if (!fbCommandLine) {
return setTimeout(init, 15);
}
fbUI.style.height = fbDoc.body.style.height = fbDoc.documentElement.style.height = '100%';
// give applet time to initialize
lodash.delay(run, useApplet ? 500 : 15);
}
if (useApplet) {
// using innerHTML avoids an alert in some versions of IE6
var div = document.createElement('div');
div.innerHTML = '<applet code=nano archive="../vendor/benchmark.js/nano.jar">';
document.body.insertBefore(div.lastChild, document.body.firstChild);
}
window.onload = init;
}());
window.onload = function() {
var sibling = document.getElementsByTagName('script')[0],
script = document.createElement('script');
document.getElementById('FirebugUI').style.height = '100%';
script.src = 'perf.js';
sibling.parentNode.insertBefore(script, sibling);
};
</script>
</body>
</html>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,10 @@
<script src="../vendor/backbone/test/vendor/jquery-1.7.1.js"></script>
<script src="../vendor/backbone/test/vendor/qunit.js"></script>
<script src="../vendor/backbone/test/vendor/jslitmus.js"></script>
<script src="../lodash.js"></script>
<script src="test-ui.js"></script>
<script>
document.write('<script src="../' + QUnit.config.lodashFilename + '.js"><\/script>');
</script>
<script src="../vendor/backbone/backbone.js"></script>
<script src="../vendor/backbone/test/noconflict.js"></script>
<script src="../vendor/backbone/test/events.js"></script>
@@ -34,6 +37,5 @@
<script src="../vendor/backbone/test/router.js"></script>
<script src="../vendor/backbone/test/view.js"></script>
<script src="../vendor/backbone/test/sync.js"></script>
<script src="../vendor/backbone/test/setdomlibrary.js"></script>
</body>
</html>
</html>

View File

@@ -7,47 +7,76 @@
</head>
<body>
<div id="qunit"></div>
<script src="../vendor/qunit/qunit/qunit.js"></script>
<script src="../vendor/platform.js/platform.js"></script>
<script>
var _2,
_3 = Object.keys;
// avoid syntax errors for `QUnit.throws` in older Firefoxes
document.write(platform.name == 'Firefox' && /^1\b/.test(platform.version)
? '<script src="../vendor/qunit/qunit/qunit-1.8.0.js"><\/script>'
: '<script src="../vendor/qunit/qunit/qunit.js"><\/script>'
);
</script>
<script src="test-ui.js"></script>
<script>
// set a bad shim
Object._keys = Object.keys;
Object.keys = function() { return []; };
</script>
<script src="../lodash.js"></script>
<script>
var lodashBadKeys = _,
_ = 1;
Object.keys = _3;
_3 = void 0;
// load Lo-Dash and expose it to the bad `Object.keys` shim
document.write('<script src="../' + QUnit.config.lodashFilename + '.js"><\/script>');
</script>
<script src="../lodash.js"></script>
<script src="../vendor/requirejs/require.js"></script>
<script>
if (/[?&]norequire=true(?:&|$)/.test(location.search)) {
require = define = null;
document.write('<script src="test.js"><\/script>');
}
else {
require({
'baseUrl': '../vendor/requirejs/',
'urlArgs': 't=' + (+new Date),
'paths': {
'lodash': '../../lodash',
'underscore': './../../lodash'
// store Lo-Dash to test for bad shim detection
var lodashBadShim = _;
// restore nativeKeys
Object.keys = Object._keys;
delete Object._keys;
// set to test `_.noConflict`
_ = 1;
// load Lo-Dash again to overwrite the existing `_` value
document.write('<script src="../' + QUnit.config.lodashFilename + '.js"><\/script>');
// load test.js if not using require.js
document.write(QUnit.urlParams.norequire
? '<script src="test.js"><\/script>'
: '<script src="../vendor/requirejs/require.js"><\/script>'
);
</script>
<script>
// load Lo-Dash as a module
var lodashModule,
underscoreModule;
window.require && require({
'baseUrl': '../vendor/requirejs/',
'urlArgs': 't=' + (+new Date),
'paths': {
'lodash': '../../' + QUnit.config.lodashFilename,
'underscore': './../../' + QUnit.config.lodashFilename
}
},
['lodash', 'underscore'], function(lodash, underscore) {
lodashModule = lodash.noConflict();
lodashModule.moduleName = 'lodash';
underscoreModule = underscore.noConflict();
underscoreModule.moduleName = 'underscore';
require(['test.js']);
});
// set a more readable browser name
window.onload = function() {
var timeoutId = setInterval(function() {
var ua = document.getElementById('qunit-userAgent');
if (ua) {
ua.innerHTML = platform;
clearInterval(timeoutId);
}
},
['lodash', 'underscore'], function(lodash, lodashAsUnderscore) {
_2 = lodash.noConflict();
_2.moduleName = 'lodash';
_3 = lodashAsUnderscore.noConflict();
_3.moduleName = 'underscore';
require(['test.js']);
});
}
}, 15);
};
</script>
</body>
</html>
</html>

View File

@@ -6,4 +6,4 @@ for cmd in rhino ringo narwhal node; do
done
echo ""
echo "Testing in a browser..."
open index.html
open index.html

90
test/test-ui.js Normal file
View File

@@ -0,0 +1,90 @@
;(function(window) {
'use strict';
/** `QUnit.addEvent` shortcut */
var addEvent = QUnit.addEvent;
/** The Lo-Dash build to load */
var build = (/build=([^&]+)/.exec(location.search) || [])[1];
/** A flag to determine if RequireJS should be loaded */
var norequire = /[?&]norequire=true(?:&|$)/.test(location.search);
/*--------------------------------------------------------------------------*/
// assign `QUnit.config` properties
QUnit.config.lodashFilename = (function() {
switch (build) {
case 'prod': return 'lodash.min';
case 'custom': return 'lodash.custom.min';
case 'custom-debug': return 'lodash.custom';
}
return 'lodash';
}());
// assign `QUnit.urlParams` properties
QUnit.extend(QUnit.urlParams, {
'build': build,
'norequire': norequire
});
// initialize the build dropdown
addEvent(window, 'load', function() {
function eventHandler(event) {
var search = location.search.replace(/^\?|&?(?:build|norequire)=[^&]*&?/g, '');
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
location.href =
location.href.split('?')[0] + '?' +
(search ? search + '&' : '') + 'build=' +
dropdown[dropdown.selectedIndex].value +
(checkbox.checked ? '&norequire=true' : '');
}
function init() {
var toolbar = document.getElementById('qunit-testrunner-toolbar');
if (toolbar) {
toolbar.appendChild(label1);
toolbar.appendChild(label2);
dropdown.selectedIndex = (function() {
switch (build) {
case 'prod': return 1;
case 'custom': return 2;
case 'custom-debug': return 3;
}
return 0;
}());
checkbox.checked = norequire;
addEvent(checkbox, 'click', eventHandler);
addEvent(dropdown, 'change', eventHandler);
}
else {
setTimeout(init, 15);
}
}
var label1 = document.createElement('label');
label1.innerHTML =
'<input name="norequire" type="checkbox">No RequireJS';
var label2 = document.createElement('label');
label2.innerHTML = '&nbsp;' +
'<select name="build">' +
'<option value="dev">Developement</option>' +
'<option value="prod">Production</option>' +
'<option value="custom">Custom</option>' +
'<option value="custom-debug">Custom (debug)</option>' +
'</select> Build';
var checkbox = label1.firstChild,
dropdown = label2.getElementsByTagName('select')[0];
init();
});
}(this));

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,10 @@
<script src="../vendor/underscore/test/vendor/jquery.js"></script>
<script src="../vendor/underscore/test/vendor/qunit.js"></script>
<script src="../vendor/underscore/test/vendor/jslitmus.js"></script>
<script src="../lodash.js"></script>
<script src="test-ui.js"></script>
<script>
document.write('<script src="../' + QUnit.config.lodashFilename + '.js"><\/script>');
</script>
<script src="../vendor/underscore/test/collections.js"></script>
<script src="../vendor/underscore/test/arrays.js"></script>
<script src="../vendor/underscore/test/functions.js"></script>
@@ -36,4 +39,4 @@
<li><%= data %></li>
</script>
</body>
</html>
</html>

1
vendor/backbone vendored

Submodule vendor/backbone deleted from 3c7c8d2f1a

22
vendor/backbone/LICENSE vendored Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2010-2012 Jeremy Ashkenas, DocumentCloud
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

26
vendor/backbone/README.md vendored Normal file
View File

@@ -0,0 +1,26 @@
____ __ __
/\ _`\ /\ \ /\ \ __
\ \ \ \ \ __ ___\ \ \/'\\ \ \____ ___ ___ __ /\_\ ____
\ \ _ <' /'__`\ /'___\ \ , < \ \ '__`\ / __`\ /' _ `\ /'__`\ \/\ \ /',__\
\ \ \ \ \/\ \ \.\_/\ \__/\ \ \\`\\ \ \ \ \/\ \ \ \/\ \/\ \/\ __/ __ \ \ \/\__, `\
\ \____/\ \__/.\_\ \____\\ \_\ \_\ \_,__/\ \____/\ \_\ \_\ \____\/\_\_\ \ \/\____/
\/___/ \/__/\/_/\/____/ \/_/\/_/\/___/ \/___/ \/_/\/_/\/____/\/_/\ \_\ \/___/
\ \____/
\/___/
(_'_______________________________________________________________________________'_)
(_.———————————————————————————————————————————————————————————————————————————————._)
Backbone supplies structure to JavaScript-heavy applications by providing models key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.
For Docs, License, Tests, pre-packed downloads, and everything else, really, see:
http://backbonejs.org
To suggest a feature, report a bug, or general discussion:
http://github.com/documentcloud/backbone/issues/
All contributors are listed here:
http://github.com/documentcloud/backbone/contributors
Special thanks to Robert Kieffer for the original philosophy behind Backbone.
http://github.com/broofa

1458
vendor/backbone/backbone.js vendored Normal file

File diff suppressed because it is too large Load Diff

669
vendor/backbone/test/collection.js vendored Normal file
View File

@@ -0,0 +1,669 @@
$(document).ready(function() {
var lastRequest = null;
var sync = Backbone.sync;
var a, b, c, d, e, col, otherCol;
module("Backbone.Collection", {
setup: function() {
a = new Backbone.Model({id: 3, label: 'a'});
b = new Backbone.Model({id: 2, label: 'b'});
c = new Backbone.Model({id: 1, label: 'c'});
d = new Backbone.Model({id: 0, label: 'd'});
e = null;
col = new Backbone.Collection([a,b,c,d]);
otherCol = new Backbone.Collection();
Backbone.sync = function(method, model, options) {
lastRequest = {
method: method,
model: model,
options: options
};
};
},
teardown: function() {
Backbone.sync = sync;
}
});
test("Collection: new and sort", 7, function() {
equal(col.first(), a, "a should be first");
equal(col.last(), d, "d should be last");
col.comparator = function(a, b) {
return a.id > b.id ? -1 : 1;
};
col.sort();
equal(col.first(), a, "a should be first");
equal(col.last(), d, "d should be last");
col.comparator = function(model) { return model.id; };
col.sort();
equal(col.first(), d, "d should be first");
equal(col.last(), a, "a should be last");
equal(col.length, 4);
});
test("Collection: get, getByCid", 3, function() {
equal(col.get(0), d);
equal(col.get(2), b);
equal(col.getByCid(col.first().cid), col.first());
});
test("Collection: get with non-default ids", 2, function() {
var col = new Backbone.Collection();
var MongoModel = Backbone.Model.extend({
idAttribute: '_id'
});
var model = new MongoModel({_id: 100});
col.push(model);
equal(col.get(100), model);
model.set({_id: 101});
equal(col.get(101), model);
});
test("Collection: update index when id changes", 3, function() {
var col = new Backbone.Collection();
col.add([
{id : 0, name : 'one'},
{id : 1, name : 'two'}
]);
var one = col.get(0);
equal(one.get('name'), 'one');
one.set({id : 101});
equal(col.get(0), null);
equal(col.get(101).get('name'), 'one');
});
test("Collection: at", 1, function() {
equal(col.at(2), c);
});
test("Collection: pluck", 1, function() {
equal(col.pluck('label').join(' '), 'a b c d');
});
test("Collection: add", 11, function() {
var added, opts, secondAdded;
added = opts = secondAdded = null;
e = new Backbone.Model({id: 10, label : 'e'});
otherCol.add(e);
otherCol.on('add', function() {
secondAdded = true;
});
col.on('add', function(model, collection, options){
added = model.get('label');
equal(options.index, 4);
opts = options;
});
col.add(e, {amazing: true});
equal(added, 'e');
equal(col.length, 5);
equal(col.last(), e);
equal(otherCol.length, 1);
equal(secondAdded, null);
ok(opts.amazing);
var f = new Backbone.Model({id: 20, label : 'f'});
var g = new Backbone.Model({id: 21, label : 'g'});
var h = new Backbone.Model({id: 22, label : 'h'});
var atCol = new Backbone.Collection([f, g, h]);
equal(atCol.length, 3);
atCol.add(e, {at: 1});
equal(atCol.length, 4);
equal(atCol.at(1), e);
equal(atCol.last(), h);
});
test("Collection: add multiple models", 6, function() {
var col = new Backbone.Collection([{at: 0}, {at: 1}, {at: 9}]);
col.add([{at: 2}, {at: 3}, {at: 4}, {at: 5}, {at: 6}, {at: 7}, {at: 8}], {at: 2});
for (var i = 0; i <= 5; i++) {
equal(col.at(i).get('at'), i);
}
});
test("Collection: add; at should have preference over comparator", 1, function() {
var Col = Backbone.Collection.extend({
comparator: function(a,b) {
return a.id > b.id ? -1 : 1;
}
});
var col = new Col([{id: 2}, {id: 3}]);
col.add(new Backbone.Model({id: 1}), {at: 1});
equal(col.pluck('id').join(' '), '3 1 2');
});
test("Collection: can't add model to collection twice", function() {
var col = new Backbone.Collection([{id: 1}, {id: 2}, {id: 1}, {id: 2}, {id: 3}]);
equal(col.pluck('id').join(' '), '1 2 3');
});
test("Collection: can't add different model with same id to collection twice", 1, function() {
var col = new Backbone.Collection;
col.unshift({id: 101});
col.add({id: 101});
equal(col.length, 1);
});
test("Collection: merge in duplicate models with {merge: true}", 3, function() {
var col = new Backbone.Collection;
col.add([{id: 1, name: 'Moe'}, {id: 2, name: 'Curly'}, {id: 3, name: 'Larry'}]);
col.add({id: 1, name: 'Moses'});
equal(col.first().get('name'), 'Moe');
col.add({id: 1, name: 'Moses'}, {merge: true});
equal(col.first().get('name'), 'Moses');
col.add({id: 1, name: 'Tim'}, {merge: true, silent: true});
equal(col.first().get('name'), 'Tim');
});
test("Collection: add model to multiple collections", 10, function() {
var counter = 0;
var e = new Backbone.Model({id: 10, label : 'e'});
e.on('add', function(model, collection) {
counter++;
equal(e, model);
if (counter > 1) {
equal(collection, colF);
} else {
equal(collection, colE);
}
});
var colE = new Backbone.Collection([]);
colE.on('add', function(model, collection) {
equal(e, model);
equal(colE, collection);
});
var colF = new Backbone.Collection([]);
colF.on('add', function(model, collection) {
equal(e, model);
equal(colF, collection);
});
colE.add(e);
equal(e.collection, colE);
colF.add(e);
equal(e.collection, colE);
});
test("Collection: add model with parse", 1, function() {
var Model = Backbone.Model.extend({
parse: function(obj) {
obj.value += 1;
return obj;
}
});
var Col = Backbone.Collection.extend({model: Model});
var col = new Col;
col.add({value: 1}, {parse: true});
equal(col.at(0).get('value'), 2);
});
test("Collection: add model to collection with sort()-style comparator", 3, function() {
var col = new Backbone.Collection;
col.comparator = function(a, b) {
return a.get('name') < b.get('name') ? -1 : 1;
};
var tom = new Backbone.Model({name: 'Tom'});
var rob = new Backbone.Model({name: 'Rob'});
var tim = new Backbone.Model({name: 'Tim'});
col.add(tom);
col.add(rob);
col.add(tim);
equal(col.indexOf(rob), 0);
equal(col.indexOf(tim), 1);
equal(col.indexOf(tom), 2);
});
test("Collection: comparator that depends on `this`", 1, function() {
var col = new Backbone.Collection;
col.negative = function(num) {
return -num;
};
col.comparator = function(a) {
return this.negative(a.id);
};
col.add([{id: 1}, {id: 2}, {id: 3}]);
equal(col.pluck('id').join(' '), '3 2 1');
});
test("Collection: remove", 5, function() {
var removed = null;
var otherRemoved = null;
col.on('remove', function(model, col, options) {
removed = model.get('label');
equal(options.index, 3);
});
otherCol.on('remove', function(model, col, options) {
otherRemoved = true;
});
col.remove(d);
equal(removed, 'd');
equal(col.length, 3);
equal(col.first(), a);
equal(otherRemoved, null);
});
test("Collection: shift and pop", 2, function() {
var col = new Backbone.Collection([{a: 'a'}, {b: 'b'}, {c: 'c'}]);
equal(col.shift().get('a'), 'a');
equal(col.pop().get('c'), 'c');
});
test("Collection: slice", 2, function() {
var col = new Backbone.Collection([{a: 'a'}, {b: 'b'}, {c: 'c'}]);
var array = col.slice(1, 3);
equal(array.length, 2);
equal(array[0].get('b'), 'b');
});
test("Collection: events are unbound on remove", 3, function() {
var counter = 0;
var dj = new Backbone.Model();
var emcees = new Backbone.Collection([dj]);
emcees.on('change', function(){ counter++; });
dj.set({name : 'Kool'});
equal(counter, 1);
emcees.reset([]);
equal(dj.collection, undefined);
dj.set({name : 'Shadow'});
equal(counter, 1);
});
test("Collection: remove in multiple collections", 7, function() {
var modelData = {
id : 5,
title : 'Othello'
};
var passed = false;
var e = new Backbone.Model(modelData);
var f = new Backbone.Model(modelData);
f.on('remove', function() {
passed = true;
});
var colE = new Backbone.Collection([e]);
var colF = new Backbone.Collection([f]);
ok(e != f);
ok(colE.length == 1);
ok(colF.length == 1);
colE.remove(e);
equal(passed, false);
ok(colE.length == 0);
colF.remove(e);
ok(colF.length == 0);
equal(passed, true);
});
test("Collection: remove same model in multiple collection", 16, function() {
var counter = 0;
var e = new Backbone.Model({id: 5, title: 'Othello'});
e.on('remove', function(model, collection) {
counter++;
equal(e, model);
if (counter > 1) {
equal(collection, colE);
} else {
equal(collection, colF);
}
});
var colE = new Backbone.Collection([e]);
colE.on('remove', function(model, collection) {
equal(e, model);
equal(colE, collection);
});
var colF = new Backbone.Collection([e]);
colF.on('remove', function(model, collection) {
equal(e, model);
equal(colF, collection);
});
equal(colE, e.collection);
colF.remove(e);
ok(colF.length == 0);
ok(colE.length == 1);
equal(counter, 1);
equal(colE, e.collection);
colE.remove(e);
equal(null, e.collection);
ok(colE.length == 0);
equal(counter, 2);
});
test("Collection: model destroy removes from all collections", 3, function() {
var e = new Backbone.Model({id: 5, title: 'Othello'});
e.sync = function(method, model, options) { options.success({}); };
var colE = new Backbone.Collection([e]);
var colF = new Backbone.Collection([e]);
e.destroy();
ok(colE.length == 0);
ok(colF.length == 0);
equal(undefined, e.collection);
});
test("Colllection: non-persisted model destroy removes from all collections", 3, function() {
var e = new Backbone.Model({title: 'Othello'});
e.sync = function(method, model, options) { throw "should not be called"; };
var colE = new Backbone.Collection([e]);
var colF = new Backbone.Collection([e]);
e.destroy();
ok(colE.length == 0);
ok(colF.length == 0);
equal(undefined, e.collection);
});
test("Collection: fetch", 4, function() {
col.fetch();
equal(lastRequest.method, 'read');
equal(lastRequest.model, col);
equal(lastRequest.options.parse, true);
col.fetch({parse: false});
equal(lastRequest.options.parse, false);
});
test("Collection: create", 4, function() {
var model = col.create({label: 'f'}, {wait: true});
equal(lastRequest.method, 'create');
equal(lastRequest.model, model);
equal(model.get('label'), 'f');
equal(model.collection, col);
});
test("Collection: create enforces validation", 1, function() {
var ValidatingModel = Backbone.Model.extend({
validate: function(attrs) {
return "fail";
}
});
var ValidatingCollection = Backbone.Collection.extend({
model: ValidatingModel
});
var col = new ValidatingCollection();
equal(col.create({"foo":"bar"}), false);
});
test("Collection: a failing create runs the error callback", 1, function() {
var ValidatingModel = Backbone.Model.extend({
validate: function(attrs) {
return "fail";
}
});
var ValidatingCollection = Backbone.Collection.extend({
model: ValidatingModel
});
var flag = false;
var callback = function(model, error) { flag = true; };
var col = new ValidatingCollection();
col.create({"foo":"bar"}, { error: callback });
equal(flag, true);
});
test("collection: initialize", 1, function() {
var Collection = Backbone.Collection.extend({
initialize: function() {
this.one = 1;
}
});
var coll = new Collection;
equal(coll.one, 1);
});
test("Collection: toJSON", 1, function() {
equal(JSON.stringify(col), '[{"id":3,"label":"a"},{"id":2,"label":"b"},{"id":1,"label":"c"},{"id":0,"label":"d"}]');
});
test("Collection: where", 6, function() {
var coll = new Backbone.Collection([
{a: 1},
{a: 1},
{a: 1, b: 2},
{a: 2, b: 2},
{a: 3}
]);
equal(coll.where({a: 1}).length, 3);
equal(coll.where({a: 2}).length, 1);
equal(coll.where({a: 3}).length, 1);
equal(coll.where({b: 1}).length, 0);
equal(coll.where({b: 2}).length, 2);
equal(coll.where({a: 1, b: 2}).length, 1);
});
test("Collection: Underscore methods", 13, function() {
equal(col.map(function(model){ return model.get('label'); }).join(' '), 'a b c d');
equal(col.any(function(model){ return model.id === 100; }), false);
equal(col.any(function(model){ return model.id === 0; }), true);
equal(col.indexOf(b), 1);
equal(col.size(), 4);
equal(col.rest().length, 3);
ok(!_.include(col.rest()), a);
ok(!_.include(col.rest()), d);
ok(!col.isEmpty());
ok(!_.include(col.without(d)), d);
equal(col.max(function(model){ return model.id; }).id, 3);
equal(col.min(function(model){ return model.id; }).id, 0);
deepEqual(col.chain()
.filter(function(o){ return o.id % 2 === 0; })
.map(function(o){ return o.id * 2; })
.value(),
[4, 0]);
});
test("Collection: reset", 10, function() {
var resetCount = 0;
var models = col.models;
col.on('reset', function() { resetCount += 1; });
col.reset([]);
equal(resetCount, 1);
equal(col.length, 0);
equal(col.last(), null);
col.reset(models);
equal(resetCount, 2);
equal(col.length, 4);
equal(col.last(), d);
col.reset(_.map(models, function(m){ return m.attributes; }));
equal(resetCount, 3);
equal(col.length, 4);
ok(col.last() !== d);
ok(_.isEqual(col.last().attributes, d.attributes));
});
test("Collection: reset passes caller options", 3, function() {
var Model = Backbone.Model.extend({
initialize: function(attrs, options) {
this.model_parameter = options.model_parameter;
}
});
var col = new (Backbone.Collection.extend({ model: Model }))();
col.reset([{ astring: "green", anumber: 1 }, { astring: "blue", anumber: 2 }], { model_parameter: 'model parameter' });
equal(col.length, 2);
col.each(function(model) {
equal(model.model_parameter, 'model parameter');
});
});
test("Collection: trigger custom events on models", 1, function() {
var fired = null;
a.on("custom", function() { fired = true; });
a.trigger("custom");
equal(fired, true);
});
test("Collection: add does not alter arguments", 2, function(){
var attrs = {};
var models = [attrs];
new Backbone.Collection().add(models);
equal(models.length, 1);
ok(attrs === models[0]);
});
test("#714: access `model.collection` in a brand new model.", 2, function() {
var col = new Backbone.Collection;
var Model = Backbone.Model.extend({
set: function(attrs) {
equal(attrs.prop, 'value');
equal(this.collection, col);
return this;
}
});
col.model = Model;
col.create({prop: 'value'});
});
test("#574, remove its own reference to the .models array.", 2, function() {
var col = new Backbone.Collection([
{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}
]);
equal(col.length, 6);
col.remove(col.models);
equal(col.length, 0);
});
test("#861, adding models to a collection which do not pass validation", 1, function() {
raises(function() {
var Model = Backbone.Model.extend({
validate: function(attrs) {
if (attrs.id == 3) return "id can't be 3";
}
});
var Collection = Backbone.Collection.extend({
model: Model
});
var col = new Collection;
col.add([{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}]);
}, function(e) {
return e.message === "Can't add an invalid model to a collection";
});
});
test("Collection: index with comparator", 4, function() {
var counter = 0;
var col = new Backbone.Collection([{id: 2}, {id: 4}], {
comparator: function(model){ return model.id; }
}).on('add', function(model, colleciton, options){
if (model.id == 1) {
equal(options.index, 0);
equal(counter++, 0);
}
if (model.id == 3) {
equal(options.index, 2);
equal(counter++, 1);
}
});
col.add([{id: 3}, {id: 1}]);
});
test("Collection: throwing during add leaves consistent state", 4, function() {
var col = new Backbone.Collection();
col.on('test', function() { ok(false); });
col.model = Backbone.Model.extend({
validate: function(attrs){ if (!attrs.valid) return 'invalid'; }
});
var model = new col.model({id: 1, valid: true});
raises(function() { col.add([model, {id: 2}]); });
model.trigger('test');
ok(!col.getByCid(model.cid));
ok(!col.get(1));
equal(col.length, 0);
});
test("Collection: multiple copies of the same model", 3, function() {
var col = new Backbone.Collection();
var model = new Backbone.Model();
col.add([model, model]);
equal(col.length, 1);
col.add([{id: 1}, {id: 1}]);
equal(col.length, 2);
equal(col.last().id, 1);
});
test("#964 - collection.get return inconsistent", 2, function() {
var c = new Backbone.Collection();
ok(c.get(null) === undefined);
ok(c.get() === undefined);
});
test("#1112 - passing options.model sets collection.model", 2, function() {
var Model = Backbone.Model.extend({});
var c = new Backbone.Collection([{id: 1}], {model: Model});
ok(c.model === Model);
ok(c.at(0) instanceof Model);
});
test("null and undefined are invalid ids.", 2, function() {
var model = new Backbone.Model({id: 1});
var collection = new Backbone.Collection([model]);
model.set({id: null});
ok(!collection.get('null'));
model.set({id: 1});
model.set({id: undefined});
ok(!collection.get('undefined'));
});
test("Collection: falsy comparator", 4, function(){
var Col = Backbone.Collection.extend({
comparator: function(model){ return model.id; }
});
var col = new Col();
var colFalse = new Col(null, {comparator: false});
var colNull = new Col(null, {comparator: null});
var colUndefined = new Col(null, {comparator: undefined});
ok(col.comparator);
ok(!colFalse.comparator);
ok(!colNull.comparator);
ok(colUndefined.comparator);
});
test("#1355 - `options` is passed to success callbacks", 2, function(){
var m = new Backbone.Model({x:1});
var col = new Backbone.Collection();
var opts = {
success: function(collection, resp, options){
ok(options);
}
};
col.sync = m.sync = function( method, collection, options ){
options.success();
};
col.fetch(opts);
col.create(m, opts);
});
test("#1412 - Trigger 'sync' event.", 2, function() {
var collection = new Backbone.Collection([], {
model: Backbone.Model.extend({
sync: function(method, model, options) {
options.success();
}
})
});
collection.sync = function(method, model, options) { options.success(); };
collection.on('sync', function() { ok(true); });
collection.fetch();
collection.create({id: 1});
});
test("#1447 - create with wait adds model.", function() {
var collection = new Backbone.Collection;
var model = new Backbone.Model;
model.sync = function(method, model, options){ options.success(); };
collection.on('add', function(){ ok(true); });
collection.create(model, {wait: true});
});
test("#1448 - add sorts collection after merge.", function() {
var collection = new Backbone.Collection([
{id: 1, x: 1},
{id: 2, x: 2}
]);
collection.comparator = function(model){ return model.get('x'); };
collection.add({id: 1, x: 3}, {merge: true});
deepEqual(collection.pluck('id'), [2, 1]);
});
});

195
vendor/backbone/test/events.js vendored Normal file
View File

@@ -0,0 +1,195 @@
$(document).ready(function() {
module("Backbone.Events");
test("Events: on and trigger", 2, function() {
var obj = { counter: 0 };
_.extend(obj,Backbone.Events);
obj.on('event', function() { obj.counter += 1; });
obj.trigger('event');
equal(obj.counter,1,'counter should be incremented.');
obj.trigger('event');
obj.trigger('event');
obj.trigger('event');
obj.trigger('event');
equal(obj.counter, 5, 'counter should be incremented five times.');
});
test("Events: binding and triggering multiple events", 4, function() {
var obj = { counter: 0 };
_.extend(obj,Backbone.Events);
obj.on('a b c', function() { obj.counter += 1; });
obj.trigger('a');
equal(obj.counter, 1);
obj.trigger('a b');
equal(obj.counter, 3);
obj.trigger('c');
equal(obj.counter, 4);
obj.off('a c');
obj.trigger('a b c');
equal(obj.counter, 5);
});
test("Events: trigger all for each event", 3, function() {
var a, b, obj = { counter: 0 };
_.extend(obj, Backbone.Events);
obj.on('all', function(event) {
obj.counter++;
if (event == 'a') a = true;
if (event == 'b') b = true;
})
.trigger('a b');
ok(a);
ok(b);
equal(obj.counter, 2);
});
test("Events: on, then unbind all functions", 1, function() {
var obj = { counter: 0 };
_.extend(obj,Backbone.Events);
var callback = function() { obj.counter += 1; };
obj.on('event', callback);
obj.trigger('event');
obj.off('event');
obj.trigger('event');
equal(obj.counter, 1, 'counter should have only been incremented once.');
});
test("Events: bind two callbacks, unbind only one", 2, function() {
var obj = { counterA: 0, counterB: 0 };
_.extend(obj,Backbone.Events);
var callback = function() { obj.counterA += 1; };
obj.on('event', callback);
obj.on('event', function() { obj.counterB += 1; });
obj.trigger('event');
obj.off('event', callback);
obj.trigger('event');
equal(obj.counterA, 1, 'counterA should have only been incremented once.');
equal(obj.counterB, 2, 'counterB should have been incremented twice.');
});
test("Events: unbind a callback in the midst of it firing", 1, function() {
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
var callback = function() {
obj.counter += 1;
obj.off('event', callback);
};
obj.on('event', callback);
obj.trigger('event');
obj.trigger('event');
obj.trigger('event');
equal(obj.counter, 1, 'the callback should have been unbound.');
});
test("Events: two binds that unbind themeselves", 2, function() {
var obj = { counterA: 0, counterB: 0 };
_.extend(obj,Backbone.Events);
var incrA = function(){ obj.counterA += 1; obj.off('event', incrA); };
var incrB = function(){ obj.counterB += 1; obj.off('event', incrB); };
obj.on('event', incrA);
obj.on('event', incrB);
obj.trigger('event');
obj.trigger('event');
obj.trigger('event');
equal(obj.counterA, 1, 'counterA should have only been incremented once.');
equal(obj.counterB, 1, 'counterB should have only been incremented once.');
});
test("Events: bind a callback with a supplied context", 1, function () {
var TestClass = function () {
return this;
};
TestClass.prototype.assertTrue = function () {
ok(true, '`this` was bound to the callback');
};
var obj = _.extend({},Backbone.Events);
obj.on('event', function () { this.assertTrue(); }, (new TestClass));
obj.trigger('event');
});
test("Events: nested trigger with unbind", 1, function () {
var obj = { counter: 0 };
_.extend(obj, Backbone.Events);
var incr1 = function(){ obj.counter += 1; obj.off('event', incr1); obj.trigger('event'); };
var incr2 = function(){ obj.counter += 1; };
obj.on('event', incr1);
obj.on('event', incr2);
obj.trigger('event');
equal(obj.counter, 3, 'counter should have been incremented three times');
});
test("Events: callback list is not altered during trigger", 2, function () {
var counter = 0, obj = _.extend({}, Backbone.Events);
var incr = function(){ counter++; };
obj.on('event', function(){ obj.on('event', incr).on('all', incr); })
.trigger('event');
equal(counter, 0, 'bind does not alter callback list');
obj.off()
.on('event', function(){ obj.off('event', incr).off('all', incr); })
.on('event', incr)
.on('all', incr)
.trigger('event');
equal(counter, 2, 'unbind does not alter callback list');
});
test("#1282 - 'all' callback list is retrieved after each event.", 1, function() {
var counter = 0;
var obj = _.extend({}, Backbone.Events);
var incr = function(){ counter++; };
obj.on('x', function() {
obj.on('y', incr).on('all', incr);
})
.trigger('x y');
strictEqual(counter, 2);
});
test("if no callback is provided, `on` is a noop", 0, function() {
_.extend({}, Backbone.Events).on('test').trigger('test');
});
test("remove all events for a specific context", 4, function() {
var obj = _.extend({}, Backbone.Events);
obj.on('x y all', function() { ok(true); });
obj.on('x y all', function() { ok(false); }, obj);
obj.off(null, null, obj);
obj.trigger('x y');
});
test("remove all events for a specific callback", 4, function() {
var obj = _.extend({}, Backbone.Events);
var success = function() { ok(true); };
var fail = function() { ok(false); };
obj.on('x y all', success);
obj.on('x y all', fail);
obj.off(null, fail);
obj.trigger('x y');
});
test("off is chainable", 3, function() {
var obj = _.extend({}, Backbone.Events);
// With no events
ok(obj.off() === obj);
// When removing all events
obj.on('event', function(){}, obj);
ok(obj.off() === obj);
// When removing some events
obj.on('event', function(){}, obj);
ok(obj.off('event') === obj);
});
test("#1310 - off does not skip consecutive events", 0, function() {
var obj = _.extend({}, Backbone.Events);
obj.on('event', function() { ok(false); }, obj);
obj.on('event', function() { ok(false); }, obj);
obj.off(null, null, obj);
obj.trigger('event');
});
});

855
vendor/backbone/test/model.js vendored Normal file
View File

@@ -0,0 +1,855 @@
$(document).ready(function() {
// Variable to catch the last request.
var lastRequest = null;
// Variable to catch ajax params.
var ajaxParams = null;
var sync = Backbone.sync;
var ajax = Backbone.ajax;
var urlRoot = null;
var proxy = Backbone.Model.extend();
var klass = Backbone.Collection.extend({
url : function() { return '/collection'; }
});
var doc, collection;
module("Backbone.Model", {
setup: function() {
doc = new proxy({
id : '1-the-tempest',
title : "The Tempest",
author : "Bill Shakespeare",
length : 123
});
collection = new klass();
collection.add(doc);
Backbone.sync = function(method, model, options) {
lastRequest = {
method: method,
model: model,
options: options
};
sync.apply(this, arguments);
};
Backbone.ajax = function(params) { ajaxParams = params; };
urlRoot = Backbone.Model.prototype.urlRoot;
Backbone.Model.prototype.urlRoot = '/';
},
teardown: function() {
Backbone.sync = sync;
Backbone.ajax = ajax;
Backbone.Model.prototype.urlRoot = urlRoot;
}
});
test("Model: initialize", 3, function() {
var Model = Backbone.Model.extend({
initialize: function() {
this.one = 1;
equal(this.collection, collection);
}
});
var model = new Model({}, {collection: collection});
equal(model.one, 1);
equal(model.collection, collection);
});
test("Model: initialize with attributes and options", 1, function() {
var Model = Backbone.Model.extend({
initialize: function(attributes, options) {
this.one = options.one;
}
});
var model = new Model({}, {one: 1});
equal(model.one, 1);
});
test("Model: initialize with parsed attributes", 1, function() {
var Model = Backbone.Model.extend({
parse: function(obj) {
obj.value += 1;
return obj;
}
});
var model = new Model({value: 1}, {parse: true});
equal(model.get('value'), 2);
});
test("Model: url", 3, function() {
doc.urlRoot = null;
equal(doc.url(), '/collection/1-the-tempest');
doc.collection.url = '/collection/';
equal(doc.url(), '/collection/1-the-tempest');
doc.collection = null;
raises(function() { doc.url(); });
doc.collection = collection;
});
test("Model: url when using urlRoot, and uri encoding", 2, function() {
var Model = Backbone.Model.extend({
urlRoot: '/collection'
});
var model = new Model();
equal(model.url(), '/collection');
model.set({id: '+1+'});
equal(model.url(), '/collection/%2B1%2B');
});
test("Model: url when using urlRoot as a function to determine urlRoot at runtime", 2, function() {
var Model = Backbone.Model.extend({
urlRoot: function() {
return '/nested/' + this.get('parent_id') + '/collection';
}
});
var model = new Model({parent_id: 1});
equal(model.url(), '/nested/1/collection');
model.set({id: 2});
equal(model.url(), '/nested/1/collection/2');
});
test("Model: clone", 8, function() {
var a = new Backbone.Model({ 'foo': 1, 'bar': 2, 'baz': 3});
var b = a.clone();
equal(a.get('foo'), 1);
equal(a.get('bar'), 2);
equal(a.get('baz'), 3);
equal(b.get('foo'), a.get('foo'), "Foo should be the same on the clone.");
equal(b.get('bar'), a.get('bar'), "Bar should be the same on the clone.");
equal(b.get('baz'), a.get('baz'), "Baz should be the same on the clone.");
a.set({foo : 100});
equal(a.get('foo'), 100);
equal(b.get('foo'), 1, "Changing a parent attribute does not change the clone.");
});
test("Model: isNew", 6, function() {
var a = new Backbone.Model({ 'foo': 1, 'bar': 2, 'baz': 3});
ok(a.isNew(), "it should be new");
a = new Backbone.Model({ 'foo': 1, 'bar': 2, 'baz': 3, 'id': -5 });
ok(!a.isNew(), "any defined ID is legal, negative or positive");
a = new Backbone.Model({ 'foo': 1, 'bar': 2, 'baz': 3, 'id': 0 });
ok(!a.isNew(), "any defined ID is legal, including zero");
ok( new Backbone.Model({ }).isNew(), "is true when there is no id");
ok(!new Backbone.Model({ 'id': 2 }).isNew(), "is false for a positive integer");
ok(!new Backbone.Model({ 'id': -5 }).isNew(), "is false for a negative integer");
});
test("Model: get", 2, function() {
equal(doc.get('title'), 'The Tempest');
equal(doc.get('author'), 'Bill Shakespeare');
});
test("Model: escape", 5, function() {
equal(doc.escape('title'), 'The Tempest');
doc.set({audience: 'Bill & Bob'});
equal(doc.escape('audience'), 'Bill &amp; Bob');
doc.set({audience: 'Tim > Joan'});
equal(doc.escape('audience'), 'Tim &gt; Joan');
doc.set({audience: 10101});
equal(doc.escape('audience'), '10101');
doc.unset('audience');
equal(doc.escape('audience'), '');
});
test("Model: has", 10, function() {
var model = new Backbone.Model();
strictEqual(model.has('name'), false);
model.set({
'0': 0,
'1': 1,
'true': true,
'false': false,
'empty': '',
'name': 'name',
'null': null,
'undefined': undefined
});
strictEqual(model.has('0'), true);
strictEqual(model.has('1'), true);
strictEqual(model.has('true'), true);
strictEqual(model.has('false'), true);
strictEqual(model.has('empty'), true);
strictEqual(model.has('name'), true);
model.unset('name');
strictEqual(model.has('name'), false);
strictEqual(model.has('null'), false);
strictEqual(model.has('undefined'), false);
});
test("Model: set and unset", 8, function() {
var a = new Backbone.Model({id: 'id', foo: 1, bar: 2, baz: 3});
var changeCount = 0;
a.on("change:foo", function() { changeCount += 1; });
a.set({'foo': 2});
ok(a.get('foo') == 2, "Foo should have changed.");
ok(changeCount == 1, "Change count should have incremented.");
a.set({'foo': 2}); // set with value that is not new shouldn't fire change event
ok(a.get('foo') == 2, "Foo should NOT have changed, still 2");
ok(changeCount == 1, "Change count should NOT have incremented.");
a.validate = function(attrs) {
equal(attrs.foo, void 0, "don't ignore values when unsetting");
};
a.unset('foo');
equal(a.get('foo'), void 0, "Foo should have changed");
delete a.validate;
ok(changeCount == 2, "Change count should have incremented for unset.");
a.unset('id');
equal(a.id, undefined, "Unsetting the id should remove the id property.");
});
test("Model: multiple unsets", 1, function() {
var i = 0;
var counter = function(){ i++; };
var model = new Backbone.Model({a: 1});
model.on("change:a", counter);
model.set({a: 2});
model.unset('a');
model.unset('a');
equal(i, 2, 'Unset does not fire an event for missing attributes.');
});
test("Model: unset and changedAttributes", 2, function() {
var model = new Backbone.Model({a: 1});
model.unset('a', {silent: true});
var changedAttributes = model.changedAttributes();
ok('a' in changedAttributes, 'changedAttributes should contain unset properties');
changedAttributes = model.changedAttributes();
ok('a' in changedAttributes, 'changedAttributes should contain unset properties when running changedAttributes again after an unset.');
});
test("Model: using a non-default id attribute.", 5, function() {
var MongoModel = Backbone.Model.extend({idAttribute : '_id'});
var model = new MongoModel({id: 'eye-dee', _id: 25, title: 'Model'});
equal(model.get('id'), 'eye-dee');
equal(model.id, 25);
equal(model.isNew(), false);
model.unset('_id');
equal(model.id, undefined);
equal(model.isNew(), true);
});
test("Model: set an empty string", 1, function() {
var model = new Backbone.Model({name : "Model"});
model.set({name : ''});
equal(model.get('name'), '');
});
test("Model: clear", 3, function() {
var changed;
var model = new Backbone.Model({id: 1, name : "Model"});
model.on("change:name", function(){ changed = true; });
model.on("change", function() {
var changedAttrs = model.changedAttributes();
ok('name' in changedAttrs);
});
model.clear();
equal(changed, true);
equal(model.get('name'), undefined);
});
test("Model: defaults", 4, function() {
var Defaulted = Backbone.Model.extend({
defaults: {
"one": 1,
"two": 2
}
});
var model = new Defaulted({two: null});
equal(model.get('one'), 1);
equal(model.get('two'), null);
Defaulted = Backbone.Model.extend({
defaults: function() {
return {
"one": 3,
"two": 4
};
}
});
var model = new Defaulted({two: null});
equal(model.get('one'), 3);
equal(model.get('two'), null);
});
test("Model: change, hasChanged, changedAttributes, previous, previousAttributes", 12, function() {
var model = new Backbone.Model({name : "Tim", age : 10});
equal(model.changedAttributes(), false);
model.on('change', function() {
ok(model.hasChanged('name'), 'name changed');
ok(!model.hasChanged('age'), 'age did not');
ok(_.isEqual(model.changedAttributes(), {name : 'Rob'}), 'changedAttributes returns the changed attrs');
equal(model.previous('name'), 'Tim');
ok(_.isEqual(model.previousAttributes(), {name : "Tim", age : 10}), 'previousAttributes is correct');
});
equal(model.hasChanged(), false);
equal(model.hasChanged(undefined), false);
model.set({name : 'Rob'}, {silent : true});
equal(model.hasChanged(), true);
equal(model.hasChanged(undefined), true);
equal(model.hasChanged('name'), true);
model.change();
equal(model.get('name'), 'Rob');
});
test("Model: changedAttributes", 3, function() {
var model = new Backbone.Model({a: 'a', b: 'b'});
equal(model.changedAttributes(), false);
equal(model.changedAttributes({a: 'a'}), false);
equal(model.changedAttributes({a: 'b'}).a, 'b');
});
test("Model: change with options", 2, function() {
var value;
var model = new Backbone.Model({name: 'Rob'});
model.on('change', function(model, options) {
value = options.prefix + model.get('name');
});
model.set({name: 'Bob'}, {silent: true});
model.change({prefix: 'Mr. '});
equal(value, 'Mr. Bob');
model.set({name: 'Sue'}, {prefix: 'Ms. '});
equal(value, 'Ms. Sue');
});
test("Model: change after initialize", 1, function () {
var changed = 0;
var attrs = {id: 1, label: 'c'};
var obj = new Backbone.Model(attrs);
obj.on('change', function() { changed += 1; });
obj.set(attrs);
equal(changed, 0);
});
test("Model: save within change event", 1, function () {
var model = new Backbone.Model({firstName : "Taylor", lastName: "Swift"});
model.on('change', function () {
model.save();
ok(_.isEqual(lastRequest.model, model));
});
model.set({lastName: 'Hicks'});
});
test("Model: validate after save", 1, function() {
var lastError, model = new Backbone.Model();
model.validate = function(attrs) {
if (attrs.admin) return "Can't change admin status.";
};
model.sync = function(method, model, options) {
options.success.call(this, {admin: true});
};
model.save(null, {error: function(model, error) {
lastError = error;
}});
equal(lastError, "Can't change admin status.");
});
test("Model: isValid", 5, function() {
var model = new Backbone.Model({valid: true});
model.validate = function(attrs) {
if (!attrs.valid) return "invalid";
};
equal(model.isValid(), true);
equal(model.set({valid: false}), false);
equal(model.isValid(), true);
ok(model.set('valid', false, {silent: true}));
equal(model.isValid(), false);
});
test("Model: save", 2, function() {
doc.save({title : "Henry V"});
equal(lastRequest.method, 'update');
ok(_.isEqual(lastRequest.model, doc));
});
test("Model: save in positional style", 1, function() {
var model = new Backbone.Model();
model.sync = function(method, model, options) {
options.success();
};
model.save('title', 'Twelfth Night');
equal(model.get('title'), 'Twelfth Night');
});
test("Model: fetch", 2, function() {
doc.fetch();
equal(lastRequest.method, 'read');
ok(_.isEqual(lastRequest.model, doc));
});
test("Model: destroy", 3, function() {
doc.destroy();
equal(lastRequest.method, 'delete');
ok(_.isEqual(lastRequest.model, doc));
var newModel = new Backbone.Model;
equal(newModel.destroy(), false);
});
test("Model: non-persisted destroy", 1, function() {
var a = new Backbone.Model({ 'foo': 1, 'bar': 2, 'baz': 3});
a.sync = function() { throw "should not be called"; };
a.destroy();
ok(true, "non-persisted model should not call sync");
});
test("Model: validate", 7, function() {
var lastError;
var model = new Backbone.Model();
model.validate = function(attrs) {
if (attrs.admin != this.get('admin')) return "Can't change admin status.";
};
model.on('error', function(model, error) {
lastError = error;
});
var result = model.set({a: 100});
equal(result, model);
equal(model.get('a'), 100);
equal(lastError, undefined);
result = model.set({admin: true}, {silent: true});
equal(model.get('admin'), true);
result = model.set({a: 200, admin: false});
equal(lastError, "Can't change admin status.");
equal(result, false);
equal(model.get('a'), 100);
});
test("Model: validate on unset and clear", 6, function() {
var error;
var model = new Backbone.Model({name: "One"});
model.validate = function(attrs) {
if (!attrs.name) {
error = true;
return "No thanks.";
}
};
model.set({name: "Two"});
equal(model.get('name'), 'Two');
equal(error, undefined);
model.unset('name');
equal(error, true);
equal(model.get('name'), 'Two');
model.clear();
equal(model.get('name'), 'Two');
delete model.validate;
model.clear();
equal(model.get('name'), undefined);
});
test("Model: validate with error callback", 8, function() {
var lastError, boundError;
var model = new Backbone.Model();
model.validate = function(attrs) {
if (attrs.admin) return "Can't change admin status.";
};
var callback = function(model, error) {
lastError = error;
};
model.on('error', function(model, error) {
boundError = true;
});
var result = model.set({a: 100}, {error: callback});
equal(result, model);
equal(model.get('a'), 100);
equal(lastError, undefined);
equal(boundError, undefined);
result = model.set({a: 200, admin: true}, {error: callback});
equal(result, false);
equal(model.get('a'), 100);
equal(lastError, "Can't change admin status.");
equal(boundError, undefined);
});
test("Model: defaults always extend attrs (#459)", 2, function() {
var Defaulted = Backbone.Model.extend({
defaults: {one: 1},
initialize : function(attrs, opts) {
equal(this.attributes.one, 1);
}
});
var providedattrs = new Defaulted({});
var emptyattrs = new Defaulted();
});
test("Model: Inherit class properties", 6, function() {
var Parent = Backbone.Model.extend({
instancePropSame: function() {},
instancePropDiff: function() {}
}, {
classProp: function() {}
});
var Child = Parent.extend({
instancePropDiff: function() {}
});
var adult = new Parent;
var kid = new Child;
equal(Child.classProp, Parent.classProp);
notEqual(Child.classProp, undefined);
equal(kid.instancePropSame, adult.instancePropSame);
notEqual(kid.instancePropSame, undefined);
notEqual(Child.prototype.instancePropDiff, Parent.prototype.instancePropDiff);
notEqual(Child.prototype.instancePropDiff, undefined);
});
test("Model: Nested change events don't clobber previous attributes", 4, function() {
new Backbone.Model()
.on('change:state', function(model, newState) {
equal(model.previous('state'), undefined);
equal(newState, 'hello');
// Fire a nested change event.
model.set({other: 'whatever'});
})
.on('change:state', function(model, newState) {
equal(model.previous('state'), undefined);
equal(newState, 'hello');
})
.set({state: 'hello'});
});
test("hasChanged/set should use same comparison", 2, function() {
var changed = 0, model = new Backbone.Model({a: null});
model.on('change', function() {
ok(this.hasChanged('a'));
})
.on('change:a', function() {
changed++;
})
.set({a: undefined});
equal(changed, 1);
});
test("#582, #425, change:attribute callbacks should fire after all changes have occurred", 9, function() {
var model = new Backbone.Model;
var assertion = function() {
equal(model.get('a'), 'a');
equal(model.get('b'), 'b');
equal(model.get('c'), 'c');
};
model.on('change:a', assertion);
model.on('change:b', assertion);
model.on('change:c', assertion);
model.set({a: 'a', b: 'b', c: 'c'});
});
test("#871, set with attributes property", 1, function() {
var model = new Backbone.Model();
model.set({attributes: true});
ok(model.has('attributes'));
});
test("set value regardless of equality/change", 1, function() {
var model = new Backbone.Model({x: []});
var a = [];
model.set({x: a});
ok(model.get('x') === a);
});
test("unset fires change for undefined attributes", 1, function() {
var model = new Backbone.Model({x: undefined});
model.on('change:x', function(){ ok(true); });
model.unset('x');
});
test("set: undefined values", 1, function() {
var model = new Backbone.Model({x: undefined});
ok('x' in model.attributes);
});
test("change fires change:attr", 1, function() {
var model = new Backbone.Model({x: 1});
model.set({x: 2}, {silent: true});
model.on('change:x', function(){ ok(true); });
model.change();
});
test("hasChanged is false after original values are set", 2, function() {
var model = new Backbone.Model({x: 1});
model.on('change:x', function(){ ok(false); });
model.set({x: 2}, {silent: true});
ok(model.hasChanged());
model.set({x: 1}, {silent: true});
ok(!model.hasChanged());
});
test("save with `wait` succeeds without `validate`", 1, function() {
var model = new Backbone.Model();
model.save({x: 1}, {wait: true});
ok(lastRequest.model === model);
});
test("`hasChanged` for falsey keys", 2, function() {
var model = new Backbone.Model();
model.set({x: true}, {silent: true});
ok(!model.hasChanged(0));
ok(!model.hasChanged(''));
});
test("`previous` for falsey keys", 2, function() {
var model = new Backbone.Model({0: true, '': true});
model.set({0: false, '': false}, {silent: true});
equal(model.previous(0), true);
equal(model.previous(''), true);
});
test("`save` with `wait` sends correct attributes", 5, function() {
var changed = 0;
var model = new Backbone.Model({x: 1, y: 2});
model.on('change:x', function() { changed++; });
model.save({x: 3}, {wait: true});
deepEqual(JSON.parse(ajaxParams.data), {x: 3, y: 2});
equal(model.get('x'), 1);
equal(changed, 0);
lastRequest.options.success({});
equal(model.get('x'), 3);
equal(changed, 1);
});
test("a failed `save` with `wait` doesn't leave attributes behind", 1, function() {
var model = new Backbone.Model;
model.save({x: 1}, {wait: true});
equal(model.get('x'), void 0);
});
test("#1030 - `save` with `wait` results in correct attributes if success is called during sync", 2, function() {
var model = new Backbone.Model({x: 1, y: 2});
model.sync = function(method, model, options) {
options.success();
};
model.on("change:x", function() { ok(true); });
model.save({x: 3}, {wait: true});
equal(model.get('x'), 3);
});
test("save with wait validates attributes", 1, function() {
var model = new Backbone.Model();
model.validate = function() { ok(true); };
model.save({x: 1}, {wait: true});
});
test("nested `set` during `'change:attr'`", 2, function() {
var events = [];
var model = new Backbone.Model();
model.on('all', function(event) { events.push(event); });
model.on('change', function() {
model.set({z: true}, {silent:true});
});
model.on('change:x', function() {
model.set({y: true});
});
model.set({x: true});
deepEqual(events, ['change:y', 'change:x', 'change']);
events = [];
model.change();
deepEqual(events, ['change:z', 'change']);
});
test("nested `change` only fires once", 1, function() {
var model = new Backbone.Model();
model.on('change', function() {
ok(true);
model.change();
});
model.set({x: true});
});
test("no `'change'` event if no changes", 0, function() {
var model = new Backbone.Model();
model.on('change', function() { ok(false); });
model.change();
});
test("nested `set` during `'change'`", 6, function() {
var count = 0;
var model = new Backbone.Model();
model.on('change', function() {
switch(count++) {
case 0:
deepEqual(this.changedAttributes(), {x: true});
equal(model.previous('x'), undefined);
model.set({y: true});
break;
case 1:
deepEqual(this.changedAttributes(), {y: true});
equal(model.previous('x'), true);
model.set({z: true});
break;
case 2:
deepEqual(this.changedAttributes(), {z: true});
equal(model.previous('y'), true);
break;
default:
ok(false);
}
});
model.set({x: true});
});
test("nested `'change'` with silent", 3, function() {
var count = 0;
var model = new Backbone.Model();
model.on('change:y', function() { ok(true); });
model.on('change', function() {
switch(count++) {
case 0:
deepEqual(this.changedAttributes(), {x: true});
model.set({y: true}, {silent: true});
break;
case 1:
deepEqual(this.changedAttributes(), {y: true, z: true});
break;
default:
ok(false);
}
});
model.set({x: true});
model.set({z: true});
});
test("nested `'change:attr'` with silent", 1, function() {
var model = new Backbone.Model();
model.on('change:y', function(){ ok(true); });
model.on('change', function() {
model.set({y: true}, {silent: true});
model.set({z: true});
});
model.set({x: true});
});
test("multiple nested changes with silent", 1, function() {
var model = new Backbone.Model();
model.on('change:x', function() {
model.set({y: 1}, {silent: true});
model.set({y: 2});
});
model.on('change:y', function(model, val) {
equal(val, 2);
});
model.set({x: true});
model.change();
});
test("multiple nested changes with silent", 2, function() {
var changes = [];
var model = new Backbone.Model();
model.on('change:b', function(model, val) { changes.push(val); });
model.on('change', function() {
model.set({b: 1});
model.set({b: 2}, {silent: true});
});
model.set({b: 0});
deepEqual(changes, [0, 1, 1]);
model.change();
deepEqual(changes, [0, 1, 1, 2, 1]);
});
test("nested set multiple times", 1, function() {
var model = new Backbone.Model();
model.on('change:b', function() {
ok(true);
});
model.on('change:a', function() {
model.set({b: true});
model.set({b: true});
});
model.set({a: true});
});
test("Backbone.wrapError triggers `'error'`", 12, function() {
var resp = {};
var options = {};
var model = new Backbone.Model();
model.on('error', error);
var callback = Backbone.wrapError(null, model, options);
callback(model, resp);
callback(resp);
callback = Backbone.wrapError(error, model, options);
callback(model, resp);
callback(resp);
function error(_model, _resp, _options) {
ok(model === _model);
ok(resp === _resp);
ok(options === _options);
}
});
test("#1179 - isValid returns true in the absence of validate.", 1, function() {
var model = new Backbone.Model();
model.validate = null;
ok(model.isValid());
});
test("#1122 - clear does not alter options.", 1, function() {
var model = new Backbone.Model();
var options = {};
model.clear(options);
ok(!options.unset);
});
test("#1122 - unset does not alter options.", 1, function() {
var model = new Backbone.Model();
var options = {};
model.unset('x', options);
ok(!options.unset);
});
test("#1355 - `options` is passed to success callbacks", 3, function() {
var model = new Backbone.Model();
var opts = {
success: function( model, resp, options ) {
ok(options);
}
};
model.sync = function(method, model, options) {
options.success();
};
model.save({id: 1}, opts);
model.fetch(opts);
model.destroy(opts);
});
test("#1412 - Trigger 'sync' event.", 3, function() {
var model = new Backbone.Model({id: 1});
model.sync = function(method, model, options) { options.success(); };
model.on('sync', function() { ok(true); });
model.fetch();
model.save();
model.destroy();
});
test("#1365 - Destroy: New models execute success callback.", 2, function() {
new Backbone.Model()
.on('sync', function() { ok(false); })
.on('destroy', function(){ ok(true); })
.destroy({ success: function(){ ok(true); }});
});
test("#1433 - Save: An invalid model cannot be persisted.", 1, function() {
var model = new Backbone.Model;
model.validate = function(){ return 'invalid'; };
model.sync = function(){ ok(false); };
strictEqual(model.save(), false);
});
});

12
vendor/backbone/test/noconflict.js vendored Normal file
View File

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

371
vendor/backbone/test/router.js vendored Normal file
View File

@@ -0,0 +1,371 @@
$(document).ready(function() {
var router = null;
var location = null;
var lastRoute = null;
var lastArgs = [];
function onRoute(router, route, args) {
lastRoute = route;
lastArgs = args;
}
var Location = function(href) {
this.replace(href);
};
_.extend(Location.prototype, {
replace: function(href) {
_.extend(this, _.pick($('<a></a>', {href: href})[0],
'href',
'hash',
'host',
'search',
'fragment',
'pathname',
'protocol'
));
// In IE, anchor.pathname does not contain a leading slash though
// window.location.pathname does.
if (!/^\//.test(this.pathname)) this.pathname = '/' + this.pathname;
},
toString: function() {
return this.href;
}
});
module("Backbone.Router", {
setup: function() {
location = new Location('http://example.com');
Backbone.history = new Backbone.History({location: location});
router = new Router({testing: 101});
Backbone.history.interval = 9;
Backbone.history.start({pushState: false});
lastRoute = null;
lastArgs = [];
Backbone.history.on('route', onRoute);
},
teardown: function() {
Backbone.history.stop();
Backbone.history.off('route', onRoute);
}
});
var Router = Backbone.Router.extend({
count: 0,
routes: {
"noCallback": "noCallback",
"counter": "counter",
"search/:query": "search",
"search/:query/p:page": "search",
"contacts": "contacts",
"contacts/new": "newContact",
"contacts/:id": "loadContact",
"splat/*args/end": "splat",
"*first/complex-:part/*rest": "complex",
":entity?*args": "query",
"*anything": "anything"
},
initialize : function(options) {
this.testing = options.testing;
this.route('implicit', 'implicit');
},
counter: function() {
this.count++;
},
implicit: function() {
this.count++;
},
search : function(query, page) {
this.query = query;
this.page = page;
},
contacts: function(){
this.contact = 'index';
},
newContact: function(){
this.contact = 'new';
},
loadContact: function(){
this.contact = 'load';
},
splat : function(args) {
this.args = args;
},
complex : function(first, part, rest) {
this.first = first;
this.part = part;
this.rest = rest;
},
query : function(entity, args) {
this.entity = entity;
this.queryArgs = args;
},
anything : function(whatever) {
this.anything = whatever;
}
});
test("Router: initialize", 1, function() {
equal(router.testing, 101);
});
test("Router: routes (simple)", 4, function() {
location.replace('http://example.com#search/news');
Backbone.history.checkUrl();
equal(router.query, 'news');
equal(router.page, undefined);
equal(lastRoute, 'search');
equal(lastArgs[0], 'news');
});
test("Router: routes (two part)", 2, function() {
location.replace('http://example.com#search/nyc/p10');
Backbone.history.checkUrl();
equal(router.query, 'nyc');
equal(router.page, '10');
});
test("Router: routes via navigate", 2, function() {
Backbone.history.navigate('search/manhattan/p20', {trigger: true});
equal(router.query, 'manhattan');
equal(router.page, '20');
});
test("Router: routes via navigate for backwards-compatibility", 2, function() {
Backbone.history.navigate('search/manhattan/p20', true);
equal(router.query, 'manhattan');
equal(router.page, '20');
});
test("Router: route precedence via navigate", 6, function(){
// check both 0.9.x and backwards-compatibility options
_.each([ { trigger: true }, true ], function( options ){
Backbone.history.navigate('contacts', options);
equal(router.contact, 'index');
Backbone.history.navigate('contacts/new', options);
equal(router.contact, 'new');
Backbone.history.navigate('contacts/foo', options);
equal(router.contact, 'load');
});
});
test("loadUrl is not called for identical routes.", 0, function() {
Backbone.history.loadUrl = function(){ ok(false); };
location.replace('http://example.com#route');
Backbone.history.navigate('route');
Backbone.history.navigate('/route');
Backbone.history.navigate('/route');
});
test("Router: use implicit callback if none provided", 1, function() {
router.count = 0;
router.navigate('implicit', {trigger: true});
equal(router.count, 1);
});
test("Router: routes via navigate with {replace: true}", 1, function() {
location.replace('http://example.com#start_here');
Backbone.history.checkUrl();
location.replace = function(href) {
strictEqual(href, new Location('http://example.com#end_here').href);
};
Backbone.history.navigate('end_here', {replace: true});
});
test("Router: routes (splats)", 1, function() {
location.replace('http://example.com#splat/long-list/of/splatted_99args/end');
Backbone.history.checkUrl();
equal(router.args, 'long-list/of/splatted_99args');
});
test("Router: routes (complex)", 3, function() {
location.replace('http://example.com#one/two/three/complex-part/four/five/six/seven');
Backbone.history.checkUrl();
equal(router.first, 'one/two/three');
equal(router.part, 'part');
equal(router.rest, 'four/five/six/seven');
});
test("Router: routes (query)", 5, function() {
location.replace('http://example.com#mandel?a=b&c=d');
Backbone.history.checkUrl();
equal(router.entity, 'mandel');
equal(router.queryArgs, 'a=b&c=d');
equal(lastRoute, 'query');
equal(lastArgs[0], 'mandel');
equal(lastArgs[1], 'a=b&c=d');
});
test("Router: routes (anything)", 1, function() {
location.replace('http://example.com#doesnt-match-a-route');
Backbone.history.checkUrl();
equal(router.anything, 'doesnt-match-a-route');
});
test("Router: fires event when router doesn't have callback on it", 1, function() {
router.on("route:noCallback", function(){ ok(true); });
location.replace('http://example.com#noCallback');
Backbone.history.checkUrl();
});
test("#933, #908 - leading slash", 2, function() {
location.replace('http://example.com/root/foo');
Backbone.history.stop();
Backbone.history = new Backbone.History({location: location});
Backbone.history.start({root: '/root', hashChange: false, silent: true});
strictEqual(Backbone.history.getFragment(), 'foo');
Backbone.history.stop();
Backbone.history = new Backbone.History({location: location});
Backbone.history.start({root: '/root/', hashChange: false, silent: true});
strictEqual(Backbone.history.getFragment(), 'foo');
});
test("#1003 - History is started before navigate is called", 1, function() {
var history = new Backbone.History();
history.navigate = function(){
ok(Backbone.History.started);
};
Backbone.history.stop();
history.start();
// If this is not an old IE navigate will not be called.
if (!history.iframe) ok(true);
});
test("Router: route callback gets passed decoded values", 3, function() {
var route = 'has%2Fslash/complex-has%23hash/has%20space';
Backbone.history.navigate(route, {trigger: true});
equal(router.first, 'has/slash');
equal(router.part, 'has#hash');
equal(router.rest, 'has space');
});
test("Router: correctly handles URLs with % (#868)", 3, function() {
location.replace('http://example.com#search/fat%3A1.5%25');
Backbone.history.checkUrl();
location.replace('http://example.com#search/fat');
Backbone.history.checkUrl();
equal(router.query, 'fat');
equal(router.page, undefined);
equal(lastRoute, 'search');
});
test("#1185 - Use pathname when hashChange is not wanted.", 1, function() {
Backbone.history.stop();
location.replace('http://example.com/path/name#hash');
Backbone.history = new Backbone.History({location: location});
Backbone.history.start({hashChange: false});
var fragment = Backbone.history.getFragment();
strictEqual(fragment, location.pathname.replace(/^\//, ''));
});
test("#1206 - Strip leading slash before location.assign.", 1, function() {
Backbone.history.stop();
location.replace('http://example.com/root/');
Backbone.history = new Backbone.History({location: location});
Backbone.history.start({hashChange: false, root: '/root/'});
location.assign = function(pathname) {
strictEqual(pathname, '/root/fragment');
};
Backbone.history.navigate('/fragment');
});
test("#1387 - Root fragment without trailing slash.", 1, function() {
Backbone.history.stop();
location.replace('http://example.com/root');
Backbone.history = new Backbone.History({location: location});
Backbone.history.start({hashChange: false, root: '/root/', silent: true});
strictEqual(Backbone.history.getFragment(), '');
});
test("#1366 - History does not prepend root to fragment.", 2, function() {
Backbone.history.stop();
location.replace('http://example.com/root/');
Backbone.history = new Backbone.History({
location: location,
history: {
pushState: function(state, title, url) {
strictEqual(url, '/root/x');
}
}
});
Backbone.history.start({
root: '/root/',
pushState: true,
hashChange: false
});
Backbone.history.navigate('x');
strictEqual(Backbone.history.fragment, 'x');
});
test("Router: Normalize root.", 1, function() {
Backbone.history.stop();
location.replace('http://example.com/root');
Backbone.history = new Backbone.History({
location: location,
history: {
pushState: function(state, title, url) {
strictEqual(url, '/root/fragment');
}
}
});
Backbone.history.start({
pushState: true,
root: '/root',
hashChange: false
});
Backbone.history.navigate('fragment');
});
test("Router: Normalize root.", 1, function() {
Backbone.history.stop();
location.replace('http://example.com/root#fragment');
Backbone.history = new Backbone.History({
location: location,
history: {
pushState: function(state, title, url) {},
replaceState: function(state, title, url) {
strictEqual(url, 'http://example.com/root/fragment');
}
}
});
Backbone.history.start({
pushState: true,
root: '/root'
});
});
test("Router: Normalize root.", 1, function() {
Backbone.history.stop();
location.replace('http://example.com/root');
Backbone.history = new Backbone.History({location: location});
Backbone.history.loadUrl = function() { ok(true); };
Backbone.history.start({
pushState: true,
root: '/root'
});
});
});

160
vendor/backbone/test/sync.js vendored Normal file
View File

@@ -0,0 +1,160 @@
$(document).ready(function() {
var ajax = Backbone.ajax;
var lastRequest = null;
var Library = Backbone.Collection.extend({
url : function() { return '/library'; }
});
var library;
var attrs = {
title : "The Tempest",
author : "Bill Shakespeare",
length : 123
};
module("Backbone.sync", {
setup : function() {
library = new Library();
Backbone.ajax = function(obj) {
lastRequest = obj;
};
library.create(attrs, {wait: false});
},
teardown: function() {
Backbone.ajax = ajax;
}
});
test("sync: read", 4, function() {
library.fetch();
equal(lastRequest.url, '/library');
equal(lastRequest.type, 'GET');
equal(lastRequest.dataType, 'json');
ok(_.isEmpty(lastRequest.data));
});
test("sync: passing data", 3, function() {
library.fetch({data: {a: 'a', one: 1}});
equal(lastRequest.url, '/library');
equal(lastRequest.data.a, 'a');
equal(lastRequest.data.one, 1);
});
test("sync: create", 6, function() {
equal(lastRequest.url, '/library');
equal(lastRequest.type, 'POST');
equal(lastRequest.dataType, 'json');
var data = JSON.parse(lastRequest.data);
equal(data.title, 'The Tempest');
equal(data.author, 'Bill Shakespeare');
equal(data.length, 123);
});
test("sync: update", 7, function() {
library.first().save({id: '1-the-tempest', author: 'William Shakespeare'});
equal(lastRequest.url, '/library/1-the-tempest');
equal(lastRequest.type, 'PUT');
equal(lastRequest.dataType, 'json');
var data = JSON.parse(lastRequest.data);
equal(data.id, '1-the-tempest');
equal(data.title, 'The Tempest');
equal(data.author, 'William Shakespeare');
equal(data.length, 123);
});
test("sync: update with emulateHTTP and emulateJSON", 7, function() {
Backbone.emulateHTTP = Backbone.emulateJSON = true;
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
equal(lastRequest.url, '/library/2-the-tempest');
equal(lastRequest.type, 'POST');
equal(lastRequest.dataType, 'json');
equal(lastRequest.data._method, 'PUT');
var data = JSON.parse(lastRequest.data.model);
equal(data.id, '2-the-tempest');
equal(data.author, 'Tim Shakespeare');
equal(data.length, 123);
Backbone.emulateHTTP = Backbone.emulateJSON = false;
});
test("sync: update with just emulateHTTP", 6, function() {
Backbone.emulateHTTP = true;
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
equal(lastRequest.url, '/library/2-the-tempest');
equal(lastRequest.type, 'POST');
equal(lastRequest.contentType, 'application/json');
var data = JSON.parse(lastRequest.data);
equal(data.id, '2-the-tempest');
equal(data.author, 'Tim Shakespeare');
equal(data.length, 123);
Backbone.emulateHTTP = false;
});
test("sync: update with just emulateJSON", 6, function() {
Backbone.emulateJSON = true;
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
equal(lastRequest.url, '/library/2-the-tempest');
equal(lastRequest.type, 'PUT');
equal(lastRequest.contentType, 'application/x-www-form-urlencoded');
var data = JSON.parse(lastRequest.data.model);
equal(data.id, '2-the-tempest');
equal(data.author, 'Tim Shakespeare');
equal(data.length, 123);
Backbone.emulateJSON = false;
});
test("sync: read model", 3, function() {
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
library.first().fetch();
equal(lastRequest.url, '/library/2-the-tempest');
equal(lastRequest.type, 'GET');
ok(_.isEmpty(lastRequest.data));
});
test("sync: destroy", 3, function() {
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
library.first().destroy({wait: true});
equal(lastRequest.url, '/library/2-the-tempest');
equal(lastRequest.type, 'DELETE');
equal(lastRequest.data, null);
});
test("sync: destroy with emulateHTTP", 3, function() {
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
Backbone.emulateHTTP = Backbone.emulateJSON = true;
library.first().destroy();
equal(lastRequest.url, '/library/2-the-tempest');
equal(lastRequest.type, 'POST');
equal(JSON.stringify(lastRequest.data), '{"_method":"DELETE"}');
Backbone.emulateHTTP = Backbone.emulateJSON = false;
});
test("sync: urlError", 2, function() {
var model = new Backbone.Model();
raises(function() {
model.fetch();
});
model.fetch({url: '/one/two'});
equal(lastRequest.url, '/one/two');
});
test("#1052 - `options` is optional.", 0, function() {
var model = new Backbone.Model();
model.url = '/test';
Backbone.sync('create', model);
});
test("Backbone.ajax", 1, function() {
Backbone.ajax = function(settings){
strictEqual(settings.url, '/test');
};
var model = new Backbone.Model();
model.url = '/test';
Backbone.sync('create', model);
});
});

File diff suppressed because it is too large Load Diff

649
vendor/backbone/test/vendor/jslitmus.js vendored Normal file
View File

@@ -0,0 +1,649 @@
// JSLitmus.js
//
// Copyright (c) 2010, Robert Kieffer, http://broofa.com
// Available under MIT license (http://en.wikipedia.org/wiki/MIT_License)
(function() {
// Private methods and state
// Get platform info but don't go crazy trying to recognize everything
// that's out there. This is just for the major platforms and OSes.
var platform = 'unknown platform', ua = navigator.userAgent;
// Detect OS
var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
// Detect browser
var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
// Detect version
var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
/**
* A smattering of methods that are needed to implement the JSLitmus testbed.
*/
var jsl = {
/**
* Enhanced version of escape()
*/
escape: function(s) {
s = s.replace(/,/g, '\\,');
s = escape(s);
s = s.replace(/\+/g, '%2b');
s = s.replace(/ /g, '+');
return s;
},
/**
* Get an element by ID.
*/
$: function(id) {
return document.getElementById(id);
},
/**
* Null function
*/
F: function() {},
/**
* Set the status shown in the UI
*/
status: function(msg) {
var el = jsl.$('jsl_status');
if (el) el.innerHTML = msg || '';
},
/**
* Convert a number to an abbreviated string like, "15K" or "10M"
*/
toLabel: function(n) {
if (n == Infinity) {
return 'Infinity';
} else if (n > 1e9) {
n = Math.round(n/1e8);
return n/10 + 'B';
} else if (n > 1e6) {
n = Math.round(n/1e5);
return n/10 + 'M';
} else if (n > 1e3) {
n = Math.round(n/1e2);
return n/10 + 'K';
}
return n;
},
/**
* Copy properties from src to dst
*/
extend: function(dst, src) {
for (var k in src) dst[k] = src[k]; return dst;
},
/**
* Like Array.join(), but for the key-value pairs in an object
*/
join: function(o, delimit1, delimit2) {
if (o.join) return o.join(delimit1); // If it's an array
var pairs = [];
for (var k in o) pairs.push(k + delimit1 + o[k]);
return pairs.join(delimit2);
},
/**
* Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
*/
indexOf: function(arr, o) {
if (arr.indexOf) return arr.indexOf(o);
for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
return -1;
}
};
/**
* Test manages a single test (created with
* JSLitmus.test())
*
* @private
*/
var Test = function (name, f) {
if (!f) throw new Error('Undefined test function');
if (!/function[^\(]*\(([^,\)]*)/.test(f.toString())) {
throw new Error('"' + name + '" test: Test is not a valid Function object');
}
this.loopArg = RegExp.$1;
this.name = name;
this.f = f;
};
jsl.extend(Test, /** @lends Test */ {
/** Calibration tests for establishing iteration loop overhead */
CALIBRATIONS: [
new Test('calibrating loop', function(count) {while (count--);}),
new Test('calibrating function', jsl.F)
],
/**
* Run calibration tests. Returns true if calibrations are not yet
* complete (in which case calling code should run the tests yet again).
* onCalibrated - Callback to invoke when calibrations have finished
*/
calibrate: function(onCalibrated) {
for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
var cal = Test.CALIBRATIONS[i];
if (cal.running) return true;
if (!cal.count) {
cal.isCalibration = true;
cal.onStop = onCalibrated;
//cal.MIN_TIME = .1; // Do calibrations quickly
cal.run(2e4);
return true;
}
}
return false;
}
});
jsl.extend(Test.prototype, {/** @lends Test.prototype */
/** Initial number of iterations */
INIT_COUNT: 10,
/** Max iterations allowed (i.e. used to detect bad looping functions) */
MAX_COUNT: 1e9,
/** Minimum time a test should take to get valid results (secs) */
MIN_TIME: .5,
/** Callback invoked when test state changes */
onChange: jsl.F,
/** Callback invoked when test is finished */
onStop: jsl.F,
/**
* Reset test state
*/
reset: function() {
delete this.count;
delete this.time;
delete this.running;
delete this.error;
},
/**
* Run the test (in a timeout). We use a timeout to make sure the browser
* has a chance to finish rendering any UI changes we've made, like
* updating the status message.
*/
run: function(count) {
count = count || this.INIT_COUNT;
jsl.status(this.name + ' x ' + count);
this.running = true;
var me = this;
setTimeout(function() {me._run(count);}, 200);
},
/**
* The nuts and bolts code that actually runs a test
*/
_run: function(count) {
var me = this;
// Make sure calibration tests have run
if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
this.error = null;
try {
var start, f = this.f, now, i = count;
// Start the timer
start = new Date();
// Now for the money shot. If this is a looping function ...
if (this.loopArg) {
// ... let it do the iteration itself
f(count);
} else {
// ... otherwise do the iteration for it
while (i--) f();
}
// Get time test took (in secs)
this.time = Math.max(1,new Date() - start)/1000;
// Store iteration count and per-operation time taken
this.count = count;
this.period = this.time/count;
// Do we need to do another run?
this.running = this.time <= this.MIN_TIME;
// ... if so, compute how many times we should iterate
if (this.running) {
// Bump the count to the nearest power of 2
var x = this.MIN_TIME/this.time;
var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
count *= pow;
if (count > this.MAX_COUNT) {
throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
}
}
} catch (e) {
// Exceptions are caught and displayed in the test UI
this.reset();
this.error = e;
}
// Figure out what to do next
if (this.running) {
me.run(count);
} else {
jsl.status('');
me.onStop(me);
}
// Finish up
this.onChange(this);
},
/**
* Get the number of operations per second for this test.
*
* @param normalize if true, iteration loop overhead taken into account
*/
getHz: function(/**Boolean*/ normalize) {
var p = this.period;
// Adjust period based on the calibration test time
if (normalize && !this.isCalibration) {
var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
// If the period is within 20% of the calibration time, then zero the
// it out
p = p < cal.period*1.2 ? 0 : p - cal.period;
}
return Math.round(1/p);
},
/**
* Get a friendly string describing the test
*/
toString: function() {
return this.name + ' - ' + this.time/this.count + ' secs';
}
});
// CSS we need for the UI
var STYLESHEET = '<style> \
#jslitmus {font-family:sans-serif; font-size: 12px;} \
#jslitmus a {text-decoration: none;} \
#jslitmus a:hover {text-decoration: underline;} \
#jsl_status { \
margin-top: 10px; \
font-size: 10px; \
color: #888; \
} \
A IMG {border:none} \
#test_results { \
margin-top: 10px; \
font-size: 12px; \
font-family: sans-serif; \
border-collapse: collapse; \
border-spacing: 0px; \
} \
#test_results th, #test_results td { \
border: solid 1px #ccc; \
vertical-align: top; \
padding: 3px; \
} \
#test_results th { \
vertical-align: bottom; \
background-color: #ccc; \
padding: 1px; \
font-size: 10px; \
} \
#test_results #test_platform { \
color: #444; \
text-align:center; \
} \
#test_results .test_row { \
color: #006; \
cursor: pointer; \
} \
#test_results .test_nonlooping { \
border-left-style: dotted; \
border-left-width: 2px; \
} \
#test_results .test_looping { \
border-left-style: solid; \
border-left-width: 2px; \
} \
#test_results .test_name {white-space: nowrap;} \
#test_results .test_pending { \
} \
#test_results .test_running { \
font-style: italic; \
} \
#test_results .test_done {} \
#test_results .test_done { \
text-align: right; \
font-family: monospace; \
} \
#test_results .test_error {color: #600;} \
#test_results .test_error .error_head {font-weight:bold;} \
#test_results .test_error .error_body {font-size:85%;} \
#test_results .test_row:hover td { \
background-color: #ffc; \
text-decoration: underline; \
} \
#chart { \
margin: 10px 0px; \
width: 250px; \
} \
#chart img { \
border: solid 1px #ccc; \
margin-bottom: 5px; \
} \
#chart #tiny_url { \
height: 40px; \
width: 250px; \
} \
#jslitmus_credit { \
font-size: 10px; \
color: #888; \
margin-top: 8px; \
} \
</style>';
// HTML markup for the UI
var MARKUP = '<div id="jslitmus"> \
<button onclick="JSLitmus.runAll(event)">Run Tests</button> \
<button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
<br \> \
<br \> \
<input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
<table id="test_results"> \
<colgroup> \
<col /> \
<col width="100" /> \
</colgroup> \
<tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
<tr><th>Test</th><th>Ops/sec</th></tr> \
<tr id="test_row_template" class="test_row" style="display:none"> \
<td class="test_name"></td> \
<td class="test_result">Ready</td> \
</tr> \
</table> \
<div id="jsl_status"></div> \
<div id="chart" style="display:none"> \
<a id="chart_link" target="_blank"><img id="chart_image"></a> \
TinyURL (for chart): \
<iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
</div> \
<a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
</div>';
/**
* The public API for creating and running tests
*/
window.JSLitmus = {
/** The list of all tests that have been registered with JSLitmus.test */
_tests: [],
/** The queue of tests that need to be run */
_queue: [],
/**
* The parsed query parameters the current page URL. This is provided as a
* convenience for test functions - it's not used by JSLitmus proper
*/
params: {},
/**
* Initialize
*/
_init: function() {
// Parse query params into JSLitmus.params[] hash
var match = (location + '').match(/([^?#]*)(#.*)?$/);
if (match) {
var pairs = match[1].split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
if (pair.length > 1) {
var key = pair.shift();
var value = pair.length > 1 ? pair.join('=') : pair[0];
this.params[key] = value;
}
}
}
// Write out the stylesheet. We have to do this here because IE
// doesn't honor sheets written after the document has loaded.
document.write(STYLESHEET);
// Setup the rest of the UI once the document is loaded
if (window.addEventListener) {
window.addEventListener('load', this._setup, false);
} else if (document.addEventListener) {
document.addEventListener('load', this._setup, false);
} else if (window.attachEvent) {
window.attachEvent('onload', this._setup);
}
return this;
},
/**
* Set up the UI
*/
_setup: function() {
var el = jsl.$('jslitmus_container');
if (!el) document.body.appendChild(el = document.createElement('div'));
el.innerHTML = MARKUP;
// Render the UI for all our tests
for (var i=0; i < JSLitmus._tests.length; i++)
JSLitmus.renderTest(JSLitmus._tests[i]);
},
/**
* (Re)render all the test results
*/
renderAll: function() {
for (var i = 0; i < JSLitmus._tests.length; i++)
JSLitmus.renderTest(JSLitmus._tests[i]);
JSLitmus.renderChart();
},
/**
* (Re)render the chart graphics
*/
renderChart: function() {
var url = JSLitmus.chartUrl();
jsl.$('chart_link').href = url;
jsl.$('chart_image').src = url;
jsl.$('chart').style.display = '';
// Update the tiny URL
jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
},
/**
* (Re)render the results for a specific test
*/
renderTest: function(test) {
// Make a new row if needed
if (!test._row) {
var trow = jsl.$('test_row_template');
if (!trow) return;
test._row = trow.cloneNode(true);
test._row.style.display = '';
test._row.id = '';
test._row.onclick = function() {JSLitmus._queueTest(test);};
test._row.title = 'Run ' + test.name + ' test';
trow.parentNode.appendChild(test._row);
test._row.cells[0].innerHTML = test.name;
}
var cell = test._row.cells[1];
var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
if (test.error) {
cns.push('test_error');
cell.innerHTML =
'<div class="error_head">' + test.error + '</div>' +
'<ul class="error_body"><li>' +
jsl.join(test.error, ': ', '</li><li>') +
'</li></ul>';
} else {
if (test.running) {
cns.push('test_running');
cell.innerHTML = 'running';
} else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
cns.push('test_pending');
cell.innerHTML = 'pending';
} else if (test.count) {
cns.push('test_done');
var hz = test.getHz(jsl.$('test_normalize').checked);
cell.innerHTML = hz != Infinity ? hz : '&infin;';
cell.title = 'Looped ' + test.count + ' times in ' + test.time + ' seconds';
} else {
cell.innerHTML = 'ready';
}
}
cell.className = cns.join(' ');
},
/**
* Create a new test
*/
test: function(name, f) {
// Create the Test object
var test = new Test(name, f);
JSLitmus._tests.push(test);
// Re-render if the test state changes
test.onChange = JSLitmus.renderTest;
// Run the next test if this one finished
test.onStop = function(test) {
if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
JSLitmus.currentTest = null;
JSLitmus._nextTest();
};
// Render the new test
this.renderTest(test);
},
/**
* Add all tests to the run queue
*/
runAll: function(e) {
e = e || window.event;
var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
for (var i = 0; i < len; i++) {
JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
}
},
/**
* Remove all tests from the run queue. The current test has to finish on
* it's own though
*/
stop: function() {
while (JSLitmus._queue.length) {
var test = JSLitmus._queue.shift();
JSLitmus.renderTest(test);
}
},
/**
* Run the next test in the run queue
*/
_nextTest: function() {
if (!JSLitmus.currentTest) {
var test = JSLitmus._queue.shift();
if (test) {
jsl.$('stop_button').disabled = false;
JSLitmus.currentTest = test;
test.run();
JSLitmus.renderTest(test);
if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
} else {
jsl.$('stop_button').disabled = true;
JSLitmus.renderChart();
}
}
},
/**
* Add a test to the run queue
*/
_queueTest: function(test) {
if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
JSLitmus._queue.push(test);
JSLitmus.renderTest(test);
JSLitmus._nextTest();
},
/**
* Generate a Google Chart URL that shows the data for all tests
*/
chartUrl: function() {
var n = JSLitmus._tests.length, markers = [], data = [];
var d, min = 0, max = -1e10;
var normalize = jsl.$('test_normalize').checked;
// Gather test data
for (var i=0; i < JSLitmus._tests.length; i++) {
var test = JSLitmus._tests[i];
if (test.count) {
var hz = test.getHz(normalize);
var v = hz != Infinity ? hz : 0;
data.push(v);
markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
markers.length + ',10');
max = Math.max(v, max);
}
}
if (markers.length <= 0) return null;
// Build chart title
var title = document.getElementsByTagName('title');
title = (title && title.length) ? title[0].innerHTML : null;
var chart_title = [];
if (title) chart_title.push(title);
chart_title.push('Ops/sec (' + platform + ')');
// Build labels
var labels = [jsl.toLabel(min), jsl.toLabel(max)];
var w = 250, bw = 15;
var bs = 5;
var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
var params = {
chtt: escape(chart_title.join('|')),
chts: '000000,10',
cht: 'bhg', // chart type
chd: 't:' + data.join(','), // data set
chds: min + ',' + max, // max/min of data
chxt: 'x', // label axes
chxl: '0:|' + labels.join('|'), // labels
chsp: '0,1',
chm: markers.join('|'), // test names
chbh: [bw, 0, bs].join(','), // bar widths
// chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
chs: w + 'x' + h
};
return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
}
};
JSLitmus._init();
})();

481
vendor/backbone/test/vendor/json2.js vendored Normal file
View File

@@ -0,0 +1,481 @@
/*
http://www.JSON.org/json2.js
2009-09-29
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, strict: false */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (!this.JSON) {
this.JSON = {};
}
(function () {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ?
'"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' :
'"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());

236
vendor/backbone/test/vendor/qunit.css vendored Executable file
View File

@@ -0,0 +1,236 @@
/**
* QUnit v1.8.0 - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2012 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 15px 15px 0 0;
-moz-border-radius: 15px 15px 0 0;
-webkit-border-top-right-radius: 15px;
-webkit-border-top-left-radius: 15px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-header label {
display: inline-block;
padding-left: 0.5em;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
box-shadow: inset 0px 2px 13px #999;
-moz-box-shadow: inset 0px 2px 13px #999;
-webkit-box-shadow: inset 0px 2px 13px #999;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
margin: 0.5em;
padding: 0.4em 0.5em 0.4em 0.5em;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #5E740B;
background-color: #fff;
border-left: 26px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
#qunit-testresult .module-name {
font-weight: bold;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}

1863
vendor/backbone/test/vendor/qunit.js vendored Executable file

File diff suppressed because it is too large Load Diff

244
vendor/backbone/test/view.js vendored Normal file
View File

@@ -0,0 +1,244 @@
$(document).ready(function() {
var view;
module("Backbone.View", {
setup: function() {
view = new Backbone.View({
id : 'test-view',
className : 'test-view'
});
}
});
test("View: constructor", 4, function() {
equal(view.el.id, 'test-view');
equal(view.el.className, 'test-view');
equal(view.options.id, 'test-view');
equal(view.options.className, 'test-view');
});
test("View: jQuery", 2, function() {
view.setElement(document.body);
ok(view.$('#qunit-header a').get(0).innerHTML.match(/Backbone Test Suite/));
ok(view.$('#qunit-header a').get(1).innerHTML.match(/Backbone Speed Suite/));
});
test("View: make", 3, function() {
var div = view.make('div', {id: 'test-div'}, "one two three");
equal(div.tagName.toLowerCase(), 'div');
equal(div.id, 'test-div');
equal($(div).text(), 'one two three');
});
test("View: make can take falsy values for content", 2, function() {
var div = view.make('div', {id: 'test-div'}, 0);
equal($(div).text(), '0');
var div = view.make('div', {id: 'test-div'}, '');
equal($(div).text(), '');
});
test("View: initialize", 1, function() {
var View = Backbone.View.extend({
initialize: function() {
this.one = 1;
}
});
var view = new View;
equal(view.one, 1);
});
test("View: delegateEvents", 6, function() {
var counter = 0;
var counter2 = 0;
view.setElement(document.body);
view.increment = function(){ counter++; };
view.$el.bind('click', function(){ counter2++; });
var events = {"click #qunit-banner": "increment"};
view.delegateEvents(events);
$('#qunit-banner').trigger('click');
equal(counter, 1);
equal(counter2, 1);
$('#qunit-banner').trigger('click');
equal(counter, 2);
equal(counter2, 2);
view.delegateEvents(events);
$('#qunit-banner').trigger('click');
equal(counter, 3);
equal(counter2, 3);
});
test("View: delegateEvents allows functions for callbacks", 3, function() {
view.counter = 0;
view.setElement("#qunit-banner");
var events = {"click": function() { this.counter++; }};
view.delegateEvents(events);
$('#qunit-banner').trigger('click');
equal(view.counter, 1);
$('#qunit-banner').trigger('click');
equal(view.counter, 2);
view.delegateEvents(events);
$('#qunit-banner').trigger('click');
equal(view.counter, 3);
});
test("View: undelegateEvents", 6, function() {
var counter = 0;
var counter2 = 0;
view.setElement(document.body);
view.increment = function(){ counter++; };
$(view.el).unbind('click');
$(view.el).bind('click', function(){ counter2++; });
var events = {"click #qunit-userAgent": "increment"};
view.delegateEvents(events);
$('#qunit-userAgent').trigger('click');
equal(counter, 1);
equal(counter2, 1);
view.undelegateEvents();
$('#qunit-userAgent').trigger('click');
equal(counter, 1);
equal(counter2, 2);
view.delegateEvents(events);
$('#qunit-userAgent').trigger('click');
equal(counter, 2);
equal(counter2, 3);
});
test("View: _ensureElement with DOM node el", 1, function() {
var ViewClass = Backbone.View.extend({
el: document.body
});
var view = new ViewClass;
equal(view.el, document.body);
});
test("View: _ensureElement with string el", 3, function() {
var ViewClass = Backbone.View.extend({
el: "body"
});
var view = new ViewClass;
strictEqual(view.el, document.body);
ViewClass = Backbone.View.extend({
el: "#testElement > h1"
});
view = new ViewClass;
strictEqual(view.el, $("#testElement > h1").get(0));
ViewClass = Backbone.View.extend({
el: "#nonexistent"
});
view = new ViewClass;
ok(!view.el);
});
test("View: with className and id functions", 2, function() {
var View = Backbone.View.extend({
className: function() {
return 'className';
},
id: function() {
return 'id';
}
});
var view = new View();
strictEqual(view.el.className, 'className');
strictEqual(view.el.id, 'id');
});
test("View: with attributes", 2, function() {
var view = new Backbone.View({attributes : {'class': 'one', id: 'two'}});
equal(view.el.className, 'one');
equal(view.el.id, 'two');
});
test("View: with attributes as a function", 1, function() {
var viewClass = Backbone.View.extend({
attributes: function() {
return {'class': 'dynamic'};
}
});
equal((new viewClass).el.className, 'dynamic');
});
test("View: multiple views per element", 3, function() {
var count = 0, ViewClass = Backbone.View.extend({
el: $("body"),
events: {
"click": "click"
},
click: function() {
count++;
}
});
var view1 = new ViewClass;
$("body").trigger("click");
equal(1, count);
var view2 = new ViewClass;
$("body").trigger("click");
equal(3, count);
view1.delegateEvents();
$("body").trigger("click");
equal(5, count);
});
test("View: custom events, with namespaces", 2, function() {
var count = 0;
var ViewClass = Backbone.View.extend({
el: $('body'),
events: function() {
return {"fake$event.namespaced": "run"};
},
run: function() {
count++;
}
});
var view = new ViewClass;
$('body').trigger('fake$event').trigger('fake$event');
equal(count, 2);
$('body').unbind('.namespaced');
$('body').trigger('fake$event');
equal(count, 2);
});
test("#1048 - setElement uses provided object.", 2, function() {
var $el = $('body');
var view = new Backbone.View({el: $el});
ok(view.$el === $el);
view.setElement($el = $($el));
ok(view.$el === $el);
});
test("#986 - Undelegate before changing element.", 1, function() {
var a = $('<button></button>');
var b = $('<button></button>');
var View = Backbone.View.extend({
events: {click: function(e) { ok(view.el === e.target); }}
});
var view = new View({el: a});
view.setElement(b);
a.trigger('click');
b.trigger('click');
});
test("#1172 - Clone attributes object", 2, function() {
var View = Backbone.View.extend({attributes: {foo: 'bar'}});
var v1 = new View({id: 'foo'});
strictEqual(v1.el.id, 'foo');
var v2 = new View();
ok(!v2.el.id);
});
test("#1228 - tagName can be provided as a function", 1, function() {
var View = Backbone.View.extend({tagName: function(){ return 'p'; }});
ok(new View().$el.is('p'));
});
});

1
vendor/benchmark.js vendored

Submodule vendor/benchmark.js deleted from f0306c0345

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

@@ -0,0 +1,22 @@
Copyright 2010-2012 Mathias Bynens <http://mathiasbynens.be/>
Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/>
Modified by John-David Dalton <http://allyoucanleet.com/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

135
vendor/benchmark.js/README.md vendored Normal file
View File

@@ -0,0 +1,135 @@
# Benchmark.js <sup>v1.0.0</sup>
A [robust](http://calendar.perfplanet.com/2010/bulletproof-javascript-benchmarks/ "Bulletproof JavaScript benchmarks") benchmarking library that works on nearly all JavaScript platforms<sup><a name="fnref1" href="#fn1">1</a></sup>, supports high-resolution timers, and returns statistically significant results. As seen on [jsPerf](http://jsperf.com/).
## Download
* [Development source](https://raw.github.com/bestiejs/benchmark.js/1.0.0/benchmark.js)
## Dive in
Weve got [API docs](http://benchmarkjs.com/docs) and [unit tests](http://benchmarkjs.com/tests).
For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/benchmark.js/wiki/Roadmap).
## Support
Benchmark.js has been tested in at least Adobe AIR 3.1, Chrome 5-21, Firefox 1.5-13, IE 6-9, Opera 9.25-12.01, Safari 3-6, Node.js 0.8.6, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5.
## Installation and usage
In a browser or Adobe AIR:
```html
<script src="benchmark.js"></script>
```
Optionally, expose Javas nanosecond timer by adding the `nano` applet to the `<body>`:
```html
<applet code="nano" archive="nano.jar"></applet>
```
Or enable Chromes microsecond timer by using the [command line switch](http://peter.sh/experiments/chromium-command-line-switches/#enable-benchmarking):
--enable-benchmarking
Via [npm](http://npmjs.org/):
```bash
npm install benchmark
```
In [Node.js](http://nodejs.org/) and [RingoJS v0.8.0+](http://ringojs.org/):
```js
var Benchmark = require('benchmark');
```
Optionally, use the [microtime module](https://github.com/wadey/node-microtime) by Wade Simmons:
```bash
npm install microtime
```
In [RingoJS v0.7.0-](http://ringojs.org/):
```js
var Benchmark = require('benchmark').Benchmark;
```
In [Rhino](http://www.mozilla.org/rhino/):
```js
load('benchmark.js');
```
In an AMD loader like [RequireJS](http://requirejs.org/):
```js
require({
'paths': {
'benchmark': 'path/to/benchmark'
}
},
['benchmark'], function(Benchmark) {
console.log(Benchmark.version);
});
// or with platform.js
// https://github.com/bestiejs/platform.js
require({
'paths': {
'benchmark': 'path/to/benchmark',
'platform': 'path/to/platform'
}
},
['benchmark', 'platform'], function(Benchmark, platform) {
Benchmark.platform = platform;
console.log(Benchmark.platform.name);
});
```
Usage example:
```js
var suite = new Benchmark.Suite;
// add tests
suite.add('RegExp#test', function() {
/o/.test('Hello World!');
})
.add('String#indexOf', function() {
'Hello World!'.indexOf('o') > -1;
})
// add listeners
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
// run async
.run({ 'async': true });
// logs:
// > RegExp#test x 4,161,532 +-0.99% (59 cycles)
// > String#indexOf x 6,139,623 +-1.00% (131 cycles)
// > Fastest is String#indexOf
```
## BestieJS
Benchmark.js is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation.
## Authors
* [Mathias Bynens](http://mathiasbynens.be/)
[![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter")
* [John-David Dalton](http://allyoucanleet.com/)
[![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter")
## Contributors
* [Kit Cambridge](http://kitcambridge.github.com/)
[![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter")

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

File diff suppressed because it is too large Load Diff

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

Binary file not shown.

1
vendor/docdown vendored

Submodule vendor/docdown deleted from 87466c279a

20
vendor/docdown/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

33
vendor/docdown/README.md vendored Normal file
View File

@@ -0,0 +1,33 @@
# Docdown <sup>v1.0.0</sup>
A simple JSDoc to Markdown documentation generator.
## Documentation
The documentation for Docdown can be viewed here: [/doc/README.md](https://github.com/jdalton/docdown/blob/master/doc/README.md#readme)
For a list of upcoming features, check out our [roadmap](https://github.com/jdalton/docdown/wiki/Roadmap).
## Installation and usage
Usage example:
```php
require("docdown.php");
// generate Markdown
$markdown = docdown(array(
"path" => $filepath,
"url" => "https://github.com/username/project/blob/master/my.js"
));
```
## Author
* [John-David Dalton](http://allyoucanleet.com/)
[![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter")
## Contributors
* [Mathias Bynens](http://mathiasbynens.be/)
[![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter")

38
vendor/docdown/docdown.php vendored Normal file
View File

@@ -0,0 +1,38 @@
<?php
/*!
* Docdown v1.0.0-pre
* Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/>
* Available under MIT license <http://mths.be/mit>
*/
require(dirname(__FILE__) . '/src/DocDown/Generator.php');
/**
* Generates Markdown from JSDoc entries in a given file.
*
* @param {Array} [$options=array()] The options array.
* @returns {String} The generated Markdown.
* @example
*
* // specify a file path
* $markdown = docdown(array(
* // path to js file
* 'path' => $filepath,
* // url used to reference line numbers in code
* 'url' => 'https://github.com/username/project/blob/master/my.js'
* ));
*
* // or pass raw js
* $markdown = docdown(array(
* // raw JavaScript source
* 'source' => $rawJS,
* // documentation title
* 'title' => 'My API Documentation',
* // url used to reference line numbers in code
* 'url' => 'https://github.com/username/project/blob/master/my.js'
* ));
*/
function docdown( $options = array() ) {
$gen = new Generator($options);
return $gen->generate();
}
?>

304
vendor/docdown/src/DocDown/Entry.php vendored Normal file
View File

@@ -0,0 +1,304 @@
<?php
/**
* A class to simplify parsing a single JSDoc entry.
*/
class Entry {
/**
* The documentation entry.
*
* @memberOf Entry
* @type String
*/
public $entry = '';
/**
* The language highlighter used for code examples.
*
* @memberOf Entry
* @type String
*/
public $lang = '';
/**
* The source code.
*
* @memberOf Entry
* @type String
*/
public $source = '';
/*--------------------------------------------------------------------------*/
/**
* The Entry constructor.
*
* @constructor
* @param {String} $entry The documentation entry to analyse.
* @param {String} $source The source code.
* @param {String} $lang The language highlighter used for code examples.
*/
public function __construct( $entry, $source, $lang = 'js' ) {
$this->entry = $entry;
$this->lang = $lang;
$this->source = str_replace(PHP_EOL, "\n", $source);
}
/*--------------------------------------------------------------------------*/
/**
* Extracts the documentation entries from source code.
*
* @static
* @memberOf Entry
* @param {String} $source The source code.
* @returns {Array} The array of entries.
*/
public static function getEntries( $source ) {
preg_match_all('#/\*\*(?![-!])[\s\S]*?\*/\s*[^\n]+#', $source, $result);
return array_pop($result);
}
/*--------------------------------------------------------------------------*/
/**
* Checks if the entry is a function reference.
*
* @private
* @memberOf Entry
* @returns {Boolean} Returns `true` if the entry is a function reference, else `false`.
*/
private function isFunction() {
return !!(
$this->isCtor() ||
count($this->getParams()) ||
count($this->getReturns()) ||
preg_match('/\*\s*@function\b/', $this->entry)
);
}
/*--------------------------------------------------------------------------*/
/**
* Extracts the function call from the entry.
*
* @memberOf Entry
* @returns {String} The function call.
*/
public function getCall() {
preg_match('#\*/\s*(?:function ([^(]*)|(.*?)(?=[:=,]|return\b))#', $this->entry, $result);
if ($result = array_pop($result)) {
$result = array_pop(explode('var ', trim(trim(array_pop(explode('.', $result))), "'")));
}
// resolve name
// avoid $this->getName() because it calls $this->getCall()
preg_match('#\*\s*@name\s+([^\n]+)#', $this->entry, $name);
if (count($name)) {
$name = trim($name[1]);
} else {
$name = $result;
}
// compile function call syntax
if ($this->isFunction()) {
// compose parts
$result = array($result);
$params = $this->getParams();
foreach ($params as $param) {
$result[] = $param[1];
}
// format
$result = $name .'('. implode(array_slice($result, 1), ', ') .')';
$result = str_replace(', [', ' [, ', str_replace('], [', ', ', $result));
}
return $result ? $result : $name;
}
/**
* Extracts the entry description.
*
* @memberOf Entry
* @returns {String} The entry description.
*/
public function getDesc() {
preg_match('#/\*\*(?:\s*\*)?([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
if (count($result)) {
$type = $this->getType();
$result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1]));
$result = ($type == 'Function' ? '' : '(' . str_replace('|', ', ', trim($type, '{}')) . '): ') . $result;
}
return $result;
}
/**
* Extracts the entry `example` data.
*
* @memberOf Entry
* @returns {String} The entry `example` data.
*/
public function getExample() {
preg_match('#\*\s*@example\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)\s*\* ?/', "\n", $result[1]));
$result = '```' . $this->lang . "\n" . $result . "\n```";
}
return $result;
}
/**
* Resolves the line number of the entry.
*
* @memberOf Entry
* @returns {Number} The line number.
*/
public function getLineNumber() {
preg_match_all('/\n/', substr($this->source, 0, strrpos($this->source, $this->entry) + strlen($this->entry)), $lines);
return count(array_pop($lines)) + 1;
}
/**
* Extracts the entry `member` data.
*
* @memberOf Entry
* @param {Number} $index The index of the array value to return.
* @returns {Array|String} The entry `member` data.
*/
public function getMembers( $index = null ) {
preg_match('#\*\s*@member(?:Of)?\s+([^\n]+)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1]));
$result = preg_split('/,\s*/', $result);
}
return $index !== null ? @$result[$index] : $result;
}
/**
* Extracts the entry `name` data.
*
* @memberOf Entry
* @returns {String} The entry `name` data.
*/
public function getName() {
preg_match('#\*\s*@name\s+([^\n]+)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1]));
} else {
$result = array_shift(explode('(', $this->getCall()));
}
return $result;
}
/**
* Extracts the entry `param` data.
*
* @memberOf Entry
* @param {Number} $index The index of the array value to return.
* @returns {Array} The entry `param` data.
*/
public function getParams( $index = null ) {
preg_match_all('#\*\s*@param\s+\{([^}]+)\}\s+(\[.+\]|[$\w]+)\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#i', $this->entry, $result);
if (count($result = array_filter(array_slice($result, 1)))) {
// repurpose array
foreach ($result as $param) {
foreach ($param as $key => $value) {
if (!is_array($result[0][$key])) {
$result[0][$key] = array();
}
$result[0][$key][] = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $value));
}
}
$result = $result[0];
}
return $index !== null ? @$result[$index] : $result;
}
/**
* Extracts the entry `returns` data.
*
* @memberOf Entry
* @returns {String} The entry `returns` data.
*/
public function getReturns() {
preg_match('#\*\s*@returns\s+\{([^}]+)\}\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
if (count($result)) {
$result = array_map('trim', array_slice($result, 1));
$result[0] = str_replace('|', ', ', $result[0]);
$result[1] = preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1]);
}
return $result;
}
/**
* Extracts the entry `type` data.
*
* @memberOf Entry
* @returns {String} The entry `type` data.
*/
public function getType() {
preg_match('#\*\s*@type\s+([^\n]+)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1]));
} else {
$result = $this->isFunction() ? 'Function' : 'Unknown';
}
return $result;
}
/**
* Checks if an entry is a constructor.
*
* @memberOf Entry
* @returns {Boolean} Returns true if a constructor, else false.
*/
public function isCtor() {
return !!preg_match('/\*\s*@constructor\b/', $this->entry);
}
/**
* Checks if an entry *is* assigned to a prototype.
*
* @memberOf Entry
* @returns {Boolean} Returns true if assigned to a prototype, else false.
*/
public function isPlugin() {
return !$this->isCtor() && !$this->isPrivate() && !$this->isStatic();
}
/**
* Checks if an entry is private.
*
* @memberOf Entry
* @returns {Boolean} Returns true if private, else false.
*/
public function isPrivate() {
return !!preg_match('/\*\s*@private\b/', $this->entry) || strrpos($this->entry, '@') === false;
}
/**
* Checks if an entry is *not* assigned to a prototype.
*
* @memberOf Entry
* @returns {Boolean} Returns true if not assigned to a prototype, else false.
*/
public function isStatic() {
$public = !$this->isPrivate();
$result = $public && !!preg_match('/\*\s*@static\b/', $this->entry);
// set in cases where it isn't explicitly stated
if ($public && !$result) {
if ($parent = array_pop(preg_split('/[#.]/', $this->getMembers(0)))) {
foreach (Entry::getEntries($this->source) as $entry) {
$entry = new Entry($entry, $this->source);
if ($entry->getName() == $parent) {
$result = !$entry->isCtor();
break;
}
}
} else {
$result = true;
}
}
return $result;
}
}
?>

416
vendor/docdown/src/DocDown/Generator.php vendored Normal file
View File

@@ -0,0 +1,416 @@
<?php
require(dirname(__FILE__) . "/Entry.php");
/**
* Generates Markdown from JSDoc entries.
*/
class Generator {
/**
* An array of JSDoc entries.
*
* @memberOf Generator
* @type Array
*/
public $entries = array();
/**
* An options array used to configure the generator.
*
* @memberOf Generator
* @type Array
*/
public $options = array();
/**
* The entire file's source code.
*
* @memberOf Generator
* @type String
*/
public $source = '';
/*--------------------------------------------------------------------------*/
/**
* The Generator constructor.
*
* @constructor
* @param {String} $source The source code to parse.
* @param {Array} $options The options array.
*/
public function __construct( $source, $options = array() ) {
// juggle arguments
if (is_array($source)) {
$options = $source;
} else {
$options['source'] = $source;
}
if (isset($options['source']) && realpath($options['source'])) {
$options['path'] = $options['source'];
}
if (isset($options['path'])) {
preg_match('/(?<=\.)[a-z]+$/', $options['path'], $ext);
$options['source'] = file_get_contents($options['path']);
$ext = array_pop($ext);
if (!isset($options['lang']) && $ext) {
$options['lang'] = $ext;
}
if (!isset($options['title'])) {
$options['title'] = ucfirst(basename($options['path'])) . ' API documentation';
}
}
if (!isset($options['lang'])) {
$options['lang'] = 'js';
}
$this->options = $options;
$this->source = str_replace(PHP_EOL, "\n", $options['source']);
$this->entries = Entry::getEntries($this->source);
foreach ($this->entries as $index => $value) {
$this->entries[$index] = new Entry($value, $this->source, $options['lang']);
}
}
/*--------------------------------------------------------------------------*/
/**
* Performs common string formatting operations.
*
* @private
* @static
* @memberOf Generator
* @param {String} $string The string to format.
* @returns {String} The formatted string.
*/
private static function format($string) {
$counter = 0;
// tokenize inline code snippets
preg_match_all('/`[^`]+`/', $string, $tokenized);
$tokenized = $tokenized[0];
foreach ($tokenized as $snippet) {
$string = str_replace($snippet, '__token' . ($counter++) .'__', $string);
}
// italicize parentheses
$string = preg_replace('/(^|\s)(\([^)]+\))/', '$1*$2*', $string);
// mark numbers as inline code
$string = preg_replace('/ (-?\d+(?:.\d+)?)(?!\.[^\n])/', ' `$1`', $string);
// detokenize inline code snippets
$counter = 0;
foreach ($tokenized as $snippet) {
$string = str_replace('__token' . ($counter++) . '__', $snippet, $string);
}
return trim($string);
}
/**
* Modify a string by replacing named tokens with matching assoc. array values.
*
* @private
* @static
* @memberOf Generator
* @param {String} $string The string to modify.
* @param {Array|Object} $object The template object.
* @returns {String} The modified string.
*/
private static function interpolate($string, $object) {
preg_match_all('/#\{([^}]+)\}/', $string, $tokens);
$tokens = array_unique(array_pop($tokens));
foreach ($tokens as $token) {
$pattern = '/#\{' . $token . '\}/';
$replacement = '';
if (is_object($object)) {
preg_match('/\(([^)]+?)\)$/', $token, $args);
$args = preg_split('/,\s*/', array_pop($args));
$method = 'get' . ucfirst(str_replace('/\([^)]+?\)$/', '', $token));
if (method_exists($object, $method)) {
$replacement = (string) call_user_func_array(array($object, $method), $args);
} else if (isset($object->{$token})) {
$replacement = (string) $object->{$token};
}
} else if (isset($object[$token])) {
$replacement = (string) $object[$token];
}
$string = preg_replace($pattern, trim($replacement), $string);
}
return Generator::format($string);
}
/*--------------------------------------------------------------------------*/
/**
* Resolves the entry's hash used to navigate the documentation.
*
* @private
* @memberOf Generator
* @param {Number|Object} $entry The entry object.
* @param {String} $member The name of the member.
* @returns {String} The url hash.
*/
private function getHash( $entry, $member = '' ) {
$entry = is_numeric($entry) ? $this->entries[$entry] : $entry;
$member = !$member ? $entry->getMembers(0) : $member;
$result = ($member ? $member . ($entry->isPlugin() ? 'prototype' : '') : '') . $entry->getCall();
$result = preg_replace('/\(\[|\[\]/', '', $result);
$result = preg_replace('/[ =\'"{}.()\]]/', '', $result);
$result = preg_replace('/[[#,]/', '-', $result);
return strtolower($result);
}
/**
* Resolves the entry's url for the specific line number.
*
* @private
* @memberOf Generator
* @param {Number|Object} $entry The entry object.
* @returns {String} The url.
*/
private function getLineUrl( $entry ) {
$entry = is_numeric($entry) ? $this->entries($entry) : $entry;
return $this->options['url'] . '#L' . $entry->getLineNumber();
}
/**
* Extracts the character used to separate the entry's name from its member.
*
* @private
* @memberOf Generator
* @param {Number|Object} $entry The entry object.
* @returns {String} The separator.
*/
private function getSeparator( $entry ) {
$entry = is_numeric($entry) ? $this->entries($entry) : $entry;
return $entry->isPlugin() ? '.prototype.' : '.';
}
/*--------------------------------------------------------------------------*/
/**
* Generates Markdown from JSDoc entries.
*
* @memberOf Generator
* @returns {String} The rendered Markdown.
*/
public function generate() {
$api = array();
$compiling = false;
$openTag = "\n<!-- div -->\n";
$closeTag = "\n<!-- /div -->\n";
$result = array('# ' . $this->options['title']);
$toc = 'toc';
// initialize $api array
foreach ($this->entries as $entry) {
if (!$entry->isPrivate()) {
$name = $entry->getName();
$members = $entry->getMembers();
$members = count($members) ? $members : array('');
foreach ($members as $member) {
// create api category arrays
if (!isset($api[$member]) && $member) {
$api[$member] = new Entry('', '', $entry->lang);
$api[$member]->static = array();
$api[$member]->plugin = array();
}
// append entry to api category
if (!$member || $entry->isCtor() || ($entry->getType() == 'Object' &&
!preg_match('/[=:]\s*null\s*[,;]?$/', $entry->entry))) {
$member = ($member ? $member . ($entry->isPlugin() ? '#' : '.') : '') . $name;
$entry->static = @$api[$member] ? $api[$member]->static : array();
$entry->plugin = @$api[$member] ? $api[$member]->plugin : array();
$api[$member] = $entry;
}
else if ($entry->isStatic()) {
$api[$member]->static[] = $entry;
} else if (!$entry->isCtor()) {
$api[$member]->plugin[] = $entry;
}
}
}
}
/*------------------------------------------------------------------------*/
// custom sort for root level entries
// TODO: see how well it handles deeper namespace traversal
function sortCompare($a, $b) {
$score = array( 'a' => 0, 'b' => 0);
foreach (array( 'a' => $a, 'b' => $b) as $key => $value) {
// capitalized keys that represent constructor properties are last
if (preg_match('/[#.][A-Z]/', $value)) {
$score[$key] = 0;
}
// lowercase keys with prototype properties are next to last
else if (preg_match('/#[a-z]/', $value)) {
$score[$key] = 1;
}
// lowercase keys with static properties next to first
else if (preg_match('/\.[a-z]/', $value)) {
$score[$key] = 2;
}
// lowercase keys with no properties are first
else if (preg_match('/^[^#.]+$/', $value)) {
$score[$key] = 3;
}
}
$score = $score['b'] - $score['a'];
return $score ? $score : strcasecmp($a, $b);
}
uksort($api, 'sortCompare');
// sort static and plugin sub-entries
foreach ($api as $entry) {
foreach (array('static', 'plugin') as $kind) {
$sortBy = array( 'a' => array(), 'b' => array(), 'c' => array() );
foreach ($entry->{$kind} as $subentry) {
$name = $subentry->getName();
// functions w/o ALL-CAPs names are last
$sortBy['a'][] = $subentry->getType() == 'Function' && !preg_match('/^[A-Z_]+$/', $name);
// ALL-CAPs properties first
$sortBy['b'][] = preg_match('/^[A-Z_]+$/', $name);
// lowercase alphanumeric sort
$sortBy['c'][] = strtolower($name);
}
array_multisort($sortBy['a'], SORT_ASC, $sortBy['b'], SORT_DESC, $sortBy['c'], SORT_ASC, $entry->{$kind});
}
}
/*------------------------------------------------------------------------*/
// compile TOC
$result[] = $openTag;
foreach ($api as $key => $entry) {
$entry->hash = $this->getHash($entry);
$entry->href = $this->getLineUrl($entry);
$member = $entry->getMembers(0);
$member = ($member ? $member . ($entry->isPlugin() ? '.prototype.' : '.') : '') . $entry->getName();
$entry->member = preg_replace('/' . $entry->getName() . '$/', '', $member);
$compiling = $compiling ? ($result[] = $closeTag) : true;
// assign TOC hash
if (count($result) == 2) {
$toc = $member;
}
// add root entry
array_push(
$result,
$openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $member . '`',
Generator::interpolate('* [`' . $member . '`](##{hash})', $entry)
);
// add static and plugin sub-entries
foreach (array('static', 'plugin') as $kind) {
if ($kind == 'plugin' && count($entry->plugin)) {
array_push(
$result,
$closeTag,
$openTag,
'## `' . $member . ($entry->isCtor() ? '.prototype`' : '`')
);
}
foreach ($entry->{$kind} as $subentry) {
$subentry->hash = $this->getHash($subentry);
$subentry->href = $this->getLineUrl($subentry);
$subentry->member = $member;
$subentry->separator = $this->getSeparator($subentry);
$result[] = Generator::interpolate('* [`#{member}#{separator}#{name}`](##{hash})', $subentry);
}
}
}
array_push($result, $closeTag, $closeTag);
/*------------------------------------------------------------------------*/
// compile content
$compiling = false;
$result[] = $openTag;
foreach ($api as $entry) {
// add root entry
$member = $entry->member . $entry->getName();
$compiling = $compiling ? ($result[] = $closeTag) : true;
array_push($result, $openTag, '## `' . $member . '`');
foreach (array($entry, 'static', 'plugin') as $kind) {
$subentries = is_string($kind) ? $entry->{$kind} : array($kind);
// title
if ($kind != 'static' && $entry->getType() != 'Object' &&
count($subentries) && $subentries[0] != $kind) {
if ($kind == 'plugin') {
$result[] = $closeTag;
}
array_push(
$result,
$openTag,
'## `' . $member . ($kind == 'plugin' ? '.prototype`' : '`')
);
}
// body
foreach ($subentries as $subentry) {
// description
array_push(
$result,
$openTag,
Generator::interpolate("### <a id=\"#{hash}\"></a>`#{member}#{separator}#{call}`\n<a href=\"##{hash}\">#</a> [&#x24C8;](#{href} \"View in source\") [&#x24C9;][1]\n\n#{desc}", $subentry)
);
// @param
if (count($params = $subentry->getParams())) {
array_push($result, '', '#### Arguments');
foreach ($params as $index => $param) {
$result[] = Generator::interpolate('#{num}. `#{name}` (#{type}): #{desc}', array(
'desc' => $param[2],
'name' => $param[1],
'num' => $index + 1,
'type' => $param[0]
));
}
}
// @returns
if (count($returns = $subentry->getReturns())) {
array_push(
$result, '',
'#### Returns',
Generator::interpolate('(#{type}): #{desc}', array('desc' => $returns[1], 'type' => $returns[0]))
);
}
// @example
if ($example = $subentry->getExample()) {
array_push($result, '', '#### Example', $example);
}
array_push($result, "\n* * *", $closeTag);
}
}
}
// close tags add TOC link reference
array_push($result, $closeTag, $closeTag, '', ' [1]: #' . $toc . ' "Jump back to the TOC."');
// cleanup whitespace
return trim(preg_replace('/ +\n/', "\n", join($result, "\n")));
}
}
?>

20
vendor/platform.js/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

98
vendor/platform.js/README.md vendored Normal file
View File

@@ -0,0 +1,98 @@
# Platform.js <sup>v1.0.0</sup>
A platform detection library that works on nearly all JavaScript platforms<sup><a name="fnref1" href="#fn1">1</a></sup>.
## Disclaimer
Platform.js is for informational purposes only and **not** intended as a substitution for [feature detection/inference](http://allyoucanleet.com/post/18087210413/feature-testing-costs#screencast2) checks.
## BestieJS
Platform.js is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation.
## Documentation
The documentation for Platform.js can be viewed here: [/doc/README.md](https://github.com/bestiejs/platform.js/blob/master/doc/README.md#readme)
For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/platform.js/wiki/Roadmap).
## Support
Platform.js has been tested in at least Adobe AIR 3.1, Chrome 5-21, Firefox 1.5-13, IE 6-9, Opera 9.25-12.01, Safari 3-6, Node.js 0.8.6, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5.
## Installation and usage
In a browser or Adobe AIR:
```html
<script src="platform.js"></script>
```
Via [npm](http://npmjs.org/):
```bash
npm install platform
```
In [Node.js](http://nodejs.org/) and [RingoJS](http://ringojs.org/):
```js
var platform = require('platform');
```
In [Rhino](http://www.mozilla.org/rhino/):
```js
load('platform.js');
```
In an AMD loader like [RequireJS](http://requirejs.org/):
```js
require({
'paths': {
'platform': 'path/to/platform'
}
},
['platform'], function(platform) {
console.log(platform.name);
});
```
Usage example:
```js
// on IE10 x86 platform preview running in IE7 compatibility mode on Windows 7 64 bit edition
platform.name; // 'IE'
platform.version; // '10.0'
platform.layout; // 'Trident'
platform.os; // 'Windows Server 2008 R2 / 7 x64'
platform.description; // 'IE 10.0 x86 (platform preview; running in IE 7 mode) on Windows Server 2008 R2 / 7 x64'
// or on an iPad
platform.name; // 'Safari'
platform.version; // '5.1'
platform.product; // 'iPad'
platform.manufacturer; // 'Apple'
platform.layout; // 'WebKit'
platform.os; // 'iOS 5.0'
platform.description; // 'Safari 5.1 on Apple iPad (iOS 5.0)'
// or parsing a given UA string
var info = platform.parse('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7.2; en; rv:2.0) Gecko/20100101 Firefox/4.0 Opera 11.52');
info.name; // 'Opera'
info.version; // '11.52'
info.layout; // 'Presto'
info.os; // 'Mac OS X 10.7.2'
info.description; // 'Opera 11.52 (identifying as Firefox 4.0) on Mac OS X 10.7.2'
```
## Author
* [John-David Dalton](http://allyoucanleet.com/)
[![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter")
## Contributors
* [Mathias Bynens](http://mathiasbynens.be/)
[![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter")

996
vendor/platform.js/platform.js vendored Normal file
View File

@@ -0,0 +1,996 @@
/*!
* Platform.js v1.0.0 <http://mths.be/platform>
* Copyright 2010-2012 John-David Dalton <http://allyoucanleet.com/>
* Available under MIT license <http://mths.be/mit>
*/
;(function(window) {
'use strict';
/** Backup possible window/global object */
var oldWin = window;
/** Detect free variable `exports` */
var freeExports = typeof exports == 'object' && exports;
/** Detect free variable `global` */
var freeGlobal = typeof global == 'object' && global &&
(global == global.global ? (window = global) : global);
/** Opera regexp */
var reOpera = /Opera/;
/** Used to resolve a value's internal [[Class]] */
var toString = {}.toString;
/** Detect Java environment */
var java = /Java/.test(getClassOf(window.java)) && window.java;
/** A character to represent alpha */
var alpha = java ? 'a' : '\u03b1';
/** A character to represent beta */
var beta = java ? 'b' : '\u03b2';
/** Browser document object */
var doc = window.document || {};
/** Used to check for own properties of an object */
var hasOwnProperty = {}.hasOwnProperty;
/** Browser navigator object */
var nav = window.navigator || {};
/**
* Detect Opera browser
* http://www.howtocreate.co.uk/operaStuff/operaObject.html
* http://dev.opera.com/articles/view/opera-mini-web-content-authoring-guidelines/#operamini
*/
var opera = window.operamini || window.opera;
/** Opera [[Class]] */
var operaClass = reOpera.test(operaClass = getClassOf(opera)) ? operaClass : (opera = null);
/** Possible global object */
var thisBinding = this;
/** Browser user agent string */
var userAgent = nav.userAgent || '';
/*--------------------------------------------------------------------------*/
/**
* Capitalizes a string value.
*
* @private
* @param {String} string The string to capitalize.
* @returns {String} The capitalized string.
*/
function capitalize(string) {
string = String(string);
return string.charAt(0).toUpperCase() + string.slice(1);
}
/**
* An iteration utility for arrays and objects.
*
* @private
* @param {Array|Object} object The object to iterate over.
* @param {Function} callback The function called per iteration.
*/
function each(object, callback) {
var index = -1,
length = object.length;
if (length == length >>> 0) {
while (++index < length) {
callback(object[index], index, object);
}
} else {
forOwn(object, callback);
}
}
/**
* Trim and conditionally capitalize string values.
*
* @private
* @param {String} string The string to format.
* @returns {String} The formatted string.
*/
function format(string) {
string = trim(string);
return /^(?:webOS|i(?:OS|P))/.test(string)
? string
: capitalize(string);
}
/**
* Iterates over an object's own properties, executing the `callback` for each.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} callback The function executed per own property.
*/
function forOwn(object, callback) {
for (var key in object) {
hasKey(object, key) && callback(object[key], key, object);
}
}
/**
* Gets the internal [[Class]] of a value.
*
* @private
* @param {Mixed} value The value.
* @returns {String} The [[Class]].
*/
function getClassOf(value) {
return value == null
? capitalize(value)
: toString.call(value).slice(8, -1);
}
/**
* Checks if an object has the specified key as a direct property.
*
* @private
* @param {Object} object The object to check.
* @param {String} key The key to check for.
* @returns {Boolean} Returns `true` if key is a direct property, else `false`.
*/
function hasKey() {
// lazy define for others (not as accurate)
hasKey = function(object, key) {
var parent = object != null && (object.constructor || Object).prototype;
return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]);
};
// for modern browsers
if (getClassOf(hasOwnProperty) == 'Function') {
hasKey = function(object, key) {
return object != null && hasOwnProperty.call(object, key);
};
}
// for Safari 2
else if ({}.__proto__ == Object.prototype) {
hasKey = function(object, key) {
var result = false;
if (object != null) {
object = Object(object);
object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0];
}
return result;
};
}
return hasKey.apply(this, arguments);
}
/**
* Host objects can return type values that are different from their actual
* data type. The objects we are concerned with usually return non-primitive
* types of object, function, or unknown.
*
* @private
* @param {Mixed} object The owner of the property.
* @param {String} property The property to check.
* @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`.
*/
function isHostType(object, property) {
var type = object != null ? typeof object[property] : 'number';
return !/^(?:boolean|number|string|undefined)$/.test(type) &&
(type == 'object' ? !!object[property] : true);
}
/**
* Prepares a string for use in a RegExp constructor by making hyphens and
* spaces optional.
*
* @private
* @param {String} string The string to qualify.
* @returns {String} The qualified string.
*/
function qualify(string) {
return String(string).replace(/([ -])(?!$)/g, '$1?');
}
/**
* A bare-bones` Array#reduce` like utility function.
*
* @private
* @param {Array} array The array to iterate over.
* @param {Function} callback The function called per iteration.
* @param {Mixed} accumulator Initial value of the accumulator.
* @returns {Mixed} The accumulator.
*/
function reduce(array, callback) {
var accumulator = null;
each(array, function(value, index) {
accumulator = callback(accumulator, value, index, array);
});
return accumulator;
}
/**
* Removes leading and trailing whitespace from a string.
*
* @private
* @param {String} string The string to trim.
* @returns {String} The trimmed string.
*/
function trim(string) {
return String(string).replace(/^ +| +$/g, '');
}
/*--------------------------------------------------------------------------*/
/**
* Creates a new platform object.
*
* @memberOf platform
* @param {String} [ua = navigator.userAgent] The user agent string.
* @returns {Object} A platform object.
*/
function parse(ua) {
ua || (ua = userAgent);
/** Temporary variable used over the script's lifetime */
var data;
/** The CPU architecture */
var arch = ua;
/** Platform description array */
var description = [];
/** Platform alpha/beta indicator */
var prerelease = null;
/** A flag to indicate that environment features should be used to resolve the platform */
var useFeatures = ua == userAgent;
/** The browser/environment version */
var version = useFeatures && opera && typeof opera.version == 'function' && opera.version();
/* Detectable layout engines (order is important) */
var layout = getLayout([
{ 'label': 'WebKit', 'pattern': 'AppleWebKit' },
'iCab',
'Presto',
'NetFront',
'Tasman',
'Trident',
'KHTML',
'Gecko'
]);
/* Detectable browser names (order is important) */
var name = getName([
'Adobe AIR',
'Arora',
'Avant Browser',
'Camino',
'Epiphany',
'Fennec',
'Flock',
'Galeon',
'GreenBrowser',
'iCab',
'Iceweasel',
'Iron',
'K-Meleon',
'Konqueror',
'Lunascape',
'Maxthon',
'Midori',
'Nook Browser',
'PhantomJS',
'Raven',
'Rekonq',
'RockMelt',
'SeaMonkey',
{ 'label': 'Silk', 'pattern': '(?:Cloud9|Silk-Accelerated)' },
'Sleipnir',
'SlimBrowser',
'Sunrise',
'Swiftfox',
'WebPositive',
'Opera Mini',
'Opera',
'Chrome',
{ 'label': 'Chrome Mobile', 'pattern': '(?:CriOS|CrMo)' },
{ 'label': 'Firefox', 'pattern': '(?:Firefox|Minefield)' },
{ 'label': 'IE', 'pattern': 'MSIE' },
'Safari'
]);
/* Detectable products (order is important) */
var product = getProduct([
'BlackBerry',
{ 'label': 'Galaxy S', 'pattern': 'GT-I9000' },
{ 'label': 'Galaxy S2', 'pattern': 'GT-I9100' },
'Google TV',
'iPad',
'iPod',
'iPhone',
'Kindle',
{ 'label': 'Kindle Fire', 'pattern': '(?:Cloud9|Silk-Accelerated)' },
'Nook',
'PlayBook',
'PlayStation Vita',
'TouchPad',
'Transformer',
'Xoom'
]);
/* Detectable manufacturers */
var manufacturer = getManufacturer({
'Apple': { 'iPad': 1, 'iPhone': 1, 'iPod': 1 },
'Amazon': { 'Kindle': 1, 'Kindle Fire': 1 },
'Asus': { 'Transformer': 1 },
'Barnes & Noble': { 'Nook': 1 },
'BlackBerry': { 'PlayBook': 1 },
'Google': { 'Google TV': 1 },
'HP': { 'TouchPad': 1 },
'LG': { },
'Motorola': { 'Xoom': 1 },
'Nokia': { },
'Samsung': { 'Galaxy S': 1, 'Galaxy S2': 1 },
'Sony': { 'PlayStation Vita': 1 }
});
/* Detectable OSes (order is important) */
var os = getOS([
'Android',
'CentOS',
'Debian',
'Fedora',
'FreeBSD',
'Gentoo',
'Haiku',
'Kubuntu',
'Linux Mint',
'Red Hat',
'SuSE',
'Ubuntu',
'Xubuntu',
'Cygwin',
'Symbian OS',
'hpwOS',
'webOS ',
'webOS',
'Tablet OS',
'Linux',
'Mac OS X',
'Macintosh',
'Mac',
'Windows 98;',
'Windows '
]);
/*------------------------------------------------------------------------*/
/**
* Picks the layout engine from an array of guesses.
*
* @private
* @param {Array} guesses An array of guesses.
* @returns {String|Null} The detected layout engine.
*/
function getLayout(guesses) {
return reduce(guesses, function(result, guess) {
return result || RegExp('\\b' + (
guess.pattern || qualify(guess)
) + '\\b', 'i').exec(ua) && (guess.label || guess);
});
}
/**
* Picks the manufacturer from an array of guesses.
*
* @private
* @param {Array} guesses An array of guesses.
* @returns {String|Null} The detected manufacturer.
*/
function getManufacturer(guesses) {
return reduce(guesses, function(result, value, key) {
// lookup the manufacturer by product or scan the UA for the manufacturer
return result || (
value[product] ||
value[0/*Opera 9.25 fix*/, /^[a-z]+(?: +[a-z]+\b)*/i.exec(product)] ||
RegExp('\\b' + (key.pattern || qualify(key)) + '(?:\\b|\\w*\\d)', 'i').exec(ua)
) && (key.label || key);
});
}
/**
* Picks the browser name from an array of guesses.
*
* @private
* @param {Array} guesses An array of guesses.
* @returns {String|Null} The detected browser name.
*/
function getName(guesses) {
return reduce(guesses, function(result, guess) {
return result || RegExp('\\b' + (
guess.pattern || qualify(guess)
) + '\\b', 'i').exec(ua) && (guess.label || guess);
});
}
/**
* Picks the OS name from an array of guesses.
*
* @private
* @param {Array} guesses An array of guesses.
* @returns {String|Null} The detected OS name.
*/
function getOS(guesses) {
return reduce(guesses, function(result, guess) {
var pattern = guess.pattern || qualify(guess);
if (!result && (result =
RegExp('\\b' + pattern + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(ua))) {
// platform tokens defined at
// http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx
// http://web.archive.org/web/20081122053950/http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx
data = {
'6.2': '8',
'6.1': 'Server 2008 R2 / 7',
'6.0': 'Server 2008 / Vista',
'5.2': 'Server 2003 / XP 64-bit',
'5.1': 'XP',
'5.01': '2000 SP1',
'5.0': '2000',
'4.0': 'NT',
'4.90': 'ME'
};
// detect Windows version from platform tokens
if (/^Win/i.test(result) &&
(data = data[0/*Opera 9.25 fix*/, /[\d.]+$/.exec(result)])) {
result = 'Windows ' + data;
}
// correct character case and cleanup
result = format(String(result)
.replace(RegExp(pattern, 'i'), guess.label || guess)
.replace(/ ce$/i, ' CE')
.replace(/hpw/i, 'web')
.replace(/Macintosh/, 'Mac OS')
.replace(/_PowerPC/i, ' OS')
.replace(/(OS X) [^ \d]+/i, '$1')
.replace(/\/(\d)/, ' $1')
.replace(/_/g, '.')
.replace(/(?: BePC|[ .]*fc[ \d.]+)$/i, '')
.replace(/x86\.64/gi, 'x86_64')
.split(' on ')[0]);
}
return result;
});
}
/**
* Picks the product name from an array of guesses.
*
* @private
* @param {Array} guesses An array of guesses.
* @returns {String|Null} The detected product name.
*/
function getProduct(guesses) {
return reduce(guesses, function(result, guess) {
var pattern = guess.pattern || qualify(guess);
if (!result && (result =
RegExp('\\b' + pattern + ' *\\d+[.\\w_]*', 'i').exec(ua) ||
RegExp('\\b' + pattern + '(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)', 'i').exec(ua)
)) {
// split by forward slash and append product version if needed
if ((result = String(guess.label || result).split('/'))[1] && !/[\d.]+/.test(result[0])) {
result[0] += ' ' + result[1];
}
// correct character case and cleanup
guess = guess.label || guess;
result = format(result[0]
.replace(RegExp(pattern, 'i'), guess)
.replace(RegExp('; *(?:' + guess + '[_-])?', 'i'), ' ')
.replace(RegExp('(' + guess + ')(\\w)', 'i'), '$1 $2'));
}
return result;
});
}
/**
* Resolves the version using an array of UA patterns.
*
* @private
* @param {Array} patterns An array of UA patterns.
* @returns {String|Null} The detected version.
*/
function getVersion(patterns) {
return reduce(patterns, function(result, pattern) {
return result || (RegExp(pattern +
'(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)', 'i').exec(ua) || 0)[1] || null;
});
}
/*------------------------------------------------------------------------*/
/**
* Returns `platform.description` when the platform object is coerced to a string.
*
* @name toString
* @memberOf platform
* @returns {String} Returns `platform.description` if available, else an empty string.
*/
function toStringPlatform() {
return this.description || '';
}
/*------------------------------------------------------------------------*/
// convert layout to an array so we can add extra details
layout && (layout = [layout]);
// detect product names that contain their manufacturer's name
if (manufacturer && !product) {
product = getProduct([manufacturer]);
}
// clean up Google TV
if ((data = /Google TV/.exec(product))) {
product = data[0];
}
// detect simulators
if (/\bSimulator\b/i.test(ua)) {
product = (product ? product + ' ' : '') + 'Simulator';
}
// detect iOS
if (/^iP/.test(product)) {
name || (name = 'Safari');
os = 'iOS' + ((data = / OS ([\d_]+)/i.exec(ua))
? ' ' + data[1].replace(/_/g, '.')
: '');
}
// detect Kubuntu
else if (name == 'Konqueror' && !/buntu/i.test(os)) {
os = 'Kubuntu';
}
// detect Android browsers
else if (manufacturer && manufacturer != 'Google' &&
/Chrome|Vita/.test(name + ';' + product)) {
name = 'Android Browser';
os = /Android/.test(os) ? os : 'Android';
}
// detect false positives for Firefox/Safari
else if (!name || (data = !/\bMinefield\b/i.test(ua) && /Firefox|Safari/.exec(name))) {
// escape the `/` for Firefox 1
if (name && !product && /[\/,]|^[^(]+?\)/.test(ua.slice(ua.indexOf(data + '/') + 8))) {
// clear name of false positives
name = null;
}
// reassign a generic name
if ((data = product || manufacturer || os) &&
(product || manufacturer || /Android|Symbian OS|Tablet OS|webOS/.test(os))) {
name = /[a-z]+(?: Hat)?/i.exec(/Android/.test(os) ? os : data) + ' Browser';
}
}
// detect non-Opera versions (order is important)
if (!version) {
version = getVersion([
'(?:Cloud9|CriOS|CrMo|Opera ?Mini|Raven|Silk(?!/[\\d.]+$))',
'Version',
qualify(name),
'(?:Firefox|Minefield|NetFront)'
]);
}
// detect stubborn layout engines
if (layout == 'iCab' && parseFloat(version) > 3) {
layout = ['WebKit'];
} else if (data =
/Opera/.test(name) && 'Presto' ||
/\b(?:Midori|Nook|Safari)\b/i.test(ua) && 'WebKit' ||
!layout && /\bMSIE\b/i.test(ua) && (/^Mac/.test(os) ? 'Tasman' : 'Trident')) {
layout = [data];
}
// leverage environment features
if (useFeatures) {
// detect server-side environments
// Rhino has a global function while others have a global object
if (isHostType(window, 'global')) {
if (java) {
data = java.lang.System;
arch = data.getProperty('os.arch');
os = os || data.getProperty('os.name') + ' ' + data.getProperty('os.version');
}
if (typeof exports == 'object' && exports) {
// if `thisBinding` is the [ModuleScope]
if (thisBinding == oldWin && typeof system == 'object' && (data = [system])[0]) {
os || (os = data[0].os || null);
try {
data[1] = require('ringo/engine').version;
version = data[1].join('.');
name = 'RingoJS';
} catch(e) {
if (data[0].global == freeGlobal) {
name = 'Narwhal';
}
}
} else if (typeof process == 'object' && (data = process)) {
name = 'Node.js';
arch = data.arch;
os = data.platform;
version = /[\d.]+/.exec(data.version)[0];
}
} else if (getClassOf(window.environment) == 'Environment') {
name = 'Rhino';
}
}
// detect Adobe AIR
else if (getClassOf(data = window.runtime) == 'ScriptBridgingProxyObject') {
name = 'Adobe AIR';
os = data.flash.system.Capabilities.os;
}
// detect PhantomJS
else if (getClassOf(data = window.phantom) == 'RuntimeObject') {
name = 'PhantomJS';
version = (data = data.version || null) && (data.major + '.' + data.minor + '.' + data.patch);
}
// detect IE compatibility modes
else if (typeof doc.documentMode == 'number' && (data = /\bTrident\/(\d+)/i.exec(ua))) {
// we're in compatibility mode when the Trident version + 4 doesn't
// equal the document mode
version = [version, doc.documentMode];
if ((data = +data[1] + 4) != version[1]) {
description.push('IE ' + version[1] + ' mode');
layout[1] = '';
version[1] = data;
}
version = name == 'IE' ? String(version[1].toFixed(1)) : version[0];
}
os = os && format(os);
}
// detect prerelease phases
if (version && (data =
/(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(version) ||
/(?:alpha|beta)(?: ?\d)?/i.exec(ua + ';' + (useFeatures && nav.appMinorVersion)) ||
/\bMinefield\b/i.test(ua) && 'a')) {
prerelease = /b/i.test(data) ? 'beta' : 'alpha';
version = version.replace(RegExp(data + '\\+?$'), '') +
(prerelease == 'beta' ? beta : alpha) + (/\d+\+?/.exec(data) || '');
}
// rename code name "Fennec"
if (name == 'Fennec') {
name = 'Firefox Mobile';
}
// obscure Maxthon's unreliable version
else if (name == 'Maxthon' && version) {
version = version.replace(/\.[\d.]+/, '.x');
}
// detect Silk desktop/accelerated modes
else if (name == 'Silk') {
if (!/Mobi/i.test(ua)) {
os = 'Android';
description.unshift('desktop mode');
}
if (/Accelerated *= *true/i.test(ua)) {
description.unshift('accelerated');
}
}
// detect Windows Phone desktop mode
else if (name == 'IE' && (data = (/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(ua) || 0)[1])) {
name += ' Mobile';
os = 'Windows Phone OS ' + data + '.x';
description.unshift('desktop mode');
}
// add mobile postfix
else if ((name == 'IE' || name && !product && !/Browser|Mobi/.test(name)) &&
(os == 'Windows CE' || /Mobi/i.test(ua))) {
name += ' Mobile';
}
// detect IE platform preview
else if (name == 'IE' && useFeatures && typeof external == 'object' && !external) {
description.unshift('platform preview');
}
// detect BlackBerry OS version
// http://docs.blackberry.com/en/developers/deliverables/18169/HTTP_headers_sent_by_BB_Browser_1234911_11.jsp
else if (/BlackBerry/.test(product) && (data =
(RegExp(product.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(ua) || 0)[1] ||
version)) {
os = 'Device Software ' + data;
version = null;
}
// detect Opera identifying/masking itself as another browser
// http://www.opera.com/support/kb/view/843/
else if (this != forOwn && (
(useFeatures && opera) ||
(/Opera/.test(name) && /\b(?:MSIE|Firefox)\b/i.test(ua)) ||
(name == 'Firefox' && /OS X (?:\d+\.){2,}/.test(os)) ||
(name == 'IE' && (
(os && !/^Win/.test(os) && version > 5.5) ||
/Windows XP/.test(os) && version > 8 ||
version == 8 && !/Trident/.test(ua)
))
) && !reOpera.test(data = parse.call(forOwn, ua.replace(reOpera, '') + ';')) && data.name) {
// when "indentifying", the UA contains both Opera and the other browser's name
data = 'ing as ' + data.name + ((data = data.version) ? ' ' + data : '');
if (reOpera.test(name)) {
if (/IE/.test(data) && os == 'Mac OS') {
os = null;
}
data = 'identify' + data;
}
// when "masking", the UA contains only the other browser's name
else {
data = 'mask' + data;
if (operaClass) {
name = format(operaClass.replace(/([a-z])([A-Z])/g, '$1 $2'));
} else {
name = 'Opera';
}
if (/IE/.test(data)) {
os = null;
}
if (!useFeatures) {
version = null;
}
}
layout = ['Presto'];
description.push(data);
}
// detect WebKit Nightly and approximate Chrome/Safari versions
if ((data = (/\bAppleWebKit\/([\d.]+\+?)/i.exec(ua) || 0)[1])) {
// correct build for numeric comparison
// (e.g. "532.5" becomes "532.05")
data = [parseFloat(data.replace(/\.(\d)$/, '.0$1')), data];
// nightly builds are postfixed with a `+`
if (name == 'Safari' && data[1].slice(-1) == '+') {
name = 'WebKit Nightly';
prerelease = 'alpha';
version = data[1].slice(0, -1);
}
// clear incorrect browser versions
else if (version == data[1] ||
version == (/\bSafari\/([\d.]+\+?)/i.exec(ua) || 0)[1]) {
version = null;
}
// use the full Chrome version when available
data = [data[0], (/\bChrome\/([\d.]+)/i.exec(ua) || 0)[1]];
// detect JavaScriptCore
// http://stackoverflow.com/questions/6768474/how-can-i-detect-which-javascript-engine-v8-or-jsc-is-used-at-runtime-in-androi
if (!useFeatures || (/internal|\n/i.test(toString.toString()) && !data[1])) {
layout[1] = 'like Safari';
data = (data = data[0], data < 400 ? 1 : data < 500 ? 2 : data < 526 ? 3 : data < 533 ? 4 : data < 534 ? '4+' : data < 535 ? 5 : '5');
} else {
layout[1] = 'like Chrome';
data = data[1] || (data = data[0], data < 530 ? 1 : data < 532 ? 2 : data < 532.05 ? 3 : data < 533 ? 4 : data < 534.03 ? 5 : data < 534.07 ? 6 : data < 534.10 ? 7 : data < 534.13 ? 8 : data < 534.16 ? 9 : data < 534.24 ? 10 : data < 534.30 ? 11 : data < 535.01 ? 12 : data < 535.02 ? '13+' : data < 535.07 ? 15 : data < 535.11 ? 16 : data < 535.19 ? 17 : data < 536.05 ? 18 : data < 536.10 ? 19 : data < 537.01 ? 20 : '21');
}
// add the postfix of ".x" or "+" for approximate versions
layout[1] += ' ' + (data += typeof data == 'number' ? '.x' : /[.+]/.test(data) ? '' : '+');
// obscure version for some Safari 1-2 releases
if (name == 'Safari' && (!version || parseInt(version) > 45)) {
version = data;
}
}
// detect Opera desktop modes
if (name == 'Opera' && (data = /(?:zbov|zvav)$/.exec(os))) {
name += ' ';
description.unshift('desktop mode');
if (data == 'zvav') {
name += 'Mini';
version = null;
} else {
name += 'Mobile';
}
}
// detect Chrome desktop mode
else if (name == 'Safari' && /Chrome/.exec(layout[1])) {
description.unshift('desktop mode');
name = 'Chrome Mobile';
version = null;
if (/Mac OS X/.test(os)) {
manufacturer = 'Apple';
os = 'iOS 4.3+';
} else {
os = null;
}
}
// strip incorrect OS versions
if (version && version.indexOf(data = /[\d.]+$/.exec(os)) == 0 &&
ua.indexOf('/' + data + '-') > -1) {
os = trim(os.replace(data, ''));
}
// add layout engine
if (layout && !/Avant|Nook/.test(name) && (
/Browser|Lunascape|Maxthon/.test(name) ||
/^(?:Adobe|Arora|Midori|Phantom|Rekonq|Rock|Sleipnir|Web)/.test(name) && layout[1])) {
// don't add layout details to description if they are falsey
(data = layout[layout.length - 1]) && description.push(data);
}
// combine contextual information
if (description.length) {
description = ['(' + description.join('; ') + ')'];
}
// append manufacturer
if (manufacturer && product && product.indexOf(manufacturer) < 0) {
description.push('on ' + manufacturer);
}
// append product
if (product) {
description.push((/^on /.test(description[description.length -1]) ? '' : 'on ') + product);
}
// parse OS into an object
if (os) {
data = / ([\d.+]+)$/.exec(os);
os = {
'architecture': 32,
'family': data ? os.replace(data[0], '') : os,
'version': data ? data[1] : null,
'toString': function() {
var version = this.version;
return this.family + (version ? ' ' + version : '') + (this.architecture == 64 ? ' 64-bit' : '');
}
};
}
// add browser/OS architecture
if ((data = / (?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) {
if (os) {
os.architecture = 64;
os.family = os.family.replace(data, '');
}
if (name && (/WOW64/i.test(ua) ||
(useFeatures && /\w(?:86|32)$/.test(nav.cpuClass || nav.platform)))) {
description.unshift('32-bit');
}
}
ua || (ua = null);
/*------------------------------------------------------------------------*/
/**
* The platform object.
*
* @name platform
* @type Object
*/
return {
/**
* The browser/environment version.
*
* @memberOf platform
* @type String|Null
*/
'version': name && version && (description.unshift(version), version),
/**
* The name of the browser/environment.
*
* @memberOf platform
* @type String|Null
*/
'name': name && (description.unshift(name), name),
/**
* The name of the operating system.
*
* @memberOf platform
* @type Object
*/
'os': os
? (name &&
!(os == String(os).split(' ')[0] && (os == name.split(' ')[0] || product)) &&
description.push(product ? '(' + os + ')' : 'on ' + os), os)
: {
/**
* The CPU architecture the OS is built for.
*
* @memberOf platform.os
* @type String|Null
*/
'architecture': null,
/**
* The family of the OS.
*
* @memberOf platform.os
* @type String|Null
*/
'family': null,
/**
* The version of the OS.
*
* @memberOf platform.os
* @type String|Null
*/
'version': null,
/**
* Returns the OS string.
*
* @memberOf platform.os
* @returns {String} The OS string.
*/
'toString': function() { return 'null'; }
},
/**
* The platform description.
*
* @memberOf platform
* @type String|Null
*/
'description': description.length ? description.join(' ') : ua,
/**
* The name of the browser layout engine.
*
* @memberOf platform
* @type String|Null
*/
'layout': layout && layout[0],
/**
* The name of the product's manufacturer.
*
* @memberOf platform
* @type String|Null
*/
'manufacturer': manufacturer,
/**
* The alpha/beta release indicator.
*
* @memberOf platform
* @type String|Null
*/
'prerelease': prerelease,
/**
* The name of the product hosting the browser.
*
* @memberOf platform
* @type String|Null
*/
'product': product,
/**
* The browser's user agent string.
*
* @memberOf platform
* @type String|Null
*/
'ua': ua,
// parses a user agent string into a platform object
'parse': parse,
// returns the platform description
'toString': toStringPlatform
};
}
/*--------------------------------------------------------------------------*/
// expose platform
// some AMD build optimizers, like r.js, check for specific condition patterns like the following:
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
// define as an anonymous module so, through path mapping, it can be aliased
define(function() {
return parse();
});
}
// check for `exports` after `define` in case a build optimizer adds an `exports` object
else if (freeExports) {
// in Narwhal, Node.js, or RingoJS
forOwn(parse(), function(value, key) {
freeExports[key] = value;
});
}
// in a browser or Rhino
else {
// use square bracket notation so Closure Compiler won't munge `platform`
// http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
window['platform'] = parse();
}
}(this));

1
vendor/qunit vendored

Submodule vendor/qunit deleted from 3f5e8b2123

1
vendor/qunit-clib vendored

Submodule vendor/qunit-clib deleted from 2ed9f21633

20
vendor/qunit-clib/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

57
vendor/qunit-clib/README.md vendored Normal file
View File

@@ -0,0 +1,57 @@
# QUnit CLIB <sup>v1.0.0</sup>
## command-line interface boilerplate
QUnit CLIB helps extend QUnit's CLI support to many common CLI environments.
## Screenshot
![QUnit CLIB brings QUnit to your favorite shell.](http://i.imgur.com/jpu9l.png)
## Support
QUnit CLIB has been tested in at least Node.js 0.4.8-0.8.6, Narwhal v0.3.2, RingoJS v0.8.0, and Rhino v1.7RC3-RC5.
## Usage
```js
(function(window) {
// use a single load function
var load = typeof require == 'function' ? require : window.load;
// load QUnit and CLIB if needed
var QUnit =
window.QUnit || (
window.setTimeout || (window.addEventListener = window.setTimeout = / /),
window.QUnit = load('path/to/qunit.js') || window.QUnit,
load('path/to/qunit-clib.js'),
(window.addEventListener || 0).test && delete window.addEventListener,
window.QUnit
);
// explicitly call `QUnit.module()` instead of `module()`
// in case we are in a CLI environment
QUnit.module('A Test Module');
test('A Test', function() {
// ...
});
// must call `QUnit.start()` if using QUnit < 1.3.0 with Node.js or any
// version of QUnit with Narwhal, Rhino, or RingoJS
if (!window.document) {
QUnit.start();
}
}(typeof global == 'object' && global || this));
```
## Footnotes
1. QUnit v1.3.0 does not work with Narwhal or Ringo < v0.8.0
2. Rhino v1.7RC4 does not support timeout fallbacks `clearTimeout` and `setTimeout`
## Author
* [John-David Dalton](http://allyoucanleet.com/)
[![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter")

319
vendor/qunit-clib/qunit-clib.js vendored Normal file
View File

@@ -0,0 +1,319 @@
/*!
* QUnit CLI Boilerplate v1.0.0
* Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/>
* Based on a gist by Jörn Zaefferer <https://gist.github.com/722381>
* Available under MIT license <http://mths.be/mit>
*/
;(function(global) {
'use strict';
/** Add `console.log()` support for Narwhal, Rhino, and RingoJS */
global.console || (global.console = { 'log': global.print });
/** Reduce global.QUnit.QUnit -> global.QUnit */
global.QUnit && (QUnit = QUnit.QUnit || QUnit);
/*--------------------------------------------------------------------------*/
/** Used as a horizontal rule in console output */
var hr = '----------------------------------------';
/** Shortcut used to convert array-like objects to arrays */
var slice = [].slice;
/** Used to resolve a value's internal [[Class]] */
var toString = {}.toString;
/** Used by timer methods */
var doneCalled,
timer,
counter = 0,
ids = {};
/*--------------------------------------------------------------------------*/
/**
* An iteration utility for arrays.
*
* @private
* @param {Array} array The array to iterate over.
* @param {Function} callback The function called per iteration.
*/
function each(array, callback) {
var index = -1,
length = array.length;
while (++index < length) {
callback(array[index], index, array);
}
}
/**
* Checks if the specified `value` is a function.
*
* @private
* @param {Mixed} value The value to check.
* @returns {Boolean} Returns `true` if `value` is a function, else `false`.
*/
function isFunction(value) {
return toString.call(value) == '[object Function]';
}
/*--------------------------------------------------------------------------*/
/**
* Timeout fallbacks based on the work of Andrea Giammarchi and Weston C.
* https://github.com/WebReflection/wru/blob/master/src/rhinoTimers.js
* http://stackoverflow.com/questions/2261705/how-to-run-a-javascript-function-asynchronously-without-using-settimeout
*/
/**
* Clears the delay set by `setInterval` or `setTimeout`.
*
* @memberOf global
* @param {Number} id The ID of the timeout to be cleared.
*/
function clearTimer(id) {
if (ids[id]) {
ids[id].cancel();
timer.purge();
delete ids[id];
}
}
/**
* Schedules timer-based callbacks.
*
* @private
* @param {Function} fn The function to call.
* @oaram {Number} delay The number of milliseconds to delay the `fn` call.
* @param [arg1, arg2, ...] Arguments to invoke `fn` with.
* @param {Boolean} repeated A flag to specify whether `fn` is called repeatedly.
* @returns {Number} The the ID of the timeout.
*/
function schedule(fn, delay, args, repeated) {
// Rhino 1.7RC4 will error assigning `task` below
// https://bugzilla.mozilla.org/show_bug.cgi?id=775566
var task = ids[++counter] = new JavaAdapter(java.util.TimerTask, {
'run': function() {
fn.apply(global, args);
}
});
// support non-functions
if (!isFunction(fn)) {
fn = (function(code) {
code = String(code);
return function() { eval(code); };
}(fn));
}
// used by setInterval
if (repeated) {
timer.schedule(task, delay, delay);
}
// used by setTimeout
else {
timer.schedule(task, delay);
}
return counter;
}
/**
* Executes a code snippet or function repeatedly, with a delay between each call.
*
* @memberOf global
* @param {Function|String} fn The function to call or string to evaluate.
* @oaram {Number} delay The number of milliseconds to delay each `fn` call.
* @param [arg1, arg2, ...] Arguments to invoke `fn` with.
* @returns {Number} The the ID of the timeout.
*/
function setInterval(fn, delay) {
return schedule(fn, delay, slice.call(arguments, 2), true);
}
/**
* Executes a code snippet or a function after specified delay.
*
* @memberOf global
* @param {Function|String} fn The function to call or string to evaluate.
* @oaram {Number} delay The number of milliseconds to delay the `fn` call.
* @param [arg1, arg2, ...] Arguments to invoke `fn` with.
* @returns {Number} The the ID of the timeout.
*/
function setTimeout(fn, delay) {
return schedule(fn, delay, slice.call(arguments, 2));
}
/*--------------------------------------------------------------------------*/
/**
* A logging callback triggered when all testing is completed.
*
* @memberOf QUnit
* @param {Object} details An object with properties `failed`, `passed`,
* `runtime`, and `total`.
*/
function done(details) {
// stop `asyncTest()` from erroneously calling `done()` twice in
// environments w/o timeouts
if (doneCalled) {
return;
}
doneCalled = true;
console.log(hr);
console.log(' PASS: ' + details.passed + ' FAIL: ' + details.failed + ' TOTAL: ' + details.total);
console.log(' Finished in ' + details.runtime + ' milliseconds.');
console.log(hr);
// exit out of Rhino
try {
quit();
} catch(e) { }
// exit out of Node.js
try {
process.exit();
} catch(e) { }
}
/**
* A logging callback triggered after every assertion.
*
* @memberOf QUnit
* @param {Object} details An object with properties `actual`, `expected`,
* `message`, and `result`.
*/
function log(details) {
var expected = details.expected,
result = details.result,
type = typeof expected != 'undefined' ? 'EQ' : 'OK';
var assertion = [
result ? 'PASS' : 'FAIL',
type,
details.message || 'ok'
];
if (!result && type == 'EQ') {
assertion.push('Expected: ' + expected + ', Actual: ' + details.actual);
}
QUnit.config.testStats.assertions.push(assertion.join(' | '));
}
/**
* A logging callback triggered at the start of every test module.
*
* @memberOf QUnit
* @param {Object} details An object with property `name`.
*/
function moduleStart(details) {
console.log(hr);
console.log(details.name);
console.log(hr);
}
/**
* Converts an object into a string representation.
*
* @memberOf QUnit
* @type Function
* @param {Object} object The object to stringify.
* @returns {String} The result string.
*/
var parseObject = (function() {
var func = QUnit.jsDump.parsers.object;
return function(object) {
// fork to support Rhino's error objects
if (typeof object.rhinoException == 'object') {
return object.name +
' { message: "' + object.message +
'", fileName: "' + object.fileName +
'", lineNumber: ' + object.lineNumber + ' }';
}
return func(object);
};
}());
/**
* A logging callback triggered after a test is completed.
*
* @memberOf QUnit
* @param {Object} details An object with properties `failed`, `name`,
* `passed`, and `total`.
*/
function testDone(details) {
var assertions = QUnit.config.testStats.assertions,
testName = details.name;
if (details.failed > 0) {
console.log(' FAIL - '+ testName);
each(assertions, function(value) {
console.log(' ' + value);
});
}
else {
console.log(' PASS - ' + testName);
}
assertions.length = 0;
}
/*--------------------------------------------------------------------------*/
/**
* An object used to hold information about the current running test.
*
* @memberOf QUnit.config
* @type Object
*/
QUnit.config.testStats = {
/**
* An array of test summaries (pipe separated).
*
* @memberOf QUnit.config.testStats
* @type Array
*/
'assertions': []
};
// add shortcuts to the global
// exclude `module` because some environments have it as a built-in object
each(['asyncTest', 'deepEqual', 'equal', 'equals', 'expect', 'notDeepEqual',
'notEqual', 'notStrictEqual', 'ok', 'raises', 'same', 'start', 'stop',
'strictEqual', 'test', 'throws'], function(funcName) {
var func = QUnit[funcName];
if (func) {
global[funcName] = func;
}
});
// expose timer methods to global
try {
timer = new java.util.Timer;
if (!isFunction(global.clearInterval)) {
global.clearInterval = clearTimer;
}
if (!isFunction(global.clearTimeout)) {
global.clearTimeout = clearTimer;
}
if (!isFunction(global.setInterval)) {
global.setInterval = setInterval;
}
if (!isFunction(global.setTimeout)) {
global.setTimeout = setTimeout;
}
} catch(e) { }
// add callbacks
QUnit.done(done);
QUnit.log(log);
QUnit.moduleStart(moduleStart);
QUnit.testDone(testDone);
// add wrapped function
QUnit.jsDump.parsers.object = parseObject;
// must call `QUnit.start()` in the test file if using QUnit < 1.3.0 with
// Node.js or any version of QUnit with Narwhal, Rhino, or RingoJS
QUnit.init();
}(typeof global == 'object' && global || this));

49
vendor/qunit/README.md vendored Normal file
View File

@@ -0,0 +1,49 @@
[QUnit](http://docs.jquery.com/QUnit) - A JavaScript Unit Testing framework.
================================
QUnit is a powerful, easy-to-use, JavaScript test suite. It's used by the jQuery
project to test its code and plugins but is capable of testing any generic
JavaScript code (and even capable of testing JavaScript code on the server-side).
QUnit is especially useful for regression testing: Whenever a bug is reported,
write a test that asserts the existence of that particular bug. Then fix it and
commit both. Every time you work on the code again, run the tests. If the bug
comes up again - a regression - you'll spot it immediately and know how to fix
it, because you know what code you just changed.
Having good unit test coverage makes safe refactoring easy and cheap. You can
run the tests after each small refactoring step and always know what change
broke something.
QUnit is similar to other unit testing frameworks like JUnit, but makes use of
the features JavaScript provides and helps with testing code in the browser, e.g.
with its stop/start facilities for testing asynchronous code.
If you are interested in helping developing QUnit, you are in the right place.
For related discussions, visit the
[QUnit and Testing forum](http://forum.jquery.com/qunit-and-testing).
Planning for a qunitjs.com site and other testing tools related work now happens
on the [jQuery Testing Team planning wiki](http://jquerytesting.pbworks.com/w/page/41556026/FrontPage).
Development
-----------
To submit patches, fork the repository, create a branch for the change. Then implement
the change, run `grunt` to lint and test it, then commit, push and create a pull request.
Include some background for the change in the commit message and `Fixes #nnn`, referring
to the issue number you're addressing.
To run `grunt`, you need `node` and `npm`, then `npm install grunt -g`.
Releases
--------
Install git-extras and run `git changelog` to update History.md.
Update qunit/qunit.js|css and package.json to the release version, commit and
tag, update them again to the next version, commit and push commits and tags
(`git push --tags origin master`).
Put the 'v' in front of the tag, e.g. `v1.8.0`. Clean up the changelog, removing merge commits
or whitespace cleanups.

1863
vendor/qunit/qunit/qunit-1.8.0.js vendored Normal file

File diff suppressed because it is too large Load Diff

231
vendor/qunit/qunit/qunit.css vendored Normal file
View File

@@ -0,0 +1,231 @@
/**
* QUnit v1.9.0 - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2012 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
-webkit-border-top-right-radius: 5px;
-webkit-border-top-left-radius: 5px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-testrunner-toolbar label {
display: inline-block;
padding: 0 .5em 0 .1em;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
padding: 5px;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #3c510c;
background-color: #fff;
border-left: 10px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 10px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
#qunit-testresult .module-name {
font-weight: bold;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}

1932
vendor/qunit/qunit/qunit.js vendored Normal file

File diff suppressed because it is too large Load Diff

1
vendor/requirejs vendored

Submodule vendor/requirejs deleted from 07de481552

58
vendor/requirejs/LICENSE vendored Normal file
View File

@@ -0,0 +1,58 @@
RequireJS is released under two licenses: new BSD, and MIT. You may pick the
license that best suits your development needs. The text of both licenses are
provided below.
The "New" BSD License:
----------------------
Copyright (c) 2010-2011, The Dojo Foundation
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the Dojo Foundation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MIT License
-----------
Copyright (c) 2010-2011, The Dojo Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

51
vendor/requirejs/README.md vendored Normal file
View File

@@ -0,0 +1,51 @@
# RequireJS
RequireJS loads plain JavaScript files as well as more defined modules. It is
optimized for in-browser use, including in
[a Web Worker](http://requirejs.org/docs/api.html#webworker), but it can be used
in other JavaScript environments, like Rhino and
[Node](http://requirejs.org/docs/node.html). It implements the
[Asynchronous Module](https://github.com/amdjs/amdjs-api/wiki/AMD)
API.
RequireJS uses plain script tags to load modules/files, so it should allow for
easy debugging. It can be used
[simply to load existing JavaScript files](http://requirejs.org/docs/api.html#jsfiles),
so you can add it to your existing project without having to re-write your
JavaScript files.
RequireJS includes [an optimization tool](http://requirejs.org/docs/optimization.html)
you can run as part of your packaging steps for deploying your code. The
optimization tool can combine and minify your JavaScript files to allow for
better performance.
If the JavaScript file defines a JavaScript module via
[define()](http://requirejs.org/docs/api.html#define), then there are other benefits
RequireJS can offer: [improvements over traditional CommonJS modules](http://requirejs.org/docs/commonjs.html)
and [loading multiple versions](http://requirejs.org/docs/api.html#multiversion)
of a module in a page. RequireJS also has a plugin system that supports features like
[i18n string bundles](http://requirejs.org/docs/api.html#i18n), and
[text file dependencies](http://requirejs.org/docs/api.html#text).
RequireJS does not have any dependencies on a JavaScript framework.
It is dual-licensed -- new BSD or MIT.
The standard require.js file is around 5.5KB when minified via Closure Compiler
and gzipped.
RequireJS works in IE 6+, Firefox 2+, Safari 3.2+, Chrome 3+, and Opera 10+.
[Latest Release](http://requirejs.org/docs/download.html)
## Directories
* **dist**: Scripts and assets to generate the requirejs.org docs, and for
generating a require.js release.
* **docs**: The raw HTML files for the requirejs.org docs. Only includes the
body of each page. Files in **dist** are used to generate a complete HTML page.
* **tests**: Tests for require.js.
* **testBaseUrl.js**: A file used in the tests inside **tests**. Purposely
placed outside the tests directory for testing paths that go outside a baseUrl.
* **updatesubs.sh**: Updates projects that depend on require.js Assumes the
projects are siblings to this directory and have specific names. Useful to
copy require.js to dependent projects easily while in development.

2053
vendor/requirejs/require.js vendored Normal file

File diff suppressed because it is too large Load Diff

1
vendor/uglifyjs vendored

Submodule vendor/uglifyjs deleted from ef4d776aed

1
vendor/underscore vendored

Submodule vendor/underscore deleted from 0da7b393b0

22
vendor/underscore/LICENSE vendored Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2009-2012 Jeremy Ashkenas, DocumentCloud
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

19
vendor/underscore/README.md vendored Normal file
View File

@@ -0,0 +1,19 @@
__
/\ \ __
__ __ ___ \_\ \ __ _ __ ____ ___ ___ _ __ __ /\_\ ____
/\ \/\ \ /' _ `\ /'_ \ /'__`\/\ __\/ ,__\ / ___\ / __`\/\ __\/'__`\ \/\ \ /',__\
\ \ \_\ \/\ \/\ \/\ \ \ \/\ __/\ \ \//\__, `\/\ \__//\ \ \ \ \ \//\ __/ __ \ \ \/\__, `\
\ \____/\ \_\ \_\ \___,_\ \____\\ \_\\/\____/\ \____\ \____/\ \_\\ \____\/\_\ _\ \ \/\____/
\/___/ \/_/\/_/\/__,_ /\/____/ \/_/ \/___/ \/____/\/___/ \/_/ \/____/\/_//\ \_\ \/___/
\ \____/
\/___/
Underscore.js is a utility-belt library for JavaScript that provides
support for the usual functional suspects (each, map, reduce, filter...)
without extending any core JavaScript objects.
For Docs, License, Tests, and pre-packed downloads, see:
http://underscorejs.org
Many thanks to our contributors:
https://github.com/documentcloud/underscore/contributors

174
vendor/underscore/test/arrays.js vendored Normal file
View File

@@ -0,0 +1,174 @@
$(document).ready(function() {
module("Arrays");
test("arrays: first", function() {
equal(_.first([1,2,3]), 1, 'can pull out the first element of an array');
equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"');
equal(_.first([1,2,3], 0).join(', '), "", 'can pass an index to first');
equal(_.first([1,2,3], 2).join(', '), '1, 2', 'can pass an index to first');
equal(_.first([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to first');
var result = (function(){ return _.first(arguments); })(4, 3, 2, 1);
equal(result, 4, 'works on an arguments object.');
result = _.map([[1,2,3],[1,2,3]], _.first);
equal(result.join(','), '1,1', 'works well with _.map');
result = (function() { return _.take([1,2,3], 2); })();
equal(result.join(','), '1,2', 'aliased as take');
});
test("arrays: rest", function() {
var numbers = [1, 2, 3, 4];
equal(_.rest(numbers).join(", "), "2, 3, 4", 'working rest()');
equal(_.rest(numbers, 0).join(", "), "1, 2, 3, 4", 'working rest(0)');
equal(_.rest(numbers, 2).join(', '), '3, 4', 'rest can take an index');
var result = (function(){ return _(arguments).tail(); })(1, 2, 3, 4);
equal(result.join(', '), '2, 3, 4', 'aliased as tail and works on arguments object');
result = _.map([[1,2,3],[1,2,3]], _.rest);
equal(_.flatten(result).join(','), '2,3,2,3', 'works well with _.map');
});
test("arrays: initial", function() {
equal(_.initial([1,2,3,4,5]).join(", "), "1, 2, 3, 4", 'working initial()');
equal(_.initial([1,2,3,4],2).join(", "), "1, 2", 'initial can take an index');
var result = (function(){ return _(arguments).initial(); })(1, 2, 3, 4);
equal(result.join(", "), "1, 2, 3", 'initial works on arguments object');
result = _.map([[1,2,3],[1,2,3]], _.initial);
equal(_.flatten(result).join(','), '1,2,1,2', 'initial works with _.map');
});
test("arrays: last", function() {
equal(_.last([1,2,3]), 3, 'can pull out the last element of an array');
equal(_.last([1,2,3], 0).join(', '), "", 'can pass an index to last');
equal(_.last([1,2,3], 2).join(', '), '2, 3', 'can pass an index to last');
equal(_.last([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to last');
var result = (function(){ return _(arguments).last(); })(1, 2, 3, 4);
equal(result, 4, 'works on an arguments object');
result = _.map([[1,2,3],[1,2,3]], _.last);
equal(result.join(','), '3,3', 'works well with _.map');
});
test("arrays: compact", function() {
equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values');
var result = (function(){ return _(arguments).compact().length; })(0, 1, false, 2, false, 3);
equal(result, 3, 'works on an arguments object');
});
test("arrays: flatten", function() {
if (window.JSON) {
var list = [1, [2], [3, [[[4]]]]];
equal(JSON.stringify(_.flatten(list)), '[1,2,3,4]', 'can flatten nested arrays');
equal(JSON.stringify(_.flatten(list, true)), '[1,2,3,[[[4]]]]', 'can shallowly flatten nested arrays');
var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]);
equal(JSON.stringify(result), '[1,2,3,4]', 'works on an arguments object');
}
});
test("arrays: without", function() {
var list = [1, 2, 1, 0, 3, 1, 4];
equal(_.without(list, 0, 1).join(', '), '2, 3, 4', 'can remove all instances of an object');
var result = (function(){ return _.without(arguments, 0, 1); })(1, 2, 1, 0, 3, 1, 4);
equal(result.join(', '), '2, 3, 4', 'works on an arguments object');
var list = [{one : 1}, {two : 2}];
ok(_.without(list, {one : 1}).length == 2, 'uses real object identity for comparisons.');
ok(_.without(list, list[0]).length == 1, 'ditto.');
});
test("arrays: uniq", function() {
var list = [1, 2, 1, 3, 1, 4];
equal(_.uniq(list).join(', '), '1, 2, 3, 4', 'can find the unique values of an unsorted array');
var list = [1, 1, 1, 2, 2, 3];
equal(_.uniq(list, true).join(', '), '1, 2, 3', 'can find the unique values of a sorted array faster');
var list = [{name:'moe'}, {name:'curly'}, {name:'larry'}, {name:'curly'}];
var iterator = function(value) { return value.name; };
equal(_.map(_.uniq(list, false, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator');
var iterator = function(value) { return value +1; };
var list = [1, 2, 2, 3, 4, 4];
equal(_.uniq(list, true, iterator).join(', '), '1, 2, 3, 4', 'iterator works with sorted array');
var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4);
equal(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
});
test("arrays: intersection", function() {
var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho'];
equal(_.intersection(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
equal(_(stooges).intersection(leaders).join(''), 'moe', 'can perform an OO-style intersection');
var result = (function(){ return _.intersection(arguments, leaders); })('moe', 'curly', 'larry');
equal(result.join(''), 'moe', 'works on an arguments object');
});
test("arrays: union", function() {
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]);
equal(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays');
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]);
equal(result.join(' '), '1 2 3 30 40 1', 'takes the union of a list of nested arrays');
});
test("arrays: difference", function() {
var result = _.difference([1, 2, 3], [2, 30, 40]);
equal(result.join(' '), '1 3', 'takes the difference of two arrays');
var result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]);
equal(result.join(' '), '3 4', 'takes the difference of three arrays');
});
test('arrays: zip', function() {
var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];
var stooges = _.zip(names, ages, leaders);
equal(String(stooges), 'moe,30,true,larry,40,,curly,50,', 'zipped together arrays of different lengths');
});
test('arrays: zipObject', function() {
var result = _.zipObject(['moe', 'larry', 'curly'], [30, 40, 50]);
var shouldBe = {moe: 30, larry: 40, curly: 50};
ok(_.isEqual(result, shouldBe), 'two arrays zipped together into an object');
});
test("arrays: indexOf", function() {
var numbers = [1, 2, 3];
numbers.indexOf = null;
equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
equal(result, 1, 'works on an arguments object');
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
var numbers = [10, 20, 30, 40, 50], num = 35;
var index = _.indexOf(numbers, num, true);
equal(index, -1, '35 is not in the list');
numbers = [10, 20, 30, 40, 50]; num = 40;
index = _.indexOf(numbers, num, true);
equal(index, 3, '40 is in the list');
numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40;
index = _.indexOf(numbers, num, true);
equal(index, 1, '40 is in the list');
});
test("arrays: lastIndexOf", function() {
var numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0];
numbers.lastIndexOf = null;
equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function');
equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0);
equal(result, 5, 'works on an arguments object');
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
});
test("arrays: range", function() {
equal(_.range(0).join(''), '', 'range with 0 as a first argument generates an empty array');
equal(_.range(4).join(' '), '0 1 2 3', 'range with a single positive argument generates an array of elements 0,1,2,...,n-1');
equal(_.range(5, 8).join(' '), '5 6 7', 'range with two arguments a &amp; b, a&lt;b generates an array of elements a,a+1,a+2,...,b-2,b-1');
equal(_.range(8, 5).join(''), '', 'range with two arguments a &amp; b, b&lt;a generates an empty array');
equal(_.range(3, 10, 3).join(' '), '3 6 9', 'range with three arguments a &amp; b &amp; c, c &lt; b-a, a &lt; b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) &lt; c');
equal(_.range(3, 10, 15).join(''), '3', 'range with three arguments a &amp; b &amp; c, c &gt; b-a, a &lt; b generates an array with a single element, equal to a');
equal(_.range(12, 7, -2).join(' '), '12 10 8', 'range with three arguments a &amp; b &amp; c, a &gt; b, c &lt; 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b');
equal(_.range(0, -10, -1).join(' '), '0 -1 -2 -3 -4 -5 -6 -7 -8 -9', 'final example in the Python docs');
});
});

59
vendor/underscore/test/chaining.js vendored Normal file
View File

@@ -0,0 +1,59 @@
$(document).ready(function() {
module("Chaining");
test("chaining: map/flatten/reduce", function() {
var lyrics = [
"I'm a lumberjack and I'm okay",
"I sleep all night and I work all day",
"He's a lumberjack and he's okay",
"He sleeps all night and he works all day"
];
var counts = _(lyrics).chain()
.map(function(line) { return line.split(''); })
.flatten()
.reduce(function(hash, l) {
hash[l] = hash[l] || 0;
hash[l]++;
return hash;
}, {}).value();
ok(counts['a'] == 16 && counts['e'] == 10, 'counted all the letters in the song');
});
test("chaining: select/reject/sortBy", function() {
var numbers = [1,2,3,4,5,6,7,8,9,10];
numbers = _(numbers).chain().select(function(n) {
return n % 2 == 0;
}).reject(function(n) {
return n % 4 == 0;
}).sortBy(function(n) {
return -n;
}).value();
equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
});
test("chaining: select/reject/sortBy in functional style", function() {
var numbers = [1,2,3,4,5,6,7,8,9,10];
numbers = _.chain(numbers).select(function(n) {
return n % 2 == 0;
}).reject(function(n) {
return n % 4 == 0;
}).sortBy(function(n) {
return -n;
}).value();
equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
});
test("chaining: reverse/concat/unshift/pop/map", function() {
var numbers = [1,2,3,4,5];
numbers = _(numbers).chain()
.reverse()
.concat([5, 5, 5])
.unshift(17)
.pop()
.map(function(n){ return n * 2; })
.value();
equal(numbers.join(', '), "34, 10, 8, 6, 4, 2, 10, 10", 'can chain together array functions.');
});
});

308
vendor/underscore/test/collections.js vendored Normal file
View File

@@ -0,0 +1,308 @@
$(document).ready(function() {
module("Collections");
test("collections: each", function() {
_.each([1, 2, 3], function(num, i) {
equal(num, i + 1, 'each iterators provide value and iteration count');
});
var answers = [];
_.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5});
equal(answers.join(', '), '5, 10, 15', 'context object property accessed');
answers = [];
_.forEach([1, 2, 3], function(num){ answers.push(num); });
equal(answers.join(', '), '1, 2, 3', 'aliased as "forEach"');
answers = [];
var obj = {one : 1, two : 2, three : 3};
obj.constructor.prototype.four = 4;
_.each(obj, function(value, key){ answers.push(key); });
equal(answers.join(", "), 'one, two, three', 'iterating over objects works, and ignores the object prototype.');
delete obj.constructor.prototype.four;
answer = null;
_.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; });
ok(answer, 'can reference the original collection from inside the iterator');
answers = 0;
_.each(null, function(){ ++answers; });
equal(answers, 0, 'handles a null properly');
});
test('collections: map', function() {
var doubled = _.map([1, 2, 3], function(num){ return num * 2; });
equal(doubled.join(', '), '2, 4, 6', 'doubled numbers');
doubled = _.collect([1, 2, 3], function(num){ return num * 2; });
equal(doubled.join(', '), '2, 4, 6', 'aliased as "collect"');
var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3});
equal(tripled.join(', '), '3, 6, 9', 'tripled numbers with context');
var doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
equal(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers');
var ids = _.map($('#map-test').children(), function(n){ return n.id; });
deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on NodeLists.');
var ids = _.map(document.images, function(n){ return n.id; });
ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections');
var ifnull = _.map(null, function(){});
ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly');
});
test('collections: reduce', function() {
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }, 0);
equal(sum, 6, 'can sum up an array');
var context = {multiplier : 3};
sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num * this.multiplier; }, 0, context);
equal(sum, 18, 'can reduce with a context object');
sum = _.inject([1, 2, 3], function(sum, num){ return sum + num; }, 0);
equal(sum, 6, 'aliased as "inject"');
sum = _([1, 2, 3]).reduce(function(sum, num){ return sum + num; }, 0);
equal(sum, 6, 'OO-style reduce');
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
equal(sum, 6, 'default initial value');
var ifnull;
try {
_.reduce(null, function(){});
} catch (ex) {
ifnull = ex;
}
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
});
test('collections: reduceRight', function() {
var list = _.reduceRight(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
equal(list, 'bazbarfoo', 'can perform right folds');
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
equal(list, 'bazbarfoo', 'aliased as "foldr"');
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; });
equal(list, 'bazbarfoo', 'default initial value');
var ifnull;
try {
_.reduceRight(null, function(){});
} catch (ex) {
ifnull = ex;
}
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
});
test('collections: find', function() {
var array = [1, 2, 3, 4];
strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`');
strictEqual(_.find(array, function() { return false; }), void 0, 'should return `undefined` if `value` is not found');
});
test('collections: detect', function() {
var result = _.detect([1, 2, 3], function(num){ return num * 2 == 4; });
equal(result, 2, 'found the first "2" and broke the loop');
});
test('collections: select', function() {
var evens = _.select([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
equal(evens.join(', '), '2, 4, 6', 'selected each even number');
evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
equal(evens.join(', '), '2, 4, 6', 'aliased as "filter"');
});
test('collections: reject', function() {
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
equal(odds.join(', '), '1, 3, 5', 'rejected each even number');
});
test('collections: all', function() {
ok(_.all([], _.identity), 'the empty set');
ok(_.all([true, true, true], _.identity), 'all true values');
ok(!_.all([true, false, true], _.identity), 'one false value');
ok(_.all([0, 10, 28], function(num){ return num % 2 == 0; }), 'even numbers');
ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number');
ok(_.all([1], _.identity) === true, 'cast to boolean - true');
ok(_.all([0], _.identity) === false, 'cast to boolean - false');
ok(_.every([true, true, true], _.identity), 'aliased as "every"');
});
test('collections: any', function() {
var nativeSome = Array.prototype.some;
Array.prototype.some = null;
ok(!_.any([]), 'the empty set');
ok(!_.any([false, false, false]), 'all false values');
ok(_.any([false, false, true]), 'one true value');
ok(_.any([null, 0, 'yes', false]), 'a string');
ok(!_.any([null, 0, '', false]), 'falsy values');
ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers');
ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number');
ok(_.any([1], _.identity) === true, 'cast to boolean - true');
ok(_.any([0], _.identity) === false, 'cast to boolean - false');
ok(_.some([false, false, true]), 'aliased as "some"');
Array.prototype.some = nativeSome;
});
test('collections: include', function() {
ok(_.include([1,2,3], 2), 'two is in the array');
ok(!_.include([1,3,9], 2), 'two is not in the array');
ok(_.contains({moe:1, larry:3, curly:9}, 3) === true, '_.include on objects checks their values');
ok(_([1,2,3]).include(2), 'OO-style include');
});
test('collections: invoke', function() {
var list = [[5, 1, 7], [3, 2, 1]];
var result = _.invoke(list, 'sort');
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
});
test('collections: invoke w/ function reference', function() {
var list = [[5, 1, 7], [3, 2, 1]];
var result = _.invoke(list, Array.prototype.sort);
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
});
// Relevant when using ClojureScript
test('collections: invoke when strings have a call method', function() {
String.prototype.call = function() {
return 42;
};
var list = [[5, 1, 7], [3, 2, 1]];
var s = "foo";
equal(s.call(), 42, "call function exists");
var result = _.invoke(list, 'sort');
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
delete String.prototype.call;
equal(s.call, undefined, "call function removed");
});
test('collections: pluck', function() {
var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}];
equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'pulls names out of objects');
});
test('collections: max', function() {
equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max');
var neg = _.max([1, 2, 3], function(num){ return -num; });
equal(neg, 1, 'can perform a computation-based max');
equal(-Infinity, _.max({}), 'Maximum value of an empty object');
equal(-Infinity, _.max([]), 'Maximum value of an empty array');
equal(299999, _.max(_.range(1,300000)), "Maximum value of a too-big array");
});
test('collections: min', function() {
equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min');
var neg = _.min([1, 2, 3], function(num){ return -num; });
equal(neg, 3, 'can perform a computation-based min');
equal(Infinity, _.min({}), 'Minimum value of an empty object');
equal(Infinity, _.min([]), 'Minimum value of an empty array');
var now = new Date(9999999999);
var then = new Date(0);
equal(_.min([now, then]), then);
equal(1, _.min(_.range(1,300000)), "Minimum value of a too-big array");
});
test('collections: sortBy', function() {
var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}];
people = _.sortBy(people, function(person){ return person.age; });
equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
var list = [undefined, 4, 1, undefined, 3, 2];
equal(_.sortBy(list, _.identity).join(','), '1,2,3,4,,', 'sortBy with undefined values');
var list = ["one", "two", "three", "four", "five"];
var sorted = _.sortBy(list, 'length');
equal(sorted.join(' '), 'one two four five three', 'sorted by length');
});
test('collections: groupBy', function() {
var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
ok('0' in parity && '1' in parity, 'created a group for each value');
equal(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
var grouped = _.groupBy(list, 'length');
equal(grouped['3'].join(' '), 'one two six ten');
equal(grouped['4'].join(' '), 'four five nine');
equal(grouped['5'].join(' '), 'three seven eight');
});
test('collections: countBy', function() {
var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 == 0; });
equal(parity['true'], 2);
equal(parity['false'], 3);
var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
var grouped = _.countBy(list, 'length');
equal(grouped['3'], 4);
equal(grouped['4'], 3);
equal(grouped['5'], 3);
});
test('collections: sortedIndex', function() {
var numbers = [10, 20, 30, 40, 50], num = 35;
var indexForNum = _.sortedIndex(numbers, num);
equal(indexForNum, 3, '35 should be inserted at index 3');
var indexFor30 = _.sortedIndex(numbers, 30);
equal(indexFor30, 2, '30 should be inserted at index 2');
});
test('collections: shuffle', function() {
var numbers = _.range(10);
var shuffled = _.shuffle(numbers).sort();
notStrictEqual(numbers, shuffled, 'original object is unmodified');
equal(shuffled.join(','), numbers.join(','), 'contains the same members before and after shuffle');
});
test('collections: toArray', function() {
ok(!_.isArray(arguments), 'arguments object is not an array');
ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array');
var a = [1,2,3];
ok(_.toArray(a) !== a, 'array is cloned');
equal(_.toArray(a).join(', '), '1, 2, 3', 'cloned array contains same elements');
var numbers = _.toArray({one : 1, two : 2, three : 3});
equal(numbers.join(', '), '1, 2, 3', 'object flattened into array');
var objectWithToArrayFunction = {toArray: function() {
return [1, 2, 3];
}};
equal(_.toArray(objectWithToArrayFunction).join(', '), '1, 2, 3', 'toArray method used if present');
var objectWithToArrayValue = {toArray: 1};
equal(_.toArray(objectWithToArrayValue).join(', '), '1', 'toArray property ignored if not a function');
});
test('collections: size', function() {
equal(_.size({one : 1, two : 2, three : 3}), 3, 'can compute the size of an object');
equal(_.size([1, 2, 3]), 3, 'can compute the size of an array');
});
});

226
vendor/underscore/test/functions.js vendored Normal file
View File

@@ -0,0 +1,226 @@
$(document).ready(function() {
module("Functions");
test("functions: bind", function() {
var context = {name : 'moe'};
var func = function(arg) { return "name: " + (this.name || arg); };
var bound = _.bind(func, context);
equal(bound(), 'name: moe', 'can bind a function to a context');
bound = _(func).bind(context);
equal(bound(), 'name: moe', 'can do OO-style binding');
bound = _.bind(func, null, 'curly');
equal(bound(), 'name: curly', 'can bind without specifying a context');
func = function(salutation, name) { return salutation + ': ' + name; };
func = _.bind(func, this, 'hello');
equal(func('moe'), 'hello: moe', 'the function was partially applied in advance');
var func = _.bind(func, this, 'curly');
equal(func(), 'hello: curly', 'the function was completely applied in advance');
var func = function(salutation, firstname, lastname) { return salutation + ': ' + firstname + ' ' + lastname; };
func = _.bind(func, this, 'hello', 'moe', 'curly');
equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments');
func = function(context, message) { equal(this, context, message); };
_.bind(func, 0, 0, 'can bind a function to `0`')();
_.bind(func, '', '', 'can bind a function to an empty string')();
_.bind(func, false, false, 'can bind a function to `false`')();
// These tests are only meaningful when using a browser without a native bind function
// To test this with a modern browser, set underscore's nativeBind to undefined
var F = function () { return this; };
var Boundf = _.bind(F, {hello: "moe curly"});
equal(new Boundf().hello, undefined, "function should not be bound to the context, to comply with ECMAScript 5");
equal(Boundf().hello, "moe curly", "When called without the new operator, it's OK to be bound to the context");
});
test("functions: bindAll", function() {
var curly = {name : 'curly'}, moe = {
name : 'moe',
getName : function() { return 'name: ' + this.name; },
sayHi : function() { return 'hi: ' + this.name; }
};
curly.getName = moe.getName;
_.bindAll(moe, 'getName', 'sayHi');
curly.sayHi = moe.sayHi;
equal(curly.getName(), 'name: curly', 'unbound function is bound to current object');
equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object');
curly = {name : 'curly'};
moe = {
name : 'moe',
getName : function() { return 'name: ' + this.name; },
sayHi : function() { return 'hi: ' + this.name; }
};
_.bindAll(moe);
curly.sayHi = moe.sayHi;
equal(curly.sayHi(), 'hi: moe', 'calling bindAll with no arguments binds all functions to the object');
});
test("functions: memoize", function() {
var fib = function(n) {
return n < 2 ? n : fib(n - 1) + fib(n - 2);
};
var fastFib = _.memoize(fib);
equal(fib(10), 55, 'a memoized version of fibonacci produces identical results');
equal(fastFib(10), 55, 'a memoized version of fibonacci produces identical results');
var o = function(str) {
return str;
};
var fastO = _.memoize(o);
equal(o('toString'), 'toString', 'checks hasOwnProperty');
equal(fastO('toString'), 'toString', 'checks hasOwnProperty');
});
asyncTest("functions: delay", 2, function() {
var delayed = false;
_.delay(function(){ delayed = true; }, 100);
setTimeout(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
setTimeout(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
});
asyncTest("functions: defer", 1, function() {
var deferred = false;
_.defer(function(bool){ deferred = bool; }, true);
_.delay(function(){ ok(deferred, "deferred the function"); start(); }, 50);
});
asyncTest("functions: throttle", 2, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100);
throttledIncr(); throttledIncr(); throttledIncr();
setTimeout(throttledIncr, 70);
setTimeout(throttledIncr, 120);
setTimeout(throttledIncr, 140);
setTimeout(throttledIncr, 190);
setTimeout(throttledIncr, 220);
setTimeout(throttledIncr, 240);
_.delay(function(){ equal(counter, 1, "incr was called immediately"); }, 30);
_.delay(function(){ equal(counter, 4, "incr was throttled"); start(); }, 400);
});
asyncTest("functions: throttle arguments", 2, function() {
var value = 0;
var update = function(val){ value = val; };
var throttledUpdate = _.throttle(update, 100);
throttledUpdate(1); throttledUpdate(2); throttledUpdate(3);
setTimeout(function(){ throttledUpdate(4); }, 120);
setTimeout(function(){ throttledUpdate(5); }, 140);
setTimeout(function(){ throttledUpdate(6); }, 250);
_.delay(function(){ equal(value, 1, "updated to latest value"); }, 40);
_.delay(function(){ equal(value, 6, "updated to latest value"); start(); }, 400);
});
asyncTest("functions: throttle once", 2, function() {
var counter = 0;
var incr = function(){ return ++counter; };
var throttledIncr = _.throttle(incr, 100);
var result = throttledIncr();
_.delay(function(){
equal(result, 1, "throttled functions return their value");
equal(counter, 1, "incr was called once"); start();
}, 220);
});
asyncTest("functions: throttle twice", 1, function() {
var counter = 0;
var incr = function(){ counter++; };
var throttledIncr = _.throttle(incr, 100);
throttledIncr(); throttledIncr();
_.delay(function(){ equal(counter, 2, "incr was called twice"); start(); }, 220);
});
asyncTest("functions: debounce", 1, function() {
var counter = 0;
var incr = function(){ counter++; };
var debouncedIncr = _.debounce(incr, 50);
debouncedIncr(); debouncedIncr(); debouncedIncr();
setTimeout(debouncedIncr, 30);
setTimeout(debouncedIncr, 60);
setTimeout(debouncedIncr, 90);
setTimeout(debouncedIncr, 120);
setTimeout(debouncedIncr, 150);
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 220);
});
asyncTest("functions: debounce asap", 2, function() {
var counter = 0;
var incr = function(){ counter++; };
var debouncedIncr = _.debounce(incr, 50, true);
debouncedIncr(); debouncedIncr(); debouncedIncr();
equal(counter, 1, 'incr was called immediately');
setTimeout(debouncedIncr, 30);
setTimeout(debouncedIncr, 60);
setTimeout(debouncedIncr, 90);
setTimeout(debouncedIncr, 120);
setTimeout(debouncedIncr, 150);
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 220);
});
asyncTest("functions: debounce asap recursively", 2, function() {
var counter = 0;
var debouncedIncr = _.debounce(function(){
counter++;
if (counter < 5) debouncedIncr();
}, 50, true);
debouncedIncr();
equal(counter, 1, 'incr was called immediately');
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 70);
});
test("functions: once", function() {
var num = 0;
var increment = _.once(function(){ num++; });
increment();
increment();
equal(num, 1);
});
test("functions: wrap", function() {
var greet = function(name){ return "hi: " + name; };
var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); });
equal(backwards('moe'), 'hi: moe eom', 'wrapped the saluation function');
var inner = function(){ return "Hello "; };
var obj = {name : "Moe"};
obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; });
equal(obj.hi(), "Hello Moe");
var noop = function(){};
var wrapped = _.wrap(noop, function(fn){ return Array.prototype.slice.call(arguments, 0); });
var ret = wrapped(['whats', 'your'], 'vector', 'victor');
deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']);
});
test("functions: compose", function() {
var greet = function(name){ return "hi: " + name; };
var exclaim = function(sentence){ return sentence + '!'; };
var composed = _.compose(exclaim, greet);
equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another');
composed = _.compose(greet, exclaim);
equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative');
});
test("functions: after", function() {
var testAfter = function(afterAmount, timesCalled) {
var afterCalled = 0;
var after = _.after(afterAmount, function() {
afterCalled++;
});
while (timesCalled--) after();
return afterCalled;
};
equal(testAfter(5, 5), 1, "after(N) should fire after being called N times");
equal(testAfter(5, 4), 0, "after(N) should not fire unless called N times");
equal(testAfter(0, 0), 1, "after(0) should fire immediately");
});
});

558
vendor/underscore/test/objects.js vendored Normal file
View File

@@ -0,0 +1,558 @@
$(document).ready(function() {
module("Objects");
test("objects: keys", function() {
equal(_.keys({one : 1, two : 2}).join(', '), 'one, two', 'can extract the keys from an object');
// the test above is not safe because it relies on for-in enumeration order
var a = []; a[1] = 0;
equal(_.keys(a).join(', '), '1', 'is not fooled by sparse arrays; see issue #95');
raises(function() { _.keys(null); }, TypeError, 'throws an error for `null` values');
raises(function() { _.keys(void 0); }, TypeError, 'throws an error for `undefined` values');
raises(function() { _.keys(1); }, TypeError, 'throws an error for number primitives');
raises(function() { _.keys('a'); }, TypeError, 'throws an error for string primitives');
raises(function() { _.keys(true); }, TypeError, 'throws an error for boolean primitives');
});
test("objects: values", function() {
equal(_.values({one : 1, two : 2}).join(', '), '1, 2', 'can extract the values from an object');
});
test("objects: functions", function() {
var obj = {a : 'dash', b : _.map, c : (/yo/), d : _.reduce};
ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object');
var Animal = function(){};
Animal.prototype.run = function(){};
equal(_.functions(new Animal).join(''), 'run', 'also looks up functions on the prototype');
});
test("objects: extend", function() {
var result;
equal(_.extend({}, {a:'b'}).a, 'b', 'can extend an object with the attributes of another');
equal(_.extend({a:'x'}, {a:'b'}).a, 'b', 'properties in source override destination');
equal(_.extend({x:'x'}, {a:'b'}).x, 'x', 'properties not in source dont get overriden');
result = _.extend({x:'x'}, {a:'a'}, {b:'b'});
ok(_.isEqual(result, {x:'x', a:'a', b:'b'}), 'can extend from multiple source objects');
result = _.extend({x:'x'}, {a:'a', x:2}, {a:'b'});
ok(_.isEqual(result, {x:2, a:'b'}), 'extending from multiple source objects last property trumps');
result = _.extend({}, {a: void 0, b: null});
equal(_.keys(result).join(''), 'ab', 'extend does not copy undefined values');
});
test("objects: pick", function() {
var result;
result = _.pick({a:1, b:2, c:3}, 'a', 'c');
ok(_.isEqual(result, {a:1, c:3}), 'can restrict properties to those named');
result = _.pick({a:1, b:2, c:3}, ['b', 'c']);
ok(_.isEqual(result, {b:2, c:3}), 'can restrict properties to those named in an array');
result = _.pick({a:1, b:2, c:3}, ['a'], 'b');
ok(_.isEqual(result, {a:1, b:2}), 'can restrict properties to those named in mixed args');
});
test("objects: defaults", function() {
var result;
var options = {zero: 0, one: 1, empty: "", nan: NaN, string: "string"};
_.defaults(options, {zero: 1, one: 10, twenty: 20});
equal(options.zero, 0, 'value exists');
equal(options.one, 1, 'value exists');
equal(options.twenty, 20, 'default applied');
_.defaults(options, {empty: "full"}, {nan: "nan"}, {word: "word"}, {word: "dog"});
equal(options.empty, "", 'value exists');
ok(_.isNaN(options.nan), "NaN isn't overridden");
equal(options.word, "word", 'new value is added, first one wins');
});
test("objects: clone", function() {
var moe = {name : 'moe', lucky : [13, 27, 34]};
var clone = _.clone(moe);
equal(clone.name, 'moe', 'the clone as the attributes of the original');
clone.name = 'curly';
ok(clone.name == 'curly' && moe.name == 'moe', 'clones can change shallow attributes without affecting the original');
clone.lucky.push(101);
equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original');
equal(_.clone(undefined), void 0, 'non objects should not be changed by clone');
equal(_.clone(1), 1, 'non objects should not be changed by clone');
equal(_.clone(null), null, 'non objects should not be changed by clone');
});
test("objects: isEqual", function() {
function First() {
this.value = 1;
}
First.prototype.value = 1;
function Second() {
this.value = 1;
}
Second.prototype.value = 2;
// Basic equality and identity comparisons.
ok(_.isEqual(null, null), "`null` is equal to `null`");
ok(_.isEqual(), "`undefined` is equal to `undefined`");
ok(!_.isEqual(0, -0), "`0` is not equal to `-0`");
ok(!_.isEqual(-0, 0), "Commutative equality is implemented for `0` and `-0`");
ok(!_.isEqual(null, undefined), "`null` is not equal to `undefined`");
ok(!_.isEqual(undefined, null), "Commutative equality is implemented for `null` and `undefined`");
// String object and primitive comparisons.
ok(_.isEqual("Curly", "Curly"), "Identical string primitives are equal");
ok(_.isEqual(new String("Curly"), new String("Curly")), "String objects with identical primitive values are equal");
ok(_.isEqual(new String("Curly"), "Curly"), "String primitives and their corresponding object wrappers are equal");
ok(_.isEqual("Curly", new String("Curly")), "Commutative equality is implemented for string objects and primitives");
ok(!_.isEqual("Curly", "Larry"), "String primitives with different values are not equal");
ok(!_.isEqual(new String("Curly"), new String("Larry")), "String objects with different primitive values are not equal");
ok(!_.isEqual(new String("Curly"), {toString: function(){ return "Curly"; }}), "String objects and objects with a custom `toString` method are not equal");
// Number object and primitive comparisons.
ok(_.isEqual(75, 75), "Identical number primitives are equal");
ok(_.isEqual(new Number(75), new Number(75)), "Number objects with identical primitive values are equal");
ok(_.isEqual(75, new Number(75)), "Number primitives and their corresponding object wrappers are equal");
ok(_.isEqual(new Number(75), 75), "Commutative equality is implemented for number objects and primitives");
ok(!_.isEqual(new Number(0), -0), "`new Number(0)` and `-0` are not equal");
ok(!_.isEqual(0, new Number(-0)), "Commutative equality is implemented for `new Number(0)` and `-0`");
ok(!_.isEqual(new Number(75), new Number(63)), "Number objects with different primitive values are not equal");
ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), "Number objects and objects with a `valueOf` method are not equal");
// Comparisons involving `NaN`.
ok(_.isEqual(NaN, NaN), "`NaN` is equal to `NaN`");
ok(!_.isEqual(61, NaN), "A number primitive is not equal to `NaN`");
ok(!_.isEqual(new Number(79), NaN), "A number object is not equal to `NaN`");
ok(!_.isEqual(Infinity, NaN), "`Infinity` is not equal to `NaN`");
// Boolean object and primitive comparisons.
ok(_.isEqual(true, true), "Identical boolean primitives are equal");
ok(_.isEqual(new Boolean, new Boolean), "Boolean objects with identical primitive values are equal");
ok(_.isEqual(true, new Boolean(true)), "Boolean primitives and their corresponding object wrappers are equal");
ok(_.isEqual(new Boolean(true), true), "Commutative equality is implemented for booleans");
ok(!_.isEqual(new Boolean(true), new Boolean), "Boolean objects with different primitive values are not equal");
// Common type coercions.
ok(!_.isEqual(true, new Boolean(false)), "Boolean objects are not equal to the boolean primitive `true`");
ok(!_.isEqual("75", 75), "String and number primitives with like values are not equal");
ok(!_.isEqual(new Number(63), new String(63)), "String and number objects with like values are not equal");
ok(!_.isEqual(75, "75"), "Commutative equality is implemented for like string and number values");
ok(!_.isEqual(0, ""), "Number and string primitives with like values are not equal");
ok(!_.isEqual(1, true), "Number and boolean primitives with like values are not equal");
ok(!_.isEqual(new Boolean(false), new Number(0)), "Boolean and number objects with like values are not equal");
ok(!_.isEqual(false, new String("")), "Boolean primitives and string objects with like values are not equal");
ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), "Dates and their corresponding numeric primitive values are not equal");
// Dates.
ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), "Date objects referencing identical times are equal");
ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), "Date objects referencing different times are not equal");
ok(!_.isEqual(new Date(2009, 11, 13), {
getTime: function(){
return 12606876e5;
}
}), "Date objects and objects with a `getTime` method are not equal");
ok(!_.isEqual(new Date("Curly"), new Date("Curly")), "Invalid dates are not equal");
// Functions.
ok(!_.isEqual(First, Second), "Different functions with identical bodies and source code representations are not equal");
// RegExps.
ok(_.isEqual(/(?:)/gim, /(?:)/gim), "RegExps with equivalent patterns and flags are equal");
ok(!_.isEqual(/(?:)/g, /(?:)/gi), "RegExps with equivalent patterns and different flags are not equal");
ok(!_.isEqual(/Moe/gim, /Curly/gim), "RegExps with different patterns and equivalent flags are not equal");
ok(!_.isEqual(/(?:)/gi, /(?:)/g), "Commutative equality is implemented for RegExps");
ok(!_.isEqual(/Curly/g, {source: "Larry", global: true, ignoreCase: false, multiline: false}), "RegExps and RegExp-like objects are not equal");
// Empty arrays, array-like objects, and object literals.
ok(_.isEqual({}, {}), "Empty object literals are equal");
ok(_.isEqual([], []), "Empty array literals are equal");
ok(_.isEqual([{}], [{}]), "Empty nested arrays and objects are equal");
ok(!_.isEqual({length: 0}, []), "Array-like objects and arrays are not equal.");
ok(!_.isEqual([], {length: 0}), "Commutative equality is implemented for array-like objects");
ok(!_.isEqual({}, []), "Object literals and array literals are not equal");
ok(!_.isEqual([], {}), "Commutative equality is implemented for objects and arrays");
// Arrays with primitive and object values.
ok(_.isEqual([1, "Larry", true], [1, "Larry", true]), "Arrays containing identical primitives are equal");
ok(_.isEqual([(/Moe/g), new Date(2009, 9, 25)], [(/Moe/g), new Date(2009, 9, 25)]), "Arrays containing equivalent elements are equal");
// Multi-dimensional arrays.
var a = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
var b = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
ok(_.isEqual(a, b), "Arrays containing nested arrays and objects are recursively compared");
// Overwrite the methods defined in ES 5.1 section 15.4.4.
a.forEach = a.map = a.filter = a.every = a.indexOf = a.lastIndexOf = a.some = a.reduce = a.reduceRight = null;
b.join = b.pop = b.reverse = b.shift = b.slice = b.splice = b.concat = b.sort = b.unshift = null;
// Array elements and properties.
ok(_.isEqual(a, b), "Arrays containing equivalent elements and different non-numeric properties are equal");
a.push("White Rocks");
ok(!_.isEqual(a, b), "Arrays of different lengths are not equal");
a.push("East Boulder");
b.push("Gunbarrel Ranch", "Teller Farm");
ok(!_.isEqual(a, b), "Arrays of identical lengths containing different elements are not equal");
// Sparse arrays.
ok(_.isEqual(Array(3), Array(3)), "Sparse arrays of identical lengths are equal");
ok(!_.isEqual(Array(3), Array(6)), "Sparse arrays of different lengths are not equal when both are empty");
// According to the Microsoft deviations spec, section 2.1.26, JScript 5.x treats `undefined`
// elements in arrays as elisions. Thus, sparse arrays and dense arrays containing `undefined`
// values are equivalent.
if (0 in [undefined]) {
ok(!_.isEqual(Array(3), [undefined, undefined, undefined]), "Sparse and dense arrays are not equal");
ok(!_.isEqual([undefined, undefined, undefined], Array(3)), "Commutative equality is implemented for sparse and dense arrays");
}
// Simple objects.
ok(_.isEqual({a: "Curly", b: 1, c: true}, {a: "Curly", b: 1, c: true}), "Objects containing identical primitives are equal");
ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), "Objects containing equivalent members are equal");
ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), "Objects of identical sizes with different values are not equal");
ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), "Objects of identical sizes with different property names are not equal");
ok(!_.isEqual({a: 1, b: 2}, {a: 1}), "Objects of different sizes are not equal");
ok(!_.isEqual({a: 1}, {a: 1, b: 2}), "Commutative equality is implemented for objects");
ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), "Objects with identical keys and different values are not equivalent");
// `A` contains nested objects and arrays.
a = {
name: new String("Moe Howard"),
age: new Number(77),
stooge: true,
hobbies: ["acting"],
film: {
name: "Sing a Song of Six Pants",
release: new Date(1947, 9, 30),
stars: [new String("Larry Fine"), "Shemp Howard"],
minutes: new Number(16),
seconds: 54
}
};
// `B` contains equivalent nested objects and arrays.
b = {
name: new String("Moe Howard"),
age: new Number(77),
stooge: true,
hobbies: ["acting"],
film: {
name: "Sing a Song of Six Pants",
release: new Date(1947, 9, 30),
stars: [new String("Larry Fine"), "Shemp Howard"],
minutes: new Number(16),
seconds: 54
}
};
ok(_.isEqual(a, b), "Objects with nested equivalent members are recursively compared");
// Instances.
ok(_.isEqual(new First, new First), "Object instances are equal");
ok(!_.isEqual(new First, new Second), "Objects with different constructors and identical own properties are not equal");
ok(!_.isEqual({value: 1}, new First), "Object instances and objects sharing equivalent properties are not equal");
ok(!_.isEqual({value: 2}, new Second), "The prototype chain of objects should not be examined");
// Circular Arrays.
(a = []).push(a);
(b = []).push(b);
ok(_.isEqual(a, b), "Arrays containing circular references are equal");
a.push(new String("Larry"));
b.push(new String("Larry"));
ok(_.isEqual(a, b), "Arrays containing circular references and equivalent properties are equal");
a.push("Shemp");
b.push("Curly");
ok(!_.isEqual(a, b), "Arrays containing circular references and different properties are not equal");
// Circular Objects.
a = {abc: null};
b = {abc: null};
a.abc = a;
b.abc = b;
ok(_.isEqual(a, b), "Objects containing circular references are equal");
a.def = 75;
b.def = 75;
ok(_.isEqual(a, b), "Objects containing circular references and equivalent properties are equal");
a.def = new Number(75);
b.def = new Number(63);
ok(!_.isEqual(a, b), "Objects containing circular references and different properties are not equal");
// Cyclic Structures.
a = [{abc: null}];
b = [{abc: null}];
(a[0].abc = a).push(a);
(b[0].abc = b).push(b);
ok(_.isEqual(a, b), "Cyclic structures are equal");
a[0].def = "Larry";
b[0].def = "Larry";
ok(_.isEqual(a, b), "Cyclic structures containing equivalent properties are equal");
a[0].def = new String("Larry");
b[0].def = new String("Curly");
ok(!_.isEqual(a, b), "Cyclic structures containing different properties are not equal");
// Complex Circular References.
a = {foo: {b: {foo: {c: {foo: null}}}}};
b = {foo: {b: {foo: {c: {foo: null}}}}};
a.foo.b.foo.c.foo = a;
b.foo.b.foo.c.foo = b;
ok(_.isEqual(a, b), "Cyclic structures with nested and identically-named properties are equal");
// Chaining.
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal');
equal(_({x: 1, y: 2}).chain().isEqual(_({x: 1, y: 2}).chain()).value(), true, '`isEqual` can be chained');
// Custom `isEqual` methods.
var isEqualObj = {isEqual: function (o) { return o.isEqual == this.isEqual; }, unique: {}};
var isEqualObjClone = {isEqual: isEqualObj.isEqual, unique: {}};
ok(_.isEqual(isEqualObj, isEqualObjClone), 'Both objects implement identical `isEqual` methods');
ok(_.isEqual(isEqualObjClone, isEqualObj), 'Commutative equality is implemented for objects with custom `isEqual` methods');
ok(!_.isEqual(isEqualObj, {}), 'Objects that do not implement equivalent `isEqual` methods are not equal');
ok(!_.isEqual({}, isEqualObj), 'Commutative equality is implemented for objects with different `isEqual` methods');
// Custom `isEqual` methods - comparing different types
LocalizedString = (function() {
function LocalizedString(id) { this.id = id; this.string = (this.id===10)? 'Bonjour': ''; }
LocalizedString.prototype.isEqual = function(that) {
if (_.isString(that)) return this.string == that;
else if (that instanceof LocalizedString) return this.id == that.id;
return false;
};
return LocalizedString;
})();
var localized_string1 = new LocalizedString(10), localized_string2 = new LocalizedString(10), localized_string3 = new LocalizedString(11);
ok(_.isEqual(localized_string1, localized_string2), 'comparing same typed instances with same ids');
ok(!_.isEqual(localized_string1, localized_string3), 'comparing same typed instances with different ids');
ok(_.isEqual(localized_string1, 'Bonjour'), 'comparing different typed instances with same values');
ok(_.isEqual('Bonjour', localized_string1), 'comparing different typed instances with same values');
ok(!_.isEqual('Bonjour', localized_string3), 'comparing two localized strings with different ids');
ok(!_.isEqual(localized_string1, 'Au revoir'), 'comparing different typed instances with different values');
ok(!_.isEqual('Au revoir', localized_string1), 'comparing different typed instances with different values');
// Custom `isEqual` methods - comparing with serialized data
Date.prototype.toJSON = function() {
return {
_type:'Date',
year:this.getUTCFullYear(),
month:this.getUTCMonth(),
day:this.getUTCDate(),
hours:this.getUTCHours(),
minutes:this.getUTCMinutes(),
seconds:this.getUTCSeconds()
};
};
Date.prototype.isEqual = function(that) {
var this_date_components = this.toJSON();
var that_date_components = (that instanceof Date) ? that.toJSON() : that;
delete this_date_components['_type']; delete that_date_components['_type'];
return _.isEqual(this_date_components, that_date_components);
};
var date = new Date();
var date_json = {
_type:'Date',
year:date.getUTCFullYear(),
month:date.getUTCMonth(),
day:date.getUTCDate(),
hours:date.getUTCHours(),
minutes:date.getUTCMinutes(),
seconds:date.getUTCSeconds()
};
ok(_.isEqual(date_json, date), 'serialized date matches date');
ok(_.isEqual(date, date_json), 'date matches serialized date');
});
test("objects: isEmpty", function() {
ok(!_([1]).isEmpty(), '[1] is not empty');
ok(_.isEmpty([]), '[] is empty');
ok(!_.isEmpty({one : 1}), '{one : 1} is not empty');
ok(_.isEmpty({}), '{} is empty');
ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty');
ok(_.isEmpty(null), 'null is empty');
ok(_.isEmpty(), 'undefined is empty');
ok(_.isEmpty(''), 'the empty string is empty');
ok(!_.isEmpty('moe'), 'but other strings are not');
var obj = {one : 1};
delete obj.one;
ok(_.isEmpty(obj), 'deleting all the keys from an object empties it');
});
// Setup remote variables for iFrame tests.
var iframe = document.createElement('iframe');
jQuery(iframe).appendTo(document.body);
var iDoc = iframe.contentDocument || iframe.contentWindow.document;
iDoc.write(
"<script>\
parent.iElement = document.createElement('div');\
parent.iArguments = (function(){ return arguments; })(1, 2, 3);\
parent.iArray = [1, 2, 3];\
parent.iString = new String('hello');\
parent.iNumber = new Number(100);\
parent.iFunction = (function(){});\
parent.iDate = new Date();\
parent.iRegExp = /hi/;\
parent.iNaN = NaN;\
parent.iNull = null;\
parent.iBoolean = new Boolean(false);\
parent.iUndefined = undefined;\
</script>"
);
iDoc.close();
test("objects: isElement", function() {
ok(!_.isElement('div'), 'strings are not dom elements');
ok(_.isElement($('html')[0]), 'the html tag is a DOM element');
ok(_.isElement(iElement), 'even from another frame');
});
test("objects: isArguments", function() {
var args = (function(){ return arguments; })(1, 2, 3);
ok(!_.isArguments('string'), 'a string is not an arguments object');
ok(!_.isArguments(_.isArguments), 'a function is not an arguments object');
ok(_.isArguments(args), 'but the arguments object is an arguments object');
ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array');
ok(!_.isArguments([1,2,3]), 'and not vanilla arrays.');
ok(_.isArguments(iArguments), 'even from another frame');
});
test("objects: isObject", function() {
ok(_.isObject(arguments), 'the arguments object is object');
ok(_.isObject([1, 2, 3]), 'and arrays');
ok(_.isObject($('html')[0]), 'and DOM element');
ok(_.isObject(iElement), 'even from another frame');
ok(_.isObject(function () {}), 'and functions');
ok(_.isObject(iFunction), 'even from another frame');
ok(!_.isObject(null), 'but not null');
ok(!_.isObject(undefined), 'and not undefined');
ok(!_.isObject('string'), 'and not string');
ok(!_.isObject(12), 'and not number');
ok(!_.isObject(true), 'and not boolean');
ok(_.isObject(new String('string')), 'but new String()');
});
test("objects: isArray", function() {
ok(!_.isArray(arguments), 'the arguments object is not an array');
ok(_.isArray([1, 2, 3]), 'but arrays are');
ok(_.isArray(iArray), 'even from another frame');
});
test("objects: isString", function() {
ok(!_.isString(document.body), 'the document body is not a string');
ok(_.isString([1, 2, 3].join(', ')), 'but strings are');
ok(_.isString(iString), 'even from another frame');
});
test("objects: isNumber", function() {
ok(!_.isNumber('string'), 'a string is not a number');
ok(!_.isNumber(arguments), 'the arguments object is not a number');
ok(!_.isNumber(undefined), 'undefined is not a number');
ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are');
ok(_.isNumber(NaN), 'NaN *is* a number');
ok(_.isNumber(Infinity), 'Infinity is a number');
ok(_.isNumber(iNumber), 'even from another frame');
ok(!_.isNumber('1'), 'numeric strings are not numbers');
});
test("objects: isBoolean", function() {
ok(!_.isBoolean(2), 'a number is not a boolean');
ok(!_.isBoolean("string"), 'a string is not a boolean');
ok(!_.isBoolean("false"), 'the string "false" is not a boolean');
ok(!_.isBoolean("true"), 'the string "true" is not a boolean');
ok(!_.isBoolean(arguments), 'the arguments object is not a boolean');
ok(!_.isBoolean(undefined), 'undefined is not a boolean');
ok(!_.isBoolean(NaN), 'NaN is not a boolean');
ok(!_.isBoolean(null), 'null is not a boolean');
ok(_.isBoolean(true), 'but true is');
ok(_.isBoolean(false), 'and so is false');
ok(_.isBoolean(iBoolean), 'even from another frame');
});
test("objects: isFunction", function() {
ok(!_.isFunction([1, 2, 3]), 'arrays are not functions');
ok(!_.isFunction('moe'), 'strings are not functions');
ok(_.isFunction(_.isFunction), 'but functions are');
ok(_.isFunction(iFunction), 'even from another frame');
});
test("objects: isDate", function() {
ok(!_.isDate(100), 'numbers are not dates');
ok(!_.isDate({}), 'objects are not dates');
ok(_.isDate(new Date()), 'but dates are');
ok(_.isDate(iDate), 'even from another frame');
});
test("objects: isRegExp", function() {
ok(!_.isRegExp(_.identity), 'functions are not RegExps');
ok(_.isRegExp(/identity/), 'but RegExps are');
ok(_.isRegExp(iRegExp), 'even from another frame');
});
test("objects: isFinite", function() {
ok(!_.isFinite(undefined), 'undefined is not Finite');
ok(!_.isFinite(null), 'null is not Finite');
ok(!_.isFinite(NaN), 'NaN is not Finite');
ok(!_.isFinite(Infinity), 'Infinity is not Finite');
ok(!_.isFinite(-Infinity), '-Infinity is not Finite');
ok(!_.isFinite('12'), 'Strings are not numbers');
var obj = new Number(5);
ok(_.isFinite(obj), 'Number instances can be finite');
ok(_.isFinite(0), '0 is Finite');
ok(_.isFinite(123), 'Ints are Finite');
ok(_.isFinite(-12.44), 'Floats are Finite');
});
test("objects: isNaN", function() {
ok(!_.isNaN(undefined), 'undefined is not NaN');
ok(!_.isNaN(null), 'null is not NaN');
ok(!_.isNaN(0), '0 is not NaN');
ok(_.isNaN(NaN), 'but NaN is');
ok(_.isNaN(iNaN), 'even from another frame');
});
test("objects: isNull", function() {
ok(!_.isNull(undefined), 'undefined is not null');
ok(!_.isNull(NaN), 'NaN is not null');
ok(_.isNull(null), 'but null is');
ok(_.isNull(iNull), 'even from another frame');
});
test("objects: isUndefined", function() {
ok(!_.isUndefined(1), 'numbers are defined');
ok(!_.isUndefined(null), 'null is defined');
ok(!_.isUndefined(false), 'false is defined');
ok(!_.isUndefined(NaN), 'NaN is defined');
ok(_.isUndefined(), 'nothing is undefined');
ok(_.isUndefined(undefined), 'undefined is undefined');
ok(_.isUndefined(iUndefined), 'even from another frame');
});
if (window.ActiveXObject) {
test("objects: IE host objects", function() {
var xml = new ActiveXObject("Msxml2.DOMDocument.3.0");
ok(!_.isNumber(xml));
ok(!_.isBoolean(xml));
ok(!_.isNaN(xml));
ok(!_.isFunction(xml));
ok(!_.isNull(xml));
ok(!_.isUndefined(xml));
});
}
test("objects: tap", function() {
var intercepted = null;
var interceptor = function(obj) { intercepted = obj; };
var returned = _.tap(1, interceptor);
equal(intercepted, 1, "passes tapped object to interceptor");
equal(returned, 1, "returns tapped object");
returned = _([1,2,3]).chain().
map(function(n){ return n * 2; }).
max().
tap(interceptor).
value();
ok(returned == 6 && intercepted == 6, 'can use tapped objects in a chain');
});
});

215
vendor/underscore/test/utility.js vendored Normal file
View File

@@ -0,0 +1,215 @@
$(document).ready(function() {
var templateSettings;
module("Utility", {
setup: function() {
templateSettings = _.clone(_.templateSettings);
},
teardown: function() {
_.templateSettings = templateSettings;
}
});
test("utility: identity", function() {
var moe = {name : 'moe'};
equal(_.identity(moe), moe, 'moe is the same as his identity');
});
test("utility: uniqueId", function() {
var ids = [], i = 0;
while(i++ < 100) ids.push(_.uniqueId());
equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids');
});
test("utility: times", function() {
var vals = [];
_.times(3, function (i) { vals.push(i); });
ok(_.isEqual(vals, [0,1,2]), "is 0 indexed");
//
vals = [];
_(3).times(function (i) { vals.push(i); });
ok(_.isEqual(vals, [0,1,2]), "works as a wrapper");
});
test("utility: mixin", function() {
_.mixin({
myReverse: function(string) {
return string.split('').reverse().join('');
}
});
equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _');
equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper');
});
test("utility: _.escape", function() {
equal(_.escape("Curly & Moe"), "Curly &amp; Moe");
equal(_.escape("Curly &amp; Moe"), "Curly &amp;amp; Moe");
});
test("utility: template", function() {
var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");
var result = basicTemplate({thing : 'This'});
equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation');
var sansSemicolonTemplate = _.template("A <% this %> B");
equal(sansSemicolonTemplate(), "A B");
var backslashTemplate = _.template("<%= thing %> is \\ridanculous");
equal(backslashTemplate({thing: 'This'}), "This is \\ridanculous");
var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>');
equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.');
var fancyTemplate = _.template("<ul><% \
for (key in people) { \
%><li><%= people[key] %></li><% } %></ul>");
result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
var escapedCharsInJavascriptTemplate = _.template("<ul><% _.each(numbers.split('\\n'), function(item) { %><li><%= item %></li><% }) %></ul>");
result = escapedCharsInJavascriptTemplate({numbers: "one\ntwo\nthree\nfour"});
equal(result, "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>", 'Can use escaped characters (e.g. \\n) in Javascript');
var namespaceCollisionTemplate = _.template("<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><div class=\"thumbnail\" rel=\"<%= p %>\"></div><% }); %>");
result = namespaceCollisionTemplate({
pageCount: 3,
thumbnails: {
1: "p1-thumbnail.gif",
2: "p2-thumbnail.gif",
3: "p3-thumbnail.gif"
}
});
equal(result, "3 p3-thumbnail.gif <div class=\"thumbnail\" rel=\"p1-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p2-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p3-thumbnail.gif\"></div>");
var noInterpolateTemplate = _.template("<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
result = noInterpolateTemplate();
equal(result, "<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
var quoteTemplate = _.template("It's its, not it's");
equal(quoteTemplate({}), "It's its, not it's");
var quoteInStatementAndBody = _.template("<%\
if(foo == 'bar'){ \
%>Statement quotes and 'quotes'.<% } %>");
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.');
equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.');
var template = _.template("<i><%- value %></i>");
var result = template({value: "<script>"});
equal(result, '<i>&lt;script&gt;</i>');
var stooge = {
name: "Moe",
template: _.template("I'm <%= this.name %>")
};
equal(stooge.template(), "I'm Moe");
if (!$.browser.msie) {
var fromHTML = _.template($('#template').html());
equal(fromHTML({data : 12345}).replace(/\s/g, ''), '<li>24690</li>');
}
_.templateSettings = {
evaluate : /\{\{([\s\S]+?)\}\}/g,
interpolate : /\{\{=([\s\S]+?)\}\}/g
};
var custom = _.template("<ul>{{ for (key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>");
result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
var customQuote = _.template("It's its, not it's");
equal(customQuote({}), "It's its, not it's");
var quoteInStatementAndBody = _.template("{{ if(foo == 'bar'){ }}Statement quotes and 'quotes'.{{ } }}");
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
_.templateSettings = {
evaluate : /<\?([\s\S]+?)\?>/g,
interpolate : /<\?=([\s\S]+?)\?>/g
};
var customWithSpecialChars = _.template("<ul><? for (key in people) { ?><li><?= people[key] ?></li><? } ?></ul>");
result = customWithSpecialChars({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
var customWithSpecialCharsQuote = _.template("It's its, not it's");
equal(customWithSpecialCharsQuote({}), "It's its, not it's");
var quoteInStatementAndBody = _.template("<? if(foo == 'bar'){ ?>Statement quotes and 'quotes'.<? } ?>");
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
_.templateSettings = {
interpolate : /\{\{(.+?)\}\}/g
};
var mustache = _.template("Hello {{planet}}!");
equal(mustache({planet : "World"}), "Hello World!", "can mimic mustache.js");
var templateWithNull = _.template("a null undefined {{planet}}");
equal(templateWithNull({planet : "world"}), "a null undefined world", "can handle missing escape and evaluate settings");
});
test('_.template handles \\u2028 & \\u2029', function() {
var tmpl = _.template('<p>\u2028<%= "\\u2028\\u2029" %>\u2029</p>');
strictEqual(tmpl(), '<p>\u2028\u2028\u2029\u2029</p>');
});
test('result calls functions and returns primitives', function() {
var obj = {w: '', x: 'x', y: function(){ return this.x; }};
strictEqual(_.result(obj, 'w'), '');
strictEqual(_.result(obj, 'x'), 'x');
strictEqual(_.result(obj, 'y'), 'x');
strictEqual(_.result(obj, 'z'), undefined);
strictEqual(_.result(null, 'x'), null);
});
test('_.templateSettings.variable', function() {
var s = '<%=data.x%>';
var data = {x: 'x'};
strictEqual(_.template(s, data, {variable: 'data'}), 'x');
_.templateSettings.variable = 'data';
strictEqual(_.template(s)(data), 'x');
});
test('#547 - _.templateSettings is unchanged by custom settings.', function() {
ok(!_.templateSettings.variable);
_.template('', {}, {variable: 'x'});
ok(!_.templateSettings.variable);
});
test('#556 - undefined template variables.', function() {
var template = _.template('<%=x%>');
strictEqual(template({x: null}), '');
strictEqual(template({x: undefined}), '');
var templateEscaped = _.template('<%-x%>');
strictEqual(templateEscaped({x: null}), '');
strictEqual(templateEscaped({x: undefined}), '');
var templateWithProperty = _.template('<%=x.foo%>');
strictEqual(templateWithProperty({x: {} }), '');
strictEqual(templateWithProperty({x: {} }), '');
var templateWithPropertyEscaped = _.template('<%-x.foo%>');
strictEqual(templateWithPropertyEscaped({x: {} }), '');
strictEqual(templateWithPropertyEscaped({x: {} }), '');
});
test('interpolate evaluates code only once.', 2, function() {
var count = 0;
var template = _.template('<%= f() %>');
template({f: function(){ ok(!(count++)); }});
var countEscaped = 0;
var templateEscaped = _.template('<%- f() %>');
templateEscaped({f: function(){ ok(!(countEscaped++)); }});
});
});

9404
vendor/underscore/test/vendor/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,670 @@
// JSLitmus.js
//
// History:
// 2008-10-27: Initial release
// 2008-11-09: Account for iteration loop overhead
// 2008-11-13: Added OS detection
// 2009-02-25: Create tinyURL automatically, shift-click runs tests in reverse
//
// Copyright (c) 2008-2009, Robert Kieffer
// All Rights Reserved
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the
// Software), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
(function() {
// Private methods and state
// Get platform info but don't go crazy trying to recognize everything
// that's out there. This is just for the major platforms and OSes.
var platform = 'unknown platform', ua = navigator.userAgent;
// Detect OS
var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
// Detect browser
var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
// Detect version
var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
/**
* A smattering of methods that are needed to implement the JSLitmus testbed.
*/
var jsl = {
/**
* Enhanced version of escape()
*/
escape: function(s) {
s = s.replace(/,/g, '\\,');
s = escape(s);
s = s.replace(/\+/g, '%2b');
s = s.replace(/ /g, '+');
return s;
},
/**
* Get an element by ID.
*/
$: function(id) {
return document.getElementById(id);
},
/**
* Null function
*/
F: function() {},
/**
* Set the status shown in the UI
*/
status: function(msg) {
var el = jsl.$('jsl_status');
if (el) el.innerHTML = msg || '';
},
/**
* Convert a number to an abbreviated string like, "15K" or "10M"
*/
toLabel: function(n) {
if (n == Infinity) {
return 'Infinity';
} else if (n > 1e9) {
n = Math.round(n/1e8);
return n/10 + 'B';
} else if (n > 1e6) {
n = Math.round(n/1e5);
return n/10 + 'M';
} else if (n > 1e3) {
n = Math.round(n/1e2);
return n/10 + 'K';
}
return n;
},
/**
* Copy properties from src to dst
*/
extend: function(dst, src) {
for (var k in src) dst[k] = src[k]; return dst;
},
/**
* Like Array.join(), but for the key-value pairs in an object
*/
join: function(o, delimit1, delimit2) {
if (o.join) return o.join(delimit1); // If it's an array
var pairs = [];
for (var k in o) pairs.push(k + delimit1 + o[k]);
return pairs.join(delimit2);
},
/**
* Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
*/
indexOf: function(arr, o) {
if (arr.indexOf) return arr.indexOf(o);
for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
return -1;
}
};
/**
* Test manages a single test (created with
* JSLitmus.test())
*
* @private
*/
var Test = function (name, f) {
if (!f) throw new Error('Undefined test function');
if (!(/function[^\(]*\(([^,\)]*)/).test(f.toString())) {
throw new Error('"' + name + '" test: Test is not a valid Function object');
}
this.loopArg = RegExp.$1;
this.name = name;
this.f = f;
};
jsl.extend(Test, /** @lends Test */ {
/** Calibration tests for establishing iteration loop overhead */
CALIBRATIONS: [
new Test('calibrating loop', function(count) {while (count--);}),
new Test('calibrating function', jsl.F)
],
/**
* Run calibration tests. Returns true if calibrations are not yet
* complete (in which case calling code should run the tests yet again).
* onCalibrated - Callback to invoke when calibrations have finished
*/
calibrate: function(onCalibrated) {
for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
var cal = Test.CALIBRATIONS[i];
if (cal.running) return true;
if (!cal.count) {
cal.isCalibration = true;
cal.onStop = onCalibrated;
//cal.MIN_TIME = .1; // Do calibrations quickly
cal.run(2e4);
return true;
}
}
return false;
}
});
jsl.extend(Test.prototype, {/** @lends Test.prototype */
/** Initial number of iterations */
INIT_COUNT: 10,
/** Max iterations allowed (i.e. used to detect bad looping functions) */
MAX_COUNT: 1e9,
/** Minimum time a test should take to get valid results (secs) */
MIN_TIME: .5,
/** Callback invoked when test state changes */
onChange: jsl.F,
/** Callback invoked when test is finished */
onStop: jsl.F,
/**
* Reset test state
*/
reset: function() {
delete this.count;
delete this.time;
delete this.running;
delete this.error;
},
/**
* Run the test (in a timeout). We use a timeout to make sure the browser
* has a chance to finish rendering any UI changes we've made, like
* updating the status message.
*/
run: function(count) {
count = count || this.INIT_COUNT;
jsl.status(this.name + ' x ' + count);
this.running = true;
var me = this;
setTimeout(function() {me._run(count);}, 200);
},
/**
* The nuts and bolts code that actually runs a test
*/
_run: function(count) {
var me = this;
// Make sure calibration tests have run
if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
this.error = null;
try {
var start, f = this.f, now, i = count;
// Start the timer
start = new Date();
// Now for the money shot. If this is a looping function ...
if (this.loopArg) {
// ... let it do the iteration itself
f(count);
} else {
// ... otherwise do the iteration for it
while (i--) f();
}
// Get time test took (in secs)
this.time = Math.max(1,new Date() - start)/1000;
// Store iteration count and per-operation time taken
this.count = count;
this.period = this.time/count;
// Do we need to do another run?
this.running = this.time <= this.MIN_TIME;
// ... if so, compute how many times we should iterate
if (this.running) {
// Bump the count to the nearest power of 2
var x = this.MIN_TIME/this.time;
var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
count *= pow;
if (count > this.MAX_COUNT) {
throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
}
}
} catch (e) {
// Exceptions are caught and displayed in the test UI
this.reset();
this.error = e;
}
// Figure out what to do next
if (this.running) {
me.run(count);
} else {
jsl.status('');
me.onStop(me);
}
// Finish up
this.onChange(this);
},
/**
* Get the number of operations per second for this test.
*
* @param normalize if true, iteration loop overhead taken into account
*/
getHz: function(/**Boolean*/ normalize) {
var p = this.period;
// Adjust period based on the calibration test time
if (normalize && !this.isCalibration) {
var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
// If the period is within 20% of the calibration time, then zero the
// it out
p = p < cal.period*1.2 ? 0 : p - cal.period;
}
return Math.round(1/p);
},
/**
* Get a friendly string describing the test
*/
toString: function() {
return this.name + ' - ' + this.time/this.count + ' secs';
}
});
// CSS we need for the UI
var STYLESHEET = '<style> \
#jslitmus {font-family:sans-serif; font-size: 12px;} \
#jslitmus a {text-decoration: none;} \
#jslitmus a:hover {text-decoration: underline;} \
#jsl_status { \
margin-top: 10px; \
font-size: 10px; \
color: #888; \
} \
A IMG {border:none} \
#test_results { \
margin-top: 10px; \
font-size: 12px; \
font-family: sans-serif; \
border-collapse: collapse; \
border-spacing: 0px; \
} \
#test_results th, #test_results td { \
border: solid 1px #ccc; \
vertical-align: top; \
padding: 3px; \
} \
#test_results th { \
vertical-align: bottom; \
background-color: #ccc; \
padding: 1px; \
font-size: 10px; \
} \
#test_results #test_platform { \
color: #444; \
text-align:center; \
} \
#test_results .test_row { \
color: #006; \
cursor: pointer; \
} \
#test_results .test_nonlooping { \
border-left-style: dotted; \
border-left-width: 2px; \
} \
#test_results .test_looping { \
border-left-style: solid; \
border-left-width: 2px; \
} \
#test_results .test_name {white-space: nowrap;} \
#test_results .test_pending { \
} \
#test_results .test_running { \
font-style: italic; \
} \
#test_results .test_done {} \
#test_results .test_done { \
text-align: right; \
font-family: monospace; \
} \
#test_results .test_error {color: #600;} \
#test_results .test_error .error_head {font-weight:bold;} \
#test_results .test_error .error_body {font-size:85%;} \
#test_results .test_row:hover td { \
background-color: #ffc; \
text-decoration: underline; \
} \
#chart { \
margin: 10px 0px; \
width: 250px; \
} \
#chart img { \
border: solid 1px #ccc; \
margin-bottom: 5px; \
} \
#chart #tiny_url { \
height: 40px; \
width: 250px; \
} \
#jslitmus_credit { \
font-size: 10px; \
color: #888; \
margin-top: 8px; \
} \
</style>';
// HTML markup for the UI
var MARKUP = '<div id="jslitmus"> \
<button onclick="JSLitmus.runAll(event)">Run Tests</button> \
<button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
<br \> \
<br \> \
<input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
<table id="test_results"> \
<colgroup> \
<col /> \
<col width="100" /> \
</colgroup> \
<tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
<tr><th>Test</th><th>Ops/sec</th></tr> \
<tr id="test_row_template" class="test_row" style="display:none"> \
<td class="test_name"></td> \
<td class="test_result">Ready</td> \
</tr> \
</table> \
<div id="jsl_status"></div> \
<div id="chart" style="display:none"> \
<a id="chart_link" target="_blank"><img id="chart_image"></a> \
TinyURL (for chart): \
<iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
</div> \
<a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
</div>';
/**
* The public API for creating and running tests
*/
window.JSLitmus = {
/** The list of all tests that have been registered with JSLitmus.test */
_tests: [],
/** The queue of tests that need to be run */
_queue: [],
/**
* The parsed query parameters the current page URL. This is provided as a
* convenience for test functions - it's not used by JSLitmus proper
*/
params: {},
/**
* Initialize
*/
_init: function() {
// Parse query params into JSLitmus.params[] hash
var match = (location + '').match(/([^?#]*)(#.*)?$/);
if (match) {
var pairs = match[1].split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
if (pair.length > 1) {
var key = pair.shift();
var value = pair.length > 1 ? pair.join('=') : pair[0];
this.params[key] = value;
}
}
}
// Write out the stylesheet. We have to do this here because IE
// doesn't honor sheets written after the document has loaded.
document.write(STYLESHEET);
// Setup the rest of the UI once the document is loaded
if (window.addEventListener) {
window.addEventListener('load', this._setup, false);
} else if (document.addEventListener) {
document.addEventListener('load', this._setup, false);
} else if (window.attachEvent) {
window.attachEvent('onload', this._setup);
}
return this;
},
/**
* Set up the UI
*/
_setup: function() {
var el = jsl.$('jslitmus_container');
if (!el) document.body.appendChild(el = document.createElement('div'));
el.innerHTML = MARKUP;
// Render the UI for all our tests
for (var i=0; i < JSLitmus._tests.length; i++)
JSLitmus.renderTest(JSLitmus._tests[i]);
},
/**
* (Re)render all the test results
*/
renderAll: function() {
for (var i = 0; i < JSLitmus._tests.length; i++)
JSLitmus.renderTest(JSLitmus._tests[i]);
JSLitmus.renderChart();
},
/**
* (Re)render the chart graphics
*/
renderChart: function() {
var url = JSLitmus.chartUrl();
jsl.$('chart_link').href = url;
jsl.$('chart_image').src = url;
jsl.$('chart').style.display = '';
// Update the tiny URL
jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
},
/**
* (Re)render the results for a specific test
*/
renderTest: function(test) {
// Make a new row if needed
if (!test._row) {
var trow = jsl.$('test_row_template');
if (!trow) return;
test._row = trow.cloneNode(true);
test._row.style.display = '';
test._row.id = '';
test._row.onclick = function() {JSLitmus._queueTest(test);};
test._row.title = 'Run ' + test.name + ' test';
trow.parentNode.appendChild(test._row);
test._row.cells[0].innerHTML = test.name;
}
var cell = test._row.cells[1];
var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
if (test.error) {
cns.push('test_error');
cell.innerHTML =
'<div class="error_head">' + test.error + '</div>' +
'<ul class="error_body"><li>' +
jsl.join(test.error, ': ', '</li><li>') +
'</li></ul>';
} else {
if (test.running) {
cns.push('test_running');
cell.innerHTML = 'running';
} else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
cns.push('test_pending');
cell.innerHTML = 'pending';
} else if (test.count) {
cns.push('test_done');
var hz = test.getHz(jsl.$('test_normalize').checked);
cell.innerHTML = hz != Infinity ? hz : '&infin;';
} else {
cell.innerHTML = 'ready';
}
}
cell.className = cns.join(' ');
},
/**
* Create a new test
*/
test: function(name, f) {
// Create the Test object
var test = new Test(name, f);
JSLitmus._tests.push(test);
// Re-render if the test state changes
test.onChange = JSLitmus.renderTest;
// Run the next test if this one finished
test.onStop = function(test) {
if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
JSLitmus.currentTest = null;
JSLitmus._nextTest();
};
// Render the new test
this.renderTest(test);
},
/**
* Add all tests to the run queue
*/
runAll: function(e) {
e = e || window.event;
var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
for (var i = 0; i < len; i++) {
JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
}
},
/**
* Remove all tests from the run queue. The current test has to finish on
* it's own though
*/
stop: function() {
while (JSLitmus._queue.length) {
var test = JSLitmus._queue.shift();
JSLitmus.renderTest(test);
}
},
/**
* Run the next test in the run queue
*/
_nextTest: function() {
if (!JSLitmus.currentTest) {
var test = JSLitmus._queue.shift();
if (test) {
jsl.$('stop_button').disabled = false;
JSLitmus.currentTest = test;
test.run();
JSLitmus.renderTest(test);
if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
} else {
jsl.$('stop_button').disabled = true;
JSLitmus.renderChart();
}
}
},
/**
* Add a test to the run queue
*/
_queueTest: function(test) {
if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
JSLitmus._queue.push(test);
JSLitmus.renderTest(test);
JSLitmus._nextTest();
},
/**
* Generate a Google Chart URL that shows the data for all tests
*/
chartUrl: function() {
var n = JSLitmus._tests.length, markers = [], data = [];
var d, min = 0, max = -1e10;
var normalize = jsl.$('test_normalize').checked;
// Gather test data
for (var i=0; i < JSLitmus._tests.length; i++) {
var test = JSLitmus._tests[i];
if (test.count) {
var hz = test.getHz(normalize);
var v = hz != Infinity ? hz : 0;
data.push(v);
markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
markers.length + ',10');
max = Math.max(v, max);
}
}
if (markers.length <= 0) return null;
// Build chart title
var title = document.getElementsByTagName('title');
title = (title && title.length) ? title[0].innerHTML : null;
var chart_title = [];
if (title) chart_title.push(title);
chart_title.push('Ops/sec (' + platform + ')');
// Build labels
var labels = [jsl.toLabel(min), jsl.toLabel(max)];
var w = 250, bw = 15;
var bs = 5;
var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
var params = {
chtt: escape(chart_title.join('|')),
chts: '000000,10',
cht: 'bhg', // chart type
chd: 't:' + data.join(','), // data set
chds: min + ',' + max, // max/min of data
chxt: 'x', // label axes
chxl: '0:|' + labels.join('|'), // labels
chsp: '0,1',
chm: markers.join('|'), // test names
chbh: [bw, 0, bs].join(','), // bar widths
// chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
chs: w + 'x' + h
};
return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
}
};
JSLitmus._init();
})();

236
vendor/underscore/test/vendor/qunit.css vendored Normal file
View File

@@ -0,0 +1,236 @@
/**
* QUnit v1.8.0 - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2012 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 15px 15px 0 0;
-moz-border-radius: 15px 15px 0 0;
-webkit-border-top-right-radius: 15px;
-webkit-border-top-left-radius: 15px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-header label {
display: inline-block;
padding-left: 0.5em;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
box-shadow: inset 0px 2px 13px #999;
-moz-box-shadow: inset 0px 2px 13px #999;
-webkit-box-shadow: inset 0px 2px 13px #999;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
margin: 0.5em;
padding: 0.4em 0.5em 0.4em 0.5em;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #5E740B;
background-color: #fff;
border-left: 26px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
#qunit-testresult .module-name {
font-weight: bold;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}

1863
vendor/underscore/test/vendor/qunit.js vendored Normal file

File diff suppressed because it is too large Load Diff

32
vendor/underscore/underscore-min.js vendored Normal file
View File

@@ -0,0 +1,32 @@
// Underscore.js 1.3.3
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore
(function(){var s=this,L=s._,p={},k=Array.prototype,q=Object.prototype,M=k.push,i=k.slice,N=k.unshift,m=q.toString,O=q.hasOwnProperty,z=k.forEach,A=k.map,B=k.reduce,C=k.reduceRight,D=k.filter,E=k.every,F=k.some,r=k.indexOf,G=k.lastIndexOf,q=Array.isArray,P=Object.keys,t=Function.prototype.bind,b=function(a){return new l(a)};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;b.VERSION="1.3.3";var j=b.each=b.forEach=function(a,c,
d){if(a!=null)if(z&&a.forEach===z)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(c.call(d,a[e],e,a)===p)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===p)break};b.map=b.collect=function(a,c,d){var b=[];if(a==null)return b;if(A&&a.map===A)return a.map(c,d);j(a,function(a,g,h){b[b.length]=c.call(d,a,g,h)});return b};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(B&&a.reduce===B){e&&(c=b.bind(c,e));return f?a.reduce(c,
d):a.reduce(c)}j(a,function(a,b,i){if(f)d=c.call(e,d,a,b,i);else{d=a;f=true}});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(C&&a.reduceRight===C){e&&(c=b.bind(c,e));return f?a.reduceRight(c,d):a.reduceRight(c)}var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,c,b){var e;H(a,function(a,g,h){if(c.call(b,a,g,h)){e=
a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(D&&a.filter===D)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(E&&a.every===E)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,a,g,h)))return p});return!!e};var H=b.some=b.any=
function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(F&&a.some===F)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return p});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(r&&a.indexOf===r)return a.indexOf(c)!=-1;return b=H(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c:a[c]).apply(a,d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};
b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0]&&a.length<65535)return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0]&&a.length<65535)return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
return e.value};b.shuffle=function(a){var c,b=0,e=[];j(a,function(a){c=Math.floor(Math.random()*++b);e[b-1]=e[c];e[c]=a});return e};b.sortBy=function(a,c,d){var e=I(a,c);return b.pluck(b.map(a,function(a,c,b){return{value:a,criteria:e.call(d,a,c,b)}}).sort(function(a,c){var b=a.criteria,d=c.criteria;return b===void 0?1:d===void 0?-1:b<d?-1:b>d?1:0}),"value")};var I=function(a,c){return b.isFunction(c)?c:function(a){return a[c]}},J=function(a,c,b){var e={},f=I(a,c);j(a,function(a,c){var i=f(a,c);b(e,
i,a)});return e};b.groupBy=function(a,c){return J(a,c,function(a,c,b){(a[c]||(a[c]=[])).push(b)})};b.countBy=function(a,c){return J(a,c,function(a,c){a[c]||(a[c]=0);a[c]++})};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var c=d(c),e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<c?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:b.isArray(a)||b.isArguments(a)?i.call(a):a.toArray&&b.isFunction(a.toArray)?a.toArray():b.values(a)};b.size=function(a){return b.isArray(a)?a.length:b.keys(a).length};
b.first=b.head=b.take=function(a,c,b){return c!=null&&!b?i.call(a,0,c):a[0]};b.initial=function(a,c,b){return i.call(a,0,a.length-(c==null||b?1:c))};b.last=function(a,c,b){return c!=null&&!b?i.call(a,Math.max(a.length-c,0)):a[a.length-1]};b.rest=b.tail=function(a,c,b){return i.call(a,c==null||b?1:c)};b.compact=function(a){return b.filter(a,function(a){return!!a})};var n=function(a,c,d){j(a,function(a){b.isArray(a)?c?M.apply(d,a):n(a,c,d):d.push(a)});return d};b.flatten=function(a,c){return n(a,c,
[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(c?b.last(d)!==g||!d.length:!b.include(d,g)){d.push(g);e.push(a[h])}return d},[]);return e};b.union=function(){return b.uniq(n(arguments,true,[]))};b.intersection=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=n(i.call(arguments,
1),true,[]);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.zipObject=function(a,c){for(var b={},e=0,f=a.length;e<f;e++)b[a[e]]=c[e];return b};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d){d=b.sortedIndex(a,c);return a[d]===c?d:-1}if(r&&a.indexOf===r)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,
c){if(a==null)return-1;if(G&&a.lastIndexOf===G)return a.lastIndexOf(c);for(var b=a.length;b--;)if(a[b]===c)return b;return-1};b.range=function(a,c,b){if(arguments.length<=1){c=a||0;a=0}for(var b=arguments[2]||1,e=Math.max(Math.ceil((c-a)/b),0),f=0,g=Array(e);f<e;){g[f++]=a;a=a+b}return g};var K=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,
e.concat(i.call(arguments)));K.prototype=a.prototype;var b=new K,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,c){var b=i.call(arguments,2);return setTimeout(function(){return a.apply(null,
b)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i,j=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);j()},c));if(g)h=true;else{g=true;i=a.apply(d,e)}j();return i}};b.debounce=function(a,b,d){var e;return function(){var f=this,g=arguments,h=d&&!e;clearTimeout(e);e=setTimeout(function(){e=null;d||a.apply(f,g)},b);h&&a.apply(f,g)}};b.once=function(a){var b=
false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=P||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,
d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.pick=function(a){var b={};j(n(i.call(arguments,1),true,[]),function(d){d in a&&(b[d]=a[d])});return b};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?
a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};var u=function(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=m.call(a);if(e!=m.call(c))return false;switch(e){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==
+c;case "[object RegExp]":return a.source==c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){f=a.length;if(g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&u(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)){f++;if(!(g=b.has(c,h)&&
u(a[h],c[h],d)))break}if(g){for(h in c)if(b.has(c,h)&&!f--)break;g=!f}}d.pop();return g};b.isEqual=function(a,b){return u(a,b,[])};b.isEmpty=function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=q||function(a){return m.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};j("Arguments,Function,String,Number,Date,RegExp".split(","),function(a){b["is"+
a]=function(b){return m.call(b)=="[object "+a+"]"}});b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||m.call(a)=="[object Boolean]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return O.call(a,b)};b.noConflict=function(){s._=L;return this};b.identity=function(a){return a};
b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};var Q={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"},R=/[&<>"'\/]/g;b.escape=function(a){return(""+a).replace(R,function(a){return Q[a]})};b.result=function(a,c){if(a==null)return null;var d=a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){S(c,b[c]=a[c])})};var T=0;b.uniqueId=function(a){var b=T++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,
escape:/<%-([\s\S]+?)%>/g};var v=/.^/,o={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},w;for(w in o)o[o[w]]=w;var U=/\\|'|\r|\n|\t|\u2028|\u2029/g,V=/\\(\\|'|r|n|t|u2028|u2029)/g,x=function(a){return a.replace(V,function(a,b){return o[b]})};b.template=function(a,c,d){d=b.defaults(d||{},b.templateSettings);a="__p+='"+a.replace(U,function(a){return"\\"+o[a]}).replace(d.escape||v,function(a,b){return"'+\n((__t=("+x(b)+"))==null?'':_.escape(__t))+\n'"}).replace(d.interpolate||
v,function(a,b){return"'+\n((__t=("+x(b)+"))==null?'':__t)+\n'"}).replace(d.evaluate||v,function(a,b){return"';\n"+x(b)+"\n__p+='"})+"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");var a="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'')};\n"+a+"return __p;\n",e=new Function(d.variable||"obj","_",a);if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};b.chain=function(a){return b(a).chain()};
var l=function(a){this._wrapped=a};b.prototype=l.prototype;var y=function(a,c){return c?b(a).chain():a},S=function(a,c){l.prototype[a]=function(){var a=i.call(arguments);N.call(a,this._wrapped);return y(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];l.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);(a=="shift"||a=="splice")&&d.length===0&&delete d[0];return y(d,this._chain)}});j(["concat","join","slice"],function(a){var b=
k[a];l.prototype[a]=function(){return y(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}}).call(this);

1104
vendor/underscore/underscore.js vendored Normal file

File diff suppressed because it is too large Load Diff