mobile_template 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +28 -0
  5. data/Rakefile +3 -0
  6. data/bin/mobile_template +71 -0
  7. data/lib/mobile_template/version.rb +4 -0
  8. data/lib/mobile_template.rb +5 -0
  9. data/mobile_template.gemspec +21 -0
  10. data/templates/assets/Gemfile +4 -0
  11. data/templates/assets/config.rb +96 -0
  12. data/templates/assets/config.ru +4 -0
  13. data/templates/assets/source/images/vendor/ajax-loader.gif +0 -0
  14. data/templates/assets/source/images/vendor/ajax-loader.png +0 -0
  15. data/templates/assets/source/images/vendor/icons-18-black.png +0 -0
  16. data/templates/assets/source/images/vendor/icons-18-white.png +0 -0
  17. data/templates/assets/source/images/vendor/icons-36-black.png +0 -0
  18. data/templates/assets/source/images/vendor/icons-36-white.png +0 -0
  19. data/templates/assets/source/index.html.erb +2 -0
  20. data/templates/assets/source/javascripts/app/index.js.coffee +2 -0
  21. data/templates/assets/source/javascripts/application.js.coffee +5 -0
  22. data/templates/assets/source/javascripts/vendor/cordova.js +4841 -0
  23. data/templates/assets/source/javascripts/vendor/jquery.js +9267 -0
  24. data/templates/assets/source/javascripts/vendor/jquery.mobile.js +7410 -0
  25. data/templates/assets/source/layout.erb +24 -0
  26. data/templates/assets/source/stylesheets/application.css.scss +2 -0
  27. data/templates/assets/source/stylesheets/vendor/jquery.mobile.css.scss +1872 -0
  28. data/templates/cordova_android/.gitignore +18 -0
  29. data/templates/cordova_android/LICENSE +202 -0
  30. data/templates/cordova_android/NOTICE +5 -0
  31. data/templates/cordova_android/README.md +95 -0
  32. data/templates/cordova_android/VERSION +1 -0
  33. data/templates/cordova_android/bin/BOOM +4 -0
  34. data/templates/cordova_android/bin/autotest +2 -0
  35. data/templates/cordova_android/bin/bench +29 -0
  36. data/templates/cordova_android/bin/create +46 -0
  37. data/templates/cordova_android/bin/create.bat +1 -0
  38. data/templates/cordova_android/bin/create.js +88 -0
  39. data/templates/cordova_android/bin/create.xml +79 -0
  40. data/templates/cordova_android/bin/node_modules/.bin/cake +7 -0
  41. data/templates/cordova_android/bin/node_modules/.bin/coffee +7 -0
  42. data/templates/cordova_android/bin/node_modules/.bin/nodeunit +120 -0
  43. data/templates/cordova_android/bin/node_modules/coffee-script/.npmignore +11 -0
  44. data/templates/cordova_android/bin/node_modules/coffee-script/LICENSE +22 -0
  45. data/templates/cordova_android/bin/node_modules/coffee-script/README +48 -0
  46. data/templates/cordova_android/bin/node_modules/coffee-script/Rakefile +78 -0
  47. data/templates/cordova_android/bin/node_modules/coffee-script/bin/cake +7 -0
  48. data/templates/cordova_android/bin/node_modules/coffee-script/bin/coffee +7 -0
  49. data/templates/cordova_android/bin/node_modules/coffee-script/extras/jsl.conf +44 -0
  50. data/templates/cordova_android/bin/node_modules/coffee-script/lib/browser.js +75 -0
  51. data/templates/cordova_android/bin/node_modules/coffee-script/lib/cake.js +76 -0
  52. data/templates/cordova_android/bin/node_modules/coffee-script/lib/coffee-script.js +135 -0
  53. data/templates/cordova_android/bin/node_modules/coffee-script/lib/command.js +301 -0
  54. data/templates/cordova_android/bin/node_modules/coffee-script/lib/grammar.js +591 -0
  55. data/templates/cordova_android/bin/node_modules/coffee-script/lib/helpers.js +66 -0
  56. data/templates/cordova_android/bin/node_modules/coffee-script/lib/index.js +8 -0
  57. data/templates/cordova_android/bin/node_modules/coffee-script/lib/lexer.js +656 -0
  58. data/templates/cordova_android/bin/node_modules/coffee-script/lib/nodes.js +2289 -0
  59. data/templates/cordova_android/bin/node_modules/coffee-script/lib/optparse.js +111 -0
  60. data/templates/cordova_android/bin/node_modules/coffee-script/lib/parser.js +676 -0
  61. data/templates/cordova_android/bin/node_modules/coffee-script/lib/repl.js +123 -0
  62. data/templates/cordova_android/bin/node_modules/coffee-script/lib/rewriter.js +363 -0
  63. data/templates/cordova_android/bin/node_modules/coffee-script/lib/scope.js +120 -0
  64. data/templates/cordova_android/bin/node_modules/coffee-script/package.json +27 -0
  65. data/templates/cordova_android/bin/node_modules/nodeunit/.gitignore +5 -0
  66. data/templates/cordova_android/bin/node_modules/nodeunit/.npmignore +3 -0
  67. data/templates/cordova_android/bin/node_modules/nodeunit/CONTRIBUTORS.md +60 -0
  68. data/templates/cordova_android/bin/node_modules/nodeunit/LICENSE +19 -0
  69. data/templates/cordova_android/bin/node_modules/nodeunit/Makefile +126 -0
  70. data/templates/cordova_android/bin/node_modules/nodeunit/README.md +432 -0
  71. data/templates/cordova_android/bin/node_modules/nodeunit/bin/nodeunit +120 -0
  72. data/templates/cordova_android/bin/node_modules/nodeunit/bin/nodeunit.json +10 -0
  73. data/templates/cordova_android/bin/node_modules/nodeunit/deps/async.js +623 -0
  74. data/templates/cordova_android/bin/node_modules/nodeunit/deps/console.log.js +55 -0
  75. data/templates/cordova_android/bin/node_modules/nodeunit/deps/ejs.js +125 -0
  76. data/templates/cordova_android/bin/node_modules/nodeunit/deps/json2.js +483 -0
  77. data/templates/cordova_android/bin/node_modules/nodeunit/examples/browser/nodeunit.js +1757 -0
  78. data/templates/cordova_android/bin/node_modules/nodeunit/examples/browser/suite1.js +12 -0
  79. data/templates/cordova_android/bin/node_modules/nodeunit/examples/browser/suite2.js +13 -0
  80. data/templates/cordova_android/bin/node_modules/nodeunit/examples/browser/test.html +16 -0
  81. data/templates/cordova_android/bin/node_modules/nodeunit/img/example_fail.png +0 -0
  82. data/templates/cordova_android/bin/node_modules/nodeunit/img/example_pass.png +0 -0
  83. data/templates/cordova_android/bin/node_modules/nodeunit/index.js +3 -0
  84. data/templates/cordova_android/bin/node_modules/nodeunit/lib/assert.js +316 -0
  85. data/templates/cordova_android/bin/node_modules/nodeunit/lib/core.js +260 -0
  86. data/templates/cordova_android/bin/node_modules/nodeunit/lib/nodeunit.js +82 -0
  87. data/templates/cordova_android/bin/node_modules/nodeunit/lib/reporters/browser.js +119 -0
  88. data/templates/cordova_android/bin/node_modules/nodeunit/lib/reporters/default.js +123 -0
  89. data/templates/cordova_android/bin/node_modules/nodeunit/lib/reporters/html.js +107 -0
  90. data/templates/cordova_android/bin/node_modules/nodeunit/lib/reporters/index.js +9 -0
  91. data/templates/cordova_android/bin/node_modules/nodeunit/lib/reporters/junit.js +183 -0
  92. data/templates/cordova_android/bin/node_modules/nodeunit/lib/reporters/minimal.js +112 -0
  93. data/templates/cordova_android/bin/node_modules/nodeunit/lib/reporters/skip_passed.js +105 -0
  94. data/templates/cordova_android/bin/node_modules/nodeunit/lib/track.js +48 -0
  95. data/templates/cordova_android/bin/node_modules/nodeunit/lib/types.js +187 -0
  96. data/templates/cordova_android/bin/node_modules/nodeunit/lib/utils.js +209 -0
  97. data/templates/cordova_android/bin/node_modules/nodeunit/man1/nodeunit.1 +95 -0
  98. data/templates/cordova_android/bin/node_modules/nodeunit/nodelint.cfg +4 -0
  99. data/templates/cordova_android/bin/node_modules/nodeunit/package.json +56 -0
  100. data/templates/cordova_android/bin/node_modules/nodeunit/share/junit.xml.ejs +19 -0
  101. data/templates/cordova_android/bin/node_modules/nodeunit/share/license.js +11 -0
  102. data/templates/cordova_android/bin/node_modules/nodeunit/share/nodeunit.css +70 -0
  103. data/templates/cordova_android/bin/templates/project/.cordova/android/readme.md +1 -0
  104. data/templates/cordova_android/bin/templates/project/.cordova/readme.md +3 -0
  105. data/templates/cordova_android/bin/templates/project/cordova/create +36 -0
  106. data/templates/cordova_android/bin/templates/project/cordova/debug +9 -0
  107. data/templates/cordova_android/bin/templates/project/cordova/emulate +12 -0
  108. data/templates/cordova_android/bin/templates/project/cordova/log +3 -0
  109. data/templates/cordova_android/bin/templates/project/cordova/templates/Activity.java +16 -0
  110. data/templates/cordova_android/bin/templates/project/cordova/templates/project/AndroidManifest.xml +50 -0
  111. data/templates/cordova_android/bin/templates/project/cordova/templates/project/assets/www/index.html +42 -0
  112. data/templates/cordova_android/bin/templates/project/cordova/templates/project/assets/www/main.js +146 -0
  113. data/templates/cordova_android/bin/templates/project/cordova/templates/project/assets/www/master.css +96 -0
  114. data/templates/cordova_android/bin/templates/project/cordova/templates/project/res/drawable/icon.png +0 -0
  115. data/templates/cordova_android/bin/templates/project/cordova/templates/project/res/xml/cordova.xml +5 -0
  116. data/templates/cordova_android/bin/templates/project/cordova/templates/project/res/xml/plugins.xml +19 -0
  117. data/templates/cordova_android/bin/test +26 -0
  118. data/templates/cordova_android/bin/tests/autotest.coffee +4 -0
  119. data/templates/cordova_android/bin/tests/create.coffee +21 -0
  120. data/templates/cordova_android/bin/tests/debug.coffee +0 -0
  121. data/templates/cordova_android/bin/tests/test.coffee +0 -0
  122. data/templates/cordova_android/framework/.classpath +8 -0
  123. data/templates/cordova_android/framework/.project +33 -0
  124. data/templates/cordova_android/framework/AndroidManifest.xml +68 -0
  125. data/templates/cordova_android/framework/ant.properties +34 -0
  126. data/templates/cordova_android/framework/assets/js/accelerometer.js +137 -0
  127. data/templates/cordova_android/framework/assets/js/app.js +89 -0
  128. data/templates/cordova_android/framework/assets/js/battery.js +134 -0
  129. data/templates/cordova_android/framework/assets/js/camera.js +168 -0
  130. data/templates/cordova_android/framework/assets/js/capture.js +203 -0
  131. data/templates/cordova_android/framework/assets/js/compass.js +168 -0
  132. data/templates/cordova_android/framework/assets/js/contact.js +310 -0
  133. data/templates/cordova_android/framework/assets/js/cordova.android.js +4841 -0
  134. data/templates/cordova_android/framework/assets/js/cordova.js.base +924 -0
  135. data/templates/cordova_android/framework/assets/js/crypto.js +54 -0
  136. data/templates/cordova_android/framework/assets/js/device.js +83 -0
  137. data/templates/cordova_android/framework/assets/js/file.js +1082 -0
  138. data/templates/cordova_android/framework/assets/js/filetransfer.js +125 -0
  139. data/templates/cordova_android/framework/assets/js/geolocation.js +209 -0
  140. data/templates/cordova_android/framework/assets/js/header.txt +19 -0
  141. data/templates/cordova_android/framework/assets/js/media.js +233 -0
  142. data/templates/cordova_android/framework/assets/js/network.js +100 -0
  143. data/templates/cordova_android/framework/assets/js/notification.js +133 -0
  144. data/templates/cordova_android/framework/assets/js/position.js +100 -0
  145. data/templates/cordova_android/framework/assets/js/storage.js +439 -0
  146. data/templates/cordova_android/framework/assets/www/index.html +27 -0
  147. data/templates/cordova_android/framework/build.xml +216 -0
  148. data/templates/cordova_android/framework/libs/commons-codec-1.3.jar +0 -0
  149. data/templates/cordova_android/framework/proguard-project.txt +20 -0
  150. data/templates/cordova_android/framework/project.properties +14 -0
  151. data/templates/cordova_android/framework/res/drawable/icon.png +0 -0
  152. data/templates/cordova_android/framework/res/drawable/splash.png +0 -0
  153. data/templates/cordova_android/framework/res/layout/main.xml +29 -0
  154. data/templates/cordova_android/framework/res/values/strings.xml +23 -0
  155. data/templates/cordova_android/framework/res/xml/cordova.xml +37 -0
  156. data/templates/cordova_android/framework/res/xml/plugins.xml +37 -0
  157. data/templates/cordova_android/framework/src/com/phonegap/api/IPlugin.java +27 -0
  158. data/templates/cordova_android/framework/src/com/phonegap/api/LOG.java +28 -0
  159. data/templates/cordova_android/framework/src/com/phonegap/api/PhonegapActivity.java +28 -0
  160. data/templates/cordova_android/framework/src/com/phonegap/api/Plugin.java +27 -0
  161. data/templates/cordova_android/framework/src/com/phonegap/api/PluginManager.java +35 -0
  162. data/templates/cordova_android/framework/src/com/phonegap/api/PluginResult.java +53 -0
  163. data/templates/cordova_android/framework/src/org/apache/cordova/AccelListener.java +311 -0
  164. data/templates/cordova_android/framework/src/org/apache/cordova/App.java +198 -0
  165. data/templates/cordova_android/framework/src/org/apache/cordova/AudioHandler.java +364 -0
  166. data/templates/cordova_android/framework/src/org/apache/cordova/AudioPlayer.java +450 -0
  167. data/templates/cordova_android/framework/src/org/apache/cordova/AuthenticationToken.java +69 -0
  168. data/templates/cordova_android/framework/src/org/apache/cordova/BatteryListener.java +156 -0
  169. data/templates/cordova_android/framework/src/org/apache/cordova/CallbackServer.java +431 -0
  170. data/templates/cordova_android/framework/src/org/apache/cordova/CameraLauncher.java +500 -0
  171. data/templates/cordova_android/framework/src/org/apache/cordova/Capture.java +400 -0
  172. data/templates/cordova_android/framework/src/org/apache/cordova/CompassListener.java +308 -0
  173. data/templates/cordova_android/framework/src/org/apache/cordova/ContactAccessor.java +198 -0
  174. data/templates/cordova_android/framework/src/org/apache/cordova/ContactAccessorSdk5.java +1934 -0
  175. data/templates/cordova_android/framework/src/org/apache/cordova/ContactManager.java +113 -0
  176. data/templates/cordova_android/framework/src/org/apache/cordova/CordovaChromeClient.java +314 -0
  177. data/templates/cordova_android/framework/src/org/apache/cordova/CordovaWebViewClient.java +306 -0
  178. data/templates/cordova_android/framework/src/org/apache/cordova/Device.java +219 -0
  179. data/templates/cordova_android/framework/src/org/apache/cordova/DirectoryManager.java +161 -0
  180. data/templates/cordova_android/framework/src/org/apache/cordova/DroidGap.java +1417 -0
  181. data/templates/cordova_android/framework/src/org/apache/cordova/ExifHelper.java +165 -0
  182. data/templates/cordova_android/framework/src/org/apache/cordova/FileTransfer.java +458 -0
  183. data/templates/cordova_android/framework/src/org/apache/cordova/FileUploadResult.java +63 -0
  184. data/templates/cordova_android/framework/src/org/apache/cordova/FileUtils.java +1048 -0
  185. data/templates/cordova_android/framework/src/org/apache/cordova/GeoBroker.java +165 -0
  186. data/templates/cordova_android/framework/src/org/apache/cordova/GeoListener.java +133 -0
  187. data/templates/cordova_android/framework/src/org/apache/cordova/GpsListener.java +163 -0
  188. data/templates/cordova_android/framework/src/org/apache/cordova/HttpHandler.java +80 -0
  189. data/templates/cordova_android/framework/src/org/apache/cordova/LinearLayoutSoftKeyboardDetect.java +104 -0
  190. data/templates/cordova_android/framework/src/org/apache/cordova/NetworkListener.java +153 -0
  191. data/templates/cordova_android/framework/src/org/apache/cordova/NetworkManager.java +248 -0
  192. data/templates/cordova_android/framework/src/org/apache/cordova/Notification.java +366 -0
  193. data/templates/cordova_android/framework/src/org/apache/cordova/PreferenceNode.java +34 -0
  194. data/templates/cordova_android/framework/src/org/apache/cordova/PreferenceSet.java +62 -0
  195. data/templates/cordova_android/framework/src/org/apache/cordova/StandAlone.java +35 -0
  196. data/templates/cordova_android/framework/src/org/apache/cordova/Storage.java +239 -0
  197. data/templates/cordova_android/framework/src/org/apache/cordova/TempListener.java +112 -0
  198. data/templates/cordova_android/framework/src/org/apache/cordova/api/CordovaInterface.java +145 -0
  199. data/templates/cordova_android/framework/src/org/apache/cordova/api/IPlugin.java +116 -0
  200. data/templates/cordova_android/framework/src/org/apache/cordova/api/LOG.java +234 -0
  201. data/templates/cordova_android/framework/src/org/apache/cordova/api/Plugin.java +210 -0
  202. data/templates/cordova_android/framework/src/org/apache/cordova/api/PluginManager.java +359 -0
  203. data/templates/cordova_android/framework/src/org/apache/cordova/api/PluginResult.java +119 -0
  204. data/templates/cordova_android/framework/src/org/apache/cordova/file/EncodingException.java +28 -0
  205. data/templates/cordova_android/framework/src/org/apache/cordova/file/FileExistsException.java +28 -0
  206. data/templates/cordova_android/framework/src/org/apache/cordova/file/InvalidModificationException.java +29 -0
  207. data/templates/cordova_android/framework/src/org/apache/cordova/file/NoModificationAllowedException.java +28 -0
  208. data/templates/cordova_android/framework/src/org/apache/cordova/file/TypeMismatchException.java +29 -0
  209. data/templates/cordova_android/framework/test/org/apache/cordova/PreferenceNodeTest.java +53 -0
  210. data/templates/cordova_android/framework/test/org/apache/cordova/PreferenceSetTest.java +73 -0
  211. metadata +279 -0
