adhoq 0.0.2

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