adhoq 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+