sidekiq_monitor 0.0.1

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 (43) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +180 -0
  3. data/Rakefile +12 -0
  4. data/app/assets/javascripts/sidekiq/monitor/abstract_jobs_table.js.coffee +165 -0
  5. data/app/assets/javascripts/sidekiq/monitor/application.js.coffee +11 -0
  6. data/app/assets/javascripts/sidekiq/monitor/bootstrap-select.min.js +1 -0
  7. data/app/assets/javascripts/sidekiq/monitor/bootstrap.min.js +6 -0
  8. data/app/assets/javascripts/sidekiq/monitor/datatables.bootstrap.js +96 -0
  9. data/app/assets/javascripts/sidekiq/monitor/datatables.js +256 -0
  10. data/app/assets/javascripts/sidekiq/monitor/datatables.standing_redraw.js.coffee +5 -0
  11. data/app/assets/javascripts/sidekiq/monitor/initialize.js.coffee.erb +5 -0
  12. data/app/assets/javascripts/sidekiq/monitor/jobs_table.js.coffee +59 -0
  13. data/app/assets/javascripts/sidekiq/monitor/jquery.timeago.js +27 -0
  14. data/app/assets/javascripts/sidekiq/monitor/queue_jobs_table.js.coffee +92 -0
  15. data/app/assets/stylesheets/sidekiq/monitor/application.css.sass +5 -0
  16. data/app/assets/stylesheets/sidekiq/monitor/bootstrap-select.min.css +1 -0
  17. data/app/assets/stylesheets/sidekiq/monitor/bootstrap.min.css +9 -0
  18. data/app/assets/stylesheets/sidekiq/monitor/jobs_table.css.sass +51 -0
  19. data/app/assets/stylesheets/sidekiq/monitor/layout.css.sass +15 -0
  20. data/app/controllers/sidekiq/monitor/api/jobs_controller.rb +32 -0
  21. data/app/controllers/sidekiq/monitor/api/queues_controller.rb +24 -0
  22. data/app/controllers/sidekiq/monitor/jobs_controller.rb +14 -0
  23. data/app/controllers/sidekiq/monitor/queues_controller.rb +15 -0
  24. data/app/datatables/sidekiq/monitor/jobs_datatable.rb +74 -0
  25. data/app/helpers/sidekiq/monitor/sidekiq_helper.rb +13 -0
  26. data/app/models/sidekiq/monitor/job.rb +37 -0
  27. data/app/views/sidekiq/monitor/jobs/_jobs.slim +13 -0
  28. data/app/views/sidekiq/monitor/jobs/index.slim +1 -0
  29. data/app/views/sidekiq/monitor/layouts/application.slim +28 -0
  30. data/app/views/sidekiq/monitor/queues/_jobs.slim +13 -0
  31. data/app/views/sidekiq/monitor/queues/index.slim +6 -0
  32. data/config/routes.rb +10 -0
  33. data/lib/generators/sidekiq/monitor/install/install_generator.rb +27 -0
  34. data/lib/generators/sidekiq/monitor/install/templates/create_sidekiq_jobs.rb +26 -0
  35. data/lib/sidekiq/monitor/cleaner.rb +58 -0
  36. data/lib/sidekiq/monitor/client/middleware.rb +16 -0
  37. data/lib/sidekiq/monitor/engine.rb +11 -0
  38. data/lib/sidekiq/monitor/processor.rb +73 -0
  39. data/lib/sidekiq/monitor/server/middleware.rb +22 -0
  40. data/lib/sidekiq/monitor/version.rb +5 -0
  41. data/lib/sidekiq/monitor.rb +26 -0
  42. data/lib/sidekiq_monitor.rb +1 -0
  43. metadata +135 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 SocialPandas
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,180 @@
1
+ Sidekiq Monitor
2
+ ===============
3
+ Advanced monitoring for Sidekiq
4
+
5
+ Description
6
+ -----------
7
+ Sidekiq Monitor offers a detailed, malleable UI for monitoring Sidekiq jobs.
8
+
9
+ It lets you:
10
+
11
+ * Sort jobs by:
12
+ * Queue
13
+ * Class
14
+ * Queued at time
15
+ * Started at time
16
+ * Duration
17
+ * Status (e.g. queued, running, complete, failed)
18
+ * Filter jobs by:
19
+ * Queue
20
+ * Class
21
+ * Status
22
+ * Set and view metadata for each job:
23
+ * Name - A customizable, human-readable name (e.g. 'Data Import for John Doe')
24
+ * Result - A customizable value describing the job's result (e.g. '{imported\_documents\_count: 241, imported\_contacts_count: 183}')
25
+ * View errors for failed jobs, including a backtrace
26
+ * Easily isolate long-running jobs and failed jobs
27
+ * Retry failed jobs via a button-click
28
+
29
+ And it looks like this:
30
+
31
+ [<img src="https://raw.github.com/socialpandas/sidekiq_monitor/master/examples/screenshot.png" />](https://raw.github.com/socialpandas/sidekiq_monitor/master/examples/screenshot.png)
32
+
33
+ Installation
34
+ ------------
35
+
36
+ Add sidekiq_monitor to your Gemfile:
37
+
38
+ gem 'sidekiq_monitor'
39
+
40
+ Install and run the migration:
41
+
42
+ rails g sidekiq:monitor:install
43
+ rake db:migrate
44
+
45
+ Mount it at a customizable path in `routes.rb`:
46
+
47
+ mount Sidekiq::Monitor::Engine => '/sidekiq'
48
+
49
+ Usage
50
+ -----
51
+
52
+ ### Setting a Job Name
53
+
54
+ To set a job's name (which makes the job's representation in the UI more human-readable), define a `self.job_name` method on your worker that takes the same arguments as its `perform` method:
55
+
56
+ ```ruby
57
+ class HardWorker
58
+ include Sidekiq::Worker
59
+
60
+ def perform(user_id)
61
+ puts 'Doing hard work'
62
+ end
63
+
64
+ def self.job_name(user_id)
65
+ User.find(user_id).username
66
+ end
67
+ end
68
+ ```
69
+
70
+ ### Setting a Job Result
71
+
72
+ To set a job's result (which can show what the job accomplished, for example), return a hash from the worker's `perform` method:
73
+
74
+ ```ruby
75
+ class HardWorker
76
+ include Sidekiq::Worker
77
+
78
+ def perform(user_ids)
79
+ puts 'Doing hard work'
80
+ { processed_users_count: user_ids.length }
81
+ end
82
+ end
83
+ ```
84
+
85
+ ### Authentication
86
+
87
+ You'll likely want to restrict access to this interface in a production setting. To do this, you can use routing constraints:
88
+
89
+ #### Devise
90
+
91
+ Checks a `User` model instance that responds to `admin?`
92
+
93
+ ```ruby
94
+ constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? }
95
+ constraints constraint do
96
+ mount Sidekiq::Monitor::Engine => '/sidekiq'
97
+ end
98
+ ```
99
+
100
+ Allow any authenticated `User`
101
+
102
+ ```ruby
103
+ constraint = lambda { |request| request.env['warden'].authenticate!({ scope: :user }) }
104
+ constraints constraint do
105
+ mount Sidekiq::Monitor::Engine => '/sidekiq'
106
+ end
107
+ ```
108
+
109
+ Short version
110
+
111
+ ```ruby
112
+ authenticate :user do
113
+ mount Sidekiq::Monitor::Engine => '/sidekiq'
114
+ end
115
+ ```
116
+
117
+ #### Authlogic
118
+
119
+ ```ruby
120
+ # lib/admin_constraint.rb
121
+ class AdminConstraint
122
+ def matches?(request)
123
+ return false unless request.cookies['user_credentials'].present?
124
+ user = User.find_by_persistence_token(request.cookies['user_credentials'].split(':')[0])
125
+ user && user.admin?
126
+ end
127
+ end
128
+
129
+ # config/routes.rb
130
+ require "admin_constraint"
131
+ mount Sidekiq::Monitor::Engine => '/sidekiq', :constraints => AdminConstraint.new
132
+ ```
133
+
134
+ #### Restful Authentication
135
+
136
+ Checks a `User` model instance that responds to `admin?`
137
+
138
+ ```
139
+ # lib/admin_constraint.rb
140
+ class AdminConstraint
141
+ def matches?(request)
142
+ return false unless request.session[:user_id]
143
+ user = User.find request.session[:user_id]
144
+ user && user.admin?
145
+ end
146
+ end
147
+
148
+ # config/routes.rb
149
+ require "admin_constraint"
150
+ mount Sidekiq::Monitor::Engine => '/sidekiq', :constraints => AdminConstraint.new
151
+ ```
152
+
153
+ #### Custom External Authentication
154
+
155
+ ```ruby
156
+ class AuthConstraint
157
+ def self.admin?(request)
158
+ return false unless (cookie = request.cookies['auth'])
159
+
160
+ Rails.cache.fetch(cookie['user'], :expires_in => 1.minute) do
161
+ auth_data = JSON.parse(Base64.decode64(cookie['data']))
162
+ response = HTTParty.post(Auth.validate_url, :query => auth_data)
163
+
164
+ response.code == 200 && JSON.parse(response.body)['roles'].to_a.include?('Admin')
165
+ end
166
+ end
167
+ end
168
+
169
+ # config/routes.rb
170
+ constraints lambda {|request| AuthConstraint.admin?(request) } do
171
+ mount Sidekiq::Monitor::Engine => '/admin/sidekiq'
172
+ end
173
+ ```
174
+
175
+ _(This authentication documentation was borrowed from the [Sidekiq wiki](https://github.com/mperham/sidekiq/wiki/Monitoring).)_
176
+
177
+ License
178
+ -------
179
+
180
+ Sidekiq Monitor is released under the MIT License. Please see the MIT-LICENSE file for details.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << "lib"
9
+ t.libs << "test"
10
+ t.test_files = FileList["test/**/*_test.rb"]
11
+ t.verbose = true
12
+ end
@@ -0,0 +1,165 @@
1
+ class SidekiqMonitor.AbstractJobsTable
2
+
3
+ constructor: ->
4
+ @api_params = {}
5
+ @initialize()
6
+
7
+ initialize_with_options: (options) =>
8
+ @options = options
9
+ @table = $(@options.table_selector)
10
+
11
+ @columns = @options.columns
12
+ @status_filter = null
13
+
14
+ $.getJSON SidekiqMonitor.settings.api_url('jobs/clean')
15
+
16
+ @table.dataTable
17
+ bProcessing: true
18
+ bServerSide: true
19
+ sAjaxSource: @table.data('source')
20
+ iDisplayLength: 10
21
+ aaSorting: [[@columns.enqueued_at, 'desc']]
22
+ sPaginationType: 'bootstrap'
23
+ aoColumns: @options.column_options
24
+ oLanguage:
25
+ sInfo: '_TOTAL_ jobs'
26
+ sInfoFiltered: ' (filtered from _MAX_)'
27
+ sLengthMenu: 'Per page: _MENU_'
28
+ sSearch: ''
29
+ fnRowCallback: (nRow, aData, iDisplayIndex) =>
30
+ $('.timeago', nRow).timeago()
31
+ fnInitComplete: () =>
32
+ filter_container = @table.siblings('.dataTables_filter')
33
+ filter_container.find('input').attr('placeholder', 'Search...')
34
+ filter_container.prepend '
35
+ <div class="btn-group status-filter" data-toggle="buttons-radio">
36
+ <button type="button" class="btn btn-small" data-value="queued">Queued</button>
37
+ <button type="button" class="btn btn-small" data-value="running">Running</button>
38
+ <button type="button" class="btn btn-small" data-value="complete">Complete</button>
39
+ <button type="button" class="btn btn-small" data-value="failed">Failed</button>
40
+ </div>'
41
+ @status_filter = filter_container.find('.status-filter')
42
+ fnServerData: (sSource, aoData, fnCallback) =>
43
+ $.each @api_params, (key, value) =>
44
+ aoData.push
45
+ name: key
46
+ value: @api_params[key]
47
+ $.getJSON sSource, aoData, (json) -> fnCallback(json)
48
+
49
+ @table.parents('.dataTables_wrapper').addClass('jobs-table-wrapper')
50
+
51
+ @initialize_ui()
52
+
53
+ initialize_ui: =>
54
+
55
+ @table.on 'click', '.status-value', (e) =>
56
+ tr = $(e.target).parents('tr:first')[0]
57
+ job = @table.fnGetData(tr)
58
+ @show_job(job)
59
+ false
60
+ @table.on 'click', '.retry-job', (e) =>
61
+ jid = $(e.target).attr('data-job-jid')
62
+ $.getJSON SidekiqMonitor.settings.api_url('jobs/retry?jid='+jid), =>
63
+ @reload_table()
64
+ false
65
+
66
+ $('body').on 'click', '.status-filter .btn', (e) =>
67
+ e.stopPropagation()
68
+ btn = $(e.target)
69
+ btn.siblings('.btn').removeClass('active')
70
+ btn.toggleClass('active')
71
+ value = @status_filter.find('.active:first').attr('data-value')
72
+ value = '' if !value?
73
+ @table.fnFilter(value, @columns.status - 1)
74
+
75
+ @start_polling()
76
+
77
+ show_job: (job) =>
78
+ return false if !job?
79
+
80
+ jid = job[@columns.jid]
81
+ class_name = job[@columns.class_name]
82
+ started_at = job[@columns.started_at]
83
+ duration = job[@columns.duration]
84
+ status = job[@columns.status]
85
+ result = job[@columns.result]
86
+ args = job[@columns.args]
87
+
88
+ # TODO: Make this cleaner; is there a way to grab the original value returned by the server?
89
+ status = $("<div>#{status}</div>").find('.status-value').text()
90
+
91
+ result_html = ''
92
+ if status == 'failed'
93
+ result_html = """
94
+ <h4>Error</h4>
95
+ #{result.message}
96
+ <h5>Backtrace</h5>
97
+ <pre>
98
+ #{result.backtrace.join("\n")}
99
+ </pre>
100
+ """
101
+ else if result?
102
+ rows_html = "<tr><td>#{key}</td><td>#{value}</td></tr>" for key, value in result
103
+ result_html = """
104
+ <table class="table table-striped">
105
+ #{rows_html}
106
+ </table>
107
+ """
108
+
109
+ modal_html = """
110
+ <div class="modal hide fade job-modal" role="dialog">
111
+ <div class="modal-header">
112
+ <button type="button" class="close" data-dismiss="modal">×</button>
113
+ <h3>Job</h3>
114
+ </div>
115
+ <div class="modal-body">
116
+ <table class="table table-striped">
117
+ <tr>
118
+ <th>JID</th>
119
+ <td>#{jid}</td>
120
+ </tr>
121
+ <tr>
122
+ <th>Class</th>
123
+ <td>#{class_name}</td>
124
+ </tr>
125
+ <tr>
126
+ <th>Args</th>
127
+ <td>#{args}</td>
128
+ </tr>
129
+ <tr>
130
+ <th>Started</th>
131
+ <td>#{started_at}</td>
132
+ </tr>
133
+ <tr>
134
+ <th>Duration</th>
135
+ <td>#{duration}</td>
136
+ </tr>
137
+ <tr>
138
+ <th>Status</th>
139
+ <td>#{status}</td>
140
+ </tr>
141
+ </table>
142
+ #{result_html}
143
+ </div>
144
+ </div>
145
+ """
146
+ $('.job-modal').modal('hide')
147
+ $('body').append(modal_html)
148
+ $('.job-modal:last').modal()
149
+
150
+ on_poll: =>
151
+ @reload_table()
152
+
153
+ reload_table: =>
154
+ @table.dataTable().fnStandingRedraw()
155
+
156
+ start_polling: =>
157
+ setInterval =>
158
+ @on_poll()
159
+ , 3000
160
+
161
+ format_time_ago: (time) =>
162
+ if time?
163
+ """<span class="timeago" title="#{time}">#{time}</span>"""
164
+ else
165
+ ""
@@ -0,0 +1,11 @@
1
+ #= require jquery
2
+ #= require sidekiq/monitor/bootstrap.min
3
+ #= require sidekiq/monitor/bootstrap-select.min
4
+ #= require sidekiq/monitor/jquery.timeago
5
+ #= require sidekiq/monitor/datatables
6
+ #= require sidekiq/monitor/datatables.bootstrap
7
+ #= require sidekiq/monitor/datatables.standing_redraw
8
+ #= require sidekiq/monitor/initialize
9
+ #= require sidekiq/monitor/abstract_jobs_table
10
+ #= require sidekiq/monitor/jobs_table
11
+ #= require sidekiq/monitor/queue_jobs_table
@@ -0,0 +1 @@
1
+ !function(b){var a=function(d,c,f){if(f){f.stopPropagation();f.preventDefault()}this.$element=b(d);this.$newElement=null;this.button=null;this.options=b.extend({},b.fn.selectpicker.defaults,this.$element.data(),typeof c=="object"&&c);this.style=this.options.style;this.size=this.options.size;this.init()};a.prototype={constructor:a,init:function(s){this.$element.hide();var v=this.$element.attr("class")!==undefined?this.$element.attr("class").split(/\s+/):"";var u=this.getTemplate();var o=this.$element.attr("id");u=this.createLi(u);this.$element.after(u);this.$newElement=this.$element.next(".bootstrap-select");var p=this.$newElement;var d=this.$newElement.find(".dropdown-menu");var m=d.find("li > a");var g=parseInt(m.css("line-height"))+m.outerHeight();var h=d.find("li .divider").outerHeight(true);var j=this.$newElement.offset().top;var l=0;var n=0;var t=this.$newElement.outerHeight();this.button=this.$newElement.find("> button");if(o!==undefined){this.button.attr("id",o);b('label[for="'+o+'"]').click(function(){p.find("button#"+o).focus()})}for(var r=0;r<v.length;r++){if(v[r]!="selectpicker"){this.$newElement.addClass(v[r])}}this.button.addClass(this.style);this.checkDisabled();this.checkTabIndex();this.clickListener();var q=parseInt(d.css("padding-top"))+parseInt(d.css("padding-bottom"))+parseInt(d.css("border-top-width"))+parseInt(d.css("border-bottom-width"));if(this.size=="auto"){function f(){var e=j-b(window).scrollTop();var x=window.innerHeight;var i=q+parseInt(d.css("margin-top"))+parseInt(d.css("margin-bottom"))+2;var w=x-e-t-i;n=w;if(p.hasClass("dropup")){n=e-i}d.css({"max-height":n+"px","overflow-y":"auto","min-height":g*3+"px"})}f();b(window).resize(f);b(window).scroll(f);this.$element.bind("DOMNodeInserted",f)}else{if(this.size&&this.size!="auto"&&d.find("li").length>this.size){var k=d.find("li > *").filter(":not(.div-contain)").slice(0,this.size).last().parent().index();var c=d.find("li").slice(0,k+1).find(".div-contain").length;n=g*this.size+c*h+q;d.css({"max-height":n+"px","overflow-y":"scroll"})}}this.$element.bind("DOMNodeInserted",b.proxy(this.reloadLi,this))},getTemplate:function(){var c="<div class='btn-group bootstrap-select'><button class='btn dropdown-toggle clearfix' data-toggle='dropdown'><span class='filter-option pull-left'>__SELECTED_OPTION</span>&nbsp;<span class='caret'></span></button><ul class='dropdown-menu' role='menu'>__ADD_LI</ul></div>";return c},reloadLi:function(){var f=[];var g=[];var c="";this.$newElement.find("li").remove();this.$element.find("option").each(function(){f.push(b(this).text())});this.$element.find("option").each(function(){var j=b(this).attr("class")!==undefined?b(this).attr("class"):"";var i=b(this).data("subtext")!==undefined?'<small class="muted">'+b(this).data("subtext")+"</small>":"";var h=b(this).parent().data("subtext")!==undefined?'<small class="muted">'+b(this).parent().data("subtext")+"</small>":"";if(b(this).parent().is("optgroup")&&b(this).data("divider")!=true){if(b(this).index()==0){if(b(this)[0].index!=0){g.push('<div class="div-contain"><div class="divider"></div></div><dt>'+b(this).parent().attr("label")+h+'</dt><a tabindex="-1" href="#" class="opt '+j+'">'+b(this).text()+i+"</a>")}else{g.push("<dt>"+b(this).parent().attr("label")+h+'</dt><a tabindex="-1" href="#" class="opt '+j+'">'+b(this).text()+i+"</a>")}}else{g.push('<a tabindex="-1" href="#" class="opt '+j+'">'+b(this).text()+i+"</a>")}}else{if(b(this).data("divider")==true){g.push('<div class="div-contain"><div class="divider"></div></div>')}else{g.push('<a tabindex="-1" href="#" class="'+j+'">'+b(this).text()+i+"</a>")}}});if(f.length>0){for(var d=0;d<f.length;d++){var e=this.$element.find("option").eq(d).is(":disabled")||this.$element.find("option").eq(d).parent().is(":disabled")?'class="disabled"':"";this.$newElement.find("ul").append("<li rel="+d+" "+e+">"+g[d]+"</li>")}}this.$newElement.find("li.disabled a, li dt, li .div-contain").on("click",function(h){h.preventDefault();h.stopPropagation();$select=b(this).parent().parents(".bootstrap-select");$select.find("button").focus()});if(this.$element.find("option:selected").attr("title")!=undefined){this.$newElement.find(".filter-option").html(this.$element.find("option:selected").attr("title"))}else{this.$newElement.find(".filter-option").html(this.$element.find("option:selected").text())}},createLi:function(g){var f=[];var k=[];var c="";var j=this;var h=this.$element[0].selectedIndex?this.$element[0].selectedIndex:0;this.$element.find("option").each(function(){f.push(b(this).text())});this.$element.find("option").each(function(){var m=b(this).attr("class")!==undefined?b(this).attr("class"):"";var l=b(this).data("subtext")!==undefined?'<small class="muted">'+b(this).data("subtext")+"</small>":"";var i=b(this).parent().data("subtext")!==undefined?'<small class="muted">'+b(this).parent().data("subtext")+"</small>":"";if(b(this).parent().is("optgroup")&&b(this).data("divider")!=true){if(b(this).index()==0){if(b(this)[0].index!=0){k.push('<div class="div-contain"><div class="divider"></div></div><dt>'+b(this).parent().attr("label")+i+'</dt><a tabindex="-1" href="#" class="opt '+m+'">'+b(this).text()+l+"</a>")}else{k.push("<dt>"+b(this).parent().attr("label")+i+'</dt><a tabindex="-1" href="#" class="opt '+m+'">'+b(this).text()+l+"</a>")}}else{k.push('<a tabindex="-1" href="#" class="opt '+m+'">'+b(this).text()+l+"</a>")}}else{if(b(this).data("divider")==true){k.push('<div class="div-contain"><div class="divider"></div></div>')}else{k.push('<a tabindex="-1" href="#" class="'+m+'">'+b(this).text()+l+"</a>")}}});if(f.length>0){g=g.replace("__SELECTED_OPTION",f[h]);for(var d=0;d<f.length;d++){var e=this.$element.find("option").eq(d).is(":disabled")||this.$element.find("option").eq(d).parent().is(":disabled")?'class="disabled"':"";c+="<li rel="+d+" "+e+">"+k[d]+"</li>"}}else{g=g.replace("__SELECTED_OPTION","")}this.$element.find("option").eq(h).prop("selected",true);g=g.replace("__ADD_LI",c);return g},checkDisabled:function(){if(this.$element.is(":disabled")){this.button.addClass("disabled");this.button.click(function(c){c.preventDefault()})}},checkTabIndex:function(){if(this.$element.is("[tabindex]")){var c=this.$element.attr("tabindex");this.button.attr("tabindex",c)}},clickListener:function(){b("body").on("touchstart.dropdown",".dropdown-menu",function(c){c.stopPropagation()});this.$newElement.find("li.disabled a, li dt, li .div-contain").on("click",function(c){c.preventDefault();c.stopPropagation();$select=b(this).parent().parents(".bootstrap-select");$select.find("button").focus()});this.$newElement.on("click","li a",function(g){g.preventDefault();var d=b(this).parent().index(),f=b(this).parent(),c=f.parents(".bootstrap-select");if(c.prev("select").not(":disabled")){c.prev("select").find("option").removeAttr("selected");c.prev("select").find("option").eq(d).prop("selected",true).attr("selected","selected");c.find(".filter-option").html(f.text());c.find("button").focus();c.prev("select").trigger("change")}});this.$element.on("change",function(c){if(b(this).find("option:selected").attr("title")!=undefined){b(this).next(".bootstrap-select").find(".filter-option").html(b(this).find("option:selected").attr("title"))}else{b(this).next(".bootstrap-select").find(".filter-option").html(b(this).find("option:selected").text())}})}};b.fn.selectpicker=function(c,d){return this.each(function(){var g=b(this),f=g.data("selectpicker"),e=typeof c=="object"&&c;if(!f){g.data("selectpicker",(f=new a(this,e,d)))}if(typeof c=="string"){f[c]()}})};b.fn.selectpicker.defaults={style:null,size:"auto"}}(window.jQuery);
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * Bootstrap.js by @fat & @mdo
3
+ * Copyright 2012 Twitter, Inc.
4
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
5
+ */
6
+ !function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||s.toggleClass("open"),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f<s.length-1&&f++,~f||(f=0),s.eq(f).focus()}};var s=e.fn.dropdown;e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.dropdown.data-api",r).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on(".dropdown-menu",function(e){e.stopPropagation()}).on("click.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.focus().trigger("shown")}):t.$element.focus().trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(){var e=this;this.$element.hide(),this.backdrop(function(){e.removeBackdrop(),e.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);if(!n.options.delay||!n.options.delay.show)return n.show();clearTimeout(this.timeout),n.hoverState="in",this.timeout=setTimeout(function(){n.hoverState=="in"&&n.show()},n.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
@@ -0,0 +1,96 @@
1
+ /* Default class modification */
2
+
3
+ $.extend( $.fn.dataTableExt.oStdClasses, {
4
+ "sWrapper": "dataTables_wrapper form-inline"
5
+ } );
6
+
7
+ /* API method to get paging information */
8
+ $.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings )
9
+ {
10
+ return {
11
+ "iStart": oSettings._iDisplayStart,
12
+ "iEnd": oSettings.fnDisplayEnd(),
13
+ "iLength": oSettings._iDisplayLength,
14
+ "iTotal": oSettings.fnRecordsTotal(),
15
+ "iFilteredTotal": oSettings.fnRecordsDisplay(),
16
+ "iPage": Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
17
+ "iTotalPages": Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
18
+ };
19
+ }
20
+
21
+ /* Bootstrap style pagination control */
22
+ $.extend( $.fn.dataTableExt.oPagination, {
23
+ "bootstrap": {
24
+ "fnInit": function( oSettings, nPaging, fnDraw ) {
25
+ var oLang = oSettings.oLanguage.oPaginate;
26
+ var fnClickHandler = function ( e ) {
27
+ e.preventDefault();
28
+ if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
29
+ fnDraw( oSettings );
30
+ }
31
+ };
32
+
33
+ $(nPaging).addClass('pagination').append(
34
+ '<ul>'+
35
+ '<li class="prev disabled"><a href="#">&larr; '+oLang.sPrevious+'</a></li>'+
36
+ '<li class="next disabled"><a href="#">'+oLang.sNext+' &rarr; </a></li>'+
37
+ '</ul>'
38
+ );
39
+ var els = $('a', nPaging);
40
+ $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler );
41
+ $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler );
42
+ },
43
+
44
+ "fnUpdate": function ( oSettings, fnDraw ) {
45
+ var iListLength = 5;
46
+ var oPaging = oSettings.oInstance.fnPagingInfo();
47
+ var an = oSettings.aanFeatures.p;
48
+ var i, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);
49
+
50
+ if ( oPaging.iTotalPages < iListLength) {
51
+ iStart = 1;
52
+ iEnd = oPaging.iTotalPages;
53
+ }
54
+ else if ( oPaging.iPage <= iHalf ) {
55
+ iStart = 1;
56
+ iEnd = iListLength;
57
+ } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
58
+ iStart = oPaging.iTotalPages - iListLength + 1;
59
+ iEnd = oPaging.iTotalPages;
60
+ } else {
61
+ iStart = oPaging.iPage - iHalf + 1;
62
+ iEnd = iStart + iListLength - 1;
63
+ }
64
+
65
+ for ( i=0, iLen=an.length ; i<iLen ; i++ ) {
66
+ // Remove the middle elements
67
+ $('li:gt(0)', an[i]).filter(':not(:last)').remove();
68
+
69
+ // Add the new list items and their event handlers
70
+ for ( j=iStart ; j<=iEnd ; j++ ) {
71
+ sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
72
+ $('<li '+sClass+'><a href="#">'+j+'</a></li>')
73
+ .insertBefore( $('li:last', an[i])[0] )
74
+ .bind('click', function (e) {
75
+ e.preventDefault();
76
+ oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
77
+ fnDraw( oSettings );
78
+ } );
79
+ }
80
+
81
+ // Add / remove disabled classes from the static elements
82
+ if ( oPaging.iPage === 0 ) {
83
+ $('li:first', an[i]).addClass('disabled');
84
+ } else {
85
+ $('li:first', an[i]).removeClass('disabled');
86
+ }
87
+
88
+ if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
89
+ $('li:last', an[i]).addClass('disabled');
90
+ } else {
91
+ $('li:last', an[i]).removeClass('disabled');
92
+ }
93
+ }
94
+ }
95
+ }
96
+ } );