sonic-screwdriver 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile.lock +26 -2
  4. data/README.md +156 -23
  5. data/bin/sonic +8 -1
  6. data/docs/.gitignore +4 -0
  7. data/docs/CNAME +1 -0
  8. data/docs/Gemfile +3 -0
  9. data/docs/LICENSE +21 -0
  10. data/docs/README.md +21 -0
  11. data/docs/_config.yml +69 -0
  12. data/docs/_docs/commands.md +10 -0
  13. data/docs/_docs/how-it-works.md +34 -0
  14. data/docs/_docs/install.md +75 -0
  15. data/docs/_docs/next-steps.md +18 -0
  16. data/docs/_docs/settings.md +73 -0
  17. data/docs/_docs/sonic-ecs-exec.md +7 -0
  18. data/docs/_docs/sonic-ecs-run.md +7 -0
  19. data/docs/_docs/sonic-execute.md +7 -0
  20. data/docs/_docs/sonic-help.md +7 -0
  21. data/docs/_docs/sonic-list.md +7 -0
  22. data/docs/_docs/sonic-ssh.md +7 -0
  23. data/docs/_docs/tutorial-ecs-exec.md +69 -0
  24. data/docs/_docs/tutorial-ecs-run.md +94 -0
  25. data/docs/_docs/tutorial-execute.md +38 -0
  26. data/docs/_docs/tutorial-ssh.md +119 -0
  27. data/docs/_docs/tutorial.md +11 -0
  28. data/docs/_docs/why.md +27 -0
  29. data/docs/_includes/about.html +19 -0
  30. data/docs/_includes/commands.html +28 -0
  31. data/docs/_includes/contact.html +17 -0
  32. data/docs/_includes/contact_disqus.html +16 -0
  33. data/docs/_includes/contact_static.html +17 -0
  34. data/docs/_includes/content.html +21 -0
  35. data/docs/_includes/css/bootstrap.min.css +7 -0
  36. data/docs/_includes/css/main.css +481 -0
  37. data/docs/_includes/css/quotes.css +102 -0
  38. data/docs/_includes/css/sonic.css +163 -0
  39. data/docs/_includes/css/syntax.css +60 -0
  40. data/docs/_includes/css/table.css +53 -0
  41. data/docs/_includes/css/timeline.css +201 -0
  42. data/docs/_includes/edit-on-github.html +11 -0
  43. data/docs/_includes/example.html +21 -0
  44. data/docs/_includes/footer.html +49 -0
  45. data/docs/_includes/head.html +32 -0
  46. data/docs/_includes/header.html +15 -0
  47. data/docs/_includes/js.html +28 -0
  48. data/docs/_includes/js_disqus.html +21 -0
  49. data/docs/_includes/modals.html +40 -0
  50. data/docs/_includes/nav.html +27 -0
  51. data/docs/_includes/quotes.html +19 -0
  52. data/docs/_includes/subnav.html +35 -0
  53. data/docs/_includes/ufo-ship-options.md +13 -0
  54. data/docs/_includes/uses.html +19 -0
  55. data/docs/_layouts/default.html +11 -0
  56. data/docs/_layouts/style.css +6 -0
  57. data/docs/articles.md +5 -0
  58. data/docs/css/font-awesome/css/font-awesome.css +1566 -0
  59. data/docs/css/font-awesome/css/font-awesome.min.css +4 -0
  60. data/docs/css/font-awesome/fonts/FontAwesome.otf +0 -0
  61. data/docs/css/font-awesome/fonts/fontawesome-webfont.eot +0 -0
  62. data/docs/css/font-awesome/fonts/fontawesome-webfont.svg +504 -0
  63. data/docs/css/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
  64. data/docs/css/font-awesome/fonts/fontawesome-webfont.woff +0 -0
  65. data/docs/docs.md +21 -0
  66. data/docs/img/logos/boltops-logo-full.png +0 -0
  67. data/docs/img/logos/boltops-logo.png +0 -0
  68. data/docs/img/sonic-screwdriver.jpg +0 -0
  69. data/docs/img/tutorials/ec2-console-public-ip.png +0 -0
  70. data/docs/img/ufo.jpg +0 -0
  71. data/docs/index.html +9 -0
  72. data/docs/js/bootstrap.js +2114 -0
  73. data/docs/js/bootstrap.min.js +6 -0
  74. data/docs/js/cbpAnimatedHeader.js +44 -0
  75. data/docs/js/cbpAnimatedHeader.min.js +11 -0
  76. data/docs/js/classie.js +80 -0
  77. data/docs/js/contact_me.js +70 -0
  78. data/docs/js/contact_me_static.js +23 -0
  79. data/docs/js/freelancer.js +37 -0
  80. data/docs/js/jqBootstrapValidation.js +912 -0
  81. data/docs/js/jquery-1.11.0.js +4 -0
  82. data/docs/js/jquery.easing.min.js +44 -0
  83. data/docs/js/nav.js +53 -0
  84. data/docs/quick-start.md +39 -0
  85. data/docs/style.css +3 -0
  86. data/lib/bash_scripts/docker-exec.sh +15 -0
  87. data/lib/bash_scripts/docker-run.sh +15 -0
  88. data/lib/sonic.rb +11 -2
  89. data/lib/sonic/aws_services.rb +19 -0
  90. data/lib/sonic/cli.rb +37 -8
  91. data/lib/sonic/cli/help.rb +123 -3
  92. data/lib/sonic/default/settings.yml +12 -0
  93. data/lib/sonic/docker.rb +128 -0
  94. data/lib/sonic/execute.rb +131 -0
  95. data/lib/sonic/list.rb +85 -0
  96. data/lib/sonic/settings.rb +80 -0
  97. data/lib/sonic/ssh.rb +136 -0
  98. data/lib/sonic/ssh/ec2_tag.rb +59 -0
  99. data/lib/sonic/ssh/identifier_detector.rb +145 -0
  100. data/lib/sonic/ui.rb +26 -0
  101. data/lib/sonic/version.rb +2 -2
  102. data/qa.md +21 -0
  103. data/sonic.gemspec +3 -1
  104. data/spec/fixtures/home/.gitkeep +0 -0
  105. data/spec/fixtures/project/.gitkeep +0 -0
  106. data/spec/fixtures/project/command.txt +2 -0
  107. data/spec/lib/cli_spec.rb +16 -6
  108. data/spec/lib/sonic/execute_spec.rb +35 -0
  109. data/spec/spec_helper.rb +5 -3
  110. metadata +133 -3
