qless 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/install_phantomjs +7 -0
- data/lib/qless.rb +4 -0
- data/lib/qless/job.rb +40 -38
- data/lib/qless/qless-core/cancel.lua +9 -9
- data/lib/qless/qless-core/failed.lua +1 -1
- data/lib/qless/qless-core/peek.lua +22 -12
- data/lib/qless/qless-core/pop.lua +31 -16
- data/lib/qless/qless-core/recur.lua +12 -3
- data/lib/qless/server.rb +96 -66
- data/lib/qless/server/static/css/bootstrap-responsive.css +686 -0
- data/lib/qless/server/static/css/bootstrap-responsive.min.css +12 -0
- data/lib/qless/server/static/css/bootstrap.css +3991 -0
- data/lib/qless/server/static/css/bootstrap.min.css +689 -0
- data/lib/qless/server/static/css/codemirror.css +112 -0
- data/lib/qless/server/static/css/docs.css +819 -0
- data/lib/qless/server/static/css/jquery.noty.css +105 -0
- data/lib/qless/server/static/css/noty_theme_twitter.css +137 -0
- data/lib/qless/server/static/css/style.css +204 -0
- data/lib/qless/server/static/favicon.ico +0 -0
- data/lib/qless/server/static/img/glyphicons-halflings-white.png +0 -0
- data/lib/qless/server/static/img/glyphicons-halflings.png +0 -0
- data/lib/qless/server/static/js/bootstrap-alert.js +94 -0
- data/lib/qless/server/static/js/bootstrap-scrollspy.js +125 -0
- data/lib/qless/server/static/js/bootstrap-tab.js +130 -0
- data/lib/qless/server/static/js/bootstrap-tooltip.js +270 -0
- data/lib/qless/server/static/js/bootstrap-typeahead.js +285 -0
- data/lib/qless/server/static/js/bootstrap.js +1726 -0
- data/lib/qless/server/static/js/bootstrap.min.js +6 -0
- data/lib/qless/server/static/js/codemirror.js +2972 -0
- data/lib/qless/server/static/js/jquery.noty.js +220 -0
- data/lib/qless/server/static/js/mode/javascript.js +360 -0
- data/lib/qless/server/static/js/theme/cobalt.css +18 -0
- data/lib/qless/server/static/js/theme/eclipse.css +25 -0
- data/lib/qless/server/static/js/theme/elegant.css +10 -0
- data/lib/qless/server/static/js/theme/lesser-dark.css +45 -0
- data/lib/qless/server/static/js/theme/monokai.css +28 -0
- data/lib/qless/server/static/js/theme/neat.css +9 -0
- data/lib/qless/server/static/js/theme/night.css +21 -0
- data/lib/qless/server/static/js/theme/rubyblue.css +21 -0
- data/lib/qless/server/static/js/theme/xq-dark.css +46 -0
- data/lib/qless/server/views/_job.erb +219 -0
- data/lib/qless/server/views/_job_list.erb +8 -0
- data/lib/qless/server/views/_pagination.erb +7 -0
- data/lib/qless/server/views/about.erb +130 -0
- data/lib/qless/server/views/config.erb +14 -0
- data/lib/qless/server/views/failed.erb +48 -0
- data/lib/qless/server/views/failed_type.erb +18 -0
- data/lib/qless/server/views/job.erb +17 -0
- data/lib/qless/server/views/layout.erb +341 -0
- data/lib/qless/server/views/overview.erb +90 -0
- data/lib/qless/server/views/queue.erb +122 -0
- data/lib/qless/server/views/queues.erb +26 -0
- data/lib/qless/server/views/tag.erb +6 -0
- data/lib/qless/server/views/track.erb +69 -0
- data/lib/qless/server/views/worker.erb +34 -0
- data/lib/qless/server/views/workers.erb +14 -0
- data/lib/qless/version.rb +1 -1
- data/lib/qless/worker.rb +11 -2
- metadata +72 -6
- data/lib/qless/qless-core/ruby/lib/qless-core.rb +0 -1
- data/lib/qless/qless-core/ruby/lib/qless/core.rb +0 -13
- data/lib/qless/qless-core/ruby/lib/qless/core/version.rb +0 -5
- data/lib/qless/qless-core/ruby/spec/qless_core_spec.rb +0 -13
@@ -34,6 +34,15 @@ if command == 'on' then
|
|
34
34
|
options.tags = assert(cjson.decode(options.tags or {}), 'Recur(): Arg "tags" must be JSON-encoded array of string. Got: ' .. tostring(options.tags))
|
35
35
|
options.priority = assert(tonumber(options.priority or 0) , 'Recur(): Arg "priority" must be a number. Got: ' .. tostring(options.priority))
|
36
36
|
options.retries = assert(tonumber(options.retries or 0) , 'Recur(): Arg "retries" must be a number. Got: ' .. tostring(options.retries))
|
37
|
+
|
38
|
+
local count, old_queue = unpack(redis.call('hmget', 'ql:r:' .. jid, 'count', 'queue'))
|
39
|
+
count = count or 0
|
40
|
+
|
41
|
+
-- If it has previously been in another queue, then we should remove
|
42
|
+
-- some information about it
|
43
|
+
if old_queue then
|
44
|
+
redis.call('zrem', 'ql:q:' .. old_queue .. '-recur', jid)
|
45
|
+
end
|
37
46
|
|
38
47
|
-- Do some insertions
|
39
48
|
redis.call('hmset', 'ql:r:' .. jid,
|
@@ -46,7 +55,7 @@ if command == 'on' then
|
|
46
55
|
'queue' , queue,
|
47
56
|
'type' , 'interval',
|
48
57
|
-- How many jobs we've spawned from this
|
49
|
-
'count' ,
|
58
|
+
'count' , count,
|
50
59
|
'interval', interval,
|
51
60
|
'retries' , options.retries)
|
52
61
|
-- Now, we should schedule the next run of the job
|
@@ -102,9 +111,9 @@ elseif command == 'update' then
|
|
102
111
|
local options = {}
|
103
112
|
|
104
113
|
-- Make sure that the job exists
|
105
|
-
if redis.call('exists', 'ql:r:' .. jid) then
|
114
|
+
if redis.call('exists', 'ql:r:' .. jid) ~= 0 then
|
106
115
|
for i = 3, #ARGV, 2 do
|
107
|
-
local key
|
116
|
+
local key = ARGV[i]
|
108
117
|
local value = ARGV[i+1]
|
109
118
|
if key == 'priority' or key == 'interval' or key == 'retries' then
|
110
119
|
value = assert(tonumber(value), 'Recur(): Arg "' .. key .. '" must be a number: ' .. tostring(value))
|
data/lib/qless/server.rb
CHANGED
@@ -9,13 +9,13 @@ module Qless
|
|
9
9
|
dir = File.dirname(File.expand_path(__FILE__))
|
10
10
|
set :views , "#{dir}/server/views"
|
11
11
|
set :public_folder, "#{dir}/server/static"
|
12
|
-
|
12
|
+
|
13
13
|
# For debugging purposes at least, I want this
|
14
14
|
set :reload_templates, true
|
15
|
-
|
15
|
+
|
16
16
|
# I'm not sure what this option is -- I'll look it up later
|
17
17
|
# set :static, true
|
18
|
-
|
18
|
+
|
19
19
|
def self.client
|
20
20
|
@client ||= Qless::Client.new
|
21
21
|
end
|
@@ -23,7 +23,7 @@ module Qless
|
|
23
23
|
def self.client=(client)
|
24
24
|
@client = client
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
helpers do
|
28
28
|
include Rack::Utils
|
29
29
|
|
@@ -35,7 +35,46 @@ module Qless
|
|
35
35
|
def path_prefix
|
36
36
|
request.env['SCRIPT_NAME']
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
|
+
def url_with_modified_query
|
40
|
+
url = URI(request.url)
|
41
|
+
existing_query = Rack::Utils.parse_query(url.query)
|
42
|
+
url.query = Rack::Utils.build_query(yield existing_query)
|
43
|
+
url.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def page_url(offset)
|
47
|
+
url_with_modified_query do |query|
|
48
|
+
query.merge('page' => current_page + offset)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def next_page_url
|
53
|
+
page_url 1
|
54
|
+
end
|
55
|
+
|
56
|
+
def prev_page_url
|
57
|
+
page_url -1
|
58
|
+
end
|
59
|
+
|
60
|
+
def current_page
|
61
|
+
@current_page ||= begin
|
62
|
+
Integer(params[:page])
|
63
|
+
rescue
|
64
|
+
1
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
PAGE_SIZE = 25
|
69
|
+
def pagination_values
|
70
|
+
start = (current_page - 1) * PAGE_SIZE
|
71
|
+
[start, start + PAGE_SIZE]
|
72
|
+
end
|
73
|
+
|
74
|
+
def paginated(qless_object, method, *args)
|
75
|
+
qless_object.send(method, *(args + pagination_values))
|
76
|
+
end
|
77
|
+
|
39
78
|
def tabs
|
40
79
|
return [
|
41
80
|
{:name => 'Queues' , :path => '/queues' },
|
@@ -46,38 +85,38 @@ module Qless
|
|
46
85
|
{:name => 'About' , :path => '/about' }
|
47
86
|
]
|
48
87
|
end
|
49
|
-
|
88
|
+
|
50
89
|
def application_name
|
51
90
|
return Server.client.config['application']
|
52
91
|
end
|
53
|
-
|
92
|
+
|
54
93
|
def queues
|
55
94
|
return Server.client.queues.counts
|
56
95
|
end
|
57
|
-
|
96
|
+
|
58
97
|
def tracked
|
59
98
|
return Server.client.jobs.tracked
|
60
99
|
end
|
61
|
-
|
100
|
+
|
62
101
|
def workers
|
63
102
|
return Server.client.workers.counts
|
64
103
|
end
|
65
|
-
|
104
|
+
|
66
105
|
def failed
|
67
106
|
return Server.client.jobs.failed
|
68
107
|
end
|
69
|
-
|
108
|
+
|
70
109
|
# Return the supplied object back as JSON
|
71
110
|
def json(obj)
|
72
111
|
content_type :json
|
73
112
|
obj.to_json
|
74
113
|
end
|
75
|
-
|
114
|
+
|
76
115
|
# Make the id acceptable as an id / att in HTML
|
77
116
|
def sanitize_attr(attr)
|
78
117
|
return attr.gsub(/[^a-zA-Z\:\_]/, '-')
|
79
118
|
end
|
80
|
-
|
119
|
+
|
81
120
|
# What are the top tags? Since it might go on, say, every
|
82
121
|
# page, then we should probably be caching it
|
83
122
|
def top_tags
|
@@ -93,7 +132,7 @@ module Qless
|
|
93
132
|
end
|
94
133
|
@top_tags[:top]
|
95
134
|
end
|
96
|
-
|
135
|
+
|
97
136
|
def strftime(t)
|
98
137
|
# From http://stackoverflow.com/questions/195740/how-do-you-do-relative-time-in-rails
|
99
138
|
diff_seconds = Time.now - t
|
@@ -104,54 +143,47 @@ module Qless
|
|
104
143
|
"#{(diff_seconds/60).to_i} minutes ago"
|
105
144
|
when 3600 ... 3600*24
|
106
145
|
"#{(diff_seconds/3600).to_i} hours ago"
|
107
|
-
when (3600*24) ... (3600*24*30)
|
146
|
+
when (3600*24) ... (3600*24*30)
|
108
147
|
"#{(diff_seconds/(3600*24)).to_i} days ago"
|
109
148
|
else
|
110
149
|
t.strftime('%b %e, %Y %H:%M:%S %Z (%z)')
|
111
150
|
end
|
112
151
|
end
|
113
152
|
end
|
114
|
-
|
153
|
+
|
115
154
|
get '/?' do
|
116
155
|
erb :overview, :layout => true, :locals => { :title => "Overview" }
|
117
156
|
end
|
118
|
-
|
157
|
+
|
119
158
|
# Returns a JSON blob with the job counts for various queues
|
120
159
|
get '/queues.json' do
|
121
160
|
json(Server.client.queues.counts)
|
122
161
|
end
|
123
|
-
|
162
|
+
|
124
163
|
get '/queues/?' do
|
125
164
|
erb :queues, :layout => true, :locals => {
|
126
165
|
:title => 'Queues'
|
127
166
|
}
|
128
167
|
end
|
129
|
-
|
168
|
+
|
130
169
|
# Return the job counts for a specific queue
|
131
170
|
get '/queues/:name.json' do
|
132
171
|
json(Server.client.queues[params[:name]].counts)
|
133
172
|
end
|
134
|
-
|
173
|
+
|
174
|
+
filtered_tabs = %w[ running scheduled stalled depends recurring ].to_set
|
135
175
|
get '/queues/:name/?:tab?' do
|
136
176
|
queue = Server.client.queues[params[:name]]
|
137
|
-
tab
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
jobs = queue.jobs.stalled
|
146
|
-
when 'depends'
|
147
|
-
jobs = queue.jobs.depends
|
148
|
-
when 'recurring'
|
149
|
-
jobs = queue.jobs.recurring
|
150
|
-
end
|
151
|
-
jobs = jobs.map { |jid| Server.client.jobs[jid] }
|
152
|
-
if tab == 'waiting'
|
153
|
-
jobs = queue.peek(20)
|
177
|
+
tab = params.fetch('tab', 'stats')
|
178
|
+
|
179
|
+
jobs = if tab == 'waiting'
|
180
|
+
queue.peek(20)
|
181
|
+
elsif filtered_tabs.include?(tab)
|
182
|
+
paginated(queue.jobs, tab).map { |jid| Server.client.jobs[jid] }
|
183
|
+
else
|
184
|
+
[]
|
154
185
|
end
|
186
|
+
|
155
187
|
erb :queue, :layout => true, :locals => {
|
156
188
|
:title => "Queue #{params[:name]}",
|
157
189
|
:tab => tab,
|
@@ -160,7 +192,11 @@ module Qless
|
|
160
192
|
:stats => queue.stats
|
161
193
|
}
|
162
194
|
end
|
163
|
-
|
195
|
+
|
196
|
+
get '/failed.json' do
|
197
|
+
json(Server.client.jobs.failed)
|
198
|
+
end
|
199
|
+
|
164
200
|
get '/failed/?' do
|
165
201
|
# qless-core doesn't provide functionality this way, so we'll
|
166
202
|
# do it ourselves. I'm not sure if this is how the core library
|
@@ -170,21 +206,21 @@ module Qless
|
|
170
206
|
:failed => Server.client.jobs.failed.keys.map { |t| Server.client.jobs.failed(t).tap { |f| f['type'] = t } }
|
171
207
|
}
|
172
208
|
end
|
173
|
-
|
209
|
+
|
174
210
|
get '/failed/:type/?' do
|
175
211
|
erb :failed_type, :layout => true, :locals => {
|
176
212
|
:title => 'Failed | ' + params[:type],
|
177
213
|
:type => params[:type],
|
178
|
-
:failed => Server.client.jobs
|
214
|
+
:failed => paginated(Server.client.jobs, :failed, params[:type])
|
179
215
|
}
|
180
216
|
end
|
181
|
-
|
217
|
+
|
182
218
|
get '/track/?' do
|
183
219
|
erb :track, :layout => true, :locals => {
|
184
220
|
:title => 'Track'
|
185
221
|
}
|
186
222
|
end
|
187
|
-
|
223
|
+
|
188
224
|
get '/jobs/:jid' do
|
189
225
|
erb :job, :layout => true, :locals => {
|
190
226
|
:title => "Job | #{params[:jid]}",
|
@@ -192,7 +228,7 @@ module Qless
|
|
192
228
|
:job => Server.client.jobs[params[:jid]]
|
193
229
|
}
|
194
230
|
end
|
195
|
-
|
231
|
+
|
196
232
|
get '/workers/?' do
|
197
233
|
erb :workers, :layout => true, :locals => {
|
198
234
|
:title => 'Workers'
|
@@ -209,9 +245,9 @@ module Qless
|
|
209
245
|
}
|
210
246
|
}
|
211
247
|
end
|
212
|
-
|
248
|
+
|
213
249
|
get '/tag/?' do
|
214
|
-
jobs = Server.client.jobs
|
250
|
+
jobs = paginated(Server.client.jobs, :tagged, params[:tag])
|
215
251
|
erb :tag, :layout => true, :locals => {
|
216
252
|
:title => "Tag | #{params[:tag]}",
|
217
253
|
:tag => params[:tag],
|
@@ -219,26 +255,20 @@ module Qless
|
|
219
255
|
:total => jobs['total']
|
220
256
|
}
|
221
257
|
end
|
222
|
-
|
258
|
+
|
223
259
|
get '/config/?' do
|
224
260
|
erb :config, :layout => true, :locals => {
|
225
261
|
:title => 'Config',
|
226
262
|
:options => Server.client.config.all
|
227
263
|
}
|
228
264
|
end
|
229
|
-
|
265
|
+
|
230
266
|
get '/about/?' do
|
231
267
|
erb :about, :layout => true, :locals => {
|
232
268
|
:title => 'About'
|
233
269
|
}
|
234
270
|
end
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
271
|
+
|
242
272
|
# These are the bits where we accept AJAX requests
|
243
273
|
post "/track/?" do
|
244
274
|
# Expects a JSON-encoded hash with a job id, and optionally some tags
|
@@ -259,7 +289,7 @@ module Qless
|
|
259
289
|
end
|
260
290
|
end
|
261
291
|
end
|
262
|
-
|
292
|
+
|
263
293
|
post "/untrack/?" do
|
264
294
|
# Expects a JSON-encoded array of job ids to stop tracking
|
265
295
|
jobs = JSON.parse(request.body.read).map { |jid| Server.client.jobs[jid] }.select { |j| not j.nil? }
|
@@ -269,7 +299,7 @@ module Qless
|
|
269
299
|
end
|
270
300
|
return json({ :untracked => jobs.map { |job| job.jid } })
|
271
301
|
end
|
272
|
-
|
302
|
+
|
273
303
|
post "/priority/?" do
|
274
304
|
# Expects a JSON-encoded dictionary of jid => priority
|
275
305
|
response = Hash.new
|
@@ -284,7 +314,7 @@ module Qless
|
|
284
314
|
end
|
285
315
|
return json(response)
|
286
316
|
end
|
287
|
-
|
317
|
+
|
288
318
|
post "/tag/?" do
|
289
319
|
# Expects a JSON-encoded dictionary of jid => [tag, tag, tag]
|
290
320
|
response = Hash.new
|
@@ -298,7 +328,7 @@ module Qless
|
|
298
328
|
end
|
299
329
|
return json(response)
|
300
330
|
end
|
301
|
-
|
331
|
+
|
302
332
|
post "/untag/?" do
|
303
333
|
# Expects a JSON-encoded dictionary of jid => [tag, tag, tag]
|
304
334
|
response = Hash.new
|
@@ -312,7 +342,7 @@ module Qless
|
|
312
342
|
end
|
313
343
|
return json(response)
|
314
344
|
end
|
315
|
-
|
345
|
+
|
316
346
|
post "/move/?" do
|
317
347
|
# Expects a JSON-encoded hash of id: jid, and queue: queue_name
|
318
348
|
data = JSON.parse(request.body.read)
|
@@ -328,7 +358,7 @@ module Qless
|
|
328
358
|
end
|
329
359
|
end
|
330
360
|
end
|
331
|
-
|
361
|
+
|
332
362
|
post "/undepend/?" do
|
333
363
|
# Expects a JSON-encoded hash of id: jid, and queue: queue_name
|
334
364
|
data = JSON.parse(request.body.read)
|
@@ -344,7 +374,7 @@ module Qless
|
|
344
374
|
end
|
345
375
|
end
|
346
376
|
end
|
347
|
-
|
377
|
+
|
348
378
|
post "/retry/?" do
|
349
379
|
# Expects a JSON-encoded hash of id: jid, and queue: queue_name
|
350
380
|
data = JSON.parse(request.body.read)
|
@@ -361,7 +391,7 @@ module Qless
|
|
361
391
|
end
|
362
392
|
end
|
363
393
|
end
|
364
|
-
|
394
|
+
|
365
395
|
# Retry all the failures of a particular type
|
366
396
|
post "/retryall/?" do
|
367
397
|
# Expects a JSON-encoded hash of type: failure-type
|
@@ -376,7 +406,7 @@ module Qless
|
|
376
406
|
end)
|
377
407
|
end
|
378
408
|
end
|
379
|
-
|
409
|
+
|
380
410
|
post "/cancel/?" do
|
381
411
|
# Expects a JSON-encoded array of job ids to cancel
|
382
412
|
jobs = JSON.parse(request.body.read).map { |jid| Server.client.jobs[jid] }.select { |j| not j.nil? }
|
@@ -384,14 +414,14 @@ module Qless
|
|
384
414
|
jobs.each do |job|
|
385
415
|
job.cancel()
|
386
416
|
end
|
387
|
-
|
417
|
+
|
388
418
|
if request.xhr?
|
389
419
|
return json({ :canceled => jobs.map { |job| job.jid } })
|
390
420
|
else
|
391
421
|
redirect to(request.referrer)
|
392
422
|
end
|
393
423
|
end
|
394
|
-
|
424
|
+
|
395
425
|
post "/cancelall/?" do
|
396
426
|
# Expects a JSON-encoded hash of type: failure-type
|
397
427
|
data = JSON.parse(request.body.read)
|
@@ -404,7 +434,7 @@ module Qless
|
|
404
434
|
end)
|
405
435
|
end
|
406
436
|
end
|
407
|
-
|
437
|
+
|
408
438
|
# start the server if ruby file executed directly
|
409
439
|
run! if app_file == $0
|
410
440
|
end
|
@@ -0,0 +1,686 @@
|
|
1
|
+
/*!
|
2
|
+
* Bootstrap Responsive v2.0.2
|
3
|
+
*
|
4
|
+
* Copyright 2012 Twitter, Inc
|
5
|
+
* Licensed under the Apache License v2.0
|
6
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
*
|
8
|
+
* Designed and built with all the love in the world @twitter by @mdo and @fat.
|
9
|
+
*/
|
10
|
+
.clearfix {
|
11
|
+
*zoom: 1;
|
12
|
+
}
|
13
|
+
.clearfix:before,
|
14
|
+
.clearfix:after {
|
15
|
+
display: table;
|
16
|
+
content: "";
|
17
|
+
}
|
18
|
+
.clearfix:after {
|
19
|
+
clear: both;
|
20
|
+
}
|
21
|
+
.hide-text {
|
22
|
+
overflow: hidden;
|
23
|
+
text-indent: 100%;
|
24
|
+
white-space: nowrap;
|
25
|
+
}
|
26
|
+
.input-block-level {
|
27
|
+
display: block;
|
28
|
+
width: 100%;
|
29
|
+
min-height: 28px;
|
30
|
+
/* Make inputs at least the height of their button counterpart */
|
31
|
+
|
32
|
+
/* Makes inputs behave like true block-level elements */
|
33
|
+
|
34
|
+
-webkit-box-sizing: border-box;
|
35
|
+
-moz-box-sizing: border-box;
|
36
|
+
-ms-box-sizing: border-box;
|
37
|
+
box-sizing: border-box;
|
38
|
+
}
|
39
|
+
.hidden {
|
40
|
+
display: none;
|
41
|
+
visibility: hidden;
|
42
|
+
}
|
43
|
+
.visible-phone {
|
44
|
+
display: none;
|
45
|
+
}
|
46
|
+
.visible-tablet {
|
47
|
+
display: none;
|
48
|
+
}
|
49
|
+
.visible-desktop {
|
50
|
+
display: block;
|
51
|
+
}
|
52
|
+
.hidden-phone {
|
53
|
+
display: block;
|
54
|
+
}
|
55
|
+
.hidden-tablet {
|
56
|
+
display: block;
|
57
|
+
}
|
58
|
+
.hidden-desktop {
|
59
|
+
display: none;
|
60
|
+
}
|
61
|
+
@media (max-width: 767px) {
|
62
|
+
.visible-phone {
|
63
|
+
display: block;
|
64
|
+
}
|
65
|
+
.hidden-phone {
|
66
|
+
display: none;
|
67
|
+
}
|
68
|
+
.hidden-desktop {
|
69
|
+
display: block;
|
70
|
+
}
|
71
|
+
.visible-desktop {
|
72
|
+
display: none;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
@media (min-width: 768px) and (max-width: 979px) {
|
76
|
+
.visible-tablet {
|
77
|
+
display: block;
|
78
|
+
}
|
79
|
+
.hidden-tablet {
|
80
|
+
display: none;
|
81
|
+
}
|
82
|
+
.hidden-desktop {
|
83
|
+
display: block;
|
84
|
+
}
|
85
|
+
.visible-desktop {
|
86
|
+
display: none;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
@media (max-width: 480px) {
|
90
|
+
.nav-collapse {
|
91
|
+
-webkit-transform: translate3d(0, 0, 0);
|
92
|
+
}
|
93
|
+
.page-header h1 small {
|
94
|
+
display: block;
|
95
|
+
line-height: 18px;
|
96
|
+
}
|
97
|
+
input[type="checkbox"],
|
98
|
+
input[type="radio"] {
|
99
|
+
border: 1px solid #ccc;
|
100
|
+
}
|
101
|
+
.form-horizontal .control-group > label {
|
102
|
+
float: none;
|
103
|
+
width: auto;
|
104
|
+
padding-top: 0;
|
105
|
+
text-align: left;
|
106
|
+
}
|
107
|
+
.form-horizontal .controls {
|
108
|
+
margin-left: 0;
|
109
|
+
}
|
110
|
+
.form-horizontal .control-list {
|
111
|
+
padding-top: 0;
|
112
|
+
}
|
113
|
+
.form-horizontal .form-actions {
|
114
|
+
padding-left: 10px;
|
115
|
+
padding-right: 10px;
|
116
|
+
}
|
117
|
+
.modal {
|
118
|
+
position: absolute;
|
119
|
+
top: 10px;
|
120
|
+
left: 10px;
|
121
|
+
right: 10px;
|
122
|
+
width: auto;
|
123
|
+
margin: 0;
|
124
|
+
}
|
125
|
+
.modal.fade.in {
|
126
|
+
top: auto;
|
127
|
+
}
|
128
|
+
.modal-header .close {
|
129
|
+
padding: 10px;
|
130
|
+
margin: -10px;
|
131
|
+
}
|
132
|
+
.carousel-caption {
|
133
|
+
position: static;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
@media (max-width: 767px) {
|
137
|
+
body {
|
138
|
+
padding-left: 20px;
|
139
|
+
padding-right: 20px;
|
140
|
+
}
|
141
|
+
.navbar-fixed-top {
|
142
|
+
margin-left: -20px;
|
143
|
+
margin-right: -20px;
|
144
|
+
}
|
145
|
+
.container {
|
146
|
+
width: auto;
|
147
|
+
}
|
148
|
+
.row-fluid {
|
149
|
+
width: 100%;
|
150
|
+
}
|
151
|
+
.row {
|
152
|
+
margin-left: 0;
|
153
|
+
}
|
154
|
+
.row > [class*="span"],
|
155
|
+
.row-fluid > [class*="span"] {
|
156
|
+
float: none;
|
157
|
+
display: block;
|
158
|
+
width: auto;
|
159
|
+
margin: 0;
|
160
|
+
}
|
161
|
+
.thumbnails [class*="span"] {
|
162
|
+
width: auto;
|
163
|
+
}
|
164
|
+
input[class*="span"],
|
165
|
+
select[class*="span"],
|
166
|
+
textarea[class*="span"],
|
167
|
+
.uneditable-input {
|
168
|
+
display: block;
|
169
|
+
width: 100%;
|
170
|
+
min-height: 28px;
|
171
|
+
/* Make inputs at least the height of their button counterpart */
|
172
|
+
|
173
|
+
/* Makes inputs behave like true block-level elements */
|
174
|
+
|
175
|
+
-webkit-box-sizing: border-box;
|
176
|
+
-moz-box-sizing: border-box;
|
177
|
+
-ms-box-sizing: border-box;
|
178
|
+
box-sizing: border-box;
|
179
|
+
}
|
180
|
+
.input-prepend input[class*="span"],
|
181
|
+
.input-append input[class*="span"] {
|
182
|
+
width: auto;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
@media (min-width: 768px) and (max-width: 979px) {
|
186
|
+
.row {
|
187
|
+
margin-left: -20px;
|
188
|
+
*zoom: 1;
|
189
|
+
}
|
190
|
+
.row:before,
|
191
|
+
.row:after {
|
192
|
+
display: table;
|
193
|
+
content: "";
|
194
|
+
}
|
195
|
+
.row:after {
|
196
|
+
clear: both;
|
197
|
+
}
|
198
|
+
[class*="span"] {
|
199
|
+
float: left;
|
200
|
+
margin-left: 20px;
|
201
|
+
}
|
202
|
+
.container,
|
203
|
+
.navbar-fixed-top .container,
|
204
|
+
.navbar-fixed-bottom .container {
|
205
|
+
width: 724px;
|
206
|
+
}
|
207
|
+
.span12 {
|
208
|
+
width: 724px;
|
209
|
+
}
|
210
|
+
.span11 {
|
211
|
+
width: 662px;
|
212
|
+
}
|
213
|
+
.span10 {
|
214
|
+
width: 600px;
|
215
|
+
}
|
216
|
+
.span9 {
|
217
|
+
width: 538px;
|
218
|
+
}
|
219
|
+
.span8 {
|
220
|
+
width: 476px;
|
221
|
+
}
|
222
|
+
.span7 {
|
223
|
+
width: 414px;
|
224
|
+
}
|
225
|
+
.span6 {
|
226
|
+
width: 352px;
|
227
|
+
}
|
228
|
+
.span5 {
|
229
|
+
width: 290px;
|
230
|
+
}
|
231
|
+
.span4 {
|
232
|
+
width: 228px;
|
233
|
+
}
|
234
|
+
.span3 {
|
235
|
+
width: 166px;
|
236
|
+
}
|
237
|
+
.span2 {
|
238
|
+
width: 104px;
|
239
|
+
}
|
240
|
+
.span1 {
|
241
|
+
width: 42px;
|
242
|
+
}
|
243
|
+
.offset12 {
|
244
|
+
margin-left: 764px;
|
245
|
+
}
|
246
|
+
.offset11 {
|
247
|
+
margin-left: 702px;
|
248
|
+
}
|
249
|
+
.offset10 {
|
250
|
+
margin-left: 640px;
|
251
|
+
}
|
252
|
+
.offset9 {
|
253
|
+
margin-left: 578px;
|
254
|
+
}
|
255
|
+
.offset8 {
|
256
|
+
margin-left: 516px;
|
257
|
+
}
|
258
|
+
.offset7 {
|
259
|
+
margin-left: 454px;
|
260
|
+
}
|
261
|
+
.offset6 {
|
262
|
+
margin-left: 392px;
|
263
|
+
}
|
264
|
+
.offset5 {
|
265
|
+
margin-left: 330px;
|
266
|
+
}
|
267
|
+
.offset4 {
|
268
|
+
margin-left: 268px;
|
269
|
+
}
|
270
|
+
.offset3 {
|
271
|
+
margin-left: 206px;
|
272
|
+
}
|
273
|
+
.offset2 {
|
274
|
+
margin-left: 144px;
|
275
|
+
}
|
276
|
+
.offset1 {
|
277
|
+
margin-left: 82px;
|
278
|
+
}
|
279
|
+
.row-fluid {
|
280
|
+
width: 100%;
|
281
|
+
*zoom: 1;
|
282
|
+
}
|
283
|
+
.row-fluid:before,
|
284
|
+
.row-fluid:after {
|
285
|
+
display: table;
|
286
|
+
content: "";
|
287
|
+
}
|
288
|
+
.row-fluid:after {
|
289
|
+
clear: both;
|
290
|
+
}
|
291
|
+
.row-fluid > [class*="span"] {
|
292
|
+
float: left;
|
293
|
+
margin-left: 2.762430939%;
|
294
|
+
}
|
295
|
+
.row-fluid > [class*="span"]:first-child {
|
296
|
+
margin-left: 0;
|
297
|
+
}
|
298
|
+
.row-fluid > .span12 {
|
299
|
+
width: 99.999999993%;
|
300
|
+
}
|
301
|
+
.row-fluid > .span11 {
|
302
|
+
width: 91.436464082%;
|
303
|
+
}
|
304
|
+
.row-fluid > .span10 {
|
305
|
+
width: 82.87292817100001%;
|
306
|
+
}
|
307
|
+
.row-fluid > .span9 {
|
308
|
+
width: 74.30939226%;
|
309
|
+
}
|
310
|
+
.row-fluid > .span8 {
|
311
|
+
width: 65.74585634900001%;
|
312
|
+
}
|
313
|
+
.row-fluid > .span7 {
|
314
|
+
width: 57.182320438000005%;
|
315
|
+
}
|
316
|
+
.row-fluid > .span6 {
|
317
|
+
width: 48.618784527%;
|
318
|
+
}
|
319
|
+
.row-fluid > .span5 {
|
320
|
+
width: 40.055248616%;
|
321
|
+
}
|
322
|
+
.row-fluid > .span4 {
|
323
|
+
width: 31.491712705%;
|
324
|
+
}
|
325
|
+
.row-fluid > .span3 {
|
326
|
+
width: 22.928176794%;
|
327
|
+
}
|
328
|
+
.row-fluid > .span2 {
|
329
|
+
width: 14.364640883%;
|
330
|
+
}
|
331
|
+
.row-fluid > .span1 {
|
332
|
+
width: 5.801104972%;
|
333
|
+
}
|
334
|
+
input,
|
335
|
+
textarea,
|
336
|
+
.uneditable-input {
|
337
|
+
margin-left: 0;
|
338
|
+
}
|
339
|
+
input.span12, textarea.span12, .uneditable-input.span12 {
|
340
|
+
width: 714px;
|
341
|
+
}
|
342
|
+
input.span11, textarea.span11, .uneditable-input.span11 {
|
343
|
+
width: 652px;
|
344
|
+
}
|
345
|
+
input.span10, textarea.span10, .uneditable-input.span10 {
|
346
|
+
width: 590px;
|
347
|
+
}
|
348
|
+
input.span9, textarea.span9, .uneditable-input.span9 {
|
349
|
+
width: 528px;
|
350
|
+
}
|
351
|
+
input.span8, textarea.span8, .uneditable-input.span8 {
|
352
|
+
width: 466px;
|
353
|
+
}
|
354
|
+
input.span7, textarea.span7, .uneditable-input.span7 {
|
355
|
+
width: 404px;
|
356
|
+
}
|
357
|
+
input.span6, textarea.span6, .uneditable-input.span6 {
|
358
|
+
width: 342px;
|
359
|
+
}
|
360
|
+
input.span5, textarea.span5, .uneditable-input.span5 {
|
361
|
+
width: 280px;
|
362
|
+
}
|
363
|
+
input.span4, textarea.span4, .uneditable-input.span4 {
|
364
|
+
width: 218px;
|
365
|
+
}
|
366
|
+
input.span3, textarea.span3, .uneditable-input.span3 {
|
367
|
+
width: 156px;
|
368
|
+
}
|
369
|
+
input.span2, textarea.span2, .uneditable-input.span2 {
|
370
|
+
width: 94px;
|
371
|
+
}
|
372
|
+
input.span1, textarea.span1, .uneditable-input.span1 {
|
373
|
+
width: 32px;
|
374
|
+
}
|
375
|
+
}
|
376
|
+
@media (max-width: 979px) {
|
377
|
+
body {
|
378
|
+
padding-top: 0;
|
379
|
+
}
|
380
|
+
.navbar-fixed-top {
|
381
|
+
position: static;
|
382
|
+
margin-bottom: 18px;
|
383
|
+
}
|
384
|
+
.navbar-fixed-top .navbar-inner {
|
385
|
+
padding: 5px;
|
386
|
+
}
|
387
|
+
.navbar .container {
|
388
|
+
width: auto;
|
389
|
+
padding: 0;
|
390
|
+
}
|
391
|
+
.navbar .brand {
|
392
|
+
padding-left: 10px;
|
393
|
+
padding-right: 10px;
|
394
|
+
margin: 0 0 0 -5px;
|
395
|
+
}
|
396
|
+
.navbar .nav-collapse {
|
397
|
+
clear: left;
|
398
|
+
}
|
399
|
+
.navbar .nav {
|
400
|
+
float: none;
|
401
|
+
margin: 0 0 9px;
|
402
|
+
}
|
403
|
+
.navbar .nav > li {
|
404
|
+
float: none;
|
405
|
+
}
|
406
|
+
.navbar .nav > li > a {
|
407
|
+
margin-bottom: 2px;
|
408
|
+
}
|
409
|
+
.navbar .nav > .divider-vertical {
|
410
|
+
display: none;
|
411
|
+
}
|
412
|
+
.navbar .nav .nav-header {
|
413
|
+
color: #999999;
|
414
|
+
text-shadow: none;
|
415
|
+
}
|
416
|
+
.navbar .nav > li > a,
|
417
|
+
.navbar .dropdown-menu a {
|
418
|
+
padding: 6px 15px;
|
419
|
+
font-weight: bold;
|
420
|
+
color: #999999;
|
421
|
+
-webkit-border-radius: 3px;
|
422
|
+
-moz-border-radius: 3px;
|
423
|
+
border-radius: 3px;
|
424
|
+
}
|
425
|
+
.navbar .dropdown-menu li + li a {
|
426
|
+
margin-bottom: 2px;
|
427
|
+
}
|
428
|
+
.navbar .nav > li > a:hover,
|
429
|
+
.navbar .dropdown-menu a:hover {
|
430
|
+
background-color: #222222;
|
431
|
+
}
|
432
|
+
.navbar .dropdown-menu {
|
433
|
+
position: static;
|
434
|
+
top: auto;
|
435
|
+
left: auto;
|
436
|
+
float: none;
|
437
|
+
display: block;
|
438
|
+
max-width: none;
|
439
|
+
margin: 0 15px;
|
440
|
+
padding: 0;
|
441
|
+
background-color: transparent;
|
442
|
+
border: none;
|
443
|
+
-webkit-border-radius: 0;
|
444
|
+
-moz-border-radius: 0;
|
445
|
+
border-radius: 0;
|
446
|
+
-webkit-box-shadow: none;
|
447
|
+
-moz-box-shadow: none;
|
448
|
+
box-shadow: none;
|
449
|
+
}
|
450
|
+
.navbar .dropdown-menu:before,
|
451
|
+
.navbar .dropdown-menu:after {
|
452
|
+
display: none;
|
453
|
+
}
|
454
|
+
.navbar .dropdown-menu .divider {
|
455
|
+
display: none;
|
456
|
+
}
|
457
|
+
.navbar-form,
|
458
|
+
.navbar-search {
|
459
|
+
float: none;
|
460
|
+
padding: 9px 15px;
|
461
|
+
margin: 9px 0;
|
462
|
+
border-top: 1px solid #222222;
|
463
|
+
border-bottom: 1px solid #222222;
|
464
|
+
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
465
|
+
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
466
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
467
|
+
}
|
468
|
+
.navbar .nav.pull-right {
|
469
|
+
float: none;
|
470
|
+
margin-left: 0;
|
471
|
+
}
|
472
|
+
.navbar-static .navbar-inner {
|
473
|
+
padding-left: 10px;
|
474
|
+
padding-right: 10px;
|
475
|
+
}
|
476
|
+
.btn-navbar {
|
477
|
+
display: block;
|
478
|
+
}
|
479
|
+
.nav-collapse {
|
480
|
+
overflow: hidden;
|
481
|
+
height: 0;
|
482
|
+
}
|
483
|
+
}
|
484
|
+
@media (min-width: 980px) {
|
485
|
+
.nav-collapse.collapse {
|
486
|
+
height: auto !important;
|
487
|
+
overflow: visible !important;
|
488
|
+
}
|
489
|
+
}
|
490
|
+
@media (min-width: 1200px) {
|
491
|
+
.row {
|
492
|
+
margin-left: -30px;
|
493
|
+
*zoom: 1;
|
494
|
+
}
|
495
|
+
.row:before,
|
496
|
+
.row:after {
|
497
|
+
display: table;
|
498
|
+
content: "";
|
499
|
+
}
|
500
|
+
.row:after {
|
501
|
+
clear: both;
|
502
|
+
}
|
503
|
+
[class*="span"] {
|
504
|
+
float: left;
|
505
|
+
margin-left: 30px;
|
506
|
+
}
|
507
|
+
.container,
|
508
|
+
.navbar-fixed-top .container,
|
509
|
+
.navbar-fixed-bottom .container {
|
510
|
+
width: 1170px;
|
511
|
+
}
|
512
|
+
.span12 {
|
513
|
+
width: 1170px;
|
514
|
+
}
|
515
|
+
.span11 {
|
516
|
+
width: 1070px;
|
517
|
+
}
|
518
|
+
.span10 {
|
519
|
+
width: 970px;
|
520
|
+
}
|
521
|
+
.span9 {
|
522
|
+
width: 870px;
|
523
|
+
}
|
524
|
+
.span8 {
|
525
|
+
width: 770px;
|
526
|
+
}
|
527
|
+
.span7 {
|
528
|
+
width: 670px;
|
529
|
+
}
|
530
|
+
.span6 {
|
531
|
+
width: 570px;
|
532
|
+
}
|
533
|
+
.span5 {
|
534
|
+
width: 470px;
|
535
|
+
}
|
536
|
+
.span4 {
|
537
|
+
width: 370px;
|
538
|
+
}
|
539
|
+
.span3 {
|
540
|
+
width: 270px;
|
541
|
+
}
|
542
|
+
.span2 {
|
543
|
+
width: 170px;
|
544
|
+
}
|
545
|
+
.span1 {
|
546
|
+
width: 70px;
|
547
|
+
}
|
548
|
+
.offset12 {
|
549
|
+
margin-left: 1230px;
|
550
|
+
}
|
551
|
+
.offset11 {
|
552
|
+
margin-left: 1130px;
|
553
|
+
}
|
554
|
+
.offset10 {
|
555
|
+
margin-left: 1030px;
|
556
|
+
}
|
557
|
+
.offset9 {
|
558
|
+
margin-left: 930px;
|
559
|
+
}
|
560
|
+
.offset8 {
|
561
|
+
margin-left: 830px;
|
562
|
+
}
|
563
|
+
.offset7 {
|
564
|
+
margin-left: 730px;
|
565
|
+
}
|
566
|
+
.offset6 {
|
567
|
+
margin-left: 630px;
|
568
|
+
}
|
569
|
+
.offset5 {
|
570
|
+
margin-left: 530px;
|
571
|
+
}
|
572
|
+
.offset4 {
|
573
|
+
margin-left: 430px;
|
574
|
+
}
|
575
|
+
.offset3 {
|
576
|
+
margin-left: 330px;
|
577
|
+
}
|
578
|
+
.offset2 {
|
579
|
+
margin-left: 230px;
|
580
|
+
}
|
581
|
+
.offset1 {
|
582
|
+
margin-left: 130px;
|
583
|
+
}
|
584
|
+
.row-fluid {
|
585
|
+
width: 100%;
|
586
|
+
*zoom: 1;
|
587
|
+
}
|
588
|
+
.row-fluid:before,
|
589
|
+
.row-fluid:after {
|
590
|
+
display: table;
|
591
|
+
content: "";
|
592
|
+
}
|
593
|
+
.row-fluid:after {
|
594
|
+
clear: both;
|
595
|
+
}
|
596
|
+
.row-fluid > [class*="span"] {
|
597
|
+
float: left;
|
598
|
+
margin-left: 2.564102564%;
|
599
|
+
}
|
600
|
+
.row-fluid > [class*="span"]:first-child {
|
601
|
+
margin-left: 0;
|
602
|
+
}
|
603
|
+
.row-fluid > .span12 {
|
604
|
+
width: 100%;
|
605
|
+
}
|
606
|
+
.row-fluid > .span11 {
|
607
|
+
width: 91.45299145300001%;
|
608
|
+
}
|
609
|
+
.row-fluid > .span10 {
|
610
|
+
width: 82.905982906%;
|
611
|
+
}
|
612
|
+
.row-fluid > .span9 {
|
613
|
+
width: 74.358974359%;
|
614
|
+
}
|
615
|
+
.row-fluid > .span8 {
|
616
|
+
width: 65.81196581200001%;
|
617
|
+
}
|
618
|
+
.row-fluid > .span7 {
|
619
|
+
width: 57.264957265%;
|
620
|
+
}
|
621
|
+
.row-fluid > .span6 {
|
622
|
+
width: 48.717948718%;
|
623
|
+
}
|
624
|
+
.row-fluid > .span5 {
|
625
|
+
width: 40.170940171000005%;
|
626
|
+
}
|
627
|
+
.row-fluid > .span4 {
|
628
|
+
width: 31.623931624%;
|
629
|
+
}
|
630
|
+
.row-fluid > .span3 {
|
631
|
+
width: 23.076923077%;
|
632
|
+
}
|
633
|
+
.row-fluid > .span2 {
|
634
|
+
width: 14.529914530000001%;
|
635
|
+
}
|
636
|
+
.row-fluid > .span1 {
|
637
|
+
width: 5.982905983%;
|
638
|
+
}
|
639
|
+
input,
|
640
|
+
textarea,
|
641
|
+
.uneditable-input {
|
642
|
+
margin-left: 0;
|
643
|
+
}
|
644
|
+
input.span12, textarea.span12, .uneditable-input.span12 {
|
645
|
+
width: 1160px;
|
646
|
+
}
|
647
|
+
input.span11, textarea.span11, .uneditable-input.span11 {
|
648
|
+
width: 1060px;
|
649
|
+
}
|
650
|
+
input.span10, textarea.span10, .uneditable-input.span10 {
|
651
|
+
width: 960px;
|
652
|
+
}
|
653
|
+
input.span9, textarea.span9, .uneditable-input.span9 {
|
654
|
+
width: 860px;
|
655
|
+
}
|
656
|
+
input.span8, textarea.span8, .uneditable-input.span8 {
|
657
|
+
width: 760px;
|
658
|
+
}
|
659
|
+
input.span7, textarea.span7, .uneditable-input.span7 {
|
660
|
+
width: 660px;
|
661
|
+
}
|
662
|
+
input.span6, textarea.span6, .uneditable-input.span6 {
|
663
|
+
width: 560px;
|
664
|
+
}
|
665
|
+
input.span5, textarea.span5, .uneditable-input.span5 {
|
666
|
+
width: 460px;
|
667
|
+
}
|
668
|
+
input.span4, textarea.span4, .uneditable-input.span4 {
|
669
|
+
width: 360px;
|
670
|
+
}
|
671
|
+
input.span3, textarea.span3, .uneditable-input.span3 {
|
672
|
+
width: 260px;
|
673
|
+
}
|
674
|
+
input.span2, textarea.span2, .uneditable-input.span2 {
|
675
|
+
width: 160px;
|
676
|
+
}
|
677
|
+
input.span1, textarea.span1, .uneditable-input.span1 {
|
678
|
+
width: 60px;
|
679
|
+
}
|
680
|
+
.thumbnails {
|
681
|
+
margin-left: -30px;
|
682
|
+
}
|
683
|
+
.thumbnails > li {
|
684
|
+
margin-left: 30px;
|
685
|
+
}
|
686
|
+
}
|