scales-monitor 0.0.1.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE +22 -0
  4. data/Rakefile +8 -0
  5. data/bin/scales-monitor +8 -0
  6. data/lib/scales-monitor.rb +11 -0
  7. data/lib/scales-monitor/app/Gemfile +3 -0
  8. data/lib/scales-monitor/app/Rakefile +0 -0
  9. data/lib/scales-monitor/app/app/assets/images/.gitignore +0 -0
  10. data/lib/scales-monitor/app/app/assets/images/glyphicons-halflings-white.png +0 -0
  11. data/lib/scales-monitor/app/app/assets/images/glyphicons-halflings.png +0 -0
  12. data/lib/scales-monitor/app/app/assets/javascripts/app/config/config.js.coffee +8 -0
  13. data/lib/scales-monitor/app/app/assets/javascripts/app/config/routes.js.coffee +15 -0
  14. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/.gitignore +0 -0
  15. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/log.jst.coffee +58 -0
  16. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/machines.js.coffee +60 -0
  17. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/queues.js.coffee +55 -0
  18. data/lib/scales-monitor/app/app/assets/javascripts/app/controllers/resources.js.coffee +128 -0
  19. data/lib/scales-monitor/app/app/assets/javascripts/app/index.js.coffee +8 -0
  20. data/lib/scales-monitor/app/app/assets/javascripts/app/models/.gitignore +0 -0
  21. data/lib/scales-monitor/app/app/assets/javascripts/app/models/socket.js.coffee +9 -0
  22. data/lib/scales-monitor/app/app/assets/javascripts/app/views/.gitignore +0 -0
  23. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_format_bar.jst.eco +10 -0
  24. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_machine.jst.eco +11 -0
  25. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_queue_item.jst.eco +10 -0
  26. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_resource.jst.eco +5 -0
  27. data/lib/scales-monitor/app/app/assets/javascripts/app/views/_top.jst.eco +1 -0
  28. data/lib/scales-monitor/app/app/assets/javascripts/app/views/log.jst.eco +11 -0
  29. data/lib/scales-monitor/app/app/assets/javascripts/app/views/machines.jst.eco +33 -0
  30. data/lib/scales-monitor/app/app/assets/javascripts/app/views/queues.jst.eco +33 -0
  31. data/lib/scales-monitor/app/app/assets/javascripts/app/views/resources.jst.eco +31 -0
  32. data/lib/scales-monitor/app/app/assets/javascripts/application.js.coffee +16 -0
  33. data/lib/scales-monitor/app/app/assets/javascripts/lib/bootstrap.js +1825 -0
  34. data/lib/scales-monitor/app/app/assets/javascripts/lib/jquery.js +4 -0
  35. data/lib/scales-monitor/app/app/assets/javascripts/lib/jquery.timeago.js +152 -0
  36. data/lib/scales-monitor/app/app/assets/javascripts/lib/json2.js +485 -0
  37. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/ajax.coffee +208 -0
  38. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/list.coffee +43 -0
  39. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/local.coffee +16 -0
  40. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/manager.coffee +83 -0
  41. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/relation.coffee +144 -0
  42. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/route.coffee +145 -0
  43. data/lib/scales-monitor/app/app/assets/javascripts/lib/spine/spine.coffee +537 -0
  44. data/lib/scales-monitor/app/app/assets/stylesheets/application.css.scss +58 -0
  45. data/lib/scales-monitor/app/app/assets/stylesheets/bootstrap-docs.css +845 -0
  46. data/lib/scales-monitor/app/app/assets/stylesheets/bootstrap-responsive.css +815 -0
  47. data/lib/scales-monitor/app/app/assets/stylesheets/bootstrap.css +4983 -0
  48. data/lib/scales-monitor/app/app/views/index.html.erb +45 -0
  49. data/lib/scales-monitor/app/config.ru +3 -0
  50. data/lib/scales-monitor/app/config/config.rb +17 -0
  51. data/lib/scales-monitor/app/config/routes.rb +13 -0
  52. data/lib/scales-monitor/app/public/assets/.gitignore +0 -0
  53. data/lib/scales-monitor/app/public/assets/application.css +6709 -0
  54. data/lib/scales-monitor/app/public/assets/application.js +5563 -0
  55. data/lib/scales-monitor/app/public/assets/glyphicons-halflings-white.png +0 -0
  56. data/lib/scales-monitor/app/public/assets/glyphicons-halflings.png +0 -0
  57. data/lib/scales-monitor/app/public/index.html +45 -0
  58. data/lib/scales-monitor/base.rb +17 -0
  59. data/lib/scales-monitor/boot/autoload.rb +5 -0
  60. data/lib/scales-monitor/boot/initializers/goliath.rb +3 -0
  61. data/lib/scales-monitor/monitor.rb +33 -0
  62. data/lib/scales-monitor/version.rb +5 -0
  63. data/lib/scales-monitor/web_socket.rb +180 -0
  64. data/scales-monitor.gemspec +24 -0
  65. data/spec/gem_spec.rb +7 -0
  66. data/spec/helper.rb +50 -0
  67. data/spec/monitor_spec.rb +50 -0
  68. data/spec/web_socket_spec.rb +103 -0
  69. metadata +174 -0