data/docs/docs.md ADDED
@@ -0,0 +1,21 @@
1
+ ---
2
+ title: Docs
3
+ ---
4
+
5
+ ### Overview
6
+
7
+ Sonic Screwdriver is a multi-functional tool to manage AWS infrastructure. It contains a variety of commands to make your job easier. It's main focus is to automate mundane repetitive tasks into simple one line commmands. With it you are to able debug environments and issues much more quickly.
8
+
9
+ The actually command that Sonic Screwdriver provides is called `sonic`. Here's a list of things that `sonic` can do:
10
+
11
+ * Quickly ssh into an instance using convenient identifiers like instance id, container instance id, ecs service names, etc. It can do this even if there is a bastion host.
12
+ * Quickly jump all the way into the instance and grab the docker name and run `docker exec -ti` on it.
13
+ * Quickly jump all the way into the instance and run `docker run` with the same environment as current running docker containers.
14
+ * Quickly execute across a set of servers.
15
+
16
+ Next we'll cover different ways to install the Sonic Screwdriver.
17
+
18
+ <a id="prev" class="btn btn-basic" href="{% link quick-start.md %}">Back</a>
19
+ <a id="next" class="btn btn-primary" href="{% link _docs/install.md %}">Next Step</a>
20
+ <p class="keyboard-tip">Pro tip: Use the <- and -> arrow keys to move back and forward.</p>
21
+
Binary file
Binary file
data/docs/img/ufo.jpg ADDED
Binary file
data/docs/index.html ADDED
@@ -0,0 +1,9 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+
5
+ {% include header.html %}
6
+ {% include commands.html %}
7
+ {% include about.html %}
8
+ {% include example.html %}
9
+ {% include contact.html %}
@@ -0,0 +1,2114 @@
1
+ /*!
2
+ * Bootstrap v3.2.0 (http://getbootstrap.com)
3
+ * Copyright 2011-2014 Twitter, Inc.
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5
+ */
6
+
7
+ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') }
8
+
9
+ /* ========================================================================
10
+ * Bootstrap: transition.js v3.2.0
11
+ * http://getbootstrap.com/javascript/#transitions
12
+ * ========================================================================
13
+ * Copyright 2011-2014 Twitter, Inc.
14
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
15
+ * ======================================================================== */
16
+
17
+
18
+ +function ($) {
19
+ 'use strict';
20
+
21
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
22
+ // ============================================================
23
+
24
+ function transitionEnd() {
25
+ var el = document.createElement('bootstrap')
26
+
27
+ var transEndEventNames = {
28
+ WebkitTransition : 'webkitTransitionEnd',
29
+ MozTransition : 'transitionend',
30
+ OTransition : 'oTransitionEnd otransitionend',
31
+ transition : 'transitionend'
32
+ }
33
+
34
+ for (var name in transEndEventNames) {
35
+ if (el.style[name] !== undefined) {
36
+ return { end: transEndEventNames[name] }
37
+ }
38
+ }
39
+
40
+ return false // explicit for ie8 ( ._.)
41
+ }
42
+
43
+ // http://blog.alexmaccaw.com/css-transitions
44
+ $.fn.emulateTransitionEnd = function (duration) {
45
+ var called = false
46
+ var $el = this
47
+ $(this).one('bsTransitionEnd', function () { called = true })
48
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
49
+ setTimeout(callback, duration)
50
+ return this
51
+ }
52
+
53
+ $(function () {
54
+ $.support.transition = transitionEnd()
55
+
56
+ if (!$.support.transition) return
57
+
58
+ $.event.special.bsTransitionEnd = {
59
+ bindType: $.support.transition.end,
60
+ delegateType: $.support.transition.end,
61
+ handle: function (e) {
62
+ if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
63
+ }
64
+ }
65
+ })
66
+
67
+ }(jQuery);
68
+
69
+ /* ========================================================================
70
+ * Bootstrap: alert.js v3.2.0
71
+ * http://getbootstrap.com/javascript/#alerts
72
+ * ========================================================================
73
+ * Copyright 2011-2014 Twitter, Inc.
74
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
75
+ * ======================================================================== */
76
+
77
+
78
+ +function ($) {
79
+ 'use strict';
80
+
81
+ // ALERT CLASS DEFINITION
82
+ // ======================
83
+
84
+ var dismiss = '[data-dismiss="alert"]'
85
+ var Alert = function (el) {
86
+ $(el).on('click', dismiss, this.close)
87
+ }
88
+
89
+ Alert.VERSION = '3.2.0'
90
+
91
+ Alert.prototype.close = function (e) {
92
+ var $this = $(this)
93
+ var selector = $this.attr('data-target')
94
+
95
+ if (!selector) {
96
+ selector = $this.attr('href')
97
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
98
+ }
99
+
100
+ var $parent = $(selector)
101
+
102
+ if (e) e.preventDefault()
103
+
104
+ if (!$parent.length) {
105
+ $parent = $this.hasClass('alert') ? $this : $this.parent()
106
+ }
107
+
108
+ $parent.trigger(e = $.Event('close.bs.alert'))
109
+
110
+ if (e.isDefaultPrevented()) return
111
+
112
+ $parent.removeClass('in')
113
+
114
+ function removeElement() {
115
+ // detach from parent, fire event then clean up data
116
+ $parent.detach().trigger('closed.bs.alert').remove()
117
+ }
118
+
119
+ $.support.transition && $parent.hasClass('fade') ?
120
+ $parent
121
+ .one('bsTransitionEnd', removeElement)
122
+ .emulateTransitionEnd(150) :
123
+ removeElement()
124
+ }
125
+
126
+
127
+ // ALERT PLUGIN DEFINITION
128
+ // =======================
129
+
130
+ function Plugin(option) {
131
+ return this.each(function () {
132
+ var $this = $(this)
133
+ var data = $this.data('bs.alert')
134
+
135
+ if (!data) $this.data('bs.alert', (data = new Alert(this)))
136
+ if (typeof option == 'string') data[option].call($this)
137
+ })
138
+ }
139
+
140
+ var old = $.fn.alert
141
+
142
+ $.fn.alert = Plugin
143
+ $.fn.alert.Constructor = Alert
144
+
145
+
146
+ // ALERT NO CONFLICT
147
+ // =================
148
+
149
+ $.fn.alert.noConflict = function () {
150
+ $.fn.alert = old
151
+ return this
152
+ }
153
+
154
+
155
+ // ALERT DATA-API
156
+ // ==============
157
+
158
+ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
159
+
160
+ }(jQuery);
161
+
162
+ /* ========================================================================
163
+ * Bootstrap: button.js v3.2.0
164
+ * http://getbootstrap.com/javascript/#buttons
165
+ * ========================================================================
166
+ * Copyright 2011-2014 Twitter, Inc.
167
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
168
+ * ======================================================================== */
169
+
170
+
171
+ +function ($) {
172
+ 'use strict';
173
+
174
+ // BUTTON PUBLIC CLASS DEFINITION
175
+ // ==============================
176
+
177
+ var Button = function (element, options) {
178
+ this.$element = $(element)
179
+ this.options = $.extend({}, Button.DEFAULTS, options)
180
+ this.isLoading = false
181
+ }
182
+
183
+ Button.VERSION = '3.2.0'
184
+
185
+ Button.DEFAULTS = {
186
+ loadingText: 'loading...'
187
+ }
188
+
189
+ Button.prototype.setState = function (state) {
190
+ var d = 'disabled'
191
+ var $el = this.$element
192
+ var val = $el.is('input') ? 'val' : 'html'
193
+ var data = $el.data()
194
+
195
+ state = state + 'Text'
196
+
197
+ if (data.resetText == null) $el.data('resetText', $el[val]())
198
+
199
+ $el[val](data[state] == null ? this.options[state] : data[state])
200
+
201
+ // push to event loop to allow forms to submit
202
+ setTimeout($.proxy(function () {
203
+ if (state == 'loadingText') {
204
+ this.isLoading = true
205
+ $el.addClass(d).attr(d, d)
206
+ } else if (this.isLoading) {
207
+ this.isLoading = false
208
+ $el.removeClass(d).removeAttr(d)
209
+ }
210
+ }, this), 0)
211
+ }
212
+
213
+ Button.prototype.toggle = function () {
214
+ var changed = true
215
+ var $parent = this.$element.closest('[data-toggle="buttons"]')
216
+
217
+ if ($parent.length) {
218
+ var $input = this.$element.find('input')
219
+ if ($input.prop('type') == 'radio') {
220
+ if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
221
+ else $parent.find('.active').removeClass('active')
222
+ }
223
+ if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
224
+ }
225
+
226
+ if (changed) this.$element.toggleClass('active')
227
+ }
228
+
229
+
230
+ // BUTTON PLUGIN DEFINITION
231
+ // ========================
232
+
233
+ function Plugin(option) {
234
+ return this.each(function () {
235
+ var $this = $(this)
236
+ var data = $this.data('bs.button')
237
+ var options = typeof option == 'object' && option
238
+
239
+ if (!data) $this.data('bs.button', (data = new Button(this, options)))
240
+
241
+ if (option == 'toggle') data.toggle()
242
+ else if (option) data.setState(option)
243
+ })
244
+ }
245
+
246
+ var old = $.fn.button
247
+
248
+ $.fn.button = Plugin
249
+ $.fn.button.Constructor = Button
250
+
251
+
252
+ // BUTTON NO CONFLICT
253
+ // ==================
254
+
255
+ $.fn.button.noConflict = function () {
256
+ $.fn.button = old
257
+ return this
258
+ }
259
+
260
+
261
+ // BUTTON DATA-API
262
+ // ===============
263
+
264
+ $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
265
+ var $btn = $(e.target)
266
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
267
+ Plugin.call($btn, 'toggle')
268
+ e.preventDefault()
269
+ })
270
+
271
+ }(jQuery);
272
+
273
+ /* ========================================================================
274
+ * Bootstrap: carousel.js v3.2.0
275
+ * http://getbootstrap.com/javascript/#carousel
276
+ * ========================================================================
277
+ * Copyright 2011-2014 Twitter, Inc.
278
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
279
+ * ======================================================================== */
280
+
281
+
282
+ +function ($) {
283
+ 'use strict';
284
+
285
+ // CAROUSEL CLASS DEFINITION
286
+ // =========================
287
+
288
+ var Carousel = function (element, options) {
289
+ this.$element = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this))
290
+ this.$indicators = this.$element.find('.carousel-indicators')
291
+ this.options = options
292
+ this.paused =
293
+ this.sliding =
294
+ this.interval =
295
+ this.$active =
296
+ this.$items = null
297
+
298
+ this.options.pause == 'hover' && this.$element
299
+ .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
300
+ .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
301
+ }
302
+
303
+ Carousel.VERSION = '3.2.0'
304
+
305
+ Carousel.DEFAULTS = {
306
+ interval: 5000,
307
+ pause: 'hover',
308
+ wrap: true
309
+ }
310
+
311
+ Carousel.prototype.keydown = function (e) {
312
+ switch (e.which) {
313
+ case 37: this.prev(); break
314
+ case 39: this.next(); break
315
+ default: return
316
+ }
317
+
318
+ e.preventDefault()
319
+ }
320
+
321
+ Carousel.prototype.cycle = function (e) {
322
+ e || (this.paused = false)
323
+
324
+ this.interval && clearInterval(this.interval)
325
+
326
+ this.options.interval
327
+ && !this.paused
328
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
329
+
330
+ return this
331
+ }
332
+
333
+ Carousel.prototype.getItemIndex = function (item) {
334
+ this.$items = item.parent().children('.item')
335
+ return this.$items.index(item || this.$active)
336
+ }
337
+
338
+ Carousel.prototype.to = function (pos) {
339
+ var that = this
340
+ var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
341
+
342
+ if (pos > (this.$items.length - 1) || pos < 0) return
343
+
344
+ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
345
+ if (activeIndex == pos) return this.pause().cycle()
346
+
347
+ return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
348
+ }
349
+
350
+ Carousel.prototype.pause = function (e) {
351
+ e || (this.paused = true)
352
+
353
+ if (this.$element.find('.next, .prev').length && $.support.transition) {
354
+ this.$element.trigger($.support.transition.end)
355
+ this.cycle(true)
356
+ }
357
+
358
+ this.interval = clearInterval(this.interval)
359
+
360
+ return this
361
+ }
362
+
363
+ Carousel.prototype.next = function () {
364
+ if (this.sliding) return
365
+ return this.slide('next')
366
+ }
367
+
368
+ Carousel.prototype.prev = function () {
369
+ if (this.sliding) return
370
+ return this.slide('prev')
371
+ }
372
+
373
+ Carousel.prototype.slide = function (type, next) {
374
+ var $active = this.$element.find('.item.active')
375
+ var $next = next || $active[type]()
376
+ var isCycling = this.interval
377
+ var direction = type == 'next' ? 'left' : 'right'
378
+ var fallback = type == 'next' ? 'first' : 'last'
379
+ var that = this
380
+
381
+ if (!$next.length) {
382
+ if (!this.options.wrap) return
383
+ $next = this.$element.find('.item')[fallback]()
384
+ }
385
+
386
+ if ($next.hasClass('active')) return (this.sliding = false)
387
+
388
+ var relatedTarget = $next[0]
389
+ var slideEvent = $.Event('slide.bs.carousel', {
390
+ relatedTarget: relatedTarget,
391
+ direction: direction
392
+ })
393
+ this.$element.trigger(slideEvent)
394
+ if (slideEvent.isDefaultPrevented()) return
395
+
396
+ this.sliding = true
397
+
398
+ isCycling && this.pause()
399
+
400
+ if (this.$indicators.length) {
401
+ this.$indicators.find('.active').removeClass('active')
402
+ var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
403
+ $nextIndicator && $nextIndicator.addClass('active')
404
+ }
405
+
406
+ var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
407
+ if ($.support.transition && this.$element.hasClass('slide')) {
408
+ $next.addClass(type)
409
+ $next[0].offsetWidth // force reflow
410
+ $active.addClass(direction)
411
+ $next.addClass(direction)
412
+ $active
413
+ .one('bsTransitionEnd', function () {
414
+ $next.removeClass([type, direction].join(' ')).addClass('active')
415
+ $active.removeClass(['active', direction].join(' '))
416
+ that.sliding = false
417
+ setTimeout(function () {
418
+ that.$element.trigger(slidEvent)
419
+ }, 0)
420
+ })
421
+ .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
422
+ } else {
423
+ $active.removeClass('active')
424
+ $next.addClass('active')
425
+ this.sliding = false
426
+ this.$element.trigger(slidEvent)
427
+ }
428
+
429
+ isCycling && this.cycle()
430
+
431
+ return this
432
+ }
433
+
434
+
435
+ // CAROUSEL PLUGIN DEFINITION
436
+ // ==========================
437
+
438
+ function Plugin(option) {
439
+ return this.each(function () {
440
+ var $this = $(this)
441
+ var data = $this.data('bs.carousel')
442
+ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
443
+ var action = typeof option == 'string' ? option : options.slide
444
+
445
+ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
446
+ if (typeof option == 'number') data.to(option)
447
+ else if (action) data[action]()
448
+ else if (options.interval) data.pause().cycle()
449
+ })
450
+ }
451
+
452
+ var old = $.fn.carousel
453
+
454
+ $.fn.carousel = Plugin
455
+ $.fn.carousel.Constructor = Carousel
456
+
457
+
458
+ // CAROUSEL NO CONFLICT
459
+ // ====================
460
+
461
+ $.fn.carousel.noConflict = function () {
462
+ $.fn.carousel = old
463
+ return this
464
+ }
465
+
466
+
467
+ // CAROUSEL DATA-API
468
+ // =================
469
+
470
+ $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
471
+ var href
472
+ var $this = $(this)
473
+ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
474
+ if (!$target.hasClass('carousel')) return
475
+ var options = $.extend({}, $target.data(), $this.data())
476
+ var slideIndex = $this.attr('data-slide-to')
477
+ if (slideIndex) options.interval = false
478
+
479
+ Plugin.call($target, options)
480
+
481
+ if (slideIndex) {
482
+ $target.data('bs.carousel').to(slideIndex)
483
+ }
484
+
485
+ e.preventDefault()
486
+ })
487
+
488
+ $(window).on('load', function () {
489
+ $('[data-ride="carousel"]').each(function () {
490
+ var $carousel = $(this)
491
+ Plugin.call($carousel, $carousel.data())
492
+ })
493
+ })
494
+
495
+ }(jQuery);
496
+
497
+ /* ========================================================================
498
+ * Bootstrap: collapse.js v3.2.0
499
+ * http://getbootstrap.com/javascript/#collapse
500
+ * ========================================================================
501
+ * Copyright 2011-2014 Twitter, Inc.
502
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
503
+ * ======================================================================== */
504
+
505
+
506
+ +function ($) {
507
+ 'use strict';
508
+
509
+ // COLLAPSE PUBLIC CLASS DEFINITION
510
+ // ================================
511
+
512
+ var Collapse = function (element, options) {
513
+ this.$element = $(element)
514
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
515
+ this.transitioning = null
516
+
517
+ if (this.options.parent) this.$parent = $(this.options.parent)
518
+ if (this.options.toggle) this.toggle()
519
+ }
520
+
521
+ Collapse.VERSION = '3.2.0'
522
+
523
+ Collapse.DEFAULTS = {
524
+ toggle: true
525
+ }
526
+
527
+ Collapse.prototype.dimension = function () {
528
+ var hasWidth = this.$element.hasClass('width')
529
+ return hasWidth ? 'width' : 'height'
530
+ }
531
+
532
+ Collapse.prototype.show = function () {
533
+ if (this.transitioning || this.$element.hasClass('in')) return
534
+
535
+ var startEvent = $.Event('show.bs.collapse')
536
+ this.$element.trigger(startEvent)
537
+ if (startEvent.isDefaultPrevented()) return
538
+
539
+ var actives = this.$parent && this.$parent.find('> .panel > .in')
540
+
541
+ if (actives && actives.length) {
542
+ var hasData = actives.data('bs.collapse')
543
+ if (hasData && hasData.transitioning) return
544
+ Plugin.call(actives, 'hide')
545
+ hasData || actives.data('bs.collapse', null)
546
+ }
547
+
548
+ var dimension = this.dimension()
549
+
550
+ this.$element
551
+ .removeClass('collapse')
552
+ .addClass('collapsing')[dimension](0)
553
+
554
+ this.transitioning = 1
555
+
556
+ var complete = function () {
557
+ this.$element
558
+ .removeClass('collapsing')
559
+ .addClass('collapse in')[dimension]('')
560
+ this.transitioning = 0
561
+ this.$element
562
+ .trigger('shown.bs.collapse')
563
+ }
564
+
565
+ if (!$.support.transition) return complete.call(this)
566
+
567
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
568
+
569
+ this.$element
570
+ .one('bsTransitionEnd', $.proxy(complete, this))
571
+ .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
572
+ }
573
+
574
+ Collapse.prototype.hide = function () {
575
+ if (this.transitioning || !this.$element.hasClass('in')) return
576
+
577
+ var startEvent = $.Event('hide.bs.collapse')
578
+ this.$element.trigger(startEvent)
579
+ if (startEvent.isDefaultPrevented()) return
580
+
581
+ var dimension = this.dimension()
582
+
583
+ this.$element[dimension](this.$element[dimension]())[0].offsetHeight
584
+
585
+ this.$element
586
+ .addClass('collapsing')
587
+ .removeClass('collapse')
588
+ .removeClass('in')
589
+
590
+ this.transitioning = 1
591
+
592
+ var complete = function () {
593
+ this.transitioning = 0
594
+ this.$element
595
+ .trigger('hidden.bs.collapse')
596
+ .removeClass('collapsing')
597
+ .addClass('collapse')
598
+ }
599
+
600
+ if (!$.support.transition) return complete.call(this)
601
+
602
+ this.$element
603
+ [dimension](0)
604
+ .one('bsTransitionEnd', $.proxy(complete, this))
605
+ .emulateTransitionEnd(350)
606
+ }
607
+
608
+ Collapse.prototype.toggle = function () {
609
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
610
+ }
611
+
612
+
613
+ // COLLAPSE PLUGIN DEFINITION
614
+ // ==========================
615
+
616
+ function Plugin(option) {
617
+ return this.each(function () {
618
+ var $this = $(this)
619
+ var data = $this.data('bs.collapse')
620
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
621
+
622
+ if (!data && options.toggle && option == 'show') option = !option
623
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
624
+ if (typeof option == 'string') data[option]()
625
+ })
626
+ }
627
+
628
+ var old = $.fn.collapse
629
+
630
+ $.fn.collapse = Plugin
631
+ $.fn.collapse.Constructor = Collapse
632
+
633
+
634
+ // COLLAPSE NO CONFLICT
635
+ // ====================
636
+
637
+ $.fn.collapse.noConflict = function () {
638
+ $.fn.collapse = old
639
+ return this
640
+ }
641
+
642
+
643
+ // COLLAPSE DATA-API
644
+ // =================
645
+
646
+ $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
647
+ var href
648
+ var $this = $(this)
649
+ var target = $this.attr('data-target')
650
+ || e.preventDefault()
651
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
652
+ var $target = $(target)
653
+ var data = $target.data('bs.collapse')
654
+ var option = data ? 'toggle' : $this.data()
655
+ var parent = $this.attr('data-parent')
656
+ var $parent = parent && $(parent)
657
+
658
+ if (!data || !data.transitioning) {
659
+ if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
660
+ $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
661
+ }
662
+
663
+ Plugin.call($target, option)
664
+ })
665
+
666
+ }(jQuery);
667
+
668
+ /* ========================================================================
669
+ * Bootstrap: dropdown.js v3.2.0
670
+ * http://getbootstrap.com/javascript/#dropdowns
671
+ * ========================================================================
672
+ * Copyright 2011-2014 Twitter, Inc.
673
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
674
+ * ======================================================================== */
675
+
676
+
677
+ +function ($) {
678
+ 'use strict';
679
+
680
+ // DROPDOWN CLASS DEFINITION
681
+ // =========================
682
+
683
+ var backdrop = '.dropdown-backdrop'
684
+ var toggle = '[data-toggle="dropdown"]'
685
+ var Dropdown = function (element) {
686
+ $(element).on('click.bs.dropdown', this.toggle)
687
+ }
688
+
689
+ Dropdown.VERSION = '3.2.0'
690
+
691
+ Dropdown.prototype.toggle = function (e) {
692
+ var $this = $(this)
693
+
694
+ if ($this.is('.disabled, :disabled')) return
695
+
696
+ var $parent = getParent($this)
697
+ var isActive = $parent.hasClass('open')
698
+
699
+ clearMenus()
700
+
701
+ if (!isActive) {
702
+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
703
+ // if mobile we use a backdrop because click events don't delegate
704
+ $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
705
+ }
706
+
707
+ var relatedTarget = { relatedTarget: this }
708
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
709
+
710
+ if (e.isDefaultPrevented()) return
711
+
712
+ $this.trigger('focus')
713
+
714
+ $parent
715
+ .toggleClass('open')
716
+ .trigger('shown.bs.dropdown', relatedTarget)
717
+ }
718
+
719
+ return false
720
+ }
721
+
722
+ Dropdown.prototype.keydown = function (e) {
723
+ if (!/(38|40|27)/.test(e.keyCode)) return
724
+
725
+ var $this = $(this)
726
+
727
+ e.preventDefault()
728
+ e.stopPropagation()
729
+
730
+ if ($this.is('.disabled, :disabled')) return
731
+
732
+ var $parent = getParent($this)
733
+ var isActive = $parent.hasClass('open')
734
+
735
+ if (!isActive || (isActive && e.keyCode == 27)) {
736
+ if (e.which == 27) $parent.find(toggle).trigger('focus')
737
+ return $this.trigger('click')
738
+ }
739
+
740
+ var desc = ' li:not(.divider):visible a'
741
+ var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
742
+
743
+ if (!$items.length) return
744
+
745
+ var index = $items.index($items.filter(':focus'))
746
+
747
+ if (e.keyCode == 38 && index > 0) index-- // up
748
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
749
+ if (!~index) index = 0
750
+
751
+ $items.eq(index).trigger('focus')
752
+ }
753
+
754
+ function clearMenus(e) {
755
+ if (e && e.which === 3) return
756
+ $(backdrop).remove()
757
+ $(toggle).each(function () {
758
+ var $parent = getParent($(this))
759
+ var relatedTarget = { relatedTarget: this }
760
+ if (!$parent.hasClass('open')) return
761
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
762
+ if (e.isDefaultPrevented()) return
763
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
764
+ })
765
+ }
766
+
767
+ function getParent($this) {
768
+ var selector = $this.attr('data-target')
769
+
770
+ if (!selector) {
771
+ selector = $this.attr('href')
772
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
773
+ }
774
+
775
+ var $parent = selector && $(selector)
776
+
777
+ return $parent && $parent.length ? $parent : $this.parent()
778
+ }
779
+
780
+
781
+ // DROPDOWN PLUGIN DEFINITION
782
+ // ==========================
783
+
784
+ function Plugin(option) {
785
+ return this.each(function () {
786
+ var $this = $(this)
787
+ var data = $this.data('bs.dropdown')
788
+
789
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
790
+ if (typeof option == 'string') data[option].call($this)
791
+ })
792
+ }
793
+
794
+ var old = $.fn.dropdown
795
+
796
+ $.fn.dropdown = Plugin
797
+ $.fn.dropdown.Constructor = Dropdown
798
+
799
+
800
+ // DROPDOWN NO CONFLICT
801
+ // ====================
802
+
803
+ $.fn.dropdown.noConflict = function () {
804
+ $.fn.dropdown = old
805
+ return this
806
+ }
807
+
808
+
809
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
810
+ // ===================================
811
+
812
+ $(document)
813
+ .on('click.bs.dropdown.data-api', clearMenus)
814
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
815
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
816
+ .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown)
817
+
818
+ }(jQuery);
819
+
820
+ /* ========================================================================
821
+ * Bootstrap: modal.js v3.2.0
822
+ * http://getbootstrap.com/javascript/#modals
823
+ * ========================================================================
824
+ * Copyright 2011-2014 Twitter, Inc.
825
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
826
+ * ======================================================================== */
827
+
828
+
829
+ +function ($) {
830
+ 'use strict';
831
+
832
+ // MODAL CLASS DEFINITION
833
+ // ======================
834
+
835
+ var Modal = function (element, options) {
836
+ this.options = options
837
+ this.$body = $(document.body)
838
+ this.$element = $(element)
839
+ this.$backdrop =
840
+ this.isShown = null
841
+ this.scrollbarWidth = 0
842
+
843
+ if (this.options.remote) {
844
+ this.$element
845
+ .find('.modal-content')
846
+ .load(this.options.remote, $.proxy(function () {
847
+ this.$element.trigger('loaded.bs.modal')
848
+ }, this))
849
+ }
850
+ }
851
+
852
+ Modal.VERSION = '3.2.0'
853
+
854
+ Modal.DEFAULTS = {
855
+ backdrop: true,
856
+ keyboard: true,
857
+ show: true
858
+ }
859
+
860
+ Modal.prototype.toggle = function (_relatedTarget) {
861
+ return this.isShown ? this.hide() : this.show(_relatedTarget)
862
+ }
863
+
864
+ Modal.prototype.show = function (_relatedTarget) {
865
+ var that = this
866
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
867
+
868
+ this.$element.trigger(e)
869
+
870
+ if (this.isShown || e.isDefaultPrevented()) return
871
+
872
+ this.isShown = true
873
+
874
+ this.checkScrollbar()
875
+ this.$body.addClass('modal-open')
876
+
877
+ this.setScrollbar()
878
+ this.escape()
879
+
880
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
881
+
882
+ this.backdrop(function () {
883
+ var transition = $.support.transition && that.$element.hasClass('fade')
884
+
885
+ if (!that.$element.parent().length) {
886
+ that.$element.appendTo(that.$body) // don't move modals dom position
887
+ }
888
+
889
+ that.$element
890
+ .show()
891
+ .scrollTop(0)
892
+
893
+ if (transition) {
894
+ that.$element[0].offsetWidth // force reflow
895
+ }
896
+
897
+ that.$element
898
+ .addClass('in')
899
+ .attr('aria-hidden', false)
900
+
901
+ that.enforceFocus()
902
+
903
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
904
+
905
+ transition ?
906
+ that.$element.find('.modal-dialog') // wait for modal to slide in
907
+ .one('bsTransitionEnd', function () {
908
+ that.$element.trigger('focus').trigger(e)
909
+ })
910
+ .emulateTransitionEnd(300) :
911
+ that.$element.trigger('focus').trigger(e)
912
+ })
913
+ }
914
+
915
+ Modal.prototype.hide = function (e) {
916
+ if (e) e.preventDefault()
917
+
918
+ e = $.Event('hide.bs.modal')
919
+
920
+ this.$element.trigger(e)
921
+
922
+ if (!this.isShown || e.isDefaultPrevented()) return
923
+
924
+ this.isShown = false
925
+
926
+ this.$body.removeClass('modal-open')
927
+
928
+ this.resetScrollbar()
929
+ this.escape()
930
+
931
+ $(document).off('focusin.bs.modal')
932
+
933
+ this.$element
934
+ .removeClass('in')
935
+ .attr('aria-hidden', true)
936
+ .off('click.dismiss.bs.modal')
937
+
938
+ $.support.transition && this.$element.hasClass('fade') ?
939
+ this.$element
940
+ .one('bsTransitionEnd', $.proxy(this.hideModal, this))
941
+ .emulateTransitionEnd(300) :
942
+ this.hideModal()
943
+ }
944
+
945
+ Modal.prototype.enforceFocus = function () {
946
+ $(document)
947
+ .off('focusin.bs.modal') // guard against infinite focus loop
948
+ .on('focusin.bs.modal', $.proxy(function (e) {
949
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
950
+ this.$element.trigger('focus')
951
+ }
952
+ }, this))
953
+ }
954
+
955
+ Modal.prototype.escape = function () {
956
+ if (this.isShown && this.options.keyboard) {
957
+ this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
958
+ e.which == 27 && this.hide()
959
+ }, this))
960
+ } else if (!this.isShown) {
961
+ this.$element.off('keyup.dismiss.bs.modal')
962
+ }
963
+ }
964
+
965
+ Modal.prototype.hideModal = function () {
966
+ var that = this
967
+ this.$element.hide()
968
+ this.backdrop(function () {
969
+ that.$element.trigger('hidden.bs.modal')
970
+ })
971
+ }
972
+
973
+ Modal.prototype.removeBackdrop = function () {
974
+ this.$backdrop && this.$backdrop.remove()
975
+ this.$backdrop = null
976
+ }
977
+
978
+ Modal.prototype.backdrop = function (callback) {
979
+ var that = this
980
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
981
+
982
+ if (this.isShown && this.options.backdrop) {
983
+ var doAnimate = $.support.transition && animate
984
+
985
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
986
+ .appendTo(this.$body)
987
+
988
+ this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
989
+ if (e.target !== e.currentTarget) return
990
+ this.options.backdrop == 'static'
991
+ ? this.$element[0].focus.call(this.$element[0])
992
+ : this.hide.call(this)
993
+ }, this))
994
+
995
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
996
+
997
+ this.$backdrop.addClass('in')
998
+
999
+ if (!callback) return
1000
+
1001
+ doAnimate ?
1002
+ this.$backdrop
1003
+ .one('bsTransitionEnd', callback)
1004
+ .emulateTransitionEnd(150) :
1005
+ callback()
1006
+
1007
+ } else if (!this.isShown && this.$backdrop) {
1008
+ this.$backdrop.removeClass('in')
1009
+
1010
+ var callbackRemove = function () {
1011
+ that.removeBackdrop()
1012
+ callback && callback()
1013
+ }
1014
+ $.support.transition && this.$element.hasClass('fade') ?
1015
+ this.$backdrop
1016
+ .one('bsTransitionEnd', callbackRemove)
1017
+ .emulateTransitionEnd(150) :
1018
+ callbackRemove()
1019
+
1020
+ } else if (callback) {
1021
+ callback()
1022
+ }
1023
+ }
1024
+
1025
+ Modal.prototype.checkScrollbar = function () {
1026
+ if (document.body.clientWidth >= window.innerWidth) return
1027
+ this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
1028
+ }
1029
+
1030
+ Modal.prototype.setScrollbar = function () {
1031
+ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
1032
+ if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
1033
+ }
1034
+
1035
+ Modal.prototype.resetScrollbar = function () {
1036
+ this.$body.css('padding-right', '')
1037
+ }
1038
+
1039
+ Modal.prototype.measureScrollbar = function () { // thx walsh
1040
+ var scrollDiv = document.createElement('div')
1041
+ scrollDiv.className = 'modal-scrollbar-measure'
1042
+ this.$body.append(scrollDiv)
1043
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
1044
+ this.$body[0].removeChild(scrollDiv)
1045
+ return scrollbarWidth
1046
+ }
1047
+
1048
+
1049
+ // MODAL PLUGIN DEFINITION
1050
+ // =======================
1051
+
1052
+ function Plugin(option, _relatedTarget) {
1053
+ return this.each(function () {
1054
+ var $this = $(this)
1055
+ var data = $this.data('bs.modal')
1056
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
1057
+
1058
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
1059
+ if (typeof option == 'string') data[option](_relatedTarget)
1060
+ else if (options.show) data.show(_relatedTarget)
1061
+ })
1062
+ }
1063
+
1064
+ var old = $.fn.modal
1065
+
1066
+ $.fn.modal = Plugin
1067
+ $.fn.modal.Constructor = Modal
1068
+
1069
+
1070
+ // MODAL NO CONFLICT
1071
+ // =================
1072
+
1073
+ $.fn.modal.noConflict = function () {
1074
+ $.fn.modal = old
1075
+ return this
1076
+ }
1077
+
1078
+
1079
+ // MODAL DATA-API
1080
+ // ==============
1081
+
1082
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
1083
+ var $this = $(this)
1084
+ var href = $this.attr('href')
1085
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
1086
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1087
+
1088
+ if ($this.is('a')) e.preventDefault()
1089
+
1090
+ $target.one('show.bs.modal', function (showEvent) {
1091
+ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
1092
+ $target.one('hidden.bs.modal', function () {
1093
+ $this.is(':visible') && $this.trigger('focus')
1094
+ })
1095
+ })
1096
+ Plugin.call($target, option, this)
1097
+ })
1098
+
1099
+ }(jQuery);
1100
+
1101
+ /* ========================================================================
1102
+ * Bootstrap: tooltip.js v3.2.0
1103
+ * http://getbootstrap.com/javascript/#tooltip
1104
+ * Inspired by the original jQuery.tipsy by Jason Frame
1105
+ * ========================================================================
1106
+ * Copyright 2011-2014 Twitter, Inc.
1107
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1108
+ * ======================================================================== */
1109
+
1110
+
1111
+ +function ($) {
1112
+ 'use strict';
1113
+
1114
+ // TOOLTIP PUBLIC CLASS DEFINITION
1115
+ // ===============================
1116
+
1117
+ var Tooltip = function (element, options) {
1118
+ this.type =
1119
+ this.options =
1120
+ this.enabled =
1121
+ this.timeout =
1122
+ this.hoverState =
1123
+ this.$element = null
1124
+
1125
+ this.init('tooltip', element, options)
1126
+ }
1127
+
1128
+ Tooltip.VERSION = '3.2.0'
1129
+
1130
+ Tooltip.DEFAULTS = {
1131
+ animation: true,
1132
+ placement: 'top',
1133
+ selector: false,
1134
+ template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
1135
+ trigger: 'hover focus',
1136
+ title: '',
1137
+ delay: 0,
1138
+ html: false,
1139
+ container: false,
1140
+ viewport: {
1141
+ selector: 'body',
1142
+ padding: 0
1143
+ }
1144
+ }
1145
+
1146
+ Tooltip.prototype.init = function (type, element, options) {
1147
+ this.enabled = true
1148
+ this.type = type
1149
+ this.$element = $(element)
1150
+ this.options = this.getOptions(options)
1151
+ this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
1152
+
1153
+ var triggers = this.options.trigger.split(' ')
1154
+
1155
+ for (var i = triggers.length; i--;) {
1156
+ var trigger = triggers[i]
1157
+
1158
+ if (trigger == 'click') {
1159
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1160
+ } else if (trigger != 'manual') {
1161
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
1162
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
1163
+
1164
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1165
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1166
+ }
1167
+ }
1168
+
1169
+ this.options.selector ?
1170
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
1171
+ this.fixTitle()
1172
+ }
1173
+
1174
+ Tooltip.prototype.getDefaults = function () {
1175
+ return Tooltip.DEFAULTS
1176
+ }
1177
+
1178
+ Tooltip.prototype.getOptions = function (options) {
1179
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
1180
+
1181
+ if (options.delay && typeof options.delay == 'number') {
1182
+ options.delay = {
1183
+ show: options.delay,
1184
+ hide: options.delay
1185
+ }
1186
+ }
1187
+
1188
+ return options
1189
+ }
1190
+
1191
+ Tooltip.prototype.getDelegateOptions = function () {
1192
+ var options = {}
1193
+ var defaults = this.getDefaults()
1194
+
1195
+ this._options && $.each(this._options, function (key, value) {
1196
+ if (defaults[key] != value) options[key] = value
1197
+ })
1198
+
1199
+ return options
1200
+ }
1201
+
1202
+ Tooltip.prototype.enter = function (obj) {
1203
+ var self = obj instanceof this.constructor ?
1204
+ obj : $(obj.currentTarget).data('bs.' + this.type)
1205
+
1206
+ if (!self) {
1207
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1208
+ $(obj.currentTarget).data('bs.' + this.type, self)
1209
+ }
1210
+
1211
+ clearTimeout(self.timeout)
1212
+
1213
+ self.hoverState = 'in'
1214
+
1215
+ if (!self.options.delay || !self.options.delay.show) return self.show()
1216
+
1217
+ self.timeout = setTimeout(function () {
1218
+ if (self.hoverState == 'in') self.show()
1219
+ }, self.options.delay.show)
1220
+ }
1221
+
1222
+ Tooltip.prototype.leave = function (obj) {
1223
+ var self = obj instanceof this.constructor ?
1224
+ obj : $(obj.currentTarget).data('bs.' + this.type)
1225
+
1226
+ if (!self) {
1227
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1228
+ $(obj.currentTarget).data('bs.' + this.type, self)
1229
+ }
1230
+
1231
+ clearTimeout(self.timeout)
1232
+
1233
+ self.hoverState = 'out'
1234
+
1235
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
1236
+
1237
+ self.timeout = setTimeout(function () {
1238
+ if (self.hoverState == 'out') self.hide()
1239
+ }, self.options.delay.hide)
1240
+ }
1241
+
1242
+ Tooltip.prototype.show = function () {
1243
+ var e = $.Event('show.bs.' + this.type)
1244
+
1245
+ if (this.hasContent() && this.enabled) {
1246
+ this.$element.trigger(e)
1247
+
1248
+ var inDom = $.contains(document.documentElement, this.$element[0])
1249
+ if (e.isDefaultPrevented() || !inDom) return
1250
+ var that = this
1251
+
1252
+ var $tip = this.tip()
1253
+
1254
+ var tipId = this.getUID(this.type)
1255
+
1256
+ this.setContent()
1257
+ $tip.attr('id', tipId)
1258
+ this.$element.attr('aria-describedby', tipId)
1259
+
1260
+ if (this.options.animation) $tip.addClass('fade')
1261
+
1262
+ var placement = typeof this.options.placement == 'function' ?
1263
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
1264
+ this.options.placement
1265
+
1266
+ var autoToken = /\s?auto?\s?/i
1267
+ var autoPlace = autoToken.test(placement)
1268
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
1269
+
1270
+ $tip
1271
+ .detach()
1272
+ .css({ top: 0, left: 0, display: 'block' })
1273
+ .addClass(placement)
1274
+ .data('bs.' + this.type, this)
1275
+
1276
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1277
+
1278
+ var pos = this.getPosition()
1279
+ var actualWidth = $tip[0].offsetWidth
1280
+ var actualHeight = $tip[0].offsetHeight
1281
+
1282
+ if (autoPlace) {
1283
+ var orgPlacement = placement
1284
+ var $parent = this.$element.parent()
1285
+ var parentDim = this.getPosition($parent)
1286
+
1287
+ placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' :
1288
+ placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' :
1289
+ placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' :
1290
+ placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' :
1291
+ placement
1292
+
1293
+ $tip
1294
+ .removeClass(orgPlacement)
1295
+ .addClass(placement)
1296
+ }
1297
+
1298
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
1299
+
1300
+ this.applyPlacement(calculatedOffset, placement)
1301
+
1302
+ var complete = function () {
1303
+ that.$element.trigger('shown.bs.' + that.type)
1304
+ that.hoverState = null
1305
+ }
1306
+
1307
+ $.support.transition && this.$tip.hasClass('fade') ?
1308
+ $tip
1309
+ .one('bsTransitionEnd', complete)
1310
+ .emulateTransitionEnd(150) :
1311
+ complete()
1312
+ }
1313
+ }
1314
+
1315
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
1316
+ var $tip = this.tip()
1317
+ var width = $tip[0].offsetWidth
1318
+ var height = $tip[0].offsetHeight
1319
+
1320
+ // manually read margins because getBoundingClientRect includes difference
1321
+ var marginTop = parseInt($tip.css('margin-top'), 10)
1322
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
1323
+
1324
+ // we must check for NaN for ie 8/9
1325
+ if (isNaN(marginTop)) marginTop = 0
1326
+ if (isNaN(marginLeft)) marginLeft = 0
1327
+
1328
+ offset.top = offset.top + marginTop
1329
+ offset.left = offset.left + marginLeft
1330
+
1331
+ // $.fn.offset doesn't round pixel values
1332
+ // so we use setOffset directly with our own function B-0
1333
+ $.offset.setOffset($tip[0], $.extend({
1334
+ using: function (props) {
1335
+ $tip.css({
1336
+ top: Math.round(props.top),
1337
+ left: Math.round(props.left)
1338
+ })
1339
+ }
1340
+ }, offset), 0)
1341
+
1342
+ $tip.addClass('in')
1343
+
1344
+ // check to see if placing tip in new offset caused the tip to resize itself
1345
+ var actualWidth = $tip[0].offsetWidth
1346
+ var actualHeight = $tip[0].offsetHeight
1347
+
1348
+ if (placement == 'top' && actualHeight != height) {
1349
+ offset.top = offset.top + height - actualHeight
1350
+ }
1351
+
1352
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
1353
+
1354
+ if (delta.left) offset.left += delta.left
1355
+ else offset.top += delta.top
1356
+
1357
+ var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
1358
+ var arrowPosition = delta.left ? 'left' : 'top'
1359
+ var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
1360
+
1361
+ $tip.offset(offset)
1362
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
1363
+ }
1364
+
1365
+ Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
1366
+ this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
1367
+ }
1368
+
1369
+ Tooltip.prototype.setContent = function () {
1370
+ var $tip = this.tip()
1371
+ var title = this.getTitle()
1372
+
1373
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
1374
+ $tip.removeClass('fade in top bottom left right')
1375
+ }
1376
+
1377
+ Tooltip.prototype.hide = function () {
1378
+ var that = this
1379
+ var $tip = this.tip()
1380
+ var e = $.Event('hide.bs.' + this.type)
1381
+
1382
+ this.$element.removeAttr('aria-describedby')
1383
+
1384
+ function complete() {
1385
+ if (that.hoverState != 'in') $tip.detach()
1386
+ that.$element.trigger('hidden.bs.' + that.type)
1387
+ }
1388
+
1389
+ this.$element.trigger(e)
1390
+
1391
+ if (e.isDefaultPrevented()) return
1392
+
1393
+ $tip.removeClass('in')
1394
+
1395
+ $.support.transition && this.$tip.hasClass('fade') ?
1396
+ $tip
1397
+ .one('bsTransitionEnd', complete)
1398
+ .emulateTransitionEnd(150) :
1399
+ complete()
1400
+
1401
+ this.hoverState = null
1402
+
1403
+ return this
1404
+ }
1405
+
1406
+ Tooltip.prototype.fixTitle = function () {
1407
+ var $e = this.$element
1408
+ if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
1409
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1410
+ }
1411
+ }
1412
+
1413
+ Tooltip.prototype.hasContent = function () {
1414
+ return this.getTitle()
1415
+ }
1416
+
1417
+ Tooltip.prototype.getPosition = function ($element) {
1418
+ $element = $element || this.$element
1419
+ var el = $element[0]
1420
+ var isBody = el.tagName == 'BODY'
1421
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
1422
+ scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
1423
+ width: isBody ? $(window).width() : $element.outerWidth(),
1424
+ height: isBody ? $(window).height() : $element.outerHeight()
1425
+ }, isBody ? { top: 0, left: 0 } : $element.offset())
1426
+ }
1427
+
1428
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
1429
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1430
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1431
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
1432
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
1433
+
1434
+ }
1435
+
1436
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
1437
+ var delta = { top: 0, left: 0 }
1438
+ if (!this.$viewport) return delta
1439
+
1440
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
1441
+ var viewportDimensions = this.getPosition(this.$viewport)
1442
+
1443
+ if (/right|left/.test(placement)) {
1444
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
1445
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
1446
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
1447
+ delta.top = viewportDimensions.top - topEdgeOffset
1448
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
1449
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
1450
+ }
1451
+ } else {
1452
+ var leftEdgeOffset = pos.left - viewportPadding
1453
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
1454
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
1455
+ delta.left = viewportDimensions.left - leftEdgeOffset
1456
+ } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
1457
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
1458
+ }
1459
+ }
1460
+
1461
+ return delta
1462
+ }
1463
+
1464
+ Tooltip.prototype.getTitle = function () {
1465
+ var title
1466
+ var $e = this.$element
1467
+ var o = this.options
1468
+
1469
+ title = $e.attr('data-original-title')
1470
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1471
+
1472
+ return title
1473
+ }
1474
+
1475
+ Tooltip.prototype.getUID = function (prefix) {
1476
+ do prefix += ~~(Math.random() * 1000000)
1477
+ while (document.getElementById(prefix))
1478
+ return prefix
1479
+ }
1480
+
1481
+ Tooltip.prototype.tip = function () {
1482
+ return (this.$tip = this.$tip || $(this.options.template))
1483
+ }
1484
+
1485
+ Tooltip.prototype.arrow = function () {
1486
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
1487
+ }
1488
+
1489
+ Tooltip.prototype.validate = function () {
1490
+ if (!this.$element[0].parentNode) {
1491
+ this.hide()
1492
+ this.$element = null
1493
+ this.options = null
1494
+ }
1495
+ }
1496
+
1497
+ Tooltip.prototype.enable = function () {
1498
+ this.enabled = true
1499
+ }
1500
+
1501
+ Tooltip.prototype.disable = function () {
1502
+ this.enabled = false
1503
+ }
1504
+
1505
+ Tooltip.prototype.toggleEnabled = function () {
1506
+ this.enabled = !this.enabled
1507
+ }
1508
+
1509
+ Tooltip.prototype.toggle = function (e) {
1510
+ var self = this
1511
+ if (e) {
1512
+ self = $(e.currentTarget).data('bs.' + this.type)
1513
+ if (!self) {
1514
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
1515
+ $(e.currentTarget).data('bs.' + this.type, self)
1516
+ }
1517
+ }
1518
+
1519
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
1520
+ }
1521
+
1522
+ Tooltip.prototype.destroy = function () {
1523
+ clearTimeout(this.timeout)
1524
+ this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
1525
+ }
1526
+
1527
+
1528
+ // TOOLTIP PLUGIN DEFINITION
1529
+ // =========================
1530
+
1531
+ function Plugin(option) {
1532
+ return this.each(function () {
1533
+ var $this = $(this)
1534
+ var data = $this.data('bs.tooltip')
1535
+ var options = typeof option == 'object' && option
1536
+
1537
+ if (!data && option == 'destroy') return
1538
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
1539
+ if (typeof option == 'string') data[option]()
1540
+ })
1541
+ }
1542
+
1543
+ var old = $.fn.tooltip
1544
+
1545
+ $.fn.tooltip = Plugin
1546
+ $.fn.tooltip.Constructor = Tooltip
1547
+
1548
+
1549
+ // TOOLTIP NO CONFLICT
1550
+ // ===================
1551
+
1552
+ $.fn.tooltip.noConflict = function () {
1553
+ $.fn.tooltip = old
1554
+ return this
1555
+ }
1556
+
1557
+ }(jQuery);
1558
+
1559
+ /* ========================================================================
1560
+ * Bootstrap: popover.js v3.2.0
1561
+ * http://getbootstrap.com/javascript/#popovers
1562
+ * ========================================================================
1563
+ * Copyright 2011-2014 Twitter, Inc.
1564
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1565
+ * ======================================================================== */
1566
+
1567
+
1568
+ +function ($) {
1569
+ 'use strict';
1570
+
1571
+ // POPOVER PUBLIC CLASS DEFINITION
1572
+ // ===============================
1573
+
1574
+ var Popover = function (element, options) {
1575
+ this.init('popover', element, options)
1576
+ }
1577
+
1578
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
1579
+
1580
+ Popover.VERSION = '3.2.0'
1581
+
1582
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
1583
+ placement: 'right',
1584
+ trigger: 'click',
1585
+ content: '',
1586
+ template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1587
+ })
1588
+
1589
+
1590
+ // NOTE: POPOVER EXTENDS tooltip.js
1591
+ // ================================
1592
+
1593
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
1594
+
1595
+ Popover.prototype.constructor = Popover
1596
+
1597
+ Popover.prototype.getDefaults = function () {
1598
+ return Popover.DEFAULTS
1599
+ }
1600
+
1601
+ Popover.prototype.setContent = function () {
1602
+ var $tip = this.tip()
1603
+ var title = this.getTitle()
1604
+ var content = this.getContent()
1605
+
1606
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1607
+ $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events
1608
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
1609
+ ](content)
1610
+
1611
+ $tip.removeClass('fade top bottom left right in')
1612
+
1613
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
1614
+ // this manually by checking the contents.
1615
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
1616
+ }
1617
+
1618
+ Popover.prototype.hasContent = function () {
1619
+ return this.getTitle() || this.getContent()
1620
+ }
1621
+
1622
+ Popover.prototype.getContent = function () {
1623
+ var $e = this.$element
1624
+ var o = this.options
1625
+
1626
+ return $e.attr('data-content')
1627
+ || (typeof o.content == 'function' ?
1628
+ o.content.call($e[0]) :
1629
+ o.content)
1630
+ }
1631
+
1632
+ Popover.prototype.arrow = function () {
1633
+ return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
1634
+ }
1635
+
1636
+ Popover.prototype.tip = function () {
1637
+ if (!this.$tip) this.$tip = $(this.options.template)
1638
+ return this.$tip
1639
+ }
1640
+
1641
+
1642
+ // POPOVER PLUGIN DEFINITION
1643
+ // =========================
1644
+
1645
+ function Plugin(option) {
1646
+ return this.each(function () {
1647
+ var $this = $(this)
1648
+ var data = $this.data('bs.popover')
1649
+ var options = typeof option == 'object' && option
1650
+
1651
+ if (!data && option == 'destroy') return
1652
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
1653
+ if (typeof option == 'string') data[option]()
1654
+ })
1655
+ }
1656
+
1657
+ var old = $.fn.popover
1658
+
1659
+ $.fn.popover = Plugin
1660
+ $.fn.popover.Constructor = Popover
1661
+
1662
+
1663
+ // POPOVER NO CONFLICT
1664
+ // ===================
1665
+
1666
+ $.fn.popover.noConflict = function () {
1667
+ $.fn.popover = old
1668
+ return this
1669
+ }
1670
+
1671
+ }(jQuery);
1672
+
1673
+ /* ========================================================================
1674
+ * Bootstrap: scrollspy.js v3.2.0
1675
+ * http://getbootstrap.com/javascript/#scrollspy
1676
+ * ========================================================================
1677
+ * Copyright 2011-2014 Twitter, Inc.
1678
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1679
+ * ======================================================================== */
1680
+
1681
+
1682
+ +function ($) {
1683
+ 'use strict';
1684
+
1685
+ // SCROLLSPY CLASS DEFINITION
1686
+ // ==========================
1687
+
1688
+ function ScrollSpy(element, options) {
1689
+ var process = $.proxy(this.process, this)
1690
+
1691
+ this.$body = $('body')
1692
+ this.$scrollElement = $(element).is('body') ? $(window) : $(element)
1693
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
1694
+ this.selector = (this.options.target || '') + ' .nav li > a'
1695
+ this.offsets = []
1696
+ this.targets = []
1697
+ this.activeTarget = null
1698
+ this.scrollHeight = 0
1699
+
1700
+ this.$scrollElement.on('scroll.bs.scrollspy', process)
1701
+ this.refresh()
1702
+ this.process()
1703
+ }
1704
+
1705
+ ScrollSpy.VERSION = '3.2.0'
1706
+
1707
+ ScrollSpy.DEFAULTS = {
1708
+ offset: 10
1709
+ }
1710
+
1711
+ ScrollSpy.prototype.getScrollHeight = function () {
1712
+ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
1713
+ }
1714
+
1715
+ ScrollSpy.prototype.refresh = function () {
1716
+ var offsetMethod = 'offset'
1717
+ var offsetBase = 0
1718
+
1719
+ if (!$.isWindow(this.$scrollElement[0])) {
1720
+ offsetMethod = 'position'
1721
+ offsetBase = this.$scrollElement.scrollTop()
1722
+ }
1723
+
1724
+ this.offsets = []
1725
+ this.targets = []
1726
+ this.scrollHeight = this.getScrollHeight()
1727
+
1728
+ var self = this
1729
+
1730
+ this.$body
1731
+ .find(this.selector)
1732
+ .map(function () {
1733
+ var $el = $(this)
1734
+ var href = $el.data('target') || $el.attr('href')
1735
+ var $href = /^#./.test(href) && $(href)
1736
+
1737
+ return ($href
1738
+ && $href.length
1739
+ && $href.is(':visible')
1740
+ && [[$href[offsetMethod]().top + offsetBase, href]]) || null
1741
+ })
1742
+ .sort(function (a, b) { return a[0] - b[0] })
1743
+ .each(function () {
1744
+ self.offsets.push(this[0])
1745
+ self.targets.push(this[1])
1746
+ })
1747
+ }
1748
+
1749
+ ScrollSpy.prototype.process = function () {
1750
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1751
+ var scrollHeight = this.getScrollHeight()
1752
+ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
1753
+ var offsets = this.offsets
1754
+ var targets = this.targets
1755
+ var activeTarget = this.activeTarget
1756
+ var i
1757
+
1758
+ if (this.scrollHeight != scrollHeight) {
1759
+ this.refresh()
1760
+ }
1761
+
1762
+ if (scrollTop >= maxScroll) {
1763
+ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
1764
+ }
1765
+
1766
+ if (activeTarget && scrollTop <= offsets[0]) {
1767
+ return activeTarget != (i = targets[0]) && this.activate(i)
1768
+ }
1769
+
1770
+ for (i = offsets.length; i--;) {
1771
+ activeTarget != targets[i]
1772
+ && scrollTop >= offsets[i]
1773
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
1774
+ && this.activate(targets[i])
1775
+ }
1776
+ }
1777
+
1778
+ ScrollSpy.prototype.activate = function (target) {
1779
+ this.activeTarget = target
1780
+
1781
+ $(this.selector)
1782
+ .parentsUntil(this.options.target, '.active')
1783
+ .removeClass('active')
1784
+
1785
+ var selector = this.selector +
1786
+ '[data-target="' + target + '"],' +
1787
+ this.selector + '[href="' + target + '"]'
1788
+
1789
+ var active = $(selector)
1790
+ .parents('li')
1791
+ .addClass('active')
1792
+
1793
+ if (active.parent('.dropdown-menu').length) {
1794
+ active = active
1795
+ .closest('li.dropdown')
1796
+ .addClass('active')
1797
+ }
1798
+
1799
+ active.trigger('activate.bs.scrollspy')
1800
+ }
1801
+
1802
+
1803
+ // SCROLLSPY PLUGIN DEFINITION
1804
+ // ===========================
1805
+
1806
+ function Plugin(option) {
1807
+ return this.each(function () {
1808
+ var $this = $(this)
1809
+ var data = $this.data('bs.scrollspy')
1810
+ var options = typeof option == 'object' && option
1811
+
1812
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
1813
+ if (typeof option == 'string') data[option]()
1814
+ })
1815
+ }
1816
+
1817
+ var old = $.fn.scrollspy
1818
+
1819
+ $.fn.scrollspy = Plugin
1820
+ $.fn.scrollspy.Constructor = ScrollSpy
1821
+
1822
+
1823
+ // SCROLLSPY NO CONFLICT
1824
+ // =====================
1825
+
1826
+ $.fn.scrollspy.noConflict = function () {
1827
+ $.fn.scrollspy = old
1828
+ return this
1829
+ }
1830
+
1831
+
1832
+ // SCROLLSPY DATA-API
1833
+ // ==================
1834
+
1835
+ $(window).on('load.bs.scrollspy.data-api', function () {
1836
+ $('[data-spy="scroll"]').each(function () {
1837
+ var $spy = $(this)
1838
+ Plugin.call($spy, $spy.data())
1839
+ })
1840
+ })
1841
+
1842
+ }(jQuery);
1843
+
1844
+ /* ========================================================================
1845
+ * Bootstrap: tab.js v3.2.0
1846
+ * http://getbootstrap.com/javascript/#tabs
1847
+ * ========================================================================
1848
+ * Copyright 2011-2014 Twitter, Inc.
1849
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1850
+ * ======================================================================== */
1851
+
1852
+
1853
+ +function ($) {
1854
+ 'use strict';
1855
+
1856
+ // TAB CLASS DEFINITION
1857
+ // ====================
1858
+
1859
+ var Tab = function (element) {
1860
+ this.element = $(element)
1861
+ }
1862
+
1863
+ Tab.VERSION = '3.2.0'
1864
+
1865
+ Tab.prototype.show = function () {
1866
+ var $this = this.element
1867
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
1868
+ var selector = $this.data('target')
1869
+
1870
+ if (!selector) {
1871
+ selector = $this.attr('href')
1872
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
1873
+ }
1874
+
1875
+ if ($this.parent('li').hasClass('active')) return
1876
+
1877
+ var previous = $ul.find('.active:last a')[0]
1878
+ var e = $.Event('show.bs.tab', {
1879
+ relatedTarget: previous
1880
+ })
1881
+
1882
+ $this.trigger(e)
1883
+
1884
+ if (e.isDefaultPrevented()) return
1885
+
1886
+ var $target = $(selector)
1887
+
1888
+ this.activate($this.closest('li'), $ul)
1889
+ this.activate($target, $target.parent(), function () {
1890
+ $this.trigger({
1891
+ type: 'shown.bs.tab',
1892
+ relatedTarget: previous
1893
+ })
1894
+ })
1895
+ }
1896
+
1897
+ Tab.prototype.activate = function (element, container, callback) {
1898
+ var $active = container.find('> .active')
1899
+ var transition = callback
1900
+ && $.support.transition
1901
+ && $active.hasClass('fade')
1902
+
1903
+ function next() {
1904
+ $active
1905
+ .removeClass('active')
1906
+ .find('> .dropdown-menu > .active')
1907
+ .removeClass('active')
1908
+
1909
+ element.addClass('active')
1910
+
1911
+ if (transition) {
1912
+ element[0].offsetWidth // reflow for transition
1913
+ element.addClass('in')
1914
+ } else {
1915
+ element.removeClass('fade')
1916
+ }
1917
+
1918
+ if (element.parent('.dropdown-menu')) {
1919
+ element.closest('li.dropdown').addClass('active')
1920
+ }
1921
+
1922
+ callback && callback()
1923
+ }
1924
+
1925
+ transition ?
1926
+ $active
1927
+ .one('bsTransitionEnd', next)
1928
+ .emulateTransitionEnd(150) :
1929
+ next()
1930
+
1931
+ $active.removeClass('in')
1932
+ }
1933
+
1934
+
1935
+ // TAB PLUGIN DEFINITION
1936
+ // =====================
1937
+
1938
+ function Plugin(option) {
1939
+ return this.each(function () {
1940
+ var $this = $(this)
1941
+ var data = $this.data('bs.tab')
1942
+
1943
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
1944
+ if (typeof option == 'string') data[option]()
1945
+ })
1946
+ }
1947
+
1948
+ var old = $.fn.tab
1949
+
1950
+ $.fn.tab = Plugin
1951
+ $.fn.tab.Constructor = Tab
1952
+
1953
+
1954
+ // TAB NO CONFLICT
1955
+ // ===============
1956
+
1957
+ $.fn.tab.noConflict = function () {
1958
+ $.fn.tab = old
1959
+ return this
1960
+ }
1961
+
1962
+
1963
+ // TAB DATA-API
1964
+ // ============
1965
+
1966
+ $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1967
+ e.preventDefault()
1968
+ Plugin.call($(this), 'show')
1969
+ })
1970
+
1971
+ }(jQuery);
1972
+
1973
+ /* ========================================================================
1974
+ * Bootstrap: affix.js v3.2.0
1975
+ * http://getbootstrap.com/javascript/#affix
1976
+ * ========================================================================
1977
+ * Copyright 2011-2014 Twitter, Inc.
1978
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1979
+ * ======================================================================== */
1980
+
1981
+
1982
+ +function ($) {
1983
+ 'use strict';
1984
+
1985
+ // AFFIX CLASS DEFINITION
1986
+ // ======================
1987
+
1988
+ var Affix = function (element, options) {
1989
+ this.options = $.extend({}, Affix.DEFAULTS, options)
1990
+
1991
+ this.$target = $(this.options.target)
1992
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
1993
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
1994
+
1995
+ this.$element = $(element)
1996
+ this.affixed =
1997
+ this.unpin =
1998
+ this.pinnedOffset = null
1999
+
2000
+ this.checkPosition()
2001
+ }
2002
+
2003
+ Affix.VERSION = '3.2.0'
2004
+
2005
+ Affix.RESET = 'affix affix-top affix-bottom'
2006
+
2007
+ Affix.DEFAULTS = {
2008
+ offset: 0,
2009
+ target: window
2010
+ }
2011
+
2012
+ Affix.prototype.getPinnedOffset = function () {
2013
+ if (this.pinnedOffset) return this.pinnedOffset
2014
+ this.$element.removeClass(Affix.RESET).addClass('affix')
2015
+ var scrollTop = this.$target.scrollTop()
2016
+ var position = this.$element.offset()
2017
+ return (this.pinnedOffset = position.top - scrollTop)
2018
+ }
2019
+
2020
+ Affix.prototype.checkPositionWithEventLoop = function () {
2021
+ setTimeout($.proxy(this.checkPosition, this), 1)
2022
+ }
2023
+
2024
+ Affix.prototype.checkPosition = function () {
2025
+ if (!this.$element.is(':visible')) return
2026
+
2027
+ var scrollHeight = $(document).height()
2028
+ var scrollTop = this.$target.scrollTop()
2029
+ var position = this.$element.offset()
2030
+ var offset = this.options.offset
2031
+ var offsetTop = offset.top
2032
+ var offsetBottom = offset.bottom
2033
+
2034
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
2035
+ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
2036
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
2037
+
2038
+ var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false :
2039
+ offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
2040
+ offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
2041
+
2042
+ if (this.affixed === affix) return
2043
+ if (this.unpin != null) this.$element.css('top', '')
2044
+
2045
+ var affixType = 'affix' + (affix ? '-' + affix : '')
2046
+ var e = $.Event(affixType + '.bs.affix')
2047
+
2048
+ this.$element.trigger(e)
2049
+
2050
+ if (e.isDefaultPrevented()) return
2051
+
2052
+ this.affixed = affix
2053
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
2054
+
2055
+ this.$element
2056
+ .removeClass(Affix.RESET)
2057
+ .addClass(affixType)
2058
+ .trigger($.Event(affixType.replace('affix', 'affixed')))
2059
+
2060
+ if (affix == 'bottom') {
2061
+ this.$element.offset({
2062
+ top: scrollHeight - this.$element.height() - offsetBottom
2063
+ })
2064
+ }
2065
+ }
2066
+
2067
+
2068
+ // AFFIX PLUGIN DEFINITION
2069
+ // =======================
2070
+
2071
+ function Plugin(option) {
2072
+ return this.each(function () {
2073
+ var $this = $(this)
2074
+ var data = $this.data('bs.affix')
2075
+ var options = typeof option == 'object' && option
2076
+
2077
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
2078
+ if (typeof option == 'string') data[option]()
2079
+ })
2080
+ }
2081
+
2082
+ var old = $.fn.affix
2083
+
2084
+ $.fn.affix = Plugin
2085
+ $.fn.affix.Constructor = Affix
2086
+
2087
+
2088
+ // AFFIX NO CONFLICT
2089
+ // =================
2090
+
2091
+ $.fn.affix.noConflict = function () {
2092
+ $.fn.affix = old
2093
+ return this
2094
+ }
2095
+
2096
+
2097
+ // AFFIX DATA-API
2098
+ // ==============
2099
+
2100
+ $(window).on('load', function () {
2101
+ $('[data-spy="affix"]').each(function () {
2102
+ var $spy = $(this)
2103
+ var data = $spy.data()
2104
+
2105
+ data.offset = data.offset || {}
2106
+
2107
+ if (data.offsetBottom) data.offset.bottom = data.offsetBottom
2108
+ if (data.offsetTop) data.offset.top = data.offsetTop
2109
+
2110
+ Plugin.call($spy, data)
2111
+ })
2112
+ })
2113
+
2114
+ }(jQuery);