twigg-app 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (208) hide show
  1. checksums.yaml +4 -4
  2. data/assets/javascripts/_bootstrap.js +7 -0
  3. data/assets/javascripts/_jquery.js +19 -0
  4. data/assets/javascripts/_tables.js +3 -0
  5. data/assets/javascripts/_views.js +10 -0
  6. data/assets/javascripts/application.js +9 -0
  7. data/{public/application.js → assets/javascripts/views/_commit_set_bar_chart.js} +32 -34
  8. data/assets/javascripts/views/_russia.js +61 -0
  9. data/assets/javascripts/views/_tags.js +56 -0
  10. data/assets/javascripts/views/_tags_word_cloud.js +51 -0
  11. data/assets/stylesheets/_bootstrap_overrides.scss +15 -0
  12. data/assets/stylesheets/_footer.scss +28 -0
  13. data/assets/stylesheets/_global.scss +14 -0
  14. data/assets/stylesheets/_tables.scss +20 -0
  15. data/assets/stylesheets/application.scss +10 -0
  16. data/assets/stylesheets/d3/_bar_chart.scss +25 -0
  17. data/assets/stylesheets/d3/_bubble_chart.scss +22 -0
  18. data/lib/twigg-app/app/routes.rb +4 -0
  19. data/lib/twigg-app/app/server.rb +78 -21
  20. data/lib/twigg-app/app/version.rb +1 -1
  21. data/public/vendor/bootstrap/Gruntfile.js +32 -10
  22. data/public/vendor/bootstrap/README.md +2 -0
  23. data/public/vendor/bootstrap/_config.yml +5 -10
  24. data/public/vendor/bootstrap/_includes/footer.html +2 -1
  25. data/public/vendor/bootstrap/_includes/nav-components.html +33 -31
  26. data/public/vendor/bootstrap/_includes/nav-css.html +32 -22
  27. data/public/vendor/bootstrap/_includes/nav-getting-started.html +17 -1
  28. data/public/vendor/bootstrap/_includes/nav-javascript.html +1 -1
  29. data/public/vendor/bootstrap/_includes/nav-main.html +1 -1
  30. data/public/vendor/bootstrap/_includes/social-buttons.html +1 -1
  31. data/public/vendor/bootstrap/_layouts/default.html +18 -14
  32. data/public/vendor/bootstrap/_layouts/home.html +9 -6
  33. data/public/vendor/bootstrap/assets/css/docs.css +584 -396
  34. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
  35. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
  36. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
  37. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
  38. data/public/vendor/bootstrap/assets/ico/favicon.png +0 -0
  39. data/public/vendor/bootstrap/assets/js/application.js +2 -1
  40. data/public/vendor/bootstrap/assets/js/customizer.js +160 -45
  41. data/public/vendor/bootstrap/assets/js/filesaver.js +169 -0
  42. data/public/vendor/bootstrap/assets/js/jquery.js +6 -5
  43. data/public/vendor/bootstrap/assets/js/raw-files.js +3 -0
  44. data/public/vendor/bootstrap/bower.json +1 -1
  45. data/public/vendor/bootstrap/components.html +787 -364
  46. data/public/vendor/bootstrap/composer.json +1 -1
  47. data/public/vendor/bootstrap/css.html +413 -248
  48. data/public/vendor/bootstrap/customize.html +413 -447
  49. data/public/vendor/bootstrap/dist/css/bootstrap-theme.css +384 -0
  50. data/public/vendor/bootstrap/dist/css/bootstrap-theme.min.css +1 -0
  51. data/public/vendor/bootstrap/dist/css/bootstrap.css +3033 -1807
  52. data/public/vendor/bootstrap/dist/css/bootstrap.min.css +1 -1
  53. data/public/vendor/bootstrap/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  54. data/public/vendor/bootstrap/dist/fonts/glyphicons-halflings-regular.svg +228 -0
  55. data/public/vendor/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  56. data/public/vendor/bootstrap/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  57. data/public/vendor/bootstrap/dist/js/bootstrap.js +18 -12
  58. data/public/vendor/bootstrap/dist/js/bootstrap.min.js +1 -1
  59. data/public/vendor/bootstrap/examples/carousel/carousel.css +128 -0
  60. data/public/vendor/bootstrap/examples/carousel/index.html +201 -0
  61. data/public/vendor/bootstrap/examples/grid/grid.css +28 -0
  62. data/public/vendor/bootstrap/examples/grid/index.html +119 -0
  63. data/public/vendor/bootstrap/examples/jumbotron/index.html +111 -0
  64. data/public/vendor/bootstrap/examples/jumbotron/jumbotron.css +5 -0
  65. data/public/vendor/bootstrap/examples/jumbotron-narrow/index.html +78 -0
  66. data/public/vendor/bootstrap/examples/jumbotron-narrow/jumbotron-narrow.css +79 -0
  67. data/public/vendor/bootstrap/examples/justified-nav/index.html +79 -0
  68. data/public/vendor/bootstrap/examples/justified-nav/justified-nav.css +88 -0
  69. data/public/vendor/bootstrap/examples/navbar/index.html +83 -0
  70. data/public/vendor/bootstrap/examples/navbar/navbar.css +7 -0
  71. data/public/vendor/bootstrap/examples/navbar-fixed-top/index.html +86 -0
  72. data/public/vendor/bootstrap/examples/navbar-fixed-top/navbar-fixed-top.css +4 -0
  73. data/public/vendor/bootstrap/examples/navbar-static-top/index.html +87 -0
  74. data/public/vendor/bootstrap/examples/navbar-static-top/navbar-static-top.css +7 -0
  75. data/public/vendor/bootstrap/examples/non-responsive/index.html +96 -0
  76. data/public/vendor/bootstrap/examples/non-responsive/non-responsive.css +117 -0
  77. data/public/vendor/bootstrap/examples/offcanvas/index.html +127 -0
  78. data/public/vendor/bootstrap/examples/offcanvas/offcanvas.css +48 -0
  79. data/public/vendor/bootstrap/examples/offcanvas/offcanvas.js +5 -0
  80. data/public/vendor/bootstrap/examples/screenshots/carousel.jpg +0 -0
  81. data/public/vendor/bootstrap/examples/screenshots/grid.jpg +0 -0
  82. data/public/vendor/bootstrap/examples/screenshots/jumbotron-narrow.jpg +0 -0
  83. data/public/vendor/bootstrap/examples/screenshots/jumbotron.jpg +0 -0
  84. data/public/vendor/bootstrap/examples/screenshots/justified-nav.jpg +0 -0
  85. data/public/vendor/bootstrap/examples/screenshots/navbar-fixed.jpg +0 -0
  86. data/public/vendor/bootstrap/examples/screenshots/navbar-static.jpg +0 -0
  87. data/public/vendor/bootstrap/examples/screenshots/navbar.jpg +0 -0
  88. data/public/vendor/bootstrap/examples/screenshots/non-responsive.jpg +0 -0
  89. data/public/vendor/bootstrap/examples/screenshots/offcanvas.jpg +0 -0
  90. data/public/vendor/bootstrap/examples/screenshots/sign-in.jpg +0 -0
  91. data/public/vendor/bootstrap/examples/screenshots/starter-template.jpg +0 -0
  92. data/public/vendor/bootstrap/examples/screenshots/sticky-footer-navbar.jpg +0 -0
  93. data/public/vendor/bootstrap/examples/screenshots/sticky-footer.jpg +0 -0
  94. data/public/vendor/bootstrap/examples/screenshots/theme.jpg +0 -0
  95. data/public/vendor/bootstrap/examples/signin/index.html +46 -0
  96. data/public/vendor/bootstrap/examples/signin/signin.css +40 -0
  97. data/public/vendor/bootstrap/examples/starter-template/index.html +63 -0
  98. data/public/vendor/bootstrap/examples/starter-template/starter-template.css +7 -0
  99. data/public/vendor/bootstrap/examples/sticky-footer/index.html +51 -0
  100. data/public/vendor/bootstrap/examples/sticky-footer/sticky-footer.css +39 -0
  101. data/public/vendor/bootstrap/examples/sticky-footer-navbar/index.html +86 -0
  102. data/public/vendor/bootstrap/examples/sticky-footer-navbar/sticky-footer-navbar.css +46 -0
  103. data/public/vendor/bootstrap/examples/theme/index.html +387 -0
  104. data/public/vendor/bootstrap/examples/theme/theme.css +14 -0
  105. data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
  106. data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.svg +228 -0
  107. data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
  108. data/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
  109. data/public/vendor/bootstrap/getting-started.html +513 -22
  110. data/public/vendor/bootstrap/index.html +3 -4
  111. data/public/vendor/bootstrap/javascript.html +123 -115
  112. data/public/vendor/bootstrap/js/dropdown.js +3 -3
  113. data/public/vendor/bootstrap/js/modal.js +5 -3
  114. data/public/vendor/bootstrap/js/tests/unit/modal.js +19 -0
  115. data/public/vendor/bootstrap/js/tests/vendor/jquery.js +6 -5
  116. data/public/vendor/bootstrap/js/tooltip.js +9 -5
  117. data/public/vendor/bootstrap/js/transition.js +1 -1
  118. data/public/vendor/bootstrap/less/alerts.less +7 -11
  119. data/public/vendor/bootstrap/less/bootstrap.less +17 -21
  120. data/public/vendor/bootstrap/less/button-groups.less +14 -10
  121. data/public/vendor/bootstrap/less/buttons.less +3 -2
  122. data/public/vendor/bootstrap/less/carousel.less +6 -1
  123. data/public/vendor/bootstrap/less/dropdowns.less +22 -5
  124. data/public/vendor/bootstrap/less/forms.less +36 -15
  125. data/public/vendor/bootstrap/less/glyphicons.less +232 -0
  126. data/public/vendor/bootstrap/less/grid.less +9 -3
  127. data/public/vendor/bootstrap/less/input-groups.less +1 -1
  128. data/public/vendor/bootstrap/less/jumbotron.less +16 -5
  129. data/public/vendor/bootstrap/less/labels.less +9 -5
  130. data/public/vendor/bootstrap/less/mixins.less +73 -43
  131. data/public/vendor/bootstrap/less/modals.less +8 -0
  132. data/public/vendor/bootstrap/less/navbar.less +251 -189
  133. data/public/vendor/bootstrap/less/navs.less +13 -12
  134. data/public/vendor/bootstrap/less/pager.less +1 -1
  135. data/public/vendor/bootstrap/less/pagination.less +20 -9
  136. data/public/vendor/bootstrap/less/panels.less +28 -8
  137. data/public/vendor/bootstrap/less/progress-bars.less +6 -10
  138. data/public/vendor/bootstrap/less/responsive-utilities.less +120 -49
  139. data/public/vendor/bootstrap/less/scaffolding.less +37 -18
  140. data/public/vendor/bootstrap/less/tables.less +84 -59
  141. data/public/vendor/bootstrap/less/theme.less +232 -0
  142. data/public/vendor/bootstrap/less/thumbnails.less +8 -19
  143. data/public/vendor/bootstrap/less/type.less +2 -2
  144. data/public/vendor/bootstrap/less/variables.less +63 -50
  145. data/public/vendor/bootstrap/package.json +2 -1
  146. data/public/vendor/components-backbone/LICENSE +22 -0
  147. data/public/vendor/components-backbone/README.md +10 -0
  148. data/public/vendor/components-backbone/backbone-min.js +4 -0
  149. data/public/vendor/components-backbone/backbone.js +1571 -0
  150. data/public/vendor/components-backbone/bower.json +17 -0
  151. data/public/vendor/components-backbone/component.json +21 -0
  152. data/public/vendor/components-backbone/composer.json +37 -0
  153. data/public/vendor/components-backbone/package.json +24 -0
  154. data/public/vendor/d3.layout.cloud.js +401 -0
  155. data/public/vendor/replacejs/CHANGELOG.md +4 -0
  156. data/public/vendor/replacejs/replace.js +21 -2
  157. data/public/vendor/underscore/CNAME +1 -0
  158. data/public/vendor/underscore/CONTRIBUTING.md +9 -0
  159. data/public/vendor/underscore/LICENSE +22 -0
  160. data/public/vendor/underscore/README.md +19 -0
  161. data/public/vendor/underscore/Rakefile +10 -0
  162. data/public/vendor/underscore/docs/docco.css +192 -0
  163. data/public/vendor/underscore/docs/favicon.ico +0 -0
  164. data/public/vendor/underscore/docs/images/background.png +0 -0
  165. data/public/vendor/underscore/docs/images/underscore.png +0 -0
  166. data/public/vendor/underscore/docs/underscore.html +823 -0
  167. data/public/vendor/underscore/favicon.ico +0 -0
  168. data/public/vendor/underscore/index.html +2467 -0
  169. data/public/vendor/underscore/index.js +1 -0
  170. data/public/vendor/underscore/package.json +16 -0
  171. data/public/vendor/underscore/test/arrays.js +200 -0
  172. data/public/vendor/underscore/test/chaining.js +59 -0
  173. data/public/vendor/underscore/test/collections.js +453 -0
  174. data/public/vendor/underscore/test/functions.js +265 -0
  175. data/public/vendor/underscore/test/index.html +44 -0
  176. data/public/vendor/underscore/test/objects.js +570 -0
  177. data/public/vendor/underscore/test/speed.js +75 -0
  178. data/public/vendor/underscore/test/utility.js +266 -0
  179. data/public/vendor/underscore/test/vendor/jquery.js +9404 -0
  180. data/public/vendor/underscore/test/vendor/jslitmus.js +670 -0
  181. data/public/vendor/underscore/test/vendor/qunit.css +235 -0
  182. data/public/vendor/underscore/test/vendor/qunit.js +1977 -0
  183. data/public/vendor/underscore/test/vendor/runner.js +98 -0
  184. data/public/vendor/underscore/underscore-min.js +1 -0
  185. data/public/vendor/underscore/underscore.js +1226 -0
  186. data/views/dashboard.haml +1 -1
  187. data/views/layout.haml +8 -4
  188. metadata +132 -25
  189. data/public/vendor/bootstrap/_layouts/customize.html +0 -52
  190. data/public/vendor/bootstrap/assets/js/jquery.bbq.min.js +0 -1287
  191. data/public/vendor/bootstrap-glyphicons/CHANGELOG.md +0 -3
  192. data/public/vendor/bootstrap-glyphicons/CNAME +0 -1
  193. data/public/vendor/bootstrap-glyphicons/CONTRIBUTING.md +0 -54
  194. data/public/vendor/bootstrap-glyphicons/LICENSE +0 -19
  195. data/public/vendor/bootstrap-glyphicons/README.md +0 -61
  196. data/public/vendor/bootstrap-glyphicons/_config.yml +0 -12
  197. data/public/vendor/bootstrap-glyphicons/composer.json +0 -9
  198. data/public/vendor/bootstrap-glyphicons/css/bootstrap-glyphicons.css +0 -2
  199. data/public/vendor/bootstrap-glyphicons/css/bootstrap.css +0 -9
  200. data/public/vendor/bootstrap-glyphicons/css/docs.css +0 -160
  201. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.eot +0 -0
  202. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.otf +0 -0
  203. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.svg +0 -175
  204. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.ttf +0 -0
  205. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.woff +0 -0
  206. data/public/vendor/bootstrap-glyphicons/index.html +0 -255
  207. data/public/vendor/bootstrap-glyphicons/less/bootstrap-glyphicons.less +0 -201
  208. data/public/vendor/bootstrap-glyphicons/package.json +0 -18
