opsask 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.yardoc/checksums +4 -0
  4. data/.yardoc/object_types +0 -0
  5. data/.yardoc/objects/root.dat +0 -0
  6. data/.yardoc/proxy_types +0 -0
  7. data/Gemfile +15 -0
  8. data/Gemfile.lock +75 -0
  9. data/LICENSE +13 -0
  10. data/Rakefile +30 -0
  11. data/Readme.md +3 -0
  12. data/VERSION +1 -0
  13. data/bin/opsask +4 -0
  14. data/lib/opsask/app.rb +540 -0
  15. data/lib/opsask/main.rb +54 -0
  16. data/lib/opsask/metadata.rb +29 -0
  17. data/lib/opsask.rb +3 -0
  18. data/opsask.gemspec +29 -0
  19. data/public/css/foundation.css +5068 -0
  20. data/public/css/foundation.min.css +1 -0
  21. data/public/css/normalize.css +410 -0
  22. data/public/css/style.css +152 -0
  23. data/public/favicon.ico +0 -0
  24. data/public/fonts/DINMittelschriftStd.woff +0 -0
  25. data/public/img/.gitkeep +1 -0
  26. data/public/js/foundation/foundation.abide.js +256 -0
  27. data/public/js/foundation/foundation.accordion.js +49 -0
  28. data/public/js/foundation/foundation.alert.js +37 -0
  29. data/public/js/foundation/foundation.clearing.js +485 -0
  30. data/public/js/foundation/foundation.dropdown.js +208 -0
  31. data/public/js/foundation/foundation.equalizer.js +64 -0
  32. data/public/js/foundation/foundation.interchange.js +326 -0
  33. data/public/js/foundation/foundation.joyride.js +848 -0
  34. data/public/js/foundation/foundation.js +587 -0
  35. data/public/js/foundation/foundation.magellan.js +171 -0
  36. data/public/js/foundation/foundation.offcanvas.js +39 -0
  37. data/public/js/foundation/foundation.orbit.js +464 -0
  38. data/public/js/foundation/foundation.reveal.js +399 -0
  39. data/public/js/foundation/foundation.tab.js +58 -0
  40. data/public/js/foundation/foundation.tooltip.js +215 -0
  41. data/public/js/foundation/foundation.topbar.js +387 -0
  42. data/public/js/foundation/jquery.cookie.js +8 -0
  43. data/public/js/foundation.min.js +10 -0
  44. data/public/js/opsask.js +19 -0
  45. data/public/js/vendor/fastclick.js +9 -0
  46. data/public/js/vendor/jquery.cookie.js +8 -0
  47. data/public/js/vendor/jquery.js +26 -0
  48. data/public/js/vendor/modernizr.js +8 -0
  49. data/public/js/vendor/placeholder.js +2 -0
  50. data/tasks/generate-email-summary.rb +73 -0
  51. data/tasks/send-email-summary.sh +13 -0
  52. data/views/_components.erb +6 -0
  53. data/views/_count.erb +11 -0
  54. data/views/_flash.erb +3 -0
  55. data/views/_form.erb +37 -0
  56. data/views/_queue.erb +16 -0
  57. data/views/agile.erb +6 -0
  58. data/views/glance.erb +19 -0
  59. data/views/index.erb +27 -0
  60. data/views/layout.erb +43 -0
  61. data/views/stragglers.erb +6 -0
  62. data/views/untracked.erb +6 -0
  63. metadata +217 -0