@@ -0,0 +1,9 @@
1
+ class App.Socket
2
+
3
+ @setup: ->
4
+ @socket = new WebSocket(App.Config.webSocket)
5
+
6
+ @socket.onmessage = (message) =>
7
+ data = JSON.parse(message.data)
8
+ type = data.type
9
+ Spine.trigger type, data
@@ -0,0 +1,10 @@
1
+ <div class="progress color" style="text-align: center;">
2
+
3
+ <div class="span4 overlay">
4
+ <span style="float:left; margin-left:20px;"><%= @.format %></span>
5
+ <span class="pull-right" style="margin-right:20px;"><%= Math.round(@.progress*100)/100 %>%</span>
6
+ <span class="pull-right" style="margin-right:115px;"><%= @.amount %></span>
7
+ </div>
8
+
9
+ <div class="bar color" style="width: <%= @.progress %>%; background-color: <%= @.color %>"></div>
10
+ </div>
@@ -0,0 +1,11 @@
1
+ <div class="well">
2
+ <h4>
3
+ <%= @.id %>
4
+ <small class="pull-right"><i class="icon-off"></i> <time class="timeago" datetime="<%= JSON.parse(JSON.stringify(new Date(@.spawned_at * 1000))) %>"></time></small>
5
+ </h4>
6
+ <hr />
7
+ <p class="machine">
8
+ <span><i class="icon-eye-open"></i> <a href="http://<%= @.ip %>:<%= @.port %>"><%= @.ip %>:<%= @.port %></a></span>
9
+ <span class="pull-right"><i class="icon-leaf"></i> <%= @.env %></span>
10
+ </p>
11
+ </div>
@@ -0,0 +1,10 @@
1
+ <div class="well">
2
+ <h4>
3
+ <%= @.id %>
4
+ </h4>
5
+ <hr />
6
+ <p class="machine">
7
+ <span><i class="icon-eye-open"></i> <%= @.method %> <%= @.path %></a></span>
8
+ <span class="pull-right"><i class="icon-leaf"></i> <%= @.server_id %></span>
9
+ </p>
10
+ </div>
@@ -0,0 +1,5 @@
1
+ <div class="span1 pagination-centered">
2
+ <div class="well block" style="background-color:<%= @.color %>">
3
+ <a href="<%= if @.server? then "http://#{@.server.ip}:#{@.server.port}#{@.path}" else "#/resources" %>" rel="tooltip" title="<%= @.path %>"><%= @.format %></a>
4
+ </div>
5
+ </div>
@@ -0,0 +1 @@
1
+ <div class="well dark-grey pagination-centered"><h2 class="white"><%= @.amount %></h2></div>
@@ -0,0 +1,11 @@
1
+ <header class="jumbotron subhead">
2
+ <h1>Log</h1>
3
+ <p class="lead">Live Event Log of the whole System</p>
4
+ </header>
5
+
6
+ <section>
7
+
8
+ <div class="page-header"><h1>Events</h1></div>
9
+ <div id="events" class="log well">Initializing ...</div>
10
+
11
+ </section>
@@ -0,0 +1,33 @@
1
+ <header class="jumbotron subhead">
2
+ <h1>Machines</h1>
3
+ <p class="lead">Overview of all Servers, Caches and Workers</p>
4
+ </header>
5
+
6
+ <section>
7
+
8
+ <div class="row">
9
+
10
+ <div class="span4">
11
+ <div class="page-header"><h1>Servers</h1></div>
12
+ <div id="servers">
13
+ <div class="well dark-grey pagination-centered"><h2 class="white">0</h2></div>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="span4">
18
+ <div class="page-header"><h1>Caches</h1></div>
19
+ <div id="caches">
20
+ <div class="well dark-grey pagination-centered"><h2 class="white">0</h2></div>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="span4">
25
+ <div class="page-header"><h1>Workers</h1></div>
26
+ <div id="workers">
27
+ <div class="well dark-grey pagination-centered"><h2 class="white">0</h2></div>
28
+ </div>
29
+ </div>
30
+
31
+ </div>
32
+
33
+ </section>
@@ -0,0 +1,33 @@
1
+ <header class="jumbotron subhead">
2
+ <h1>Queues</h1>
3
+ <p class="lead">Overview of all Requests, the Processing and the Responses</p>
4
+ </header>
5
+
6
+ <section>
7
+
8
+ <div class="row">
9
+
10
+ <div class="span4">
11
+ <div class="page-header"><h1>Requests</h1></div>
12
+ <div id="requests">
13
+ <div class="well dark-grey pagination-centered"><h2 class="white">0</h2></div>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="span4">
18
+ <div class="page-header"><h1>In Processing</h1></div>
19
+ <div id="processing">
20
+ <div class="well dark-grey pagination-centered"><h2 class="white">0</h2></div>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="span4">
25
+ <div class="page-header"><h1>Responses</h1></div>
26
+ <div id="responses">
27
+ <div class="well dark-grey pagination-centered"><h2 class="white">0</h2></div>
28
+ </div>
29
+ </div>
30
+
31
+ </div>
32
+
33
+ </section>
@@ -0,0 +1,31 @@
1
+ <header class="jumbotron subhead">
2
+ <h1>Resources</h1>
3
+ <p class="lead">Overview of all Resources, the Partials and Content Types</p>
4
+ </header>
5
+
6
+ <section>
7
+
8
+ <div class="row">
9
+
10
+ <div class="span4">
11
+ <div class="page-header"><h1>Resources</h1></div>
12
+ <div id="resources">
13
+ <div class="well dark-grey pagination-centered"><h2 class="white">0</h2></div>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="span4">
18
+ <div class="page-header"><h1>Partials</h1></div>
19
+ <div id="partials">
20
+ <div class="well dark-grey pagination-centered"><h2 class="white">0</h2></div>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="span4">
25
+ <div class="page-header"><h1>Content Types</h1></div>
26
+ <div id="content_types"></div>
27
+ </div>
28
+
29
+ </div>
30
+
31
+ </section>
@@ -0,0 +1,16 @@
1
+ #= require ./lib/jquery
2
+ #= require ./lib/json2
3
+ #= require ./lib/spine/spine
4
+ #= require ./lib/spine/manager
5
+ #= require ./lib/spine/ajax
6
+ #= require ./lib/spine/route
7
+ #= require_tree ./lib
8
+
9
+ #= require ./app/config/config
10
+ #= require_tree ./app/controllers
11
+ #= require_tree ./app/models
12
+ #= require_tree ./app/views
13
+ #= require_tree ./app/config
14
+ #= require ./app/index
15
+
16
+ $(document).ready -> new App.Index({ el:"#app" })
@@ -0,0 +1,1825 @@
1
+ /* ===================================================
2
+ * bootstrap-transition.js v2.0.4
3
+ * http://twitter.github.com/bootstrap/javascript.html#transitions
4
+ * ===================================================
5
+ * Copyright 2012 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ========================================================== */
19
+
20
+
21
+ !function ($) {
22
+
23
+ $(function () {
24
+
25
+ "use strict"; // jshint ;_;
26
+
27
+
28
+ /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
29
+ * ======================================================= */
30
+
31
+ $.support.transition = (function () {
32
+
33
+ var transitionEnd = (function () {
34
+
35
+ var el = document.createElement('bootstrap')
36
+ , transEndEventNames = {
37
+ 'WebkitTransition' : 'webkitTransitionEnd'
38
+ , 'MozTransition' : 'transitionend'
39
+ , 'OTransition' : 'oTransitionEnd'
40
+ , 'msTransition' : 'MSTransitionEnd'
41
+ , 'transition' : 'transitionend'
42
+ }
43
+ , name
44
+
45
+ for (name in transEndEventNames){
46
+ if (el.style[name] !== undefined) {
47
+ return transEndEventNames[name]
48
+ }
49
+ }
50
+
51
+ }())
52
+
53
+ return transitionEnd && {
54
+ end: transitionEnd
55
+ }
56
+
57
+ })()
58
+
59
+ })
60
+
61
+ }(window.jQuery);/* ==========================================================
62
+ * bootstrap-alert.js v2.0.4
63
+ * http://twitter.github.com/bootstrap/javascript.html#alerts
64
+ * ==========================================================
65
+ * Copyright 2012 Twitter, Inc.
66
+ *
67
+ * Licensed under the Apache License, Version 2.0 (the "License");
68
+ * you may not use this file except in compliance with the License.
69
+ * You may obtain a copy of the License at
70
+ *
71
+ * http://www.apache.org/licenses/LICENSE-2.0
72
+ *
73
+ * Unless required by applicable law or agreed to in writing, software
74
+ * distributed under the License is distributed on an "AS IS" BASIS,
75
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
76
+ * See the License for the specific language governing permissions and
77
+ * limitations under the License.
78
+ * ========================================================== */
79
+
80
+
81
+ !function ($) {
82
+
83
+ "use strict"; // jshint ;_;
84
+
85
+
86
+ /* ALERT CLASS DEFINITION
87
+ * ====================== */
88
+
89
+ var dismiss = '[data-dismiss="alert"]'
90
+ , Alert = function (el) {
91
+ $(el).on('click', dismiss, this.close)
92
+ }
93
+
94
+ Alert.prototype.close = function (e) {
95
+ var $this = $(this)
96
+ , selector = $this.attr('data-target')
97
+ , $parent
98
+
99
+ if (!selector) {
100
+ selector = $this.attr('href')
101
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
102
+ }
103
+
104
+ $parent = $(selector)
105
+
106
+ e && e.preventDefault()
107
+
108
+ $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
109
+
110
+ $parent.trigger(e = $.Event('close'))
111
+
112
+ if (e.isDefaultPrevented()) return
113
+
114
+ $parent.removeClass('in')
115
+
116
+ function removeElement() {
117
+ $parent
118
+ .trigger('closed')
119
+ .remove()
120
+ }
121
+
122
+ $.support.transition && $parent.hasClass('fade') ?
123
+ $parent.on($.support.transition.end, removeElement) :
124
+ removeElement()
125
+ }
126
+
127
+
128
+ /* ALERT PLUGIN DEFINITION
129
+ * ======================= */
130
+
131
+ $.fn.alert = function (option) {
132
+ return this.each(function () {
133
+ var $this = $(this)
134
+ , data = $this.data('alert')
135
+ if (!data) $this.data('alert', (data = new Alert(this)))
136
+ if (typeof option == 'string') data[option].call($this)
137
+ })
138
+ }
139
+
140
+ $.fn.alert.Constructor = Alert
141
+
142
+
143
+ /* ALERT DATA-API
144
+ * ============== */
145
+
146
+ $(function () {
147
+ $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
148
+ })
149
+
150
+ }(window.jQuery);/* ============================================================
151
+ * bootstrap-button.js v2.0.4
152
+ * http://twitter.github.com/bootstrap/javascript.html#buttons
153
+ * ============================================================
154
+ * Copyright 2012 Twitter, Inc.
155
+ *
156
+ * Licensed under the Apache License, Version 2.0 (the "License");
157
+ * you may not use this file except in compliance with the License.
158
+ * You may obtain a copy of the License at
159
+ *
160
+ * http://www.apache.org/licenses/LICENSE-2.0
161
+ *
162
+ * Unless required by applicable law or agreed to in writing, software
163
+ * distributed under the License is distributed on an "AS IS" BASIS,
164
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
165
+ * See the License for the specific language governing permissions and
166
+ * limitations under the License.
167
+ * ============================================================ */
168
+
169
+
170
+ !function ($) {
171
+
172
+ "use strict"; // jshint ;_;
173
+
174
+
175
+ /* BUTTON PUBLIC CLASS DEFINITION
176
+ * ============================== */
177
+
178
+ var Button = function (element, options) {
179
+ this.$element = $(element)
180
+ this.options = $.extend({}, $.fn.button.defaults, options)
181
+ }
182
+
183
+ Button.prototype.setState = function (state) {
184
+ var d = 'disabled'
185
+ , $el = this.$element
186
+ , data = $el.data()
187
+ , val = $el.is('input') ? 'val' : 'html'
188
+
189
+ state = state + 'Text'
190
+ data.resetText || $el.data('resetText', $el[val]())
191
+
192
+ $el[val](data[state] || this.options[state])
193
+
194
+ // push to event loop to allow forms to submit
195
+ setTimeout(function () {
196
+ state == 'loadingText' ?
197
+ $el.addClass(d).attr(d, d) :
198
+ $el.removeClass(d).removeAttr(d)
199
+ }, 0)
200
+ }
201
+
202
+ Button.prototype.toggle = function () {
203
+ var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
204
+
205
+ $parent && $parent
206
+ .find('.active')
207
+ .removeClass('active')
208
+
209
+ this.$element.toggleClass('active')
210
+ }
211
+
212
+
213
+ /* BUTTON PLUGIN DEFINITION
214
+ * ======================== */
215
+
216
+ $.fn.button = function (option) {
217
+ return this.each(function () {
218
+ var $this = $(this)
219
+ , data = $this.data('button')
220
+ , options = typeof option == 'object' && option
221
+ if (!data) $this.data('button', (data = new Button(this, options)))
222
+ if (option == 'toggle') data.toggle()
223
+ else if (option) data.setState(option)
224
+ })
225
+ }
226
+
227
+ $.fn.button.defaults = {
228
+ loadingText: 'loading...'
229
+ }
230
+
231
+ $.fn.button.Constructor = Button
232
+
233
+
234
+ /* BUTTON DATA-API
235
+ * =============== */
236
+
237
+ $(function () {
238
+ $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
239
+ var $btn = $(e.target)
240
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
241
+ $btn.button('toggle')
242
+ })
243
+ })
244
+
245
+ }(window.jQuery);/* ==========================================================
246
+ * bootstrap-carousel.js v2.0.4
247
+ * http://twitter.github.com/bootstrap/javascript.html#carousel
248
+ * ==========================================================
249
+ * Copyright 2012 Twitter, Inc.
250
+ *
251
+ * Licensed under the Apache License, Version 2.0 (the "License");
252
+ * you may not use this file except in compliance with the License.
253
+ * You may obtain a copy of the License at
254
+ *
255
+ * http://www.apache.org/licenses/LICENSE-2.0
256
+ *
257
+ * Unless required by applicable law or agreed to in writing, software
258
+ * distributed under the License is distributed on an "AS IS" BASIS,
259
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
260
+ * See the License for the specific language governing permissions and
261
+ * limitations under the License.
262
+ * ========================================================== */
263
+
264
+
265
+ !function ($) {
266
+
267
+ "use strict"; // jshint ;_;
268
+
269
+
270
+ /* CAROUSEL CLASS DEFINITION
271
+ * ========================= */
272
+
273
+ var Carousel = function (element, options) {
274
+ this.$element = $(element)
275
+ this.options = options
276
+ this.options.slide && this.slide(this.options.slide)
277
+ this.options.pause == 'hover' && this.$element
278
+ .on('mouseenter', $.proxy(this.pause, this))
279
+ .on('mouseleave', $.proxy(this.cycle, this))
280
+ }
281
+
282
+ Carousel.prototype = {
283
+
284
+ cycle: function (e) {
285
+ if (!e) this.paused = false
286
+ this.options.interval
287
+ && !this.paused
288
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
289
+ return this
290
+ }
291
+
292
+ , to: function (pos) {
293
+ var $active = this.$element.find('.active')
294
+ , children = $active.parent().children()
295
+ , activePos = children.index($active)
296
+ , that = this
297
+
298
+ if (pos > (children.length - 1) || pos < 0) return
299
+
300
+ if (this.sliding) {
301
+ return this.$element.one('slid', function () {
302
+ that.to(pos)
303
+ })
304
+ }
305
+
306
+ if (activePos == pos) {
307
+ return this.pause().cycle()
308
+ }
309
+
310
+ return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
311
+ }
312
+
313
+ , pause: function (e) {
314
+ if (!e) this.paused = true
315
+ clearInterval(this.interval)
316
+ this.interval = null
317
+ return this
318
+ }
319
+
320
+ , next: function () {
321
+ if (this.sliding) return
322
+ return this.slide('next')
323
+ }
324
+
325
+ , prev: function () {
326
+ if (this.sliding) return
327
+ return this.slide('prev')
328
+ }
329
+
330
+ , slide: function (type, next) {
331
+ var $active = this.$element.find('.active')
332
+ , $next = next || $active[type]()
333
+ , isCycling = this.interval
334
+ , direction = type == 'next' ? 'left' : 'right'
335
+ , fallback = type == 'next' ? 'first' : 'last'
336
+ , that = this
337
+ , e = $.Event('slide')
338
+
339
+ this.sliding = true
340
+
341
+ isCycling && this.pause()
342
+
343
+ $next = $next.length ? $next : this.$element.find('.item')[fallback]()
344
+
345
+ if ($next.hasClass('active')) return
346
+
347
+ if ($.support.transition && this.$element.hasClass('slide')) {
348
+ this.$element.trigger(e)
349
+ if (e.isDefaultPrevented()) return
350
+ $next.addClass(type)
351
+ $next[0].offsetWidth // force reflow
352
+ $active.addClass(direction)
353
+ $next.addClass(direction)
354
+ this.$element.one($.support.transition.end, function () {
355
+ $next.removeClass([type, direction].join(' ')).addClass('active')
356
+ $active.removeClass(['active', direction].join(' '))
357
+ that.sliding = false
358
+ setTimeout(function () { that.$element.trigger('slid') }, 0)
359
+ })
360
+ } else {
361
+ this.$element.trigger(e)
362
+ if (e.isDefaultPrevented()) return
363
+ $active.removeClass('active')
364
+ $next.addClass('active')
365
+ this.sliding = false
366
+ this.$element.trigger('slid')
367
+ }
368
+
369
+ isCycling && this.cycle()
370
+
371
+ return this
372
+ }
373
+
374
+ }
375
+
376
+
377
+ /* CAROUSEL PLUGIN DEFINITION
378
+ * ========================== */
379
+
380
+ $.fn.carousel = function (option) {
381
+ return this.each(function () {
382
+ var $this = $(this)
383
+ , data = $this.data('carousel')
384
+ , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
385
+ if (!data) $this.data('carousel', (data = new Carousel(this, options)))
386
+ if (typeof option == 'number') data.to(option)
387
+ else if (typeof option == 'string' || (option = options.slide)) data[option]()
388
+ else if (options.interval) data.cycle()
389
+ })
390
+ }
391
+
392
+ $.fn.carousel.defaults = {
393
+ interval: 5000
394
+ , pause: 'hover'
395
+ }
396
+
397
+ $.fn.carousel.Constructor = Carousel
398
+
399
+
400
+ /* CAROUSEL DATA-API
401
+ * ================= */
402
+
403
+ $(function () {
404
+ $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
405
+ var $this = $(this), href
406
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
407
+ , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
408
+ $target.carousel(options)
409
+ e.preventDefault()
410
+ })
411
+ })
412
+
413
+ }(window.jQuery);/* =============================================================
414
+ * bootstrap-collapse.js v2.0.4
415
+ * http://twitter.github.com/bootstrap/javascript.html#collapse
416
+ * =============================================================
417
+ * Copyright 2012 Twitter, Inc.
418
+ *
419
+ * Licensed under the Apache License, Version 2.0 (the "License");
420
+ * you may not use this file except in compliance with the License.
421
+ * You may obtain a copy of the License at
422
+ *
423
+ * http://www.apache.org/licenses/LICENSE-2.0
424
+ *
425
+ * Unless required by applicable law or agreed to in writing, software
426
+ * distributed under the License is distributed on an "AS IS" BASIS,
427
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
428
+ * See the License for the specific language governing permissions and
429
+ * limitations under the License.
430
+ * ============================================================ */
431
+
432
+
433
+ !function ($) {
434
+
435
+ "use strict"; // jshint ;_;
436
+
437
+
438
+ /* COLLAPSE PUBLIC CLASS DEFINITION
439
+ * ================================ */
440
+
441
+ var Collapse = function (element, options) {
442
+ this.$element = $(element)
443
+ this.options = $.extend({}, $.fn.collapse.defaults, options)
444
+
445
+ if (this.options.parent) {
446
+ this.$parent = $(this.options.parent)
447
+ }
448
+
449
+ this.options.toggle && this.toggle()
450
+ }
451
+
452
+ Collapse.prototype = {
453
+
454
+ constructor: Collapse
455
+
456
+ , dimension: function () {
457
+ var hasWidth = this.$element.hasClass('width')
458
+ return hasWidth ? 'width' : 'height'
459
+ }
460
+
461
+ , show: function () {
462
+ var dimension
463
+ , scroll
464
+ , actives
465
+ , hasData
466
+
467
+ if (this.transitioning) return
468
+
469
+ dimension = this.dimension()
470
+ scroll = $.camelCase(['scroll', dimension].join('-'))
471
+ actives = this.$parent && this.$parent.find('> .accordion-group > .in')
472
+
473
+ if (actives && actives.length) {
474
+ hasData = actives.data('collapse')
475
+ if (hasData && hasData.transitioning) return
476
+ actives.collapse('hide')
477
+ hasData || actives.data('collapse', null)
478
+ }
479
+
480
+ this.$element[dimension](0)
481
+ this.transition('addClass', $.Event('show'), 'shown')
482
+ this.$element[dimension](this.$element[0][scroll])
483
+ }
484
+
485
+ , hide: function () {
486
+ var dimension
487
+ if (this.transitioning) return
488
+ dimension = this.dimension()
489
+ this.reset(this.$element[dimension]())
490
+ this.transition('removeClass', $.Event('hide'), 'hidden')
491
+ this.$element[dimension](0)
492
+ }
493
+
494
+ , reset: function (size) {
495
+ var dimension = this.dimension()
496
+
497
+ this.$element
498
+ .removeClass('collapse')
499
+ [dimension](size || 'auto')
500
+ [0].offsetWidth
501
+
502
+ this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
503
+
504
+ return this
505
+ }
506
+
507
+ , transition: function (method, startEvent, completeEvent) {
508
+ var that = this
509
+ , complete = function () {
510
+ if (startEvent.type == 'show') that.reset()
511
+ that.transitioning = 0
512
+ that.$element.trigger(completeEvent)
513
+ }
514
+
515
+ this.$element.trigger(startEvent)
516
+
517
+ if (startEvent.isDefaultPrevented()) return
518
+
519
+ this.transitioning = 1
520
+
521
+ this.$element[method]('in')
522
+
523
+ $.support.transition && this.$element.hasClass('collapse') ?
524
+ this.$element.one($.support.transition.end, complete) :
525
+ complete()
526
+ }
527
+
528
+ , toggle: function () {
529
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
530
+ }
531
+
532
+ }
533
+
534
+
535
+ /* COLLAPSIBLE PLUGIN DEFINITION
536
+ * ============================== */
537
+
538
+ $.fn.collapse = function (option) {
539
+ return this.each(function () {
540
+ var $this = $(this)
541
+ , data = $this.data('collapse')
542
+ , options = typeof option == 'object' && option
543
+ if (!data) $this.data('collapse', (data = new Collapse(this, options)))
544
+ if (typeof option == 'string') data[option]()
545
+ })
546
+ }
547
+
548
+ $.fn.collapse.defaults = {
549
+ toggle: true
550
+ }
551
+
552
+ $.fn.collapse.Constructor = Collapse
553
+
554
+
555
+ /* COLLAPSIBLE DATA-API
556
+ * ==================== */
557
+
558
+ $(function () {
559
+ $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
560
+ var $this = $(this), href
561
+ , target = $this.attr('data-target')
562
+ || e.preventDefault()
563
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
564
+ , option = $(target).data('collapse') ? 'toggle' : $this.data()
565
+ $(target).collapse(option)
566
+ })
567
+ })
568
+
569
+ }(window.jQuery);/* ============================================================
570
+ * bootstrap-dropdown.js v2.0.4
571
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
572
+ * ============================================================
573
+ * Copyright 2012 Twitter, Inc.
574
+ *
575
+ * Licensed under the Apache License, Version 2.0 (the "License");
576
+ * you may not use this file except in compliance with the License.
577
+ * You may obtain a copy of the License at
578
+ *
579
+ * http://www.apache.org/licenses/LICENSE-2.0
580
+ *
581
+ * Unless required by applicable law or agreed to in writing, software
582
+ * distributed under the License is distributed on an "AS IS" BASIS,
583
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
584
+ * See the License for the specific language governing permissions and
585
+ * limitations under the License.
586
+ * ============================================================ */
587
+
588
+
589
+ !function ($) {
590
+
591
+ "use strict"; // jshint ;_;
592
+
593
+
594
+ /* DROPDOWN CLASS DEFINITION
595
+ * ========================= */
596
+
597
+ var toggle = '[data-toggle="dropdown"]'
598
+ , Dropdown = function (element) {
599
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
600
+ $('html').on('click.dropdown.data-api', function () {
601
+ $el.parent().removeClass('open')
602
+ })
603
+ }
604
+
605
+ Dropdown.prototype = {
606
+
607
+ constructor: Dropdown
608
+
609
+ , toggle: function (e) {
610
+ var $this = $(this)
611
+ , $parent
612
+ , selector
613
+ , isActive
614
+
615
+ if ($this.is('.disabled, :disabled')) return
616
+
617
+ selector = $this.attr('data-target')
618
+
619
+ if (!selector) {
620
+ selector = $this.attr('href')
621
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
622
+ }
623
+
624
+ $parent = $(selector)
625
+ $parent.length || ($parent = $this.parent())
626
+
627
+ isActive = $parent.hasClass('open')
628
+
629
+ clearMenus()
630
+
631
+ if (!isActive) $parent.toggleClass('open')
632
+
633
+ return false
634
+ }
635
+
636
+ }
637
+
638
+ function clearMenus() {
639
+ $(toggle).parent().removeClass('open')
640
+ }
641
+
642
+
643
+ /* DROPDOWN PLUGIN DEFINITION
644
+ * ========================== */
645
+
646
+ $.fn.dropdown = function (option) {
647
+ return this.each(function () {
648
+ var $this = $(this)
649
+ , data = $this.data('dropdown')
650
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
651
+ if (typeof option == 'string') data[option].call($this)
652
+ })
653
+ }
654
+
655
+ $.fn.dropdown.Constructor = Dropdown
656
+
657
+
658
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
659
+ * =================================== */
660
+
661
+ $(function () {
662
+ $('html').on('click.dropdown.data-api', clearMenus)
663
+ $('body')
664
+ .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
665
+ .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
666
+ })
667
+
668
+ }(window.jQuery);/* =========================================================
669
+ * bootstrap-modal.js v2.0.4
670
+ * http://twitter.github.com/bootstrap/javascript.html#modals
671
+ * =========================================================
672
+ * Copyright 2012 Twitter, Inc.
673
+ *
674
+ * Licensed under the Apache License, Version 2.0 (the "License");
675
+ * you may not use this file except in compliance with the License.
676
+ * You may obtain a copy of the License at
677
+ *
678
+ * http://www.apache.org/licenses/LICENSE-2.0
679
+ *
680
+ * Unless required by applicable law or agreed to in writing, software
681
+ * distributed under the License is distributed on an "AS IS" BASIS,
682
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
683
+ * See the License for the specific language governing permissions and
684
+ * limitations under the License.
685
+ * ========================================================= */
686
+
687
+
688
+ !function ($) {
689
+
690
+ "use strict"; // jshint ;_;
691
+
692
+
693
+ /* MODAL CLASS DEFINITION
694
+ * ====================== */
695
+
696
+ var Modal = function (content, options) {
697
+ this.options = options
698
+ this.$element = $(content)
699
+ .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
700
+ }
701
+
702
+ Modal.prototype = {
703
+
704
+ constructor: Modal
705
+
706
+ , toggle: function () {
707
+ return this[!this.isShown ? 'show' : 'hide']()
708
+ }
709
+
710
+ , show: function () {
711
+ var that = this
712
+ , e = $.Event('show')
713
+
714
+ this.$element.trigger(e)
715
+
716
+ if (this.isShown || e.isDefaultPrevented()) return
717
+
718
+ $('body').addClass('modal-open')
719
+
720
+ this.isShown = true
721
+
722
+ escape.call(this)
723
+ backdrop.call(this, function () {
724
+ var transition = $.support.transition && that.$element.hasClass('fade')
725
+
726
+ if (!that.$element.parent().length) {
727
+ that.$element.appendTo(document.body) //don't move modals dom position
728
+ }
729
+
730
+ that.$element
731
+ .show()
732
+
733
+ if (transition) {
734
+ that.$element[0].offsetWidth // force reflow
735
+ }
736
+
737
+ that.$element.addClass('in')
738
+
739
+ transition ?
740
+ that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
741
+ that.$element.trigger('shown')
742
+
743
+ })
744
+ }
745
+
746
+ , hide: function (e) {
747
+ e && e.preventDefault()
748
+
749
+ var that = this
750
+
751
+ e = $.Event('hide')
752
+
753
+ this.$element.trigger(e)
754
+
755
+ if (!this.isShown || e.isDefaultPrevented()) return
756
+
757
+ this.isShown = false
758
+
759
+ $('body').removeClass('modal-open')
760
+
761
+ escape.call(this)
762
+
763
+ this.$element.removeClass('in')
764
+
765
+ $.support.transition && this.$element.hasClass('fade') ?
766
+ hideWithTransition.call(this) :
767
+ hideModal.call(this)
768
+ }
769
+
770
+ }
771
+
772
+
773
+ /* MODAL PRIVATE METHODS
774
+ * ===================== */
775
+
776
+ function hideWithTransition() {
777
+ var that = this
778
+ , timeout = setTimeout(function () {
779
+ that.$element.off($.support.transition.end)
780
+ hideModal.call(that)
781
+ }, 500)
782
+
783
+ this.$element.one($.support.transition.end, function () {
784
+ clearTimeout(timeout)
785
+ hideModal.call(that)
786
+ })
787
+ }
788
+
789
+ function hideModal(that) {
790
+ this.$element
791
+ .hide()
792
+ .trigger('hidden')
793
+
794
+ backdrop.call(this)
795
+ }
796
+
797
+ function backdrop(callback) {
798
+ var that = this
799
+ , animate = this.$element.hasClass('fade') ? 'fade' : ''
800
+
801
+ if (this.isShown && this.options.backdrop) {
802
+ var doAnimate = $.support.transition && animate
803
+
804
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
805
+ .appendTo(document.body)
806
+
807
+ if (this.options.backdrop != 'static') {
808
+ this.$backdrop.click($.proxy(this.hide, this))
809
+ }
810
+
811
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
812
+
813
+ this.$backdrop.addClass('in')
814
+
815
+ doAnimate ?
816
+ this.$backdrop.one($.support.transition.end, callback) :
817
+ callback()
818
+
819
+ } else if (!this.isShown && this.$backdrop) {
820
+ this.$backdrop.removeClass('in')
821
+
822
+ $.support.transition && this.$element.hasClass('fade')?
823
+ this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
824
+ removeBackdrop.call(this)
825
+
826
+ } else if (callback) {
827
+ callback()
828
+ }
829
+ }
830
+
831
+ function removeBackdrop() {
832
+ this.$backdrop.remove()
833
+ this.$backdrop = null
834
+ }
835
+
836
+ function escape() {
837
+ var that = this
838
+ if (this.isShown && this.options.keyboard) {
839
+ $(document).on('keyup.dismiss.modal', function ( e ) {
840
+ e.which == 27 && that.hide()
841
+ })
842
+ } else if (!this.isShown) {
843
+ $(document).off('keyup.dismiss.modal')
844
+ }
845
+ }
846
+
847
+
848
+ /* MODAL PLUGIN DEFINITION
849
+ * ======================= */
850
+
851
+ $.fn.modal = function (option) {
852
+ return this.each(function () {
853
+ var $this = $(this)
854
+ , data = $this.data('modal')
855
+ , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
856
+ if (!data) $this.data('modal', (data = new Modal(this, options)))
857
+ if (typeof option == 'string') data[option]()
858
+ else if (options.show) data.show()
859
+ })
860
+ }
861
+
862
+ $.fn.modal.defaults = {
863
+ backdrop: true
864
+ , keyboard: true
865
+ , show: true
866
+ }
867
+
868
+ $.fn.modal.Constructor = Modal
869
+
870
+
871
+ /* MODAL DATA-API
872
+ * ============== */
873
+
874
+ $(function () {
875
+ $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
876
+ var $this = $(this), href
877
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
878
+ , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
879
+
880
+ e.preventDefault()
881
+ $target.modal(option)
882
+ })
883
+ })
884
+
885
+ }(window.jQuery);/* ===========================================================
886
+ * bootstrap-tooltip.js v2.0.4
887
+ * http://twitter.github.com/bootstrap/javascript.html#tooltips
888
+ * Inspired by the original jQuery.tipsy by Jason Frame
889
+ * ===========================================================
890
+ * Copyright 2012 Twitter, Inc.
891
+ *
892
+ * Licensed under the Apache License, Version 2.0 (the "License");
893
+ * you may not use this file except in compliance with the License.
894
+ * You may obtain a copy of the License at
895
+ *
896
+ * http://www.apache.org/licenses/LICENSE-2.0
897
+ *
898
+ * Unless required by applicable law or agreed to in writing, software
899
+ * distributed under the License is distributed on an "AS IS" BASIS,
900
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
901
+ * See the License for the specific language governing permissions and
902
+ * limitations under the License.
903
+ * ========================================================== */
904
+
905
+
906
+ !function ($) {
907
+
908
+ "use strict"; // jshint ;_;
909
+
910
+
911
+ /* TOOLTIP PUBLIC CLASS DEFINITION
912
+ * =============================== */
913
+
914
+ var Tooltip = function (element, options) {
915
+ this.init('tooltip', element, options)
916
+ }
917
+
918
+ Tooltip.prototype = {
919
+
920
+ constructor: Tooltip
921
+
922
+ , init: function (type, element, options) {
923
+ var eventIn
924
+ , eventOut
925
+
926
+ this.type = type
927
+ this.$element = $(element)
928
+ this.options = this.getOptions(options)
929
+ this.enabled = true
930
+
931
+ if (this.options.trigger != 'manual') {
932
+ eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
933
+ eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
934
+ this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
935
+ this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
936
+ }
937
+
938
+ this.options.selector ?
939
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
940
+ this.fixTitle()
941
+ }
942
+
943
+ , getOptions: function (options) {
944
+ options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
945
+
946
+ if (options.delay && typeof options.delay == 'number') {
947
+ options.delay = {
948
+ show: options.delay
949
+ , hide: options.delay
950
+ }
951
+ }
952
+
953
+ return options
954
+ }
955
+
956
+ , enter: function (e) {
957
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
958
+
959
+ if (!self.options.delay || !self.options.delay.show) return self.show()
960
+
961
+ clearTimeout(this.timeout)
962
+ self.hoverState = 'in'
963
+ this.timeout = setTimeout(function() {
964
+ if (self.hoverState == 'in') self.show()
965
+ }, self.options.delay.show)
966
+ }
967
+
968
+ , leave: function (e) {
969
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
970
+
971
+ if (this.timeout) clearTimeout(this.timeout)
972
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
973
+
974
+ self.hoverState = 'out'
975
+ this.timeout = setTimeout(function() {
976
+ if (self.hoverState == 'out') self.hide()
977
+ }, self.options.delay.hide)
978
+ }
979
+
980
+ , show: function () {
981
+ var $tip
982
+ , inside
983
+ , pos
984
+ , actualWidth
985
+ , actualHeight
986
+ , placement
987
+ , tp
988
+
989
+ if (this.hasContent() && this.enabled) {
990
+ $tip = this.tip()
991
+ this.setContent()
992
+
993
+ if (this.options.animation) {
994
+ $tip.addClass('fade')
995
+ }
996
+
997
+ placement = typeof this.options.placement == 'function' ?
998
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
999
+ this.options.placement
1000
+
1001
+ inside = /in/.test(placement)
1002
+
1003
+ $tip
1004
+ .remove()
1005
+ .css({ top: 0, left: 0, display: 'block' })
1006
+ .appendTo(inside ? this.$element : document.body)
1007
+
1008
+ pos = this.getPosition(inside)
1009
+
1010
+ actualWidth = $tip[0].offsetWidth
1011
+ actualHeight = $tip[0].offsetHeight
1012
+
1013
+ switch (inside ? placement.split(' ')[1] : placement) {
1014
+ case 'bottom':
1015
+ tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
1016
+ break
1017
+ case 'top':
1018
+ tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
1019
+ break
1020
+ case 'left':
1021
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
1022
+ break
1023
+ case 'right':
1024
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
1025
+ break
1026
+ }
1027
+
1028
+ $tip
1029
+ .css(tp)
1030
+ .addClass(placement)
1031
+ .addClass('in')
1032
+ }
1033
+ }
1034
+
1035
+ , isHTML: function(text) {
1036
+ // html string detection logic adapted from jQuery
1037
+ return typeof text != 'string'
1038
+ || ( text.charAt(0) === "<"
1039
+ && text.charAt( text.length - 1 ) === ">"
1040
+ && text.length >= 3
1041
+ ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
1042
+ }
1043
+
1044
+ , setContent: function () {
1045
+ var $tip = this.tip()
1046
+ , title = this.getTitle()
1047
+
1048
+ $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
1049
+ $tip.removeClass('fade in top bottom left right')
1050
+ }
1051
+
1052
+ , hide: function () {
1053
+ var that = this
1054
+ , $tip = this.tip()
1055
+
1056
+ $tip.removeClass('in')
1057
+
1058
+ function removeWithAnimation() {
1059
+ var timeout = setTimeout(function () {
1060
+ $tip.off($.support.transition.end).remove()
1061
+ }, 500)
1062
+
1063
+ $tip.one($.support.transition.end, function () {
1064
+ clearTimeout(timeout)
1065
+ $tip.remove()
1066
+ })
1067
+ }
1068
+
1069
+ $.support.transition && this.$tip.hasClass('fade') ?
1070
+ removeWithAnimation() :
1071
+ $tip.remove()
1072
+ }
1073
+
1074
+ , fixTitle: function () {
1075
+ var $e = this.$element
1076
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
1077
+ $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
1078
+ }
1079
+ }
1080
+
1081
+ , hasContent: function () {
1082
+ return this.getTitle()
1083
+ }
1084
+
1085
+ , getPosition: function (inside) {
1086
+ return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
1087
+ width: this.$element[0].offsetWidth
1088
+ , height: this.$element[0].offsetHeight
1089
+ })
1090
+ }
1091
+
1092
+ , getTitle: function () {
1093
+ var title
1094
+ , $e = this.$element
1095
+ , o = this.options
1096
+
1097
+ title = $e.attr('data-original-title')
1098
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1099
+
1100
+ return title
1101
+ }
1102
+
1103
+ , tip: function () {
1104
+ return this.$tip = this.$tip || $(this.options.template)
1105
+ }
1106
+
1107
+ , validate: function () {
1108
+ if (!this.$element[0].parentNode) {
1109
+ this.hide()
1110
+ this.$element = null
1111
+ this.options = null
1112
+ }
1113
+ }
1114
+
1115
+ , enable: function () {
1116
+ this.enabled = true
1117
+ }
1118
+
1119
+ , disable: function () {
1120
+ this.enabled = false
1121
+ }
1122
+
1123
+ , toggleEnabled: function () {
1124
+ this.enabled = !this.enabled
1125
+ }
1126
+
1127
+ , toggle: function () {
1128
+ this[this.tip().hasClass('in') ? 'hide' : 'show']()
1129
+ }
1130
+
1131
+ }
1132
+
1133
+
1134
+ /* TOOLTIP PLUGIN DEFINITION
1135
+ * ========================= */
1136
+
1137
+ $.fn.tooltip = function ( option ) {
1138
+ return this.each(function () {
1139
+ var $this = $(this)
1140
+ , data = $this.data('tooltip')
1141
+ , options = typeof option == 'object' && option
1142
+ if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
1143
+ if (typeof option == 'string') data[option]()
1144
+ })
1145
+ }
1146
+
1147
+ $.fn.tooltip.Constructor = Tooltip
1148
+
1149
+ $.fn.tooltip.defaults = {
1150
+ animation: true
1151
+ , placement: 'top'
1152
+ , selector: false
1153
+ , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
1154
+ , trigger: 'hover'
1155
+ , title: ''
1156
+ , delay: 0
1157
+ }
1158
+
1159
+ }(window.jQuery);
1160
+ /* ===========================================================
1161
+ * bootstrap-popover.js v2.0.4
1162
+ * http://twitter.github.com/bootstrap/javascript.html#popovers
1163
+ * ===========================================================
1164
+ * Copyright 2012 Twitter, Inc.
1165
+ *
1166
+ * Licensed under the Apache License, Version 2.0 (the "License");
1167
+ * you may not use this file except in compliance with the License.
1168
+ * You may obtain a copy of the License at
1169
+ *
1170
+ * http://www.apache.org/licenses/LICENSE-2.0
1171
+ *
1172
+ * Unless required by applicable law or agreed to in writing, software
1173
+ * distributed under the License is distributed on an "AS IS" BASIS,
1174
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1175
+ * See the License for the specific language governing permissions and
1176
+ * limitations under the License.
1177
+ * =========================================================== */
1178
+
1179
+
1180
+ !function ($) {
1181
+
1182
+ "use strict"; // jshint ;_;
1183
+
1184
+
1185
+ /* POPOVER PUBLIC CLASS DEFINITION
1186
+ * =============================== */
1187
+
1188
+ var Popover = function ( element, options ) {
1189
+ this.init('popover', element, options)
1190
+ }
1191
+
1192
+
1193
+ /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
1194
+ ========================================== */
1195
+
1196
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
1197
+
1198
+ constructor: Popover
1199
+
1200
+ , setContent: function () {
1201
+ var $tip = this.tip()
1202
+ , title = this.getTitle()
1203
+ , content = this.getContent()
1204
+
1205
+ $tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
1206
+ $tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
1207
+
1208
+ $tip.removeClass('fade top bottom left right in')
1209
+ }
1210
+
1211
+ , hasContent: function () {
1212
+ return this.getTitle() || this.getContent()
1213
+ }
1214
+
1215
+ , getContent: function () {
1216
+ var content
1217
+ , $e = this.$element
1218
+ , o = this.options
1219
+
1220
+ content = $e.attr('data-content')
1221
+ || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1222
+
1223
+ return content
1224
+ }
1225
+
1226
+ , tip: function () {
1227
+ if (!this.$tip) {
1228
+ this.$tip = $(this.options.template)
1229
+ }
1230
+ return this.$tip
1231
+ }
1232
+
1233
+ })
1234
+
1235
+
1236
+ /* POPOVER PLUGIN DEFINITION
1237
+ * ======================= */
1238
+
1239
+ $.fn.popover = function (option) {
1240
+ return this.each(function () {
1241
+ var $this = $(this)
1242
+ , data = $this.data('popover')
1243
+ , options = typeof option == 'object' && option
1244
+ if (!data) $this.data('popover', (data = new Popover(this, options)))
1245
+ if (typeof option == 'string') data[option]()
1246
+ })
1247
+ }
1248
+
1249
+ $.fn.popover.Constructor = Popover
1250
+
1251
+ $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
1252
+ placement: 'right'
1253
+ , content: ''
1254
+ , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
1255
+ })
1256
+
1257
+ }(window.jQuery);/* =============================================================
1258
+ * bootstrap-scrollspy.js v2.0.4
1259
+ * http://twitter.github.com/bootstrap/javascript.html#scrollspy
1260
+ * =============================================================
1261
+ * Copyright 2012 Twitter, Inc.
1262
+ *
1263
+ * Licensed under the Apache License, Version 2.0 (the "License");
1264
+ * you may not use this file except in compliance with the License.
1265
+ * You may obtain a copy of the License at
1266
+ *
1267
+ * http://www.apache.org/licenses/LICENSE-2.0
1268
+ *
1269
+ * Unless required by applicable law or agreed to in writing, software
1270
+ * distributed under the License is distributed on an "AS IS" BASIS,
1271
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1272
+ * See the License for the specific language governing permissions and
1273
+ * limitations under the License.
1274
+ * ============================================================== */
1275
+
1276
+
1277
+ !function ($) {
1278
+
1279
+ "use strict"; // jshint ;_;
1280
+
1281
+
1282
+ /* SCROLLSPY CLASS DEFINITION
1283
+ * ========================== */
1284
+
1285
+ function ScrollSpy( element, options) {
1286
+ var process = $.proxy(this.process, this)
1287
+ , $element = $(element).is('body') ? $(window) : $(element)
1288
+ , href
1289
+ this.options = $.extend({}, $.fn.scrollspy.defaults, options)
1290
+ this.$scrollElement = $element.on('scroll.scroll.data-api', process)
1291
+ this.selector = (this.options.target
1292
+ || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
1293
+ || '') + ' .nav li > a'
1294
+ this.$body = $('body')
1295
+ this.refresh()
1296
+ this.process()
1297
+ }
1298
+
1299
+ ScrollSpy.prototype = {
1300
+
1301
+ constructor: ScrollSpy
1302
+
1303
+ , refresh: function () {
1304
+ var self = this
1305
+ , $targets
1306
+
1307
+ this.offsets = $([])
1308
+ this.targets = $([])
1309
+
1310
+ $targets = this.$body
1311
+ .find(this.selector)
1312
+ .map(function () {
1313
+ var $el = $(this)
1314
+ , href = $el.data('target') || $el.attr('href')
1315
+ , $href = /^#\w/.test(href) && $(href)
1316
+ return ( $href
1317
+ && href.length
1318
+ && [[ $href.position().top, href ]] ) || null
1319
+ })
1320
+ .sort(function (a, b) { return a[0] - b[0] })
1321
+ .each(function () {
1322
+ self.offsets.push(this[0])
1323
+ self.targets.push(this[1])
1324
+ })
1325
+ }
1326
+
1327
+ , process: function () {
1328
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1329
+ , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
1330
+ , maxScroll = scrollHeight - this.$scrollElement.height()
1331
+ , offsets = this.offsets
1332
+ , targets = this.targets
1333
+ , activeTarget = this.activeTarget
1334
+ , i
1335
+
1336
+ if (scrollTop >= maxScroll) {
1337
+ return activeTarget != (i = targets.last()[0])
1338
+ && this.activate ( i )
1339
+ }
1340
+
1341
+ for (i = offsets.length; i--;) {
1342
+ activeTarget != targets[i]
1343
+ && scrollTop >= offsets[i]
1344
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
1345
+ && this.activate( targets[i] )
1346
+ }
1347
+ }
1348
+
1349
+ , activate: function (target) {
1350
+ var active
1351
+ , selector
1352
+
1353
+ this.activeTarget = target
1354
+
1355
+ $(this.selector)
1356
+ .parent('.active')
1357
+ .removeClass('active')
1358
+
1359
+ selector = this.selector
1360
+ + '[data-target="' + target + '"],'
1361
+ + this.selector + '[href="' + target + '"]'
1362
+
1363
+ active = $(selector)
1364
+ .parent('li')
1365
+ .addClass('active')
1366
+
1367
+ if (active.parent('.dropdown-menu')) {
1368
+ active = active.closest('li.dropdown').addClass('active')
1369
+ }
1370
+
1371
+ active.trigger('activate')
1372
+ }
1373
+
1374
+ }
1375
+
1376
+
1377
+ /* SCROLLSPY PLUGIN DEFINITION
1378
+ * =========================== */
1379
+
1380
+ $.fn.scrollspy = function ( option ) {
1381
+ return this.each(function () {
1382
+ var $this = $(this)
1383
+ , data = $this.data('scrollspy')
1384
+ , options = typeof option == 'object' && option
1385
+ if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
1386
+ if (typeof option == 'string') data[option]()
1387
+ })
1388
+ }
1389
+
1390
+ $.fn.scrollspy.Constructor = ScrollSpy
1391
+
1392
+ $.fn.scrollspy.defaults = {
1393
+ offset: 10
1394
+ }
1395
+
1396
+
1397
+ /* SCROLLSPY DATA-API
1398
+ * ================== */
1399
+
1400
+ $(function () {
1401
+ $('[data-spy="scroll"]').each(function () {
1402
+ var $spy = $(this)
1403
+ $spy.scrollspy($spy.data())
1404
+ })
1405
+ })
1406
+
1407
+ }(window.jQuery);/* ========================================================
1408
+ * bootstrap-tab.js v2.0.4
1409
+ * http://twitter.github.com/bootstrap/javascript.html#tabs
1410
+ * ========================================================
1411
+ * Copyright 2012 Twitter, Inc.
1412
+ *
1413
+ * Licensed under the Apache License, Version 2.0 (the "License");
1414
+ * you may not use this file except in compliance with the License.
1415
+ * You may obtain a copy of the License at
1416
+ *
1417
+ * http://www.apache.org/licenses/LICENSE-2.0
1418
+ *
1419
+ * Unless required by applicable law or agreed to in writing, software
1420
+ * distributed under the License is distributed on an "AS IS" BASIS,
1421
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1422
+ * See the License for the specific language governing permissions and
1423
+ * limitations under the License.
1424
+ * ======================================================== */
1425
+
1426
+
1427
+ !function ($) {
1428
+
1429
+ "use strict"; // jshint ;_;
1430
+
1431
+
1432
+ /* TAB CLASS DEFINITION
1433
+ * ==================== */
1434
+
1435
+ var Tab = function ( element ) {
1436
+ this.element = $(element)
1437
+ }
1438
+
1439
+ Tab.prototype = {
1440
+
1441
+ constructor: Tab
1442
+
1443
+ , show: function () {
1444
+ var $this = this.element
1445
+ , $ul = $this.closest('ul:not(.dropdown-menu)')
1446
+ , selector = $this.attr('data-target')
1447
+ , previous
1448
+ , $target
1449
+ , e
1450
+
1451
+ if (!selector) {
1452
+ selector = $this.attr('href')
1453
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
1454
+ }
1455
+
1456
+ if ( $this.parent('li').hasClass('active') ) return
1457
+
1458
+ previous = $ul.find('.active a').last()[0]
1459
+
1460
+ e = $.Event('show', {
1461
+ relatedTarget: previous
1462
+ })
1463
+
1464
+ $this.trigger(e)
1465
+
1466
+ if (e.isDefaultPrevented()) return
1467
+
1468
+ $target = $(selector)
1469
+
1470
+ this.activate($this.parent('li'), $ul)
1471
+ this.activate($target, $target.parent(), function () {
1472
+ $this.trigger({
1473
+ type: 'shown'
1474
+ , relatedTarget: previous
1475
+ })
1476
+ })
1477
+ }
1478
+
1479
+ , activate: function ( element, container, callback) {
1480
+ var $active = container.find('> .active')
1481
+ , transition = callback
1482
+ && $.support.transition
1483
+ && $active.hasClass('fade')
1484
+
1485
+ function next() {
1486
+ $active
1487
+ .removeClass('active')
1488
+ .find('> .dropdown-menu > .active')
1489
+ .removeClass('active')
1490
+
1491
+ element.addClass('active')
1492
+
1493
+ if (transition) {
1494
+ element[0].offsetWidth // reflow for transition
1495
+ element.addClass('in')
1496
+ } else {
1497
+ element.removeClass('fade')
1498
+ }
1499
+
1500
+ if ( element.parent('.dropdown-menu') ) {
1501
+ element.closest('li.dropdown').addClass('active')
1502
+ }
1503
+
1504
+ callback && callback()
1505
+ }
1506
+
1507
+ transition ?
1508
+ $active.one($.support.transition.end, next) :
1509
+ next()
1510
+
1511
+ $active.removeClass('in')
1512
+ }
1513
+ }
1514
+
1515
+
1516
+ /* TAB PLUGIN DEFINITION
1517
+ * ===================== */
1518
+
1519
+ $.fn.tab = function ( option ) {
1520
+ return this.each(function () {
1521
+ var $this = $(this)
1522
+ , data = $this.data('tab')
1523
+ if (!data) $this.data('tab', (data = new Tab(this)))
1524
+ if (typeof option == 'string') data[option]()
1525
+ })
1526
+ }
1527
+
1528
+ $.fn.tab.Constructor = Tab
1529
+
1530
+
1531
+ /* TAB DATA-API
1532
+ * ============ */
1533
+
1534
+ $(function () {
1535
+ $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1536
+ e.preventDefault()
1537
+ $(this).tab('show')
1538
+ })
1539
+ })
1540
+
1541
+ }(window.jQuery);/* =============================================================
1542
+ * bootstrap-typeahead.js v2.0.4
1543
+ * http://twitter.github.com/bootstrap/javascript.html#typeahead
1544
+ * =============================================================
1545
+ * Copyright 2012 Twitter, Inc.
1546
+ *
1547
+ * Licensed under the Apache License, Version 2.0 (the "License");
1548
+ * you may not use this file except in compliance with the License.
1549
+ * You may obtain a copy of the License at
1550
+ *
1551
+ * http://www.apache.org/licenses/LICENSE-2.0
1552
+ *
1553
+ * Unless required by applicable law or agreed to in writing, software
1554
+ * distributed under the License is distributed on an "AS IS" BASIS,
1555
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1556
+ * See the License for the specific language governing permissions and
1557
+ * limitations under the License.
1558
+ * ============================================================ */
1559
+
1560
+
1561
+ !function($){
1562
+
1563
+ "use strict"; // jshint ;_;
1564
+
1565
+
1566
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
1567
+ * ================================= */
1568
+
1569
+ var Typeahead = function (element, options) {
1570
+ this.$element = $(element)
1571
+ this.options = $.extend({}, $.fn.typeahead.defaults, options)
1572
+ this.matcher = this.options.matcher || this.matcher
1573
+ this.sorter = this.options.sorter || this.sorter
1574
+ this.highlighter = this.options.highlighter || this.highlighter
1575
+ this.updater = this.options.updater || this.updater
1576
+ this.$menu = $(this.options.menu).appendTo('body')
1577
+ this.source = this.options.source
1578
+ this.shown = false
1579
+ this.listen()
1580
+ }
1581
+
1582
+ Typeahead.prototype = {
1583
+
1584
+ constructor: Typeahead
1585
+
1586
+ , select: function () {
1587
+ var val = this.$menu.find('.active').attr('data-value')
1588
+ this.$element
1589
+ .val(this.updater(val))
1590
+ .change()
1591
+ return this.hide()
1592
+ }
1593
+
1594
+ , updater: function (item) {
1595
+ return item
1596
+ }
1597
+
1598
+ , show: function () {
1599
+ var pos = $.extend({}, this.$element.offset(), {
1600
+ height: this.$element[0].offsetHeight
1601
+ })
1602
+
1603
+ this.$menu.css({
1604
+ top: pos.top + pos.height
1605
+ , left: pos.left
1606
+ })
1607
+
1608
+ this.$menu.show()
1609
+ this.shown = true
1610
+ return this
1611
+ }
1612
+
1613
+ , hide: function () {
1614
+ this.$menu.hide()
1615
+ this.shown = false
1616
+ return this
1617
+ }
1618
+
1619
+ , lookup: function (event) {
1620
+ var that = this
1621
+ , items
1622
+ , q
1623
+
1624
+ this.query = this.$element.val()
1625
+
1626
+ if (!this.query) {
1627
+ return this.shown ? this.hide() : this
1628
+ }
1629
+
1630
+ items = $.grep(this.source, function (item) {
1631
+ return that.matcher(item)
1632
+ })
1633
+
1634
+ items = this.sorter(items)
1635
+
1636
+ if (!items.length) {
1637
+ return this.shown ? this.hide() : this
1638
+ }
1639
+
1640
+ return this.render(items.slice(0, this.options.items)).show()
1641
+ }
1642
+
1643
+ , matcher: function (item) {
1644
+ return ~item.toLowerCase().indexOf(this.query.toLowerCase())
1645
+ }
1646
+
1647
+ , sorter: function (items) {
1648
+ var beginswith = []
1649
+ , caseSensitive = []
1650
+ , caseInsensitive = []
1651
+ , item
1652
+
1653
+ while (item = items.shift()) {
1654
+ if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
1655
+ else if (~item.indexOf(this.query)) caseSensitive.push(item)
1656
+ else caseInsensitive.push(item)
1657
+ }
1658
+
1659
+ return beginswith.concat(caseSensitive, caseInsensitive)
1660
+ }
1661
+
1662
+ , highlighter: function (item) {
1663
+ var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
1664
+ return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
1665
+ return '<strong>' + match + '</strong>'
1666
+ })
1667
+ }
1668
+
1669
+ , render: function (items) {
1670
+ var that = this
1671
+
1672
+ items = $(items).map(function (i, item) {
1673
+ i = $(that.options.item).attr('data-value', item)
1674
+ i.find('a').html(that.highlighter(item))
1675
+ return i[0]
1676
+ })
1677
+
1678
+ items.first().addClass('active')
1679
+ this.$menu.html(items)
1680
+ return this
1681
+ }
1682
+
1683
+ , next: function (event) {
1684
+ var active = this.$menu.find('.active').removeClass('active')
1685
+ , next = active.next()
1686
+
1687
+ if (!next.length) {
1688
+ next = $(this.$menu.find('li')[0])
1689
+ }
1690
+
1691
+ next.addClass('active')
1692
+ }
1693
+
1694
+ , prev: function (event) {
1695
+ var active = this.$menu.find('.active').removeClass('active')
1696
+ , prev = active.prev()
1697
+
1698
+ if (!prev.length) {
1699
+ prev = this.$menu.find('li').last()
1700
+ }
1701
+
1702
+ prev.addClass('active')
1703
+ }
1704
+
1705
+ , listen: function () {
1706
+ this.$element
1707
+ .on('blur', $.proxy(this.blur, this))
1708
+ .on('keypress', $.proxy(this.keypress, this))
1709
+ .on('keyup', $.proxy(this.keyup, this))
1710
+
1711
+ if ($.browser.webkit || $.browser.msie) {
1712
+ this.$element.on('keydown', $.proxy(this.keypress, this))
1713
+ }
1714
+
1715
+ this.$menu
1716
+ .on('click', $.proxy(this.click, this))
1717
+ .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
1718
+ }
1719
+
1720
+ , keyup: function (e) {
1721
+ switch(e.keyCode) {
1722
+ case 40: // down arrow
1723
+ case 38: // up arrow
1724
+ break
1725
+
1726
+ case 9: // tab
1727
+ case 13: // enter
1728
+ if (!this.shown) return
1729
+ this.select()
1730
+ break
1731
+
1732
+ case 27: // escape
1733
+ if (!this.shown) return
1734
+ this.hide()
1735
+ break
1736
+
1737
+ default:
1738
+ this.lookup()
1739
+ }
1740
+
1741
+ e.stopPropagation()
1742
+ e.preventDefault()
1743
+ }
1744
+
1745
+ , keypress: function (e) {
1746
+ if (!this.shown) return
1747
+
1748
+ switch(e.keyCode) {
1749
+ case 9: // tab
1750
+ case 13: // enter
1751
+ case 27: // escape
1752
+ e.preventDefault()
1753
+ break
1754
+
1755
+ case 38: // up arrow
1756
+ if (e.type != 'keydown') break
1757
+ e.preventDefault()
1758
+ this.prev()
1759
+ break
1760
+
1761
+ case 40: // down arrow
1762
+ if (e.type != 'keydown') break
1763
+ e.preventDefault()
1764
+ this.next()
1765
+ break
1766
+ }
1767
+
1768
+ e.stopPropagation()
1769
+ }
1770
+
1771
+ , blur: function (e) {
1772
+ var that = this
1773
+ setTimeout(function () { that.hide() }, 150)
1774
+ }
1775
+
1776
+ , click: function (e) {
1777
+ e.stopPropagation()
1778
+ e.preventDefault()
1779
+ this.select()
1780
+ }
1781
+
1782
+ , mouseenter: function (e) {
1783
+ this.$menu.find('.active').removeClass('active')
1784
+ $(e.currentTarget).addClass('active')
1785
+ }
1786
+
1787
+ }
1788
+
1789
+
1790
+ /* TYPEAHEAD PLUGIN DEFINITION
1791
+ * =========================== */
1792
+
1793
+ $.fn.typeahead = function (option) {
1794
+ return this.each(function () {
1795
+ var $this = $(this)
1796
+ , data = $this.data('typeahead')
1797
+ , options = typeof option == 'object' && option
1798
+ if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
1799
+ if (typeof option == 'string') data[option]()
1800
+ })
1801
+ }
1802
+
1803
+ $.fn.typeahead.defaults = {
1804
+ source: []
1805
+ , items: 8
1806
+ , menu: '<ul class="typeahead dropdown-menu"></ul>'
1807
+ , item: '<li><a href="#"></a></li>'
1808
+ }
1809
+
1810
+ $.fn.typeahead.Constructor = Typeahead
1811
+
1812
+
1813
+ /* TYPEAHEAD DATA-API
1814
+ * ================== */
1815
+
1816
+ $(function () {
1817
+ $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
1818
+ var $this = $(this)
1819
+ if ($this.data('typeahead')) return
1820
+ e.preventDefault()
1821
+ $this.typeahead($this.data())
1822
+ })
1823
+ })
1824
+
1825
+ }(window.jQuery);