@@ -0,0 +1,670 @@
1
+ // JSLitmus.js
2
+ //
3
+ // History:
4
+ // 2008-10-27: Initial release
5
+ // 2008-11-09: Account for iteration loop overhead
6
+ // 2008-11-13: Added OS detection
7
+ // 2009-02-25: Create tinyURL automatically, shift-click runs tests in reverse
8
+ //
9
+ // Copyright (c) 2008-2009, Robert Kieffer
10
+ // All Rights Reserved
11
+ //
12
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ // of this software and associated documentation files (the
14
+ // Software), to deal in the Software without restriction, including
15
+ // without limitation the rights to use, copy, modify, merge, publish,
16
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
17
+ // persons to whom the Software is furnished to do so, subject to the
18
+ // following conditions:
19
+ //
20
+ // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
21
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
23
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
24
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
26
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+
28
+ (function() {
29
+ // Private methods and state
30
+
31
+ // Get platform info but don't go crazy trying to recognize everything
32
+ // that's out there. This is just for the major platforms and OSes.
33
+ var platform = 'unknown platform', ua = navigator.userAgent;
34
+
35
+ // Detect OS
36
+ var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
37
+ var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
38
+ if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
39
+
40
+ // Detect browser
41
+ var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
42
+
43
+ // Detect version
44
+ var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
45
+ var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
46
+ var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
47
+
48
+ /**
49
+ * A smattering of methods that are needed to implement the JSLitmus testbed.
50
+ */
51
+ var jsl = {
52
+ /**
53
+ * Enhanced version of escape()
54
+ */
55
+ escape: function(s) {
56
+ s = s.replace(/,/g, '\\,');
57
+ s = escape(s);
58
+ s = s.replace(/\+/g, '%2b');
59
+ s = s.replace(/ /g, '+');
60
+ return s;
61
+ },
62
+
63
+ /**
64
+ * Get an element by ID.
65
+ */
66
+ $: function(id) {
67
+ return document.getElementById(id);
68
+ },
69
+
70
+ /**
71
+ * Null function
72
+ */
73
+ F: function() {},
74
+
75
+ /**
76
+ * Set the status shown in the UI
77
+ */
78
+ status: function(msg) {
79
+ var el = jsl.$('jsl_status');
80
+ if (el) el.innerHTML = msg || '';
81
+ },
82
+
83
+ /**
84
+ * Convert a number to an abbreviated string like, "15K" or "10M"
85
+ */
86
+ toLabel: function(n) {
87
+ if (n == Infinity) {
88
+ return 'Infinity';
89
+ } else if (n > 1e9) {
90
+ n = Math.round(n/1e8);
91
+ return n/10 + 'B';
92
+ } else if (n > 1e6) {
93
+ n = Math.round(n/1e5);
94
+ return n/10 + 'M';
95
+ } else if (n > 1e3) {
96
+ n = Math.round(n/1e2);
97
+ return n/10 + 'K';
98
+ }
99
+ return n;
100
+ },
101
+
102
+ /**
103
+ * Copy properties from src to dst
104
+ */
105
+ extend: function(dst, src) {
106
+ for (var k in src) dst[k] = src[k]; return dst;
107
+ },
108
+
109
+ /**
110
+ * Like Array.join(), but for the key-value pairs in an object
111
+ */
112
+ join: function(o, delimit1, delimit2) {
113
+ if (o.join) return o.join(delimit1); // If it's an array
114
+ var pairs = [];
115
+ for (var k in o) pairs.push(k + delimit1 + o[k]);
116
+ return pairs.join(delimit2);
117
+ },
118
+
119
+ /**
120
+ * Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
121
+ */
122
+ indexOf: function(arr, o) {
123
+ if (arr.indexOf) return arr.indexOf(o);
124
+ for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
125
+ return -1;
126
+ }
127
+ };
128
+
129
+ /**
130
+ * Test manages a single test (created with
131
+ * JSLitmus.test())
132
+ *
133
+ * @private
134
+ */
135
+ var Test = function (name, f) {
136
+ if (!f) throw new Error('Undefined test function');
137
+ if (!(/function[^\(]*\(([^,\)]*)/).test(f.toString())) {
138
+ throw new Error('"' + name + '" test: Test is not a valid Function object');
139
+ }
140
+ this.loopArg = RegExp.$1;
141
+ this.name = name;
142
+ this.f = f;
143
+ };
144
+
145
+ jsl.extend(Test, /** @lends Test */ {
146
+ /** Calibration tests for establishing iteration loop overhead */
147
+ CALIBRATIONS: [
148
+ new Test('calibrating loop', function(count) {while (count--);}),
149
+ new Test('calibrating function', jsl.F)
150
+ ],
151
+
152
+ /**
153
+ * Run calibration tests. Returns true if calibrations are not yet
154
+ * complete (in which case calling code should run the tests yet again).
155
+ * onCalibrated - Callback to invoke when calibrations have finished
156
+ */
157
+ calibrate: function(onCalibrated) {
158
+ for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
159
+ var cal = Test.CALIBRATIONS[i];
160
+ if (cal.running) return true;
161
+ if (!cal.count) {
162
+ cal.isCalibration = true;
163
+ cal.onStop = onCalibrated;
164
+ //cal.MIN_TIME = .1; // Do calibrations quickly
165
+ cal.run(2e4);
166
+ return true;
167
+ }
168
+ }
169
+ return false;
170
+ }
171
+ });
172
+
173
+ jsl.extend(Test.prototype, {/** @lends Test.prototype */
174
+ /** Initial number of iterations */
175
+ INIT_COUNT: 10,
176
+ /** Max iterations allowed (i.e. used to detect bad looping functions) */
177
+ MAX_COUNT: 1e9,
178
+ /** Minimum time a test should take to get valid results (secs) */
179
+ MIN_TIME: .5,
180
+
181
+ /** Callback invoked when test state changes */
182
+ onChange: jsl.F,
183
+
184
+ /** Callback invoked when test is finished */
185
+ onStop: jsl.F,
186
+
187
+ /**
188
+ * Reset test state
189
+ */
190
+ reset: function() {
191
+ delete this.count;
192
+ delete this.time;
193
+ delete this.running;
194
+ delete this.error;
195
+ },
196
+
197
+ /**
198
+ * Run the test (in a timeout). We use a timeout to make sure the browser
199
+ * has a chance to finish rendering any UI changes we've made, like
200
+ * updating the status message.
201
+ */
202
+ run: function(count) {
203
+ count = count || this.INIT_COUNT;
204
+ jsl.status(this.name + ' x ' + count);
205
+ this.running = true;
206
+ var me = this;
207
+ setTimeout(function() {me._run(count);}, 200);
208
+ },
209
+
210
+ /**
211
+ * The nuts and bolts code that actually runs a test
212
+ */
213
+ _run: function(count) {
214
+ var me = this;
215
+
216
+ // Make sure calibration tests have run
217
+ if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
218
+ this.error = null;
219
+
220
+ try {
221
+ var start, f = this.f, now, i = count;
222
+
223
+ // Start the timer
224
+ start = new Date();
225
+
226
+ // Now for the money shot. If this is a looping function ...
227
+ if (this.loopArg) {
228
+ // ... let it do the iteration itself
229
+ f(count);
230
+ } else {
231
+ // ... otherwise do the iteration for it
232
+ while (i--) f();
233
+ }
234
+
235
+ // Get time test took (in secs)
236
+ this.time = Math.max(1,new Date() - start)/1000;
237
+
238
+ // Store iteration count and per-operation time taken
239
+ this.count = count;
240
+ this.period = this.time/count;
241
+
242
+ // Do we need to do another run?
243
+ this.running = this.time <= this.MIN_TIME;
244
+
245
+ // ... if so, compute how many times we should iterate
246
+ if (this.running) {
247
+ // Bump the count to the nearest power of 2
248
+ var x = this.MIN_TIME/this.time;
249
+ var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
250
+ count *= pow;
251
+ if (count > this.MAX_COUNT) {
252
+ throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
253
+ }
254
+ }
255
+ } catch (e) {
256
+ // Exceptions are caught and displayed in the test UI
257
+ this.reset();
258
+ this.error = e;
259
+ }
260
+
261
+ // Figure out what to do next
262
+ if (this.running) {
263
+ me.run(count);
264
+ } else {
265
+ jsl.status('');
266
+ me.onStop(me);
267
+ }
268
+
269
+ // Finish up
270
+ this.onChange(this);
271
+ },
272
+
273
+ /**
274
+ * Get the number of operations per second for this test.
275
+ *
276
+ * @param normalize if true, iteration loop overhead taken into account
277
+ */
278
+ getHz: function(/**Boolean*/ normalize) {
279
+ var p = this.period;
280
+
281
+ // Adjust period based on the calibration test time
282
+ if (normalize && !this.isCalibration) {
283
+ var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
284
+
285
+ // If the period is within 20% of the calibration time, then zero the
286
+ // it out
287
+ p = p < cal.period*1.2 ? 0 : p - cal.period;
288
+ }
289
+
290
+ return Math.round(1/p);
291
+ },
292
+
293
+ /**
294
+ * Get a friendly string describing the test
295
+ */
296
+ toString: function() {
297
+ return this.name + ' - ' + this.time/this.count + ' secs';
298
+ }
299
+ });
300
+
301
+ // CSS we need for the UI
302
+ var STYLESHEET = '<style> \
303
+ #jslitmus {font-family:sans-serif; font-size: 12px;} \
304
+ #jslitmus a {text-decoration: none;} \
305
+ #jslitmus a:hover {text-decoration: underline;} \
306
+ #jsl_status { \
307
+ margin-top: 10px; \
308
+ font-size: 10px; \
309
+ color: #888; \
310
+ } \
311
+ A IMG {border:none} \
312
+ #test_results { \
313
+ margin-top: 10px; \
314
+ font-size: 12px; \
315
+ font-family: sans-serif; \
316
+ border-collapse: collapse; \
317
+ border-spacing: 0px; \
318
+ } \
319
+ #test_results th, #test_results td { \
320
+ border: solid 1px #ccc; \
321
+ vertical-align: top; \
322
+ padding: 3px; \
323
+ } \
324
+ #test_results th { \
325
+ vertical-align: bottom; \
326
+ background-color: #ccc; \
327
+ padding: 1px; \
328
+ font-size: 10px; \
329
+ } \
330
+ #test_results #test_platform { \
331
+ color: #444; \
332
+ text-align:center; \
333
+ } \
334
+ #test_results .test_row { \
335
+ color: #006; \
336
+ cursor: pointer; \
337
+ } \
338
+ #test_results .test_nonlooping { \
339
+ border-left-style: dotted; \
340
+ border-left-width: 2px; \
341
+ } \
342
+ #test_results .test_looping { \
343
+ border-left-style: solid; \
344
+ border-left-width: 2px; \
345
+ } \
346
+ #test_results .test_name {white-space: nowrap;} \
347
+ #test_results .test_pending { \
348
+ } \
349
+ #test_results .test_running { \
350
+ font-style: italic; \
351
+ } \
352
+ #test_results .test_done {} \
353
+ #test_results .test_done { \
354
+ text-align: right; \
355
+ font-family: monospace; \
356
+ } \
357
+ #test_results .test_error {color: #600;} \
358
+ #test_results .test_error .error_head {font-weight:bold;} \
359
+ #test_results .test_error .error_body {font-size:85%;} \
360
+ #test_results .test_row:hover td { \
361
+ background-color: #ffc; \
362
+ text-decoration: underline; \
363
+ } \
364
+ #chart { \
365
+ margin: 10px 0px; \
366
+ width: 250px; \
367
+ } \
368
+ #chart img { \
369
+ border: solid 1px #ccc; \
370
+ margin-bottom: 5px; \
371
+ } \
372
+ #chart #tiny_url { \
373
+ height: 40px; \
374
+ width: 250px; \
375
+ } \
376
+ #jslitmus_credit { \
377
+ font-size: 10px; \
378
+ color: #888; \
379
+ margin-top: 8px; \
380
+ } \
381
+ </style>';
382
+
383
+ // HTML markup for the UI
384
+ var MARKUP = '<div id="jslitmus"> \
385
+ <button onclick="JSLitmus.runAll(event)">Run Tests</button> \
386
+ <button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
387
+ <br \> \
388
+ <br \> \
389
+ <input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
390
+ <table id="test_results"> \
391
+ <colgroup> \
392
+ <col /> \
393
+ <col width="100" /> \
394
+ </colgroup> \
395
+ <tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
396
+ <tr><th>Test</th><th>Ops/sec</th></tr> \
397
+ <tr id="test_row_template" class="test_row" style="display:none"> \
398
+ <td class="test_name"></td> \
399
+ <td class="test_result">Ready</td> \
400
+ </tr> \
401
+ </table> \
402
+ <div id="jsl_status"></div> \
403
+ <div id="chart" style="display:none"> \
404
+ <a id="chart_link" target="_blank"><img id="chart_image"></a> \
405
+ TinyURL (for chart): \
406
+ <iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
407
+ </div> \
408
+ <a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
409
+ </div>';
410
+
411
+ /**
412
+ * The public API for creating and running tests
413
+ */
414
+ window.JSLitmus = {
415
+ /** The list of all tests that have been registered with JSLitmus.test */
416
+ _tests: [],
417
+ /** The queue of tests that need to be run */
418
+ _queue: [],
419
+
420
+ /**
421
+ * The parsed query parameters the current page URL. This is provided as a
422
+ * convenience for test functions - it's not used by JSLitmus proper
423
+ */
424
+ params: {},
425
+
426
+ /**
427
+ * Initialize
428
+ */
429
+ _init: function() {
430
+ // Parse query params into JSLitmus.params[] hash
431
+ var match = (location + '').match(/([^?#]*)(#.*)?$/);
432
+ if (match) {
433
+ var pairs = match[1].split('&');
434
+ for (var i = 0; i < pairs.length; i++) {
435
+ var pair = pairs[i].split('=');
436
+ if (pair.length > 1) {
437
+ var key = pair.shift();
438
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
439
+ this.params[key] = value;
440
+ }
441
+ }
442
+ }
443
+
444
+ // Write out the stylesheet. We have to do this here because IE
445
+ // doesn't honor sheets written after the document has loaded.
446
+ document.write(STYLESHEET);
447
+
448
+ // Setup the rest of the UI once the document is loaded
449
+ if (window.addEventListener) {
450
+ window.addEventListener('load', this._setup, false);
451
+ } else if (document.addEventListener) {
452
+ document.addEventListener('load', this._setup, false);
453
+ } else if (window.attachEvent) {
454
+ window.attachEvent('onload', this._setup);
455
+ }
456
+
457
+ return this;
458
+ },
459
+
460
+ /**
461
+ * Set up the UI
462
+ */
463
+ _setup: function() {
464
+ var el = jsl.$('jslitmus_container');
465
+ if (!el) document.body.appendChild(el = document.createElement('div'));
466
+
467
+ el.innerHTML = MARKUP;
468
+
469
+ // Render the UI for all our tests
470
+ for (var i=0; i < JSLitmus._tests.length; i++)
471
+ JSLitmus.renderTest(JSLitmus._tests[i]);
472
+ },
473
+
474
+ /**
475
+ * (Re)render all the test results
476
+ */
477
+ renderAll: function() {
478
+ for (var i = 0; i < JSLitmus._tests.length; i++)
479
+ JSLitmus.renderTest(JSLitmus._tests[i]);
480
+ JSLitmus.renderChart();
481
+ },
482
+
483
+ /**
484
+ * (Re)render the chart graphics
485
+ */
486
+ renderChart: function() {
487
+ var url = JSLitmus.chartUrl();
488
+ jsl.$('chart_link').href = url;
489
+ jsl.$('chart_image').src = url;
490
+ jsl.$('chart').style.display = '';
491
+
492
+ // Update the tiny URL
493
+ jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
494
+ },
495
+
496
+ /**
497
+ * (Re)render the results for a specific test
498
+ */
499
+ renderTest: function(test) {
500
+ // Make a new row if needed
501
+ if (!test._row) {
502
+ var trow = jsl.$('test_row_template');
503
+ if (!trow) return;
504
+
505
+ test._row = trow.cloneNode(true);
506
+ test._row.style.display = '';
507
+ test._row.id = '';
508
+ test._row.onclick = function() {JSLitmus._queueTest(test);};
509
+ test._row.title = 'Run ' + test.name + ' test';
510
+ trow.parentNode.appendChild(test._row);
511
+ test._row.cells[0].innerHTML = test.name;
512
+ }
513
+
514
+ var cell = test._row.cells[1];
515
+ var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
516
+
517
+ if (test.error) {
518
+ cns.push('test_error');
519
+ cell.innerHTML =
520
+ '<div class="error_head">' + test.error + '</div>' +
521
+ '<ul class="error_body"><li>' +
522
+ jsl.join(test.error, ': ', '</li><li>') +
523
+ '</li></ul>';
524
+ } else {
525
+ if (test.running) {
526
+ cns.push('test_running');
527
+ cell.innerHTML = 'running';
528
+ } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
529
+ cns.push('test_pending');
530
+ cell.innerHTML = 'pending';
531
+ } else if (test.count) {
532
+ cns.push('test_done');
533
+ var hz = test.getHz(jsl.$('test_normalize').checked);
534
+ cell.innerHTML = hz != Infinity ? hz : '&infin;';
535
+ } else {
536
+ cell.innerHTML = 'ready';
537
+ }
538
+ }
539
+ cell.className = cns.join(' ');
540
+ },
541
+
542
+ /**
543
+ * Create a new test
544
+ */
545
+ test: function(name, f) {
546
+ // Create the Test object
547
+ var test = new Test(name, f);
548
+ JSLitmus._tests.push(test);
549
+
550
+ // Re-render if the test state changes
551
+ test.onChange = JSLitmus.renderTest;
552
+
553
+ // Run the next test if this one finished
554
+ test.onStop = function(test) {
555
+ if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
556
+ JSLitmus.currentTest = null;
557
+ JSLitmus._nextTest();
558
+ };
559
+
560
+ // Render the new test
561
+ this.renderTest(test);
562
+ },
563
+
564
+ /**
565
+ * Add all tests to the run queue
566
+ */
567
+ runAll: function(e) {
568
+ e = e || window.event;
569
+ var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
570
+ for (var i = 0; i < len; i++) {
571
+ JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
572
+ }
573
+ },
574
+
575
+ /**
576
+ * Remove all tests from the run queue. The current test has to finish on
577
+ * it's own though
578
+ */
579
+ stop: function() {
580
+ while (JSLitmus._queue.length) {
581
+ var test = JSLitmus._queue.shift();
582
+ JSLitmus.renderTest(test);
583
+ }
584
+ },
585
+
586
+ /**
587
+ * Run the next test in the run queue
588
+ */
589
+ _nextTest: function() {
590
+ if (!JSLitmus.currentTest) {
591
+ var test = JSLitmus._queue.shift();
592
+ if (test) {
593
+ jsl.$('stop_button').disabled = false;
594
+ JSLitmus.currentTest = test;
595
+ test.run();
596
+ JSLitmus.renderTest(test);
597
+ if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
598
+ } else {
599
+ jsl.$('stop_button').disabled = true;
600
+ JSLitmus.renderChart();
601
+ }
602
+ }
603
+ },
604
+
605
+ /**
606
+ * Add a test to the run queue
607
+ */
608
+ _queueTest: function(test) {
609
+ if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
610
+ JSLitmus._queue.push(test);
611
+ JSLitmus.renderTest(test);
612
+ JSLitmus._nextTest();
613
+ },
614
+
615
+ /**
616
+ * Generate a Google Chart URL that shows the data for all tests
617
+ */
618
+ chartUrl: function() {
619
+ var n = JSLitmus._tests.length, markers = [], data = [];
620
+ var d, min = 0, max = -1e10;
621
+ var normalize = jsl.$('test_normalize').checked;
622
+
623
+ // Gather test data
624
+ for (var i=0; i < JSLitmus._tests.length; i++) {
625
+ var test = JSLitmus._tests[i];
626
+ if (test.count) {
627
+ var hz = test.getHz(normalize);
628
+ var v = hz != Infinity ? hz : 0;
629
+ data.push(v);
630
+ markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
631
+ markers.length + ',10');
632
+ max = Math.max(v, max);
633
+ }
634
+ }
635
+ if (markers.length <= 0) return null;
636
+
637
+ // Build chart title
638
+ var title = document.getElementsByTagName('title');
639
+ title = (title && title.length) ? title[0].innerHTML : null;
640
+ var chart_title = [];
641
+ if (title) chart_title.push(title);
642
+ chart_title.push('Ops/sec (' + platform + ')');
643
+
644
+ // Build labels
645
+ var labels = [jsl.toLabel(min), jsl.toLabel(max)];
646
+
647
+ var w = 250, bw = 15;
648
+ var bs = 5;
649
+ var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
650
+
651
+ var params = {
652
+ chtt: escape(chart_title.join('|')),
653
+ chts: '000000,10',
654
+ cht: 'bhg', // chart type
655
+ chd: 't:' + data.join(','), // data set
656
+ chds: min + ',' + max, // max/min of data
657
+ chxt: 'x', // label axes
658
+ chxl: '0:|' + labels.join('|'), // labels
659
+ chsp: '0,1',
660
+ chm: markers.join('|'), // test names
661
+ chbh: [bw, 0, bs].join(','), // bar widths
662
+ // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
663
+ chs: w + 'x' + h
664
+ };
665
+ return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
666
+ }
667
+ };
668
+
669
+ JSLitmus._init();
670
+ })();