@@ -0,0 +1,1757 @@
1
+ /*!
2
+ * Nodeunit
3
+ * https://github.com/caolan/nodeunit
4
+ * Copyright (c) 2010 Caolan McMahon
5
+ * MIT Licensed
6
+ *
7
+ * json2.js
8
+ * http://www.JSON.org/json2.js
9
+ * Public Domain.
10
+ * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
11
+ */
12
+ nodeunit = (function(){
13
+ /*
14
+ http://www.JSON.org/json2.js
15
+ 2010-11-17
16
+
17
+ Public Domain.
18
+
19
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
20
+
21
+ See http://www.JSON.org/js.html
22
+
23
+
24
+ This code should be minified before deployment.
25
+ See http://javascript.crockford.com/jsmin.html
26
+
27
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
28
+ NOT CONTROL.
29
+
30
+
31
+ This file creates a global JSON object containing two methods: stringify
32
+ and parse.
33
+
34
+ JSON.stringify(value, replacer, space)
35
+ value any JavaScript value, usually an object or array.
36
+
37
+ replacer an optional parameter that determines how object
38
+ values are stringified for objects. It can be a
39
+ function or an array of strings.
40
+
41
+ space an optional parameter that specifies the indentation
42
+ of nested structures. If it is omitted, the text will
43
+ be packed without extra whitespace. If it is a number,
44
+ it will specify the number of spaces to indent at each
45
+ level. If it is a string (such as '\t' or ' '),
46
+ it contains the characters used to indent at each level.
47
+
48
+ This method produces a JSON text from a JavaScript value.
49
+
50
+ When an object value is found, if the object contains a toJSON
51
+ method, its toJSON method will be called and the result will be
52
+ stringified. A toJSON method does not serialize: it returns the
53
+ value represented by the name/value pair that should be serialized,
54
+ or undefined if nothing should be serialized. The toJSON method
55
+ will be passed the key associated with the value, and this will be
56
+ bound to the value
57
+
58
+ For example, this would serialize Dates as ISO strings.
59
+
60
+ Date.prototype.toJSON = function (key) {
61
+ function f(n) {
62
+ // Format integers to have at least two digits.
63
+ return n < 10 ? '0' + n : n;
64
+ }
65
+
66
+ return this.getUTCFullYear() + '-' +
67
+ f(this.getUTCMonth() + 1) + '-' +
68
+ f(this.getUTCDate()) + 'T' +
69
+ f(this.getUTCHours()) + ':' +
70
+ f(this.getUTCMinutes()) + ':' +
71
+ f(this.getUTCSeconds()) + 'Z';
72
+ };
73
+
74
+ You can provide an optional replacer method. It will be passed the
75
+ key and value of each member, with this bound to the containing
76
+ object. The value that is returned from your method will be
77
+ serialized. If your method returns undefined, then the member will
78
+ be excluded from the serialization.
79
+
80
+ If the replacer parameter is an array of strings, then it will be
81
+ used to select the members to be serialized. It filters the results
82
+ such that only members with keys listed in the replacer array are
83
+ stringified.
84
+
85
+ Values that do not have JSON representations, such as undefined or
86
+ functions, will not be serialized. Such values in objects will be
87
+ dropped; in arrays they will be replaced with null. You can use
88
+ a replacer function to replace those with JSON values.
89
+ JSON.stringify(undefined) returns undefined.
90
+
91
+ The optional space parameter produces a stringification of the
92
+ value that is filled with line breaks and indentation to make it
93
+ easier to read.
94
+
95
+ If the space parameter is a non-empty string, then that string will
96
+ be used for indentation. If the space parameter is a number, then
97
+ the indentation will be that many spaces.
98
+
99
+ Example:
100
+
101
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
102
+ // text is '["e",{"pluribus":"unum"}]'
103
+
104
+
105
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
106
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
107
+
108
+ text = JSON.stringify([new Date()], function (key, value) {
109
+ return this[key] instanceof Date ?
110
+ 'Date(' + this[key] + ')' : value;
111
+ });
112
+ // text is '["Date(---current time---)"]'
113
+
114
+
115
+ JSON.parse(text, reviver)
116
+ This method parses a JSON text to produce an object or array.
117
+ It can throw a SyntaxError exception.
118
+
119
+ The optional reviver parameter is a function that can filter and
120
+ transform the results. It receives each of the keys and values,
121
+ and its return value is used instead of the original value.
122
+ If it returns what it received, then the structure is not modified.
123
+ If it returns undefined then the member is deleted.
124
+
125
+ Example:
126
+
127
+ // Parse the text. Values that look like ISO date strings will
128
+ // be converted to Date objects.
129
+
130
+ myData = JSON.parse(text, function (key, value) {
131
+ var a;
132
+ if (typeof value === 'string') {
133
+ a =
134
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
135
+ if (a) {
136
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
137
+ +a[5], +a[6]));
138
+ }
139
+ }
140
+ return value;
141
+ });
142
+
143
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
144
+ var d;
145
+ if (typeof value === 'string' &&
146
+ value.slice(0, 5) === 'Date(' &&
147
+ value.slice(-1) === ')') {
148
+ d = new Date(value.slice(5, -1));
149
+ if (d) {
150
+ return d;
151
+ }
152
+ }
153
+ return value;
154
+ });
155
+
156
+
157
+ This is a reference implementation. You are free to copy, modify, or
158
+ redistribute.
159
+ */
160
+
161
+ /*jslint evil: true, strict: false, regexp: false */
162
+
163
+ /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
164
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
165
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
166
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
167
+ test, toJSON, toString, valueOf
168
+ */
169
+
170
+
171
+ // Create a JSON object only if one does not already exist. We create the
172
+ // methods in a closure to avoid creating global variables.
173
+
174
+ if (!this.JSON) {
175
+ this.JSON = {};
176
+ }
177
+
178
+ (function () {
179
+ "use strict";
180
+
181
+ function f(n) {
182
+ // Format integers to have at least two digits.
183
+ return n < 10 ? '0' + n : n;
184
+ }
185
+
186
+ if (typeof Date.prototype.toJSON !== 'function') {
187
+
188
+ Date.prototype.toJSON = function (key) {
189
+
190
+ return isFinite(this.valueOf()) ?
191
+ this.getUTCFullYear() + '-' +
192
+ f(this.getUTCMonth() + 1) + '-' +
193
+ f(this.getUTCDate()) + 'T' +
194
+ f(this.getUTCHours()) + ':' +
195
+ f(this.getUTCMinutes()) + ':' +
196
+ f(this.getUTCSeconds()) + 'Z' : null;
197
+ };
198
+
199
+ String.prototype.toJSON =
200
+ Number.prototype.toJSON =
201
+ Boolean.prototype.toJSON = function (key) {
202
+ return this.valueOf();
203
+ };
204
+ }
205
+
206
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
207
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
208
+ gap,
209
+ indent,
210
+ meta = { // table of character substitutions
211
+ '\b': '\\b',
212
+ '\t': '\\t',
213
+ '\n': '\\n',
214
+ '\f': '\\f',
215
+ '\r': '\\r',
216
+ '"' : '\\"',
217
+ '\\': '\\\\'
218
+ },
219
+ rep;
220
+
221
+
222
+ function quote(string) {
223
+
224
+ // If the string contains no control characters, no quote characters, and no
225
+ // backslash characters, then we can safely slap some quotes around it.
226
+ // Otherwise we must also replace the offending characters with safe escape
227
+ // sequences.
228
+
229
+ escapable.lastIndex = 0;
230
+ return escapable.test(string) ?
231
+ '"' + string.replace(escapable, function (a) {
232
+ var c = meta[a];
233
+ return typeof c === 'string' ? c :
234
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
235
+ }) + '"' :
236
+ '"' + string + '"';
237
+ }
238
+
239
+
240
+ function str(key, holder) {
241
+
242
+ // Produce a string from holder[key].
243
+
244
+ var i, // The loop counter.
245
+ k, // The member key.
246
+ v, // The member value.
247
+ length,
248
+ mind = gap,
249
+ partial,
250
+ value = holder[key];
251
+
252
+ // If the value has a toJSON method, call it to obtain a replacement value.
253
+
254
+ if (value && typeof value === 'object' &&
255
+ typeof value.toJSON === 'function') {
256
+ value = value.toJSON(key);
257
+ }
258
+
259
+ // If we were called with a replacer function, then call the replacer to
260
+ // obtain a replacement value.
261
+
262
+ if (typeof rep === 'function') {
263
+ value = rep.call(holder, key, value);
264
+ }
265
+
266
+ // What happens next depends on the value's type.
267
+
268
+ switch (typeof value) {
269
+ case 'string':
270
+ return quote(value);
271
+
272
+ case 'number':
273
+
274
+ // JSON numbers must be finite. Encode non-finite numbers as null.
275
+
276
+ return isFinite(value) ? String(value) : 'null';
277
+
278
+ case 'boolean':
279
+ case 'null':
280
+
281
+ // If the value is a boolean or null, convert it to a string. Note:
282
+ // typeof null does not produce 'null'. The case is included here in
283
+ // the remote chance that this gets fixed someday.
284
+
285
+ return String(value);
286
+
287
+ // If the type is 'object', we might be dealing with an object or an array or
288
+ // null.
289
+
290
+ case 'object':
291
+
292
+ // Due to a specification blunder in ECMAScript, typeof null is 'object',
293
+ // so watch out for that case.
294
+
295
+ if (!value) {
296
+ return 'null';
297
+ }
298
+
299
+ // Make an array to hold the partial results of stringifying this object value.
300
+
301
+ gap += indent;
302
+ partial = [];
303
+
304
+ // Is the value an array?
305
+
306
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
307
+
308
+ // The value is an array. Stringify every element. Use null as a placeholder
309
+ // for non-JSON values.
310
+
311
+ length = value.length;
312
+ for (i = 0; i < length; i += 1) {
313
+ partial[i] = str(i, value) || 'null';
314
+ }
315
+
316
+ // Join all of the elements together, separated with commas, and wrap them in
317
+ // brackets.
318
+
319
+ v = partial.length === 0 ? '[]' :
320
+ gap ? '[\n' + gap +
321
+ partial.join(',\n' + gap) + '\n' +
322
+ mind + ']' :
323
+ '[' + partial.join(',') + ']';
324
+ gap = mind;
325
+ return v;
326
+ }
327
+
328
+ // If the replacer is an array, use it to select the members to be stringified.
329
+
330
+ if (rep && typeof rep === 'object') {
331
+ length = rep.length;
332
+ for (i = 0; i < length; i += 1) {
333
+ k = rep[i];
334
+ if (typeof k === 'string') {
335
+ v = str(k, value);
336
+ if (v) {
337
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
338
+ }
339
+ }
340
+ }
341
+ } else {
342
+
343
+ // Otherwise, iterate through all of the keys in the object.
344
+
345
+ for (k in value) {
346
+ if (Object.hasOwnProperty.call(value, k)) {
347
+ v = str(k, value);
348
+ if (v) {
349
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
350
+ }
351
+ }
352
+ }
353
+ }
354
+
355
+ // Join all of the member texts together, separated with commas,
356
+ // and wrap them in braces.
357
+
358
+ v = partial.length === 0 ? '{}' :
359
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
360
+ mind + '}' : '{' + partial.join(',') + '}';
361
+ gap = mind;
362
+ return v;
363
+ }
364
+ }
365
+
366
+ // If the JSON object does not yet have a stringify method, give it one.
367
+
368
+ if (typeof JSON.stringify !== 'function') {
369
+ JSON.stringify = function (value, replacer, space) {
370
+
371
+ // The stringify method takes a value and an optional replacer, and an optional
372
+ // space parameter, and returns a JSON text. The replacer can be a function
373
+ // that can replace values, or an array of strings that will select the keys.
374
+ // A default replacer method can be provided. Use of the space parameter can
375
+ // produce text that is more easily readable.
376
+
377
+ var i;
378
+ gap = '';
379
+ indent = '';
380
+
381
+ // If the space parameter is a number, make an indent string containing that
382
+ // many spaces.
383
+
384
+ if (typeof space === 'number') {
385
+ for (i = 0; i < space; i += 1) {
386
+ indent += ' ';
387
+ }
388
+
389
+ // If the space parameter is a string, it will be used as the indent string.
390
+
391
+ } else if (typeof space === 'string') {
392
+ indent = space;
393
+ }
394
+
395
+ // If there is a replacer, it must be a function or an array.
396
+ // Otherwise, throw an error.
397
+
398
+ rep = replacer;
399
+ if (replacer && typeof replacer !== 'function' &&
400
+ (typeof replacer !== 'object' ||
401
+ typeof replacer.length !== 'number')) {
402
+ throw new Error('JSON.stringify');
403
+ }
404
+
405
+ // Make a fake root object containing our value under the key of ''.
406
+ // Return the result of stringifying the value.
407
+
408
+ return str('', {'': value});
409
+ };
410
+ }
411
+
412
+
413
+ // If the JSON object does not yet have a parse method, give it one.
414
+
415
+ if (typeof JSON.parse !== 'function') {
416
+ JSON.parse = function (text, reviver) {
417
+
418
+ // The parse method takes a text and an optional reviver function, and returns
419
+ // a JavaScript value if the text is a valid JSON text.
420
+
421
+ var j;
422
+
423
+ function walk(holder, key) {
424
+
425
+ // The walk method is used to recursively walk the resulting structure so
426
+ // that modifications can be made.
427
+
428
+ var k, v, value = holder[key];
429
+ if (value && typeof value === 'object') {
430
+ for (k in value) {
431
+ if (Object.hasOwnProperty.call(value, k)) {
432
+ v = walk(value, k);
433
+ if (v !== undefined) {
434
+ value[k] = v;
435
+ } else {
436
+ delete value[k];
437
+ }
438
+ }
439
+ }
440
+ }
441
+ return reviver.call(holder, key, value);
442
+ }
443
+
444
+
445
+ // Parsing happens in four stages. In the first stage, we replace certain
446
+ // Unicode characters with escape sequences. JavaScript handles many characters
447
+ // incorrectly, either silently deleting them, or treating them as line endings.
448
+
449
+ text = String(text);
450
+ cx.lastIndex = 0;
451
+ if (cx.test(text)) {
452
+ text = text.replace(cx, function (a) {
453
+ return '\\u' +
454
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
455
+ });
456
+ }
457
+
458
+ // In the second stage, we run the text against regular expressions that look
459
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
460
+ // because they can cause invocation, and '=' because it can cause mutation.
461
+ // But just to be safe, we want to reject all unexpected forms.
462
+
463
+ // We split the second stage into 4 regexp operations in order to work around
464
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
465
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
466
+ // replace all simple value tokens with ']' characters. Third, we delete all
467
+ // open brackets that follow a colon or comma or that begin the text. Finally,
468
+ // we look to see that the remaining characters are only whitespace or ']' or
469
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
470
+
471
+ if (/^[\],:{}\s]*$/
472
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
473
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
474
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
475
+
476
+ // In the third stage we use the eval function to compile the text into a
477
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
478
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
479
+ // in parens to eliminate the ambiguity.
480
+
481
+ j = eval('(' + text + ')');
482
+
483
+ // In the optional fourth stage, we recursively walk the new structure, passing
484
+ // each name/value pair to a reviver function for possible transformation.
485
+
486
+ return typeof reviver === 'function' ?
487
+ walk({'': j}, '') : j;
488
+ }
489
+
490
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
491
+
492
+ throw new SyntaxError('JSON.parse');
493
+ };
494
+ }
495
+ }());
496
+ var assert = {};
497
+ var types = {};
498
+ var core = {};
499
+ var nodeunit = {};
500
+ var reporter = {};
501
+ (function(){
502
+
503
+ var async = {};
504
+
505
+ // global on the server, window in the browser
506
+ var root = this;
507
+ var previous_async = root.async;
508
+
509
+ if(typeof module !== 'undefined' && module.exports) module.exports = async;
510
+ else root.async = async;
511
+
512
+ async.noConflict = function(){
513
+ root.async = previous_async;
514
+ return async;
515
+ };
516
+
517
+ //// cross-browser compatiblity functions ////
518
+
519
+ var _forEach = function(arr, iterator){
520
+ if(arr.forEach) return arr.forEach(iterator);
521
+ for(var i=0; i<arr.length; i++){
522
+ iterator(arr[i], i, arr);
523
+ }
524
+ };
525
+
526
+ var _map = function(arr, iterator){
527
+ if(arr.map) return arr.map(iterator);
528
+ var results = [];
529
+ _forEach(arr, function(x, i, a){
530
+ results.push(iterator(x, i, a));
531
+ })
532
+ return results;
533
+ };
534
+
535
+ var _reduce = function(arr, iterator, memo){
536
+ if(arr.reduce) return arr.reduce(iterator, memo);
537
+ _forEach(arr, function(x, i, a){
538
+ memo = iterator(memo, x, i, a);
539
+ });
540
+ return memo;
541
+ };
542
+
543
+ var _keys = function(obj){
544
+ if(Object.keys) return Object.keys(obj);
545
+ var keys = [];
546
+ for(var k in obj){
547
+ if(obj.hasOwnProperty(k)) keys.push(k);
548
+ }
549
+ return keys;
550
+ };
551
+
552
+ var _indexOf = function(arr, item){
553
+ if(arr.indexOf) return arr.indexOf(item);
554
+ for(var i=0; i<arr.length; i++){
555
+ if(arr[i] === item) return i;
556
+ }
557
+ return -1;
558
+ };
559
+
560
+ //// exported async module functions ////
561
+
562
+ //// nextTick implementation with browser-compatible fallback ////
563
+ async.nextTick = function(fn){
564
+ if(typeof process == 'undefined' || !(process.nextTick)){
565
+ setTimeout(fn, 0);
566
+ }
567
+ else process.nextTick(fn);
568
+ };
569
+
570
+ async.forEach = function(arr, iterator, callback){
571
+ if(!arr.length) return callback();
572
+ var completed = 0;
573
+ _forEach(arr, function(x){
574
+ iterator(x, function(err){
575
+ if(err){
576
+ callback(err);
577
+ callback = function(){};
578
+ }
579
+ else {
580
+ completed++;
581
+ if(completed == arr.length) callback();
582
+ }
583
+ });
584
+ });
585
+ };
586
+
587
+ async.forEachSeries = function(arr, iterator, callback){
588
+ if(!arr.length) return callback();
589
+ var completed = 0;
590
+ var iterate = function(){
591
+ iterator(arr[completed], function(err){
592
+ if(err){
593
+ callback(err);
594
+ callback = function(){};
595
+ }
596
+ else {
597
+ completed++;
598
+ if(completed == arr.length) callback();
599
+ else iterate();
600
+ }
601
+ });
602
+ };
603
+ iterate();
604
+ };
605
+
606
+
607
+ var doParallel = function(fn){
608
+ return function(){
609
+ var args = Array.prototype.slice.call(arguments);
610
+ return fn.apply(null, [async.forEach].concat(args));
611
+ };
612
+ };
613
+ var doSeries = function(fn){
614
+ return function(){
615
+ var args = Array.prototype.slice.call(arguments);
616
+ return fn.apply(null, [async.forEachSeries].concat(args));
617
+ };
618
+ };
619
+
620
+
621
+ var _asyncMap = function(eachfn, arr, iterator, callback){
622
+ var results = [];
623
+ arr = _map(arr, function(x, i){
624
+ return {index: i, value: x};
625
+ });
626
+ eachfn(arr, function(x, callback){
627
+ iterator(x.value, function(err, v){
628
+ results[x.index] = v;
629
+ callback(err);
630
+ });
631
+ }, function(err){
632
+ callback(err, results);
633
+ });
634
+ };
635
+ async.map = doParallel(_asyncMap);
636
+ async.mapSeries = doSeries(_asyncMap);
637
+
638
+
639
+ // reduce only has a series version, as doing reduce in parallel won't
640
+ // work in many situations.
641
+ async.reduce = function(arr, memo, iterator, callback){
642
+ async.forEachSeries(arr, function(x, callback){
643
+ iterator(memo, x, function(err, v){
644
+ memo = v;
645
+ callback(err);
646
+ });
647
+ }, function(err){
648
+ callback(err, memo);
649
+ });
650
+ };
651
+ // inject alias
652
+ async.inject = async.reduce;
653
+ // foldl alias
654
+ async.foldl = async.reduce;
655
+
656
+ async.reduceRight = function(arr, memo, iterator, callback){
657
+ var reversed = _map(arr, function(x){return x;}).reverse();
658
+ async.reduce(reversed, memo, iterator, callback);
659
+ };
660
+ // foldr alias
661
+ async.foldr = async.reduceRight;
662
+
663
+ var _filter = function(eachfn, arr, iterator, callback){
664
+ var results = [];
665
+ arr = _map(arr, function(x, i){
666
+ return {index: i, value: x};
667
+ });
668
+ eachfn(arr, function(x, callback){
669
+ iterator(x.value, function(v){
670
+ if(v) results.push(x);
671
+ callback();
672
+ });
673
+ }, function(err){
674
+ callback(_map(results.sort(function(a,b){
675
+ return a.index - b.index;
676
+ }), function(x){
677
+ return x.value;
678
+ }));
679
+ });
680
+ };
681
+ async.filter = doParallel(_filter);
682
+ async.filterSeries = doSeries(_filter);
683
+ // select alias
684
+ async.select = async.filter;
685
+ async.selectSeries = async.filterSeries;
686
+
687
+ var _reject = function(eachfn, arr, iterator, callback){
688
+ var results = [];
689
+ arr = _map(arr, function(x, i){
690
+ return {index: i, value: x};
691
+ });
692
+ eachfn(arr, function(x, callback){
693
+ iterator(x.value, function(v){
694
+ if(!v) results.push(x);
695
+ callback();
696
+ });
697
+ }, function(err){
698
+ callback(_map(results.sort(function(a,b){
699
+ return a.index - b.index;
700
+ }), function(x){
701
+ return x.value;
702
+ }));
703
+ });
704
+ };
705
+ async.reject = doParallel(_reject);
706
+ async.rejectSeries = doSeries(_reject);
707
+
708
+ var _detect = function(eachfn, arr, iterator, main_callback){
709
+ eachfn(arr, function(x, callback){
710
+ iterator(x, function(result){
711
+ if(result) main_callback(x);
712
+ else callback();
713
+ });
714
+ }, function(err){
715
+ main_callback();
716
+ });
717
+ };
718
+ async.detect = doParallel(_detect);
719
+ async.detectSeries = doSeries(_detect);
720
+
721
+ async.some = function(arr, iterator, main_callback){
722
+ async.forEach(arr, function(x, callback){
723
+ iterator(x, function(v){
724
+ if(v){
725
+ main_callback(true);
726
+ main_callback = function(){};
727
+ }
728
+ callback();
729
+ });
730
+ }, function(err){
731
+ main_callback(false);
732
+ });
733
+ };
734
+ // any alias
735
+ async.any = async.some;
736
+
737
+ async.every = function(arr, iterator, main_callback){
738
+ async.forEach(arr, function(x, callback){
739
+ iterator(x, function(v){
740
+ if(!v){
741
+ main_callback(false);
742
+ main_callback = function(){};
743
+ }
744
+ callback();
745
+ });
746
+ }, function(err){
747
+ main_callback(true);
748
+ });
749
+ };
750
+ // all alias
751
+ async.all = async.every;
752
+
753
+ async.sortBy = function(arr, iterator, callback){
754
+ async.map(arr, function(x, callback){
755
+ iterator(x, function(err, criteria){
756
+ if(err) callback(err);
757
+ else callback(null, {value: x, criteria: criteria});
758
+ });
759
+ }, function(err, results){
760
+ if(err) return callback(err);
761
+ else callback(null, _map(results.sort(function(left, right){
762
+ var a = left.criteria, b = right.criteria;
763
+ return a < b ? -1 : a > b ? 1 : 0;
764
+ }), function(x){return x.value;}));
765
+ })
766
+ };
767
+
768
+ async.auto = function(tasks, callback){
769
+ callback = callback || function(){};
770
+ var keys = _keys(tasks);
771
+ if(!keys.length) return callback(null);
772
+
773
+ var completed = [];
774
+
775
+ var listeners = [];
776
+ var addListener = function(fn){
777
+ listeners.unshift(fn);
778
+ };
779
+ var removeListener = function(fn){
780
+ for(var i=0; i<listeners.length; i++){
781
+ if(listeners[i] === fn){
782
+ listeners.splice(i, 1);
783
+ return;
784
+ }
785
+ }
786
+ };
787
+ var taskComplete = function(){
788
+ _forEach(listeners, function(fn){fn();});
789
+ };
790
+
791
+ addListener(function(){
792
+ if(completed.length == keys.length){
793
+ callback(null);
794
+ }
795
+ });
796
+
797
+ _forEach(keys, function(k){
798
+ var task = (tasks[k] instanceof Function)? [tasks[k]]: tasks[k];
799
+ var taskCallback = function(err){
800
+ if(err){
801
+ callback(err);
802
+ // stop subsequent errors hitting callback multiple times
803
+ callback = function(){};
804
+ }
805
+ else {
806
+ completed.push(k);
807
+ taskComplete();
808
+ }
809
+ };
810
+ var requires = task.slice(0, Math.abs(task.length-1)) || [];
811
+ var ready = function(){
812
+ return _reduce(requires, function(a,x){
813
+ return (a && _indexOf(completed, x) != -1);
814
+ }, true);
815
+ };
816
+ if(ready()) task[task.length-1](taskCallback);
817
+ else {
818
+ var listener = function(){
819
+ if(ready()){
820
+ removeListener(listener);
821
+ task[task.length-1](taskCallback);
822
+ }
823
+ };
824
+ addListener(listener);
825
+ }
826
+ });
827
+ };
828
+
829
+ async.waterfall = function(tasks, callback){
830
+ if(!tasks.length) return callback();
831
+ callback = callback || function(){};
832
+ var wrapIterator = function(iterator){
833
+ return function(err){
834
+ if(err){
835
+ callback(err);
836
+ callback = function(){};
837
+ }
838
+ else {
839
+ var args = Array.prototype.slice.call(arguments, 1);
840
+ var next = iterator.next();
841
+ if(next) args.push(wrapIterator(next));
842
+ else args.push(callback);
843
+ async.nextTick(function(){iterator.apply(null, args);});
844
+ }
845
+ };
846
+ };
847
+ wrapIterator(async.iterator(tasks))();
848
+ };
849
+
850
+ async.parallel = function(tasks, callback){
851
+ callback = callback || function(){};
852
+ async.map(tasks, function(fn, callback){
853
+ if(fn){
854
+ fn(function(err){
855
+ var args = Array.prototype.slice.call(arguments,1);
856
+ if(args.length <= 1) args = args[0];
857
+ callback.call(null, err, args || null);
858
+ });
859
+ }
860
+ }, callback);
861
+ };
862
+
863
+ async.series = function(tasks, callback){
864
+ callback = callback || function(){};
865
+ async.mapSeries(tasks, function(fn, callback){
866
+ if(fn){
867
+ fn(function(err){
868
+ var args = Array.prototype.slice.call(arguments,1);
869
+ if(args.length <= 1) args = args[0];
870
+ callback.call(null, err, args || null);
871
+ });
872
+ }
873
+ }, callback);
874
+ };
875
+
876
+ async.iterator = function(tasks){
877
+ var makeCallback = function(index){
878
+ var fn = function(){
879
+ if(tasks.length) tasks[index].apply(null, arguments);
880
+ return fn.next();
881
+ };
882
+ fn.next = function(){
883
+ return (index < tasks.length-1)? makeCallback(index+1): null;
884
+ };
885
+ return fn;
886
+ };
887
+ return makeCallback(0);
888
+ };
889
+
890
+ async.apply = function(fn){
891
+ var args = Array.prototype.slice.call(arguments, 1);
892
+ return function(){
893
+ return fn.apply(
894
+ null, args.concat(Array.prototype.slice.call(arguments))
895
+ );
896
+ };
897
+ };
898
+
899
+ var _concat = function(eachfn, arr, fn, callback){
900
+ var r = [];
901
+ eachfn(arr, function(x, cb){
902
+ fn(x, function(err, y){
903
+ r = r.concat(y || []);
904
+ cb(err);
905
+ });
906
+ }, function(err){
907
+ callback(err, r);
908
+ });
909
+ };
910
+ async.concat = doParallel(_concat);
911
+ async.concatSeries = doSeries(_concat);
912
+
913
+ var _console_fn = function(name){
914
+ return function(fn){
915
+ var args = Array.prototype.slice.call(arguments, 1);
916
+ fn.apply(null, args.concat([function(err){
917
+ var args = Array.prototype.slice.call(arguments, 1);
918
+ if(typeof console != 'undefined'){
919
+ if(err){
920
+ if(console.error) console.error(err);
921
+ }
922
+ else if(console[name]){
923
+ _forEach(args, function(x){console[name](x);});
924
+ }
925
+ }
926
+ }]));
927
+ };
928
+ };
929
+ async.log = _console_fn('log');
930
+ async.dir = _console_fn('dir');
931
+ /*async.info = _console_fn('info');
932
+ async.warn = _console_fn('warn');
933
+ async.error = _console_fn('error');*/
934
+
935
+ })();
936
+ (function(exports){
937
+ /**
938
+ * This file is based on the node.js assert module, but with some small
939
+ * changes for browser-compatibility
940
+ * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
941
+ */
942
+
943
+
944
+ /**
945
+ * Added for browser compatibility
946
+ */
947
+
948
+ var _keys = function(obj){
949
+ if(Object.keys) return Object.keys(obj);
950
+ var keys = [];
951
+ for(var k in obj){
952
+ if(obj.hasOwnProperty(k)) keys.push(k);
953
+ }
954
+ return keys;
955
+ };
956
+
957
+
958
+
959
+ // http://wiki.commonjs.org/wiki/Unit_Testing/1.0
960
+ //
961
+ // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
962
+ //
963
+ // Originally from narwhal.js (http://narwhaljs.org)
964
+ // Copyright (c) 2009 Thomas Robinson <280north.com>
965
+ //
966
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
967
+ // of this software and associated documentation files (the 'Software'), to
968
+ // deal in the Software without restriction, including without limitation the
969
+ // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
970
+ // sell copies of the Software, and to permit persons to whom the Software is
971
+ // furnished to do so, subject to the following conditions:
972
+ //
973
+ // The above copyright notice and this permission notice shall be included in
974
+ // all copies or substantial portions of the Software.
975
+ //
976
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
977
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
978
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
979
+ // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
980
+ // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
981
+ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
982
+
983
+
984
+ var pSlice = Array.prototype.slice;
985
+
986
+ // 1. The assert module provides functions that throw
987
+ // AssertionError's when particular conditions are not met. The
988
+ // assert module must conform to the following interface.
989
+
990
+ var assert = exports;
991
+
992
+ // 2. The AssertionError is defined in assert.
993
+ // new assert.AssertionError({message: message, actual: actual, expected: expected})
994
+
995
+ assert.AssertionError = function AssertionError (options) {
996
+ this.name = "AssertionError";
997
+ this.message = options.message;
998
+ this.actual = options.actual;
999
+ this.expected = options.expected;
1000
+ this.operator = options.operator;
1001
+ var stackStartFunction = options.stackStartFunction || fail;
1002
+
1003
+ if (Error.captureStackTrace) {
1004
+ Error.captureStackTrace(this, stackStartFunction);
1005
+ }
1006
+ };
1007
+ // code from util.inherits in node
1008
+ assert.AssertionError.super_ = Error;
1009
+
1010
+
1011
+ // EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call
1012
+ // TODO: test what effect this may have
1013
+ var ctor = function () { this.constructor = assert.AssertionError; };
1014
+ ctor.prototype = Error.prototype;
1015
+ assert.AssertionError.prototype = new ctor();
1016
+
1017
+
1018
+ assert.AssertionError.prototype.toString = function() {
1019
+ if (this.message) {
1020
+ return [this.name+":", this.message].join(' ');
1021
+ } else {
1022
+ return [ this.name+":"
1023
+ , JSON.stringify(this.expected )
1024
+ , this.operator
1025
+ , JSON.stringify(this.actual)
1026
+ ].join(" ");
1027
+ }
1028
+ };
1029
+
1030
+ // assert.AssertionError instanceof Error
1031
+
1032
+ assert.AssertionError.__proto__ = Error.prototype;
1033
+
1034
+ // At present only the three keys mentioned above are used and
1035
+ // understood by the spec. Implementations or sub modules can pass
1036
+ // other keys to the AssertionError's constructor - they will be
1037
+ // ignored.
1038
+
1039
+ // 3. All of the following functions must throw an AssertionError
1040
+ // when a corresponding condition is not met, with a message that
1041
+ // may be undefined if not provided. All assertion methods provide
1042
+ // both the actual and expected values to the assertion error for
1043
+ // display purposes.
1044
+
1045
+ function fail(actual, expected, message, operator, stackStartFunction) {
1046
+ throw new assert.AssertionError({
1047
+ message: message,
1048
+ actual: actual,
1049
+ expected: expected,
1050
+ operator: operator,
1051
+ stackStartFunction: stackStartFunction
1052
+ });
1053
+ }
1054
+
1055
+ // EXTENSION! allows for well behaved errors defined elsewhere.
1056
+ assert.fail = fail;
1057
+
1058
+ // 4. Pure assertion tests whether a value is truthy, as determined
1059
+ // by !!guard.
1060
+ // assert.ok(guard, message_opt);
1061
+ // This statement is equivalent to assert.equal(true, guard,
1062
+ // message_opt);. To test strictly for the value true, use
1063
+ // assert.strictEqual(true, guard, message_opt);.
1064
+
1065
+ assert.ok = function ok(value, message) {
1066
+ if (!!!value) fail(value, true, message, "==", assert.ok);
1067
+ };
1068
+
1069
+ // 5. The equality assertion tests shallow, coercive equality with
1070
+ // ==.
1071
+ // assert.equal(actual, expected, message_opt);
1072
+
1073
+ assert.equal = function equal(actual, expected, message) {
1074
+ if (actual != expected) fail(actual, expected, message, "==", assert.equal);
1075
+ };
1076
+
1077
+ // 6. The non-equality assertion tests for whether two objects are not equal
1078
+ // with != assert.notEqual(actual, expected, message_opt);
1079
+
1080
+ assert.notEqual = function notEqual(actual, expected, message) {
1081
+ if (actual == expected) {
1082
+ fail(actual, expected, message, "!=", assert.notEqual);
1083
+ }
1084
+ };
1085
+
1086
+ // 7. The equivalence assertion tests a deep equality relation.
1087
+ // assert.deepEqual(actual, expected, message_opt);
1088
+
1089
+ assert.deepEqual = function deepEqual(actual, expected, message) {
1090
+ if (!_deepEqual(actual, expected)) {
1091
+ fail(actual, expected, message, "deepEqual", assert.deepEqual);
1092
+ }
1093
+ };
1094
+
1095
+ function _deepEqual(actual, expected) {
1096
+ // 7.1. All identical values are equivalent, as determined by ===.
1097
+ if (actual === expected) {
1098
+ return true;
1099
+
1100
+ } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
1101
+ if (actual.length != expected.length) return false;
1102
+
1103
+ for (var i = 0; i < actual.length; i++) {
1104
+ if (actual[i] !== expected[i]) return false;
1105
+ }
1106
+
1107
+ return true;
1108
+
1109
+ // 7.2. If the expected value is a Date object, the actual value is
1110
+ // equivalent if it is also a Date object that refers to the same time.
1111
+ } else if (actual instanceof Date && expected instanceof Date) {
1112
+ return actual.getTime() === expected.getTime();
1113
+
1114
+ // 7.3. Other pairs that do not both pass typeof value == "object",
1115
+ // equivalence is determined by ==.
1116
+ } else if (typeof actual != 'object' && typeof expected != 'object') {
1117
+ return actual == expected;
1118
+
1119
+ // 7.4. For all other Object pairs, including Array objects, equivalence is
1120
+ // determined by having the same number of owned properties (as verified
1121
+ // with Object.prototype.hasOwnProperty.call), the same set of keys
1122
+ // (although not necessarily the same order), equivalent values for every
1123
+ // corresponding key, and an identical "prototype" property. Note: this
1124
+ // accounts for both named and indexed properties on Arrays.
1125
+ } else {
1126
+ return objEquiv(actual, expected);
1127
+ }
1128
+ }
1129
+
1130
+ function isUndefinedOrNull (value) {
1131
+ return value === null || value === undefined;
1132
+ }
1133
+
1134
+ function isArguments (object) {
1135
+ return Object.prototype.toString.call(object) == '[object Arguments]';
1136
+ }
1137
+
1138
+ function objEquiv (a, b) {
1139
+ if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
1140
+ return false;
1141
+ // an identical "prototype" property.
1142
+ if (a.prototype !== b.prototype) return false;
1143
+ //~~~I've managed to break Object.keys through screwy arguments passing.
1144
+ // Converting to array solves the problem.
1145
+ if (isArguments(a)) {
1146
+ if (!isArguments(b)) {
1147
+ return false;
1148
+ }
1149
+ a = pSlice.call(a);
1150
+ b = pSlice.call(b);
1151
+ return _deepEqual(a, b);
1152
+ }
1153
+ try{
1154
+ var ka = _keys(a),
1155
+ kb = _keys(b),
1156
+ key, i;
1157
+ } catch (e) {//happens when one is a string literal and the other isn't
1158
+ return false;
1159
+ }
1160
+ // having the same number of owned properties (keys incorporates hasOwnProperty)
1161
+ if (ka.length != kb.length)
1162
+ return false;
1163
+ //the same set of keys (although not necessarily the same order),
1164
+ ka.sort();
1165
+ kb.sort();
1166
+ //~~~cheap key test
1167
+ for (i = ka.length - 1; i >= 0; i--) {
1168
+ if (ka[i] != kb[i])
1169
+ return false;
1170
+ }
1171
+ //equivalent values for every corresponding key, and
1172
+ //~~~possibly expensive deep test
1173
+ for (i = ka.length - 1; i >= 0; i--) {
1174
+ key = ka[i];
1175
+ if (!_deepEqual(a[key], b[key] ))
1176
+ return false;
1177
+ }
1178
+ return true;
1179
+ }
1180
+
1181
+ // 8. The non-equivalence assertion tests for any deep inequality.
1182
+ // assert.notDeepEqual(actual, expected, message_opt);
1183
+
1184
+ assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
1185
+ if (_deepEqual(actual, expected)) {
1186
+ fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual);
1187
+ }
1188
+ };
1189
+
1190
+ // 9. The strict equality assertion tests strict equality, as determined by ===.
1191
+ // assert.strictEqual(actual, expected, message_opt);
1192
+
1193
+ assert.strictEqual = function strictEqual(actual, expected, message) {
1194
+ if (actual !== expected) {
1195
+ fail(actual, expected, message, "===", assert.strictEqual);
1196
+ }
1197
+ };
1198
+
1199
+ // 10. The strict non-equality assertion tests for strict inequality, as determined by !==.
1200
+ // assert.notStrictEqual(actual, expected, message_opt);
1201
+
1202
+ assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
1203
+ if (actual === expected) {
1204
+ fail(actual, expected, message, "!==", assert.notStrictEqual);
1205
+ }
1206
+ };
1207
+
1208
+ function _throws (shouldThrow, block, err, message) {
1209
+ var exception = null,
1210
+ threw = false,
1211
+ typematters = true;
1212
+
1213
+ message = message || "";
1214
+
1215
+ //handle optional arguments
1216
+ if (arguments.length == 3) {
1217
+ if (typeof(err) == "string") {
1218
+ message = err;
1219
+ typematters = false;
1220
+ }
1221
+ } else if (arguments.length == 2) {
1222
+ typematters = false;
1223
+ }
1224
+
1225
+ try {
1226
+ block();
1227
+ } catch (e) {
1228
+ threw = true;
1229
+ exception = e;
1230
+ }
1231
+
1232
+ if (shouldThrow && !threw) {
1233
+ fail( "Missing expected exception"
1234
+ + (err && err.name ? " ("+err.name+")." : '.')
1235
+ + (message ? " " + message : "")
1236
+ );
1237
+ }
1238
+ if (!shouldThrow && threw && typematters && exception instanceof err) {
1239
+ fail( "Got unwanted exception"
1240
+ + (err && err.name ? " ("+err.name+")." : '.')
1241
+ + (message ? " " + message : "")
1242
+ );
1243
+ }
1244
+ if ((shouldThrow && threw && typematters && !(exception instanceof err)) ||
1245
+ (!shouldThrow && threw)) {
1246
+ throw exception;
1247
+ }
1248
+ };
1249
+
1250
+ // 11. Expected to throw an error:
1251
+ // assert.throws(block, Error_opt, message_opt);
1252
+
1253
+ assert.throws = function(block, /*optional*/error, /*optional*/message) {
1254
+ _throws.apply(this, [true].concat(pSlice.call(arguments)));
1255
+ };
1256
+
1257
+ // EXTENSION! This is annoying to write outside this module.
1258
+ assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
1259
+ _throws.apply(this, [false].concat(pSlice.call(arguments)));
1260
+ };
1261
+
1262
+ assert.ifError = function (err) { if (err) {throw err;}};
1263
+ })(assert);
1264
+ (function(exports){
1265
+ /*!
1266
+ * Nodeunit
1267
+ * Copyright (c) 2010 Caolan McMahon
1268
+ * MIT Licensed
1269
+ *
1270
+ * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
1271
+ * Only code on that line will be removed, its mostly to avoid requiring code
1272
+ * that is node specific
1273
+ */
1274
+
1275
+ /**
1276
+ * Module dependencies
1277
+ */
1278
+
1279
+
1280
+
1281
+ /**
1282
+ * Creates assertion objects representing the result of an assert call.
1283
+ * Accepts an object or AssertionError as its argument.
1284
+ *
1285
+ * @param {object} obj
1286
+ * @api public
1287
+ */
1288
+
1289
+ exports.assertion = function (obj) {
1290
+ return {
1291
+ method: obj.method || '',
1292
+ message: obj.message || (obj.error && obj.error.message) || '',
1293
+ error: obj.error,
1294
+ passed: function () {
1295
+ return !this.error;
1296
+ },
1297
+ failed: function () {
1298
+ return Boolean(this.error);
1299
+ }
1300
+ };
1301
+ };
1302
+
1303
+ /**
1304
+ * Creates an assertion list object representing a group of assertions.
1305
+ * Accepts an array of assertion objects.
1306
+ *
1307
+ * @param {Array} arr
1308
+ * @param {Number} duration
1309
+ * @api public
1310
+ */
1311
+
1312
+ exports.assertionList = function (arr, duration) {
1313
+ var that = arr || [];
1314
+ that.failures = function () {
1315
+ var failures = 0;
1316
+ for (var i=0; i<this.length; i++) {
1317
+ if (this[i].failed()) failures++;
1318
+ }
1319
+ return failures;
1320
+ };
1321
+ that.duration = duration || 0;
1322
+ return that;
1323
+ };
1324
+
1325
+ /**
1326
+ * Create a wrapper function for assert module methods. Executes a callback
1327
+ * after the it's complete with an assertion object representing the result.
1328
+ *
1329
+ * @param {Function} callback
1330
+ * @api private
1331
+ */
1332
+
1333
+ var assertWrapper = function (callback) {
1334
+ return function (new_method, assert_method, arity) {
1335
+ return function () {
1336
+ var message = arguments[arity-1];
1337
+ var a = exports.assertion({method: new_method, message: message});
1338
+ try {
1339
+ assert[assert_method].apply(null, arguments);
1340
+ }
1341
+ catch (e) {
1342
+ a.error = e;
1343
+ }
1344
+ callback(a);
1345
+ };
1346
+ };
1347
+ };
1348
+
1349
+ /**
1350
+ * Creates the 'test' object that gets passed to every test function.
1351
+ * Accepts the name of the test function as its first argument, followed by
1352
+ * the start time in ms, the options object and a callback function.
1353
+ *
1354
+ * @param {String} name
1355
+ * @param {Number} start
1356
+ * @param {Object} options
1357
+ * @param {Function} callback
1358
+ * @api public
1359
+ */
1360
+
1361
+ exports.test = function (name, start, options, callback) {
1362
+ var expecting;
1363
+ var a_list = [];
1364
+
1365
+ var wrapAssert = assertWrapper(function (a) {
1366
+ a_list.push(a);
1367
+ async.nextTick(function () {
1368
+ options.log(a);
1369
+ });
1370
+ });
1371
+
1372
+ var test = {
1373
+ done: function (err) {
1374
+ if (expecting !== undefined && expecting !== a_list.length) {
1375
+ var e = new Error(
1376
+ 'Expected ' + expecting + ' assertions, ' +
1377
+ a_list.length + ' ran'
1378
+ );
1379
+ var a1 = exports.assertion({method: 'expect', error: e});
1380
+ a_list.push(a1);
1381
+ async.nextTick(function () {
1382
+ options.log(a1);
1383
+ });
1384
+ }
1385
+ if (err) {
1386
+ var a2 = exports.assertion({error: err});
1387
+ a_list.push(a2);
1388
+ async.nextTick(function () {
1389
+ options.log(a2);
1390
+ });
1391
+ }
1392
+ var end = new Date().getTime();
1393
+ async.nextTick(function () {
1394
+ var assertion_list = exports.assertionList(a_list, end - start);
1395
+ options.testDone(name, assertion_list);
1396
+ callback(null, a_list);
1397
+ });
1398
+ },
1399
+ ok: wrapAssert('ok', 'ok', 2),
1400
+ same: wrapAssert('same', 'deepEqual', 3),
1401
+ equals: wrapAssert('equals', 'equal', 3),
1402
+ expect: function (num) {
1403
+ expecting = num;
1404
+ },
1405
+ _assertion_list: a_list
1406
+ };
1407
+ // add all functions from the assert module
1408
+ for (var k in assert) {
1409
+ if (assert.hasOwnProperty(k)) {
1410
+ test[k] = wrapAssert(k, k, assert[k].length);
1411
+ }
1412
+ }
1413
+ return test;
1414
+ };
1415
+
1416
+ /**
1417
+ * Ensures an options object has all callbacks, adding empty callback functions
1418
+ * if any are missing.
1419
+ *
1420
+ * @param {Object} opt
1421
+ * @return {Object}
1422
+ * @api public
1423
+ */
1424
+
1425
+ exports.options = function (opt) {
1426
+ var optionalCallback = function (name) {
1427
+ opt[name] = opt[name] || function () {};
1428
+ };
1429
+
1430
+ optionalCallback('moduleStart');
1431
+ optionalCallback('moduleDone');
1432
+ optionalCallback('testStart');
1433
+ optionalCallback('testDone');
1434
+ optionalCallback('log');
1435
+
1436
+ // 'done' callback is not optional.
1437
+
1438
+ return opt;
1439
+ };
1440
+ })(types);
1441
+ (function(exports){
1442
+ /*!
1443
+ * Nodeunit
1444
+ * Copyright (c) 2010 Caolan McMahon
1445
+ * MIT Licensed
1446
+ *
1447
+ * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
1448
+ * Only code on that line will be removed, its mostly to avoid requiring code
1449
+ * that is node specific
1450
+ */
1451
+
1452
+ /**
1453
+ * Module dependencies
1454
+ */
1455
+
1456
+
1457
+
1458
+ /**
1459
+ * Added for browser compatibility
1460
+ */
1461
+
1462
+ var _keys = function(obj){
1463
+ if(Object.keys) return Object.keys(obj);
1464
+ var keys = [];
1465
+ for(var k in obj){
1466
+ if(obj.hasOwnProperty(k)) keys.push(k);
1467
+ }
1468
+ return keys;
1469
+ };
1470
+
1471
+
1472
+ /**
1473
+ * Runs a test function (fn) from a loaded module. After the test function
1474
+ * calls test.done(), the callback is executed with an assertionList as its
1475
+ * second argument.
1476
+ *
1477
+ * @param {String} name
1478
+ * @param {Function} fn
1479
+ * @param {Object} opt
1480
+ * @param {Function} callback
1481
+ * @api public
1482
+ */
1483
+
1484
+ exports.runTest = function (name, fn, opt, callback) {
1485
+ var options = types.options(opt);
1486
+
1487
+ options.testStart(name);
1488
+ var start = new Date().getTime();
1489
+ var test = types.test(name, start, options, callback);
1490
+
1491
+ try {
1492
+ fn(test);
1493
+ }
1494
+ catch (e) {
1495
+ test.done(e);
1496
+ }
1497
+ };
1498
+
1499
+ /**
1500
+ * Takes an object containing test functions or other test suites as properties
1501
+ * and runs each in series. After all tests have completed, the callback is
1502
+ * called with a list of all assertions as the second argument.
1503
+ *
1504
+ * If a name is passed to this function it is prepended to all test and suite
1505
+ * names that run within it.
1506
+ *
1507
+ * @param {String} name
1508
+ * @param {Object} suite
1509
+ * @param {Object} opt
1510
+ * @param {Function} callback
1511
+ * @api public
1512
+ */
1513
+
1514
+ exports.runSuite = function (name, suite, opt, callback) {
1515
+ var keys = _keys(suite);
1516
+
1517
+ async.concatSeries(keys, function (k, cb) {
1518
+ var prop = suite[k], _name;
1519
+
1520
+ _name = name ? [].concat(name, k) : [k];
1521
+
1522
+ _name.toString = function () {
1523
+ // fallback for old one
1524
+ return this.join(' - ');
1525
+ };
1526
+
1527
+ if (typeof prop === 'function') {
1528
+ exports.runTest(_name, suite[k], opt, cb);
1529
+ }
1530
+ else {
1531
+ exports.runSuite(_name, suite[k], opt, cb);
1532
+ }
1533
+ }, callback);
1534
+ };
1535
+
1536
+ /**
1537
+ * Run each exported test function or test suite from a loaded module.
1538
+ *
1539
+ * @param {String} name
1540
+ * @param {Object} mod
1541
+ * @param {Object} opt
1542
+ * @param {Function} callback
1543
+ * @api public
1544
+ */
1545
+
1546
+ exports.runModule = function (name, mod, opt, callback) {
1547
+ var options = types.options(opt);
1548
+
1549
+ options.moduleStart(name);
1550
+ var start = new Date().getTime();
1551
+
1552
+ exports.runSuite(null, mod, opt, function (err, a_list) {
1553
+ var end = new Date().getTime();
1554
+ var assertion_list = types.assertionList(a_list, end - start);
1555
+ options.moduleDone(name, assertion_list);
1556
+ callback(null, a_list);
1557
+ });
1558
+ };
1559
+
1560
+ /**
1561
+ * Treats an object literal as a list of modules keyed by name. Runs each
1562
+ * module and finished with calling 'done'. You can think of this as a browser
1563
+ * safe alternative to runFiles in the nodeunit module.
1564
+ *
1565
+ * @param {Object} modules
1566
+ * @param {Object} opt
1567
+ * @api public
1568
+ */
1569
+
1570
+ // TODO: add proper unit tests for this function
1571
+ exports.runModules = function (modules, opt) {
1572
+ var all_assertions = [];
1573
+ var options = types.options(opt);
1574
+ var start = new Date().getTime();
1575
+
1576
+ async.concatSeries(_keys(modules), function (k, cb) {
1577
+ exports.runModule(k, modules[k], options, cb);
1578
+ },
1579
+ function (err, all_assertions) {
1580
+ var end = new Date().getTime();
1581
+ options.done(types.assertionList(all_assertions, end - start));
1582
+ });
1583
+ };
1584
+
1585
+
1586
+ /**
1587
+ * Utility for wrapping a suite of test functions with setUp and tearDown
1588
+ * functions.
1589
+ *
1590
+ * @param {Object} suite
1591
+ * @return {Object}
1592
+ * @api public
1593
+ */
1594
+
1595
+ exports.testCase = function (suite) {
1596
+ var tests = {};
1597
+
1598
+ var setUp = suite.setUp;
1599
+ var tearDown = suite.tearDown;
1600
+ delete suite.setUp;
1601
+ delete suite.tearDown;
1602
+
1603
+ var keys = _keys(suite);
1604
+
1605
+ // TODO: replace reduce here with browser-safe alternative
1606
+ return keys.reduce(function (tests, k) {
1607
+ tests[k] = function (test) {
1608
+ var context = {};
1609
+ if (tearDown) {
1610
+ var done = test.done;
1611
+ test.done = function (err) {
1612
+ try {
1613
+ tearDown.call(context, function (err2) {
1614
+ if (err && err2) {
1615
+ test._assertion_list.push(
1616
+ types.assertion({error: err})
1617
+ );
1618
+ return done(err2);
1619
+ }
1620
+ done(err || err2);
1621
+ });
1622
+ }
1623
+ catch (e) {
1624
+ done(e);
1625
+ }
1626
+ };
1627
+ }
1628
+ if (setUp) {
1629
+ setUp.call(context, function (err) {
1630
+ if (err) {
1631
+ return test.done(err);
1632
+ }
1633
+ suite[k].call(context, test);
1634
+ });
1635
+ }
1636
+ else {
1637
+ suite[k].call(context, test);
1638
+ }
1639
+ };
1640
+
1641
+ return tests;
1642
+ }, {});
1643
+ };
1644
+ })(core);
1645
+ (function(exports){
1646
+ /*!
1647
+ * Nodeunit
1648
+ * Copyright (c) 2010 Caolan McMahon
1649
+ * MIT Licensed
1650
+ *
1651
+ * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
1652
+ * Only code on that line will be removed, its mostly to avoid requiring code
1653
+ * that is node specific
1654
+ */
1655
+
1656
+
1657
+ /**
1658
+ * NOTE: this test runner is not listed in index.js because it cannot be
1659
+ * used with the command-line tool, only inside the browser.
1660
+ */
1661
+
1662
+
1663
+ /**
1664
+ * Reporter info string
1665
+ */
1666
+
1667
+ exports.info = "Browser-based test reporter";
1668
+
1669
+
1670
+ exports.addStyles = function () {
1671
+ document.body.innerHTML += '<style type="text/css">' +
1672
+ 'body { font: 12px Helvetica Neue }' +
1673
+ 'h2 { margin:0 ; padding:0 }' +
1674
+ 'pre {' +
1675
+ 'font: 11px Andale Mono;' +
1676
+ 'margin-left: 1em;' +
1677
+ 'padding-left: 1em;' +
1678
+ 'margin-top: 0;' +
1679
+ 'font-size:smaller;' +
1680
+ '}' +
1681
+ '.assertion_message { margin-left: 1em; }' +
1682
+ ' ol {' +
1683
+ 'list-style: none;' +
1684
+ 'margin-left: 1em;' +
1685
+ 'padding-left: 1em;' +
1686
+ 'text-indent: -1em;' +
1687
+ '}' +
1688
+ ' ol li.pass:before { content: "\\2714 \\0020"; }' +
1689
+ ' ol li.fail:before { content: "\\2716 \\0020"; }' +
1690
+ '</style>';
1691
+ };
1692
+
1693
+
1694
+ /**
1695
+ * Run all tests within each module, reporting the results
1696
+ *
1697
+ * @param {Array} files
1698
+ * @api public
1699
+ */
1700
+
1701
+ exports.run = function (modules, options) {
1702
+ var start = new Date().getTime();
1703
+ exports.addStyles();
1704
+
1705
+ var html = '';
1706
+ nodeunit.runModules(modules, {
1707
+ moduleStart: function (name) {
1708
+ html += '<h2>' + name + '</h2>';
1709
+ html += '<ol>';
1710
+ },
1711
+ testDone: function (name, assertions) {
1712
+ if (!assertions.failures()) {
1713
+ html += '<li class="pass">' + name + '</li>';
1714
+ }
1715
+ else {
1716
+ html += '<li class="fail">' + name;
1717
+ for (var i=0; i<assertions.length; i++) {
1718
+ var a = assertions[i];
1719
+ if (a.failed()) {
1720
+ if (a.error instanceof assert.AssertionError && a.message) {
1721
+ html += '<div class="assertion_message">' +
1722
+ 'Assertion Message: ' + a.message +
1723
+ '</div>';
1724
+ }
1725
+ html += '<pre>';
1726
+ html += a.error.stack || a.error;
1727
+ html += '</pre>';
1728
+ }
1729
+ };
1730
+ html += '</li>';
1731
+ }
1732
+ },
1733
+ moduleDone: function () {
1734
+ html += '</ol>';
1735
+ },
1736
+ done: function (assertions) {
1737
+ var end = new Date().getTime();
1738
+ var duration = end - start;
1739
+ if (assertions.failures()) {
1740
+ html += '<h3>FAILURES: ' + assertions.failures() +
1741
+ '/' + assertions.length + ' assertions failed (' +
1742
+ assertions.duration + 'ms)</h3>';
1743
+ }
1744
+ else {
1745
+ html += '<h3>OK: ' + assertions.length +
1746
+ ' assertions (' + assertions.duration + 'ms)</h3>';
1747
+ }
1748
+ document.body.innerHTML += html;
1749
+ }
1750
+ });
1751
+ };
1752
+ })(reporter);
1753
+ nodeunit = core;
1754
+ nodeunit.assert = assert;
1755
+ nodeunit.reporter = reporter;
1756
+ nodeunit.run = reporter.run;
1757
+ return nodeunit; })();