@@ -0,0 +1,587 @@
1
+ /*
2
+ * Foundation Responsive Library
3
+ * http://foundation.zurb.com
4
+ * Copyright 2014, ZURB
5
+ * Free to use under the MIT license.
6
+ * http://www.opensource.org/licenses/mit-license.php
7
+ */
8
+
9
+ (function ($, window, document, undefined) {
10
+ 'use strict';
11
+
12
+ var header_helpers = function (class_array) {
13
+ var i = class_array.length;
14
+
15
+ while (i--) {
16
+ if($('head').has('.' + class_array[i]).length === 0) {
17
+ $('head').append('<meta class="' + class_array[i] + '">');
18
+ }
19
+ }
20
+ };
21
+
22
+ header_helpers([
23
+ 'foundation-mq-small',
24
+ 'foundation-mq-medium',
25
+ 'foundation-mq-large',
26
+ 'foundation-mq-xlarge',
27
+ 'foundation-mq-xxlarge',
28
+ 'foundation-data-attribute-namespace']);
29
+
30
+ // Enable FastClick if present
31
+
32
+ $(function() {
33
+ if(typeof FastClick !== 'undefined') {
34
+ // Don't attach to body if undefined
35
+ if (typeof document.body !== 'undefined') {
36
+ FastClick.attach(document.body);
37
+ }
38
+ }
39
+ });
40
+
41
+ // private Fast Selector wrapper,
42
+ // returns jQuery object. Only use where
43
+ // getElementById is not available.
44
+ var S = function (selector, context) {
45
+ if (typeof selector === 'string') {
46
+ if (context) {
47
+ var cont;
48
+ if (context.jquery) {
49
+ cont = context[0];
50
+ } else {
51
+ cont = context;
52
+ }
53
+ return $(cont.querySelectorAll(selector));
54
+ }
55
+
56
+ return $(document.querySelectorAll(selector));
57
+ }
58
+
59
+ return $(selector, context);
60
+ };
61
+
62
+ // Namespace functions.
63
+
64
+ var attr_name = function (init) {
65
+ var arr = [];
66
+ if (!init) arr.push('data');
67
+ if (this.namespace.length > 0) arr.push(this.namespace);
68
+ arr.push(this.name);
69
+
70
+ return arr.join('-');
71
+ };
72
+
73
+ var header_helpers = function (class_array) {
74
+ var i = class_array.length;
75
+
76
+ while (i--) {
77
+ if($('head').has('.' + class_array[i]).length === 0) {
78
+ $('head').append('<meta class="' + class_array[i] + '">');
79
+ }
80
+ }
81
+ };
82
+
83
+ var add_namespace = function (str) {
84
+ var parts = str.split('-'),
85
+ i = parts.length,
86
+ arr = [];
87
+
88
+ while(i--) {
89
+ if (i !== 0) {
90
+ arr.push(parts[i]);
91
+ } else {
92
+ if (this.namespace.length > 0) {
93
+ arr.push(this.namespace, parts[i]);
94
+ } else {
95
+ arr.push(parts[i]);
96
+ }
97
+ }
98
+ }
99
+
100
+ return arr.reverse().join('-');
101
+ };
102
+
103
+ // Event binding and data-options updating.
104
+
105
+ var bindings = function (method, options) {
106
+ var self = this,
107
+ should_bind_events = !S(this).data(this.attr_name(true));
108
+
109
+ if (typeof method === 'string') {
110
+ return this[method].call(this, options);
111
+ }
112
+
113
+ if (S(this.scope).is('[' + this.attr_name() +']')) {
114
+ S(this.scope).data(this.attr_name(true) + '-init', $.extend({}, this.settings, (options || method), this.data_options(S(this.scope))));
115
+
116
+ if (should_bind_events) {
117
+ this.events(this.scope);
118
+ }
119
+
120
+ } else {
121
+ S('[' + this.attr_name() +']', this.scope).each(function () {
122
+ var should_bind_events = !S(this).data(self.attr_name(true) + '-init');
123
+
124
+ S(this).data(self.attr_name(true) + '-init', $.extend({}, self.settings, (options || method), self.data_options(S(this))));
125
+
126
+ if (should_bind_events) {
127
+ self.events(this);
128
+ }
129
+ });
130
+ }
131
+ };
132
+
133
+ var single_image_loaded = function (image, callback) {
134
+ function loaded () {
135
+ callback(image[0]);
136
+ }
137
+
138
+ function bindLoad () {
139
+ this.one('load', loaded);
140
+
141
+ if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
142
+ var src = this.attr( 'src' ),
143
+ param = src.match( /\?/ ) ? '&' : '?';
144
+
145
+ param += 'random=' + (new Date()).getTime();
146
+ this.attr('src', src + param);
147
+ }
148
+ }
149
+
150
+ if (!image.attr('src')) {
151
+ loaded();
152
+ return;
153
+ }
154
+
155
+ if (image[0].complete || image[0].readyState === 4) {
156
+ loaded();
157
+ } else {
158
+ bindLoad.call(image);
159
+ }
160
+ }
161
+
162
+ /*
163
+ https://github.com/paulirish/matchMedia.js
164
+ */
165
+
166
+ window.matchMedia = window.matchMedia || (function( doc, undefined ) {
167
+
168
+ "use strict";
169
+
170
+ var bool,
171
+ docElem = doc.documentElement,
172
+ refNode = docElem.firstElementChild || docElem.firstChild,
173
+ // fakeBody required for <FF4 when executed in <head>
174
+ fakeBody = doc.createElement( "body" ),
175
+ div = doc.createElement( "div" );
176
+
177
+ div.id = "mq-test-1";
178
+ div.style.cssText = "position:absolute;top:-100em";
179
+ fakeBody.style.background = "none";
180
+ fakeBody.appendChild(div);
181
+
182
+ return function(q){
183
+
184
+ div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
185
+
186
+ docElem.insertBefore( fakeBody, refNode );
187
+ bool = div.offsetWidth === 42;
188
+ docElem.removeChild( fakeBody );
189
+
190
+ return {
191
+ matches: bool,
192
+ media: q
193
+ };
194
+
195
+ };
196
+
197
+ }( document ));
198
+
199
+ /*
200
+ * jquery.requestAnimationFrame
201
+ * https://github.com/gnarf37/jquery-requestAnimationFrame
202
+ * Requires jQuery 1.8+
203
+ *
204
+ * Copyright (c) 2012 Corey Frang
205
+ * Licensed under the MIT license.
206
+ */
207
+
208
+ (function( $ ) {
209
+
210
+ // requestAnimationFrame polyfill adapted from Erik Möller
211
+ // fixes from Paul Irish and Tino Zijdel
212
+ // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
213
+ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
214
+
215
+
216
+ var animating,
217
+ lastTime = 0,
218
+ vendors = ['webkit', 'moz'],
219
+ requestAnimationFrame = window.requestAnimationFrame,
220
+ cancelAnimationFrame = window.cancelAnimationFrame;
221
+
222
+ for(; lastTime < vendors.length && !requestAnimationFrame; lastTime++) {
223
+ requestAnimationFrame = window[ vendors[lastTime] + "RequestAnimationFrame" ];
224
+ cancelAnimationFrame = cancelAnimationFrame ||
225
+ window[ vendors[lastTime] + "CancelAnimationFrame" ] ||
226
+ window[ vendors[lastTime] + "CancelRequestAnimationFrame" ];
227
+ }
228
+
229
+ function raf() {
230
+ if ( animating ) {
231
+ requestAnimationFrame( raf );
232
+ jQuery.fx.tick();
233
+ }
234
+ }
235
+
236
+ if ( requestAnimationFrame ) {
237
+ // use rAF
238
+ window.requestAnimationFrame = requestAnimationFrame;
239
+ window.cancelAnimationFrame = cancelAnimationFrame;
240
+ jQuery.fx.timer = function( timer ) {
241
+ if ( timer() && jQuery.timers.push( timer ) && !animating ) {
242
+ animating = true;
243
+ raf();
244
+ }
245
+ };
246
+
247
+ jQuery.fx.stop = function() {
248
+ animating = false;
249
+ };
250
+ } else {
251
+ // polyfill
252
+ window.requestAnimationFrame = function( callback, element ) {
253
+ var currTime = new Date().getTime(),
254
+ timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ),
255
+ id = window.setTimeout( function() {
256
+ callback( currTime + timeToCall );
257
+ }, timeToCall );
258
+ lastTime = currTime + timeToCall;
259
+ return id;
260
+ };
261
+
262
+ window.cancelAnimationFrame = function(id) {
263
+ clearTimeout(id);
264
+ };
265
+
266
+ }
267
+
268
+ }( jQuery ));
269
+
270
+
271
+ function removeQuotes (string) {
272
+ if (typeof string === 'string' || string instanceof String) {
273
+ string = string.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g, '');
274
+ }
275
+
276
+ return string;
277
+ }
278
+
279
+ window.Foundation = {
280
+ name : 'Foundation',
281
+
282
+ version : '5.1.1',
283
+
284
+ media_queries : {
285
+ small : S('.foundation-mq-small').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
286
+ medium : S('.foundation-mq-medium').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
287
+ large : S('.foundation-mq-large').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
288
+ xlarge: S('.foundation-mq-xlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
289
+ xxlarge: S('.foundation-mq-xxlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, '')
290
+ },
291
+
292
+ stylesheet : $('<style></style>').appendTo('head')[0].sheet,
293
+
294
+ global: {
295
+ namespace: ''
296
+ },
297
+
298
+ init : function (scope, libraries, method, options, response) {
299
+ var library_arr,
300
+ args = [scope, method, options, response],
301
+ responses = [];
302
+
303
+ // check RTL
304
+ this.rtl = /rtl/i.test(S('html').attr('dir'));
305
+
306
+ // set foundation global scope
307
+ this.scope = scope || this.scope;
308
+
309
+ this.set_namespace();
310
+
311
+ if (libraries && typeof libraries === 'string' && !/reflow/i.test(libraries)) {
312
+ if (this.libs.hasOwnProperty(libraries)) {
313
+ responses.push(this.init_lib(libraries, args));
314
+ }
315
+ } else {
316
+ for (var lib in this.libs) {
317
+ responses.push(this.init_lib(lib, libraries));
318
+ }
319
+ }
320
+
321
+ return scope;
322
+ },
323
+
324
+ init_lib : function (lib, args) {
325
+ if (this.libs.hasOwnProperty(lib)) {
326
+ this.patch(this.libs[lib]);
327
+
328
+ if (args && args.hasOwnProperty(lib)) {
329
+ return this.libs[lib].init.apply(this.libs[lib], [this.scope, args[lib]]);
330
+ }
331
+
332
+ args = args instanceof Array ? args : Array(args); // PATCH: added this line
333
+ return this.libs[lib].init.apply(this.libs[lib], args);
334
+ }
335
+
336
+ return function () {};
337
+ },
338
+
339
+ patch : function (lib) {
340
+ lib.scope = this.scope;
341
+ lib.namespace = this.global.namespace;
342
+ lib.rtl = this.rtl;
343
+ lib['data_options'] = this.utils.data_options;
344
+ lib['attr_name'] = attr_name;
345
+ lib['add_namespace'] = add_namespace;
346
+ lib['bindings'] = bindings;
347
+ lib['S'] = this.utils.S;
348
+ },
349
+
350
+ inherit : function (scope, methods) {
351
+ var methods_arr = methods.split(' '),
352
+ i = methods_arr.length;
353
+
354
+ while (i--) {
355
+ if (this.utils.hasOwnProperty(methods_arr[i])) {
356
+ scope[methods_arr[i]] = this.utils[methods_arr[i]];
357
+ }
358
+ }
359
+ },
360
+
361
+ set_namespace: function () {
362
+ var namespace = $('.foundation-data-attribute-namespace').css('font-family');
363
+
364
+ if (/false/i.test(namespace)) return;
365
+
366
+ this.global.namespace = namespace;
367
+ },
368
+
369
+ libs : {},
370
+
371
+ // methods that can be inherited in libraries
372
+ utils : {
373
+
374
+ // Description:
375
+ // Fast Selector wrapper returns jQuery object. Only use where getElementById
376
+ // is not available.
377
+ //
378
+ // Arguments:
379
+ // Selector (String): CSS selector describing the element(s) to be
380
+ // returned as a jQuery object.
381
+ //
382
+ // Scope (String): CSS selector describing the area to be searched. Default
383
+ // is document.
384
+ //
385
+ // Returns:
386
+ // Element (jQuery Object): jQuery object containing elements matching the
387
+ // selector within the scope.
388
+ S : S,
389
+
390
+ // Description:
391
+ // Executes a function a max of once every n milliseconds
392
+ //
393
+ // Arguments:
394
+ // Func (Function): Function to be throttled.
395
+ //
396
+ // Delay (Integer): Function execution threshold in milliseconds.
397
+ //
398
+ // Returns:
399
+ // Lazy_function (Function): Function with throttling applied.
400
+ throttle : function(func, delay) {
401
+ var timer = null;
402
+
403
+ return function () {
404
+ var context = this, args = arguments;
405
+
406
+ clearTimeout(timer);
407
+ timer = setTimeout(function () {
408
+ func.apply(context, args);
409
+ }, delay);
410
+ };
411
+ },
412
+
413
+ // Description:
414
+ // Executes a function when it stops being invoked for n seconds
415
+ // Modified version of _.debounce() http://underscorejs.org
416
+ //
417
+ // Arguments:
418
+ // Func (Function): Function to be debounced.
419
+ //
420
+ // Delay (Integer): Function execution threshold in milliseconds.
421
+ //
422
+ // Immediate (Bool): Whether the function should be called at the beginning
423
+ // of the delay instead of the end. Default is false.
424
+ //
425
+ // Returns:
426
+ // Lazy_function (Function): Function with debouncing applied.
427
+ debounce : function(func, delay, immediate) {
428
+ var timeout, result;
429
+ return function() {
430
+ var context = this, args = arguments;
431
+ var later = function() {
432
+ timeout = null;
433
+ if (!immediate) result = func.apply(context, args);
434
+ };
435
+ var callNow = immediate && !timeout;
436
+ clearTimeout(timeout);
437
+ timeout = setTimeout(later, delay);
438
+ if (callNow) result = func.apply(context, args);
439
+ return result;
440
+ };
441
+ },
442
+
443
+ // Description:
444
+ // Parses data-options attribute
445
+ //
446
+ // Arguments:
447
+ // El (jQuery Object): Element to be parsed.
448
+ //
449
+ // Returns:
450
+ // Options (Javascript Object): Contents of the element's data-options
451
+ // attribute.
452
+ data_options : function (el) {
453
+ var opts = {}, ii, p, opts_arr,
454
+ data_options = function (el) {
455
+ var namespace = Foundation.global.namespace;
456
+
457
+ if (namespace.length > 0) {
458
+ return el.data(namespace + '-options');
459
+ }
460
+
461
+ return el.data('options');
462
+ };
463
+
464
+ var cached_options = data_options(el);
465
+
466
+ if (typeof cached_options === 'object') {
467
+ return cached_options;
468
+ }
469
+
470
+ opts_arr = (cached_options || ':').split(';'),
471
+ ii = opts_arr.length;
472
+
473
+ function isNumber (o) {
474
+ return ! isNaN (o-0) && o !== null && o !== "" && o !== false && o !== true;
475
+ }
476
+
477
+ function trim(str) {
478
+ if (typeof str === 'string') return $.trim(str);
479
+ return str;
480
+ }
481
+
482
+ while (ii--) {
483
+ p = opts_arr[ii].split(':');
484
+
485
+ if (/true/i.test(p[1])) p[1] = true;
486
+ if (/false/i.test(p[1])) p[1] = false;
487
+ if (isNumber(p[1])) p[1] = parseInt(p[1], 10);
488
+
489
+ if (p.length === 2 && p[0].length > 0) {
490
+ opts[trim(p[0])] = trim(p[1]);
491
+ }
492
+ }
493
+
494
+ return opts;
495
+ },
496
+
497
+ // Description:
498
+ // Adds JS-recognizable media queries
499
+ //
500
+ // Arguments:
501
+ // Media (String): Key string for the media query to be stored as in
502
+ // Foundation.media_queries
503
+ //
504
+ // Class (String): Class name for the generated <meta> tag
505
+ register_media : function(media, media_class) {
506
+ if(Foundation.media_queries[media] === undefined) {
507
+ $('head').append('<meta class="' + media_class + '">');
508
+ Foundation.media_queries[media] = removeQuotes($('.' + media_class).css('font-family'));
509
+ }
510
+ },
511
+
512
+ // Description:
513
+ // Add custom CSS within a JS-defined media query
514
+ //
515
+ // Arguments:
516
+ // Rule (String): CSS rule to be appended to the document.
517
+ //
518
+ // Media (String): Optional media query string for the CSS rule to be
519
+ // nested under.
520
+ add_custom_rule : function(rule, media) {
521
+ if(media === undefined) {
522
+ Foundation.stylesheet.insertRule(rule, Foundation.stylesheet.cssRules.length);
523
+ } else {
524
+ var query = Foundation.media_queries[media];
525
+ if(query !== undefined) {
526
+ Foundation.stylesheet.insertRule('@media ' +
527
+ Foundation.media_queries[media] + '{ ' + rule + ' }');
528
+ }
529
+ }
530
+ },
531
+
532
+ // Description:
533
+ // Performs a callback function when an image is fully loaded
534
+ //
535
+ // Arguments:
536
+ // Image (jQuery Object): Image(s) to check if loaded.
537
+ //
538
+ // Callback (Function): Fundation to execute when image is fully loaded.
539
+ image_loaded : function (images, callback) {
540
+ var self = this,
541
+ unloaded = images.length;
542
+
543
+ images.each(function(){
544
+ single_image_loaded(self.S(this),function(){
545
+ unloaded -= 1;
546
+ if(unloaded == 0){
547
+ callback(images);
548
+ }
549
+ });
550
+ });
551
+ },
552
+
553
+ // Description:
554
+ // Returns a random, alphanumeric string
555
+ //
556
+ // Arguments:
557
+ // Length (Integer): Length of string to be generated. Defaults to random
558
+ // integer.
559
+ //
560
+ // Returns:
561
+ // Rand (String): Pseudo-random, alphanumeric string.
562
+ random_str : function (length) {
563
+ var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
564
+
565
+ if (!length) {
566
+ length = Math.floor(Math.random() * chars.length);
567
+ }
568
+
569
+ var str = '';
570
+ while (length--) {
571
+ str += chars[Math.floor(Math.random() * chars.length)];
572
+ }
573
+ return str;
574
+ }
575
+ }
576
+ };
577
+
578
+ $.fn.foundation = function () {
579
+ var args = Array.prototype.slice.call(arguments, 0);
580
+
581
+ return this.each(function () {
582
+ Foundation.init.apply(Foundation, [this].concat(args));
583
+ return this;
584
+ });
585
+ };
586
+
587
+ }(jQuery, this, this.document));