network-projector 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/NOTES CHANGED
@@ -1,7 +1,10 @@
1
- - on the server keep the display out of web server to make him stateless
2
- - multi-client
1
+ - multi-client policy
3
2
  - screenshot of current clients
4
3
  - supervision to choose between multi-client
5
- - multi-view at the same time
4
+ - multi-view at the same time (ie: 2x2 display)
6
5
  - add some security layers
7
6
  - integration with kde/krfb, gnome/vino ?
7
+ - on the server keep the display out of web server to make him stateless
8
+ - split server in multiple screen and rest web server
9
+ - web server would be on a classic server
10
+ - screen would be a minimal libvncserver/client c program
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
1
  Network Projector
2
2
  =================
3
3
 
4
+ Requirements
5
+ ------------
6
+
7
+ - x11vnc on the client side
8
+ - vncviewer & vncpasswd on the server side
9
+
4
10
  Goals
5
11
  -----
6
12
 
@@ -8,3 +14,15 @@ Goals
8
14
  - Display your desktop/laptop current screen on the projector using lan/wifi
9
15
  - Upload a pdf with your phone, display it on the projector, turn the pages using the web app
10
16
  - Take control of students desktop, choose one to be displayed
17
+
18
+
19
+ Usage
20
+ -----
21
+
22
+ On the server side :
23
+
24
+ DISPLAY=:0 np-server
25
+
26
+ On the client side :
27
+
28
+ np-client -h server-ip
@@ -1,3 +1,4 @@
1
+ require 'socket'
1
2
  require 'optparse'
2
3
  require 'net/http'
3
4
  require 'network-projector/vnc/share'
@@ -5,7 +6,7 @@ require 'network-projector/vnc/share'
5
6
  module NetworkProjector
6
7
  class NPClient
7
8
  def run!
8
- options = {:passwd=>'unsecure', :host=>'localhost', :display=>":0", :clip => "xinerama0"}
9
+ options = {:passwd=>'unsecure', :host=>'localhost', :display=>":0", :clip => "xinerama0", :user=>Socket.gethostname}
9
10
 
10
11
  parser = OptionParser.new
11
12
 
@@ -22,6 +23,10 @@ module NetworkProjector
22
23
  options[:display] = v
23
24
  end
24
25
 
26
+ parser.on('-u=USER', '--user=USER', "User label (#{options[:label]})") do |v|
27
+ options[:user] = v
28
+ end
29
+
25
30
  parser.on('-p=PASSWD', '--passwd=PASSWD', 'Vnc password') do |v|
26
31
  options[:passwd] = v
27
32
  end
@@ -33,21 +38,45 @@ module NetworkProjector
33
38
  exit
34
39
  end
35
40
 
36
- vs = VncShare.new options
41
+ @user = options[:user]
37
42
 
38
- vs.run
43
+ @vs = VncShare.new options
39
44
 
40
- http = Net::HTTP.new(options[:host], 4567)
41
- request = Net::HTTP::Post.new("/connect")
42
- request.set_form_data({"vnc[port]" => vs.port, "vnc[passwd]" => vs.passwd})
45
+ @vs.run
46
+
47
+ if not @vs.started? then
48
+ puts "Can't start, leaving"
49
+ return
50
+ end
43
51
  begin
44
- response = http.request(request)
52
+ @http = Net::HTTP.new(options[:host], 4567)
53
+ connect
45
54
  puts "Ready for connection"
46
- vs.join
55
+ @vs.join
47
56
  rescue SystemCallError => e
48
57
  puts "Connection to #{options[:host]}:4567 failed : #{e}"
49
- vs.stop
58
+ @vs.stop
59
+ rescue Interrupt
60
+ @vs.stop
61
+ ensure
62
+ disconnect
50
63
  end
64
+ puts "Leaving"
65
+ end
66
+
67
+ def connect
68
+ request = Net::HTTP::Post.new("/connect")
69
+ request.set_form_data({"user" => @user, "vnc[port]" => @vs.port, "vnc[passwd]" => @vs.passwd})
70
+ response = @http.request(request)
71
+ @id = response.body
72
+ puts "Connected as #{@id}"
73
+ end
74
+
75
+ def disconnect
76
+ request = Net::HTTP::Post.new("/disconnect")
77
+ request.set_form_data({"id" => @id})
78
+ response = @http.request(request)
79
+ puts "Disconnect response (#{response.code}) : #{response.body}" unless response.code == "200"
51
80
  end
52
81
  end
53
82
  end
@@ -1,42 +1,108 @@
1
+ require 'uuid'
1
2
  require 'sinatra'
2
3
  require 'network-projector/vnc/client'
3
4
 
4
5
  module NetworkProjector
6
+
7
+ class NPConnection
8
+ attr_reader :host, :port, :passwd, :id, :client, :label
9
+
10
+ def initialize options = {}
11
+ @id = UUID.generate
12
+ @label = options[:label]
13
+ @host = options[:host]
14
+ @port = options[:port]
15
+ @passwd = options[:passwd]
16
+ @client = VncClient.new
17
+ end
18
+
19
+ def status
20
+ @client.started? ? "Started" : "Stopped"
21
+ end
22
+
23
+ def run
24
+ @client.run :host => @host, :port => @port, :passwd => @passwd
25
+ end
26
+ end
27
+
5
28
  class NPServer < Sinatra::Base
6
- VC = VncClient.new
29
+ STACK=[]
30
+
31
+ set :logging, true
32
+ set :dump_errors, false
7
33
 
8
34
  helpers do
9
- def vncclient
10
- VC
11
- end
35
+ def register connection
36
+ STACK.push connection
37
+ end
38
+
39
+ def menu_active id
40
+ "class='active'" if id == @menu
41
+ end
42
+
43
+ def connection_by_id id
44
+ STACK.find do |c| c.id == id end
45
+ end
46
+
47
+ def unregister connection
48
+ connection.client.stop
49
+ STACK.delete connection
50
+ connect_one
51
+ end
52
+
53
+ def connect_one
54
+ return if STACK.empty?
55
+ connection = STACK[-2]
56
+ if connection then
57
+ connection.client.stop
58
+ end
59
+ connection = STACK[-1]
60
+ connection.run
61
+ end
62
+ def connected
63
+ STACK.find do |c| c.client.started? end
64
+ end
12
65
  end
13
66
 
14
67
  get '/' do
15
- redirect '/status'
68
+ redirect '/screen'
69
+ end
70
+ get '/screen' do
71
+ @menu = :screen
72
+ @stack = STACK
73
+ @connection = connected
74
+ erb :screen
16
75
  end
17
-
18
76
  get '/status' do
77
+ @menu = :status
78
+ @stack = STACK
19
79
  erb :status
20
80
  end
21
81
 
22
- post '/stop' do
23
- if VC.started? then
24
- VC.stop
25
- redirect '/status'
26
- else
27
- "Not started"
28
- end
82
+ post '/disconnect' do
83
+ id = params[:id]
84
+ connection = connection_by_id(id)
85
+ if connection then
86
+ unregister connection
87
+ ""
88
+ else
89
+ halt "Connection not found"
90
+ end
29
91
  end
30
-
31
92
  post '/connect' do
32
- raise "client already started" if VC.started?
33
93
  host = request.ip
34
- port = params[:vnc][:port]
35
- passwd = params[:vnc][:passwd]
94
+ label = params[:user]
95
+ if params[:vnc] then
96
+ port = params[:vnc][:port]
97
+ passwd = params[:vnc][:passwd]
98
+ end
99
+ halt 'Need a port' unless port
100
+ halt 'need a passwd' unless passwd
36
101
  puts "Connection request from #{host}:#{port}"
37
-
38
- VC.run :host=> host, :port => port, :passwd => passwd
39
-
102
+ connection = NPConnection.new(:host => host, :port => port, :passwd => passwd, :label => label)
103
+ register connection
104
+ connect_one
105
+ return connection.id
40
106
  end
41
107
  end
42
108
  end
@@ -0,0 +1,1058 @@
1
+ /*!
2
+ * Bootstrap Responsive v2.1.1
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
+
11
+ .clearfix {
12
+ *zoom: 1;
13
+ }
14
+
15
+ .clearfix:before,
16
+ .clearfix:after {
17
+ display: table;
18
+ line-height: 0;
19
+ content: "";
20
+ }
21
+
22
+ .clearfix:after {
23
+ clear: both;
24
+ }
25
+
26
+ .hide-text {
27
+ font: 0/0 a;
28
+ color: transparent;
29
+ text-shadow: none;
30
+ background-color: transparent;
31
+ border: 0;
32
+ }
33
+
34
+ .input-block-level {
35
+ display: block;
36
+ width: 100%;
37
+ min-height: 30px;
38
+ -webkit-box-sizing: border-box;
39
+ -moz-box-sizing: border-box;
40
+ box-sizing: border-box;
41
+ }
42
+
43
+ .hidden {
44
+ display: none;
45
+ visibility: hidden;
46
+ }
47
+
48
+ .visible-phone {
49
+ display: none !important;
50
+ }
51
+
52
+ .visible-tablet {
53
+ display: none !important;
54
+ }
55
+
56
+ .hidden-desktop {
57
+ display: none !important;
58
+ }
59
+
60
+ .visible-desktop {
61
+ display: inherit !important;
62
+ }
63
+
64
+ @media (min-width: 768px) and (max-width: 979px) {
65
+ .hidden-desktop {
66
+ display: inherit !important;
67
+ }
68
+ .visible-desktop {
69
+ display: none !important ;
70
+ }
71
+ .visible-tablet {
72
+ display: inherit !important;
73
+ }
74
+ .hidden-tablet {
75
+ display: none !important;
76
+ }
77
+ }
78
+
79
+ @media (max-width: 767px) {
80
+ .hidden-desktop {
81
+ display: inherit !important;
82
+ }
83
+ .visible-desktop {
84
+ display: none !important;
85
+ }
86
+ .visible-phone {
87
+ display: inherit !important;
88
+ }
89
+ .hidden-phone {
90
+ display: none !important;
91
+ }
92
+ }
93
+
94
+ @media (min-width: 1200px) {
95
+ .row {
96
+ margin-left: -30px;
97
+ *zoom: 1;
98
+ }
99
+ .row:before,
100
+ .row:after {
101
+ display: table;
102
+ line-height: 0;
103
+ content: "";
104
+ }
105
+ .row:after {
106
+ clear: both;
107
+ }
108
+ [class*="span"] {
109
+ float: left;
110
+ min-height: 1px;
111
+ margin-left: 30px;
112
+ }
113
+ .container,
114
+ .navbar-static-top .container,
115
+ .navbar-fixed-top .container,
116
+ .navbar-fixed-bottom .container {
117
+ width: 1170px;
118
+ }
119
+ .span12 {
120
+ width: 1170px;
121
+ }
122
+ .span11 {
123
+ width: 1070px;
124
+ }
125
+ .span10 {
126
+ width: 970px;
127
+ }
128
+ .span9 {
129
+ width: 870px;
130
+ }
131
+ .span8 {
132
+ width: 770px;
133
+ }
134
+ .span7 {
135
+ width: 670px;
136
+ }
137
+ .span6 {
138
+ width: 570px;
139
+ }
140
+ .span5 {
141
+ width: 470px;
142
+ }
143
+ .span4 {
144
+ width: 370px;
145
+ }
146
+ .span3 {
147
+ width: 270px;
148
+ }
149
+ .span2 {
150
+ width: 170px;
151
+ }
152
+ .span1 {
153
+ width: 70px;
154
+ }
155
+ .offset12 {
156
+ margin-left: 1230px;
157
+ }
158
+ .offset11 {
159
+ margin-left: 1130px;
160
+ }
161
+ .offset10 {
162
+ margin-left: 1030px;
163
+ }
164
+ .offset9 {
165
+ margin-left: 930px;
166
+ }
167
+ .offset8 {
168
+ margin-left: 830px;
169
+ }
170
+ .offset7 {
171
+ margin-left: 730px;
172
+ }
173
+ .offset6 {
174
+ margin-left: 630px;
175
+ }
176
+ .offset5 {
177
+ margin-left: 530px;
178
+ }
179
+ .offset4 {
180
+ margin-left: 430px;
181
+ }
182
+ .offset3 {
183
+ margin-left: 330px;
184
+ }
185
+ .offset2 {
186
+ margin-left: 230px;
187
+ }
188
+ .offset1 {
189
+ margin-left: 130px;
190
+ }
191
+ .row-fluid {
192
+ width: 100%;
193
+ *zoom: 1;
194
+ }
195
+ .row-fluid:before,
196
+ .row-fluid:after {
197
+ display: table;
198
+ line-height: 0;
199
+ content: "";
200
+ }
201
+ .row-fluid:after {
202
+ clear: both;
203
+ }
204
+ .row-fluid [class*="span"] {
205
+ display: block;
206
+ float: left;
207
+ width: 100%;
208
+ min-height: 30px;
209
+ margin-left: 2.564102564102564%;
210
+ *margin-left: 2.5109110747408616%;
211
+ -webkit-box-sizing: border-box;
212
+ -moz-box-sizing: border-box;
213
+ box-sizing: border-box;
214
+ }
215
+ .row-fluid [class*="span"]:first-child {
216
+ margin-left: 0;
217
+ }
218
+ .row-fluid .span12 {
219
+ width: 100%;
220
+ *width: 99.94680851063829%;
221
+ }
222
+ .row-fluid .span11 {
223
+ width: 91.45299145299145%;
224
+ *width: 91.39979996362975%;
225
+ }
226
+ .row-fluid .span10 {
227
+ width: 82.90598290598291%;
228
+ *width: 82.8527914166212%;
229
+ }
230
+ .row-fluid .span9 {
231
+ width: 74.35897435897436%;
232
+ *width: 74.30578286961266%;
233
+ }
234
+ .row-fluid .span8 {
235
+ width: 65.81196581196582%;
236
+ *width: 65.75877432260411%;
237
+ }
238
+ .row-fluid .span7 {
239
+ width: 57.26495726495726%;
240
+ *width: 57.21176577559556%;
241
+ }
242
+ .row-fluid .span6 {
243
+ width: 48.717948717948715%;
244
+ *width: 48.664757228587014%;
245
+ }
246
+ .row-fluid .span5 {
247
+ width: 40.17094017094017%;
248
+ *width: 40.11774868157847%;
249
+ }
250
+ .row-fluid .span4 {
251
+ width: 31.623931623931625%;
252
+ *width: 31.570740134569924%;
253
+ }
254
+ .row-fluid .span3 {
255
+ width: 23.076923076923077%;
256
+ *width: 23.023731587561375%;
257
+ }
258
+ .row-fluid .span2 {
259
+ width: 14.52991452991453%;
260
+ *width: 14.476723040552828%;
261
+ }
262
+ .row-fluid .span1 {
263
+ width: 5.982905982905983%;
264
+ *width: 5.929714493544281%;
265
+ }
266
+ .row-fluid .offset12 {
267
+ margin-left: 105.12820512820512%;
268
+ *margin-left: 105.02182214948171%;
269
+ }
270
+ .row-fluid .offset12:first-child {
271
+ margin-left: 102.56410256410257%;
272
+ *margin-left: 102.45771958537915%;
273
+ }
274
+ .row-fluid .offset11 {
275
+ margin-left: 96.58119658119658%;
276
+ *margin-left: 96.47481360247316%;
277
+ }
278
+ .row-fluid .offset11:first-child {
279
+ margin-left: 94.01709401709402%;
280
+ *margin-left: 93.91071103837061%;
281
+ }
282
+ .row-fluid .offset10 {
283
+ margin-left: 88.03418803418803%;
284
+ *margin-left: 87.92780505546462%;
285
+ }
286
+ .row-fluid .offset10:first-child {
287
+ margin-left: 85.47008547008548%;
288
+ *margin-left: 85.36370249136206%;
289
+ }
290
+ .row-fluid .offset9 {
291
+ margin-left: 79.48717948717949%;
292
+ *margin-left: 79.38079650845607%;
293
+ }
294
+ .row-fluid .offset9:first-child {
295
+ margin-left: 76.92307692307693%;
296
+ *margin-left: 76.81669394435352%;
297
+ }
298
+ .row-fluid .offset8 {
299
+ margin-left: 70.94017094017094%;
300
+ *margin-left: 70.83378796144753%;
301
+ }
302
+ .row-fluid .offset8:first-child {
303
+ margin-left: 68.37606837606839%;
304
+ *margin-left: 68.26968539734497%;
305
+ }
306
+ .row-fluid .offset7 {
307
+ margin-left: 62.393162393162385%;
308
+ *margin-left: 62.28677941443899%;
309
+ }
310
+ .row-fluid .offset7:first-child {
311
+ margin-left: 59.82905982905982%;
312
+ *margin-left: 59.72267685033642%;
313
+ }
314
+ .row-fluid .offset6 {
315
+ margin-left: 53.84615384615384%;
316
+ *margin-left: 53.739770867430444%;
317
+ }
318
+ .row-fluid .offset6:first-child {
319
+ margin-left: 51.28205128205128%;
320
+ *margin-left: 51.175668303327875%;
321
+ }
322
+ .row-fluid .offset5 {
323
+ margin-left: 45.299145299145295%;
324
+ *margin-left: 45.1927623204219%;
325
+ }
326
+ .row-fluid .offset5:first-child {
327
+ margin-left: 42.73504273504273%;
328
+ *margin-left: 42.62865975631933%;
329
+ }
330
+ .row-fluid .offset4 {
331
+ margin-left: 36.75213675213675%;
332
+ *margin-left: 36.645753773413354%;
333
+ }
334
+ .row-fluid .offset4:first-child {
335
+ margin-left: 34.18803418803419%;
336
+ *margin-left: 34.081651209310785%;
337
+ }
338
+ .row-fluid .offset3 {
339
+ margin-left: 28.205128205128204%;
340
+ *margin-left: 28.0987452264048%;
341
+ }
342
+ .row-fluid .offset3:first-child {
343
+ margin-left: 25.641025641025642%;
344
+ *margin-left: 25.53464266230224%;
345
+ }
346
+ .row-fluid .offset2 {
347
+ margin-left: 19.65811965811966%;
348
+ *margin-left: 19.551736679396257%;
349
+ }
350
+ .row-fluid .offset2:first-child {
351
+ margin-left: 17.094017094017094%;
352
+ *margin-left: 16.98763411529369%;
353
+ }
354
+ .row-fluid .offset1 {
355
+ margin-left: 11.11111111111111%;
356
+ *margin-left: 11.004728132387708%;
357
+ }
358
+ .row-fluid .offset1:first-child {
359
+ margin-left: 8.547008547008547%;
360
+ *margin-left: 8.440625568285142%;
361
+ }
362
+ input,
363
+ textarea,
364
+ .uneditable-input {
365
+ margin-left: 0;
366
+ }
367
+ .controls-row [class*="span"] + [class*="span"] {
368
+ margin-left: 30px;
369
+ }
370
+ input.span12,
371
+ textarea.span12,
372
+ .uneditable-input.span12 {
373
+ width: 1156px;
374
+ }
375
+ input.span11,
376
+ textarea.span11,
377
+ .uneditable-input.span11 {
378
+ width: 1056px;
379
+ }
380
+ input.span10,
381
+ textarea.span10,
382
+ .uneditable-input.span10 {
383
+ width: 956px;
384
+ }
385
+ input.span9,
386
+ textarea.span9,
387
+ .uneditable-input.span9 {
388
+ width: 856px;
389
+ }
390
+ input.span8,
391
+ textarea.span8,
392
+ .uneditable-input.span8 {
393
+ width: 756px;
394
+ }
395
+ input.span7,
396
+ textarea.span7,
397
+ .uneditable-input.span7 {
398
+ width: 656px;
399
+ }
400
+ input.span6,
401
+ textarea.span6,
402
+ .uneditable-input.span6 {
403
+ width: 556px;
404
+ }
405
+ input.span5,
406
+ textarea.span5,
407
+ .uneditable-input.span5 {
408
+ width: 456px;
409
+ }
410
+ input.span4,
411
+ textarea.span4,
412
+ .uneditable-input.span4 {
413
+ width: 356px;
414
+ }
415
+ input.span3,
416
+ textarea.span3,
417
+ .uneditable-input.span3 {
418
+ width: 256px;
419
+ }
420
+ input.span2,
421
+ textarea.span2,
422
+ .uneditable-input.span2 {
423
+ width: 156px;
424
+ }
425
+ input.span1,
426
+ textarea.span1,
427
+ .uneditable-input.span1 {
428
+ width: 56px;
429
+ }
430
+ .thumbnails {
431
+ margin-left: -30px;
432
+ }
433
+ .thumbnails > li {
434
+ margin-left: 30px;
435
+ }
436
+ .row-fluid .thumbnails {
437
+ margin-left: 0;
438
+ }
439
+ }
440
+
441
+ @media (min-width: 768px) and (max-width: 979px) {
442
+ .row {
443
+ margin-left: -20px;
444
+ *zoom: 1;
445
+ }
446
+ .row:before,
447
+ .row:after {
448
+ display: table;
449
+ line-height: 0;
450
+ content: "";
451
+ }
452
+ .row:after {
453
+ clear: both;
454
+ }
455
+ [class*="span"] {
456
+ float: left;
457
+ min-height: 1px;
458
+ margin-left: 20px;
459
+ }
460
+ .container,
461
+ .navbar-static-top .container,
462
+ .navbar-fixed-top .container,
463
+ .navbar-fixed-bottom .container {
464
+ width: 724px;
465
+ }
466
+ .span12 {
467
+ width: 724px;
468
+ }
469
+ .span11 {
470
+ width: 662px;
471
+ }
472
+ .span10 {
473
+ width: 600px;
474
+ }
475
+ .span9 {
476
+ width: 538px;
477
+ }
478
+ .span8 {
479
+ width: 476px;
480
+ }
481
+ .span7 {
482
+ width: 414px;
483
+ }
484
+ .span6 {
485
+ width: 352px;
486
+ }
487
+ .span5 {
488
+ width: 290px;
489
+ }
490
+ .span4 {
491
+ width: 228px;
492
+ }
493
+ .span3 {
494
+ width: 166px;
495
+ }
496
+ .span2 {
497
+ width: 104px;
498
+ }
499
+ .span1 {
500
+ width: 42px;
501
+ }
502
+ .offset12 {
503
+ margin-left: 764px;
504
+ }
505
+ .offset11 {
506
+ margin-left: 702px;
507
+ }
508
+ .offset10 {
509
+ margin-left: 640px;
510
+ }
511
+ .offset9 {
512
+ margin-left: 578px;
513
+ }
514
+ .offset8 {
515
+ margin-left: 516px;
516
+ }
517
+ .offset7 {
518
+ margin-left: 454px;
519
+ }
520
+ .offset6 {
521
+ margin-left: 392px;
522
+ }
523
+ .offset5 {
524
+ margin-left: 330px;
525
+ }
526
+ .offset4 {
527
+ margin-left: 268px;
528
+ }
529
+ .offset3 {
530
+ margin-left: 206px;
531
+ }
532
+ .offset2 {
533
+ margin-left: 144px;
534
+ }
535
+ .offset1 {
536
+ margin-left: 82px;
537
+ }
538
+ .row-fluid {
539
+ width: 100%;
540
+ *zoom: 1;
541
+ }
542
+ .row-fluid:before,
543
+ .row-fluid:after {
544
+ display: table;
545
+ line-height: 0;
546
+ content: "";
547
+ }
548
+ .row-fluid:after {
549
+ clear: both;
550
+ }
551
+ .row-fluid [class*="span"] {
552
+ display: block;
553
+ float: left;
554
+ width: 100%;
555
+ min-height: 30px;
556
+ margin-left: 2.7624309392265194%;
557
+ *margin-left: 2.709239449864817%;
558
+ -webkit-box-sizing: border-box;
559
+ -moz-box-sizing: border-box;
560
+ box-sizing: border-box;
561
+ }
562
+ .row-fluid [class*="span"]:first-child {
563
+ margin-left: 0;
564
+ }
565
+ .row-fluid .span12 {
566
+ width: 100%;
567
+ *width: 99.94680851063829%;
568
+ }
569
+ .row-fluid .span11 {
570
+ width: 91.43646408839778%;
571
+ *width: 91.38327259903608%;
572
+ }
573
+ .row-fluid .span10 {
574
+ width: 82.87292817679558%;
575
+ *width: 82.81973668743387%;
576
+ }
577
+ .row-fluid .span9 {
578
+ width: 74.30939226519337%;
579
+ *width: 74.25620077583166%;
580
+ }
581
+ .row-fluid .span8 {
582
+ width: 65.74585635359117%;
583
+ *width: 65.69266486422946%;
584
+ }
585
+ .row-fluid .span7 {
586
+ width: 57.18232044198895%;
587
+ *width: 57.12912895262725%;
588
+ }
589
+ .row-fluid .span6 {
590
+ width: 48.61878453038674%;
591
+ *width: 48.56559304102504%;
592
+ }
593
+ .row-fluid .span5 {
594
+ width: 40.05524861878453%;
595
+ *width: 40.00205712942283%;
596
+ }
597
+ .row-fluid .span4 {
598
+ width: 31.491712707182323%;
599
+ *width: 31.43852121782062%;
600
+ }
601
+ .row-fluid .span3 {
602
+ width: 22.92817679558011%;
603
+ *width: 22.87498530621841%;
604
+ }
605
+ .row-fluid .span2 {
606
+ width: 14.3646408839779%;
607
+ *width: 14.311449394616199%;
608
+ }
609
+ .row-fluid .span1 {
610
+ width: 5.801104972375691%;
611
+ *width: 5.747913483013988%;
612
+ }
613
+ .row-fluid .offset12 {
614
+ margin-left: 105.52486187845304%;
615
+ *margin-left: 105.41847889972962%;
616
+ }
617
+ .row-fluid .offset12:first-child {
618
+ margin-left: 102.76243093922652%;
619
+ *margin-left: 102.6560479605031%;
620
+ }
621
+ .row-fluid .offset11 {
622
+ margin-left: 96.96132596685082%;
623
+ *margin-left: 96.8549429881274%;
624
+ }
625
+ .row-fluid .offset11:first-child {
626
+ margin-left: 94.1988950276243%;
627
+ *margin-left: 94.09251204890089%;
628
+ }
629
+ .row-fluid .offset10 {
630
+ margin-left: 88.39779005524862%;
631
+ *margin-left: 88.2914070765252%;
632
+ }
633
+ .row-fluid .offset10:first-child {
634
+ margin-left: 85.6353591160221%;
635
+ *margin-left: 85.52897613729868%;
636
+ }
637
+ .row-fluid .offset9 {
638
+ margin-left: 79.8342541436464%;
639
+ *margin-left: 79.72787116492299%;
640
+ }
641
+ .row-fluid .offset9:first-child {
642
+ margin-left: 77.07182320441989%;
643
+ *margin-left: 76.96544022569647%;
644
+ }
645
+ .row-fluid .offset8 {
646
+ margin-left: 71.2707182320442%;
647
+ *margin-left: 71.16433525332079%;
648
+ }
649
+ .row-fluid .offset8:first-child {
650
+ margin-left: 68.50828729281768%;
651
+ *margin-left: 68.40190431409427%;
652
+ }
653
+ .row-fluid .offset7 {
654
+ margin-left: 62.70718232044199%;
655
+ *margin-left: 62.600799341718584%;
656
+ }
657
+ .row-fluid .offset7:first-child {
658
+ margin-left: 59.94475138121547%;
659
+ *margin-left: 59.838368402492065%;
660
+ }
661
+ .row-fluid .offset6 {
662
+ margin-left: 54.14364640883978%;
663
+ *margin-left: 54.037263430116376%;
664
+ }
665
+ .row-fluid .offset6:first-child {
666
+ margin-left: 51.38121546961326%;
667
+ *margin-left: 51.27483249088986%;
668
+ }
669
+ .row-fluid .offset5 {
670
+ margin-left: 45.58011049723757%;
671
+ *margin-left: 45.47372751851417%;
672
+ }
673
+ .row-fluid .offset5:first-child {
674
+ margin-left: 42.81767955801105%;
675
+ *margin-left: 42.71129657928765%;
676
+ }
677
+ .row-fluid .offset4 {
678
+ margin-left: 37.01657458563536%;
679
+ *margin-left: 36.91019160691196%;
680
+ }
681
+ .row-fluid .offset4:first-child {
682
+ margin-left: 34.25414364640884%;
683
+ *margin-left: 34.14776066768544%;
684
+ }
685
+ .row-fluid .offset3 {
686
+ margin-left: 28.45303867403315%;
687
+ *margin-left: 28.346655695309746%;
688
+ }
689
+ .row-fluid .offset3:first-child {
690
+ margin-left: 25.69060773480663%;
691
+ *margin-left: 25.584224756083227%;
692
+ }
693
+ .row-fluid .offset2 {
694
+ margin-left: 19.88950276243094%;
695
+ *margin-left: 19.783119783707537%;
696
+ }
697
+ .row-fluid .offset2:first-child {
698
+ margin-left: 17.12707182320442%;
699
+ *margin-left: 17.02068884448102%;
700
+ }
701
+ .row-fluid .offset1 {
702
+ margin-left: 11.32596685082873%;
703
+ *margin-left: 11.219583872105325%;
704
+ }
705
+ .row-fluid .offset1:first-child {
706
+ margin-left: 8.56353591160221%;
707
+ *margin-left: 8.457152932878806%;
708
+ }
709
+ input,
710
+ textarea,
711
+ .uneditable-input {
712
+ margin-left: 0;
713
+ }
714
+ .controls-row [class*="span"] + [class*="span"] {
715
+ margin-left: 20px;
716
+ }
717
+ input.span12,
718
+ textarea.span12,
719
+ .uneditable-input.span12 {
720
+ width: 710px;
721
+ }
722
+ input.span11,
723
+ textarea.span11,
724
+ .uneditable-input.span11 {
725
+ width: 648px;
726
+ }
727
+ input.span10,
728
+ textarea.span10,
729
+ .uneditable-input.span10 {
730
+ width: 586px;
731
+ }
732
+ input.span9,
733
+ textarea.span9,
734
+ .uneditable-input.span9 {
735
+ width: 524px;
736
+ }
737
+ input.span8,
738
+ textarea.span8,
739
+ .uneditable-input.span8 {
740
+ width: 462px;
741
+ }
742
+ input.span7,
743
+ textarea.span7,
744
+ .uneditable-input.span7 {
745
+ width: 400px;
746
+ }
747
+ input.span6,
748
+ textarea.span6,
749
+ .uneditable-input.span6 {
750
+ width: 338px;
751
+ }
752
+ input.span5,
753
+ textarea.span5,
754
+ .uneditable-input.span5 {
755
+ width: 276px;
756
+ }
757
+ input.span4,
758
+ textarea.span4,
759
+ .uneditable-input.span4 {
760
+ width: 214px;
761
+ }
762
+ input.span3,
763
+ textarea.span3,
764
+ .uneditable-input.span3 {
765
+ width: 152px;
766
+ }
767
+ input.span2,
768
+ textarea.span2,
769
+ .uneditable-input.span2 {
770
+ width: 90px;
771
+ }
772
+ input.span1,
773
+ textarea.span1,
774
+ .uneditable-input.span1 {
775
+ width: 28px;
776
+ }
777
+ }
778
+
779
+ @media (max-width: 767px) {
780
+ body {
781
+ padding-right: 20px;
782
+ padding-left: 20px;
783
+ }
784
+ .navbar-fixed-top,
785
+ .navbar-fixed-bottom,
786
+ .navbar-static-top {
787
+ margin-right: -20px;
788
+ margin-left: -20px;
789
+ }
790
+ .container-fluid {
791
+ padding: 0;
792
+ }
793
+ .dl-horizontal dt {
794
+ float: none;
795
+ width: auto;
796
+ clear: none;
797
+ text-align: left;
798
+ }
799
+ .dl-horizontal dd {
800
+ margin-left: 0;
801
+ }
802
+ .container {
803
+ width: auto;
804
+ }
805
+ .row-fluid {
806
+ width: 100%;
807
+ }
808
+ .row,
809
+ .thumbnails {
810
+ margin-left: 0;
811
+ }
812
+ .thumbnails > li {
813
+ float: none;
814
+ margin-left: 0;
815
+ }
816
+ [class*="span"],
817
+ .row-fluid [class*="span"] {
818
+ display: block;
819
+ float: none;
820
+ width: 100%;
821
+ margin-left: 0;
822
+ -webkit-box-sizing: border-box;
823
+ -moz-box-sizing: border-box;
824
+ box-sizing: border-box;
825
+ }
826
+ .span12,
827
+ .row-fluid .span12 {
828
+ width: 100%;
829
+ -webkit-box-sizing: border-box;
830
+ -moz-box-sizing: border-box;
831
+ box-sizing: border-box;
832
+ }
833
+ .input-large,
834
+ .input-xlarge,
835
+ .input-xxlarge,
836
+ input[class*="span"],
837
+ select[class*="span"],
838
+ textarea[class*="span"],
839
+ .uneditable-input {
840
+ display: block;
841
+ width: 100%;
842
+ min-height: 30px;
843
+ -webkit-box-sizing: border-box;
844
+ -moz-box-sizing: border-box;
845
+ box-sizing: border-box;
846
+ }
847
+ .input-prepend input,
848
+ .input-append input,
849
+ .input-prepend input[class*="span"],
850
+ .input-append input[class*="span"] {
851
+ display: inline-block;
852
+ width: auto;
853
+ }
854
+ .controls-row [class*="span"] + [class*="span"] {
855
+ margin-left: 0;
856
+ }
857
+ .modal {
858
+ position: fixed;
859
+ top: 20px;
860
+ right: 20px;
861
+ left: 20px;
862
+ width: auto;
863
+ margin: 0;
864
+ }
865
+ .modal.fade.in {
866
+ top: auto;
867
+ }
868
+ }
869
+
870
+ @media (max-width: 480px) {
871
+ .nav-collapse {
872
+ -webkit-transform: translate3d(0, 0, 0);
873
+ }
874
+ .page-header h1 small {
875
+ display: block;
876
+ line-height: 20px;
877
+ }
878
+ input[type="checkbox"],
879
+ input[type="radio"] {
880
+ border: 1px solid #ccc;
881
+ }
882
+ .form-horizontal .control-label {
883
+ float: none;
884
+ width: auto;
885
+ padding-top: 0;
886
+ text-align: left;
887
+ }
888
+ .form-horizontal .controls {
889
+ margin-left: 0;
890
+ }
891
+ .form-horizontal .control-list {
892
+ padding-top: 0;
893
+ }
894
+ .form-horizontal .form-actions {
895
+ padding-right: 10px;
896
+ padding-left: 10px;
897
+ }
898
+ .modal {
899
+ top: 10px;
900
+ right: 10px;
901
+ left: 10px;
902
+ }
903
+ .modal-header .close {
904
+ padding: 10px;
905
+ margin: -10px;
906
+ }
907
+ .carousel-caption {
908
+ position: static;
909
+ }
910
+ }
911
+
912
+ @media (max-width: 979px) {
913
+ body {
914
+ padding-top: 0;
915
+ }
916
+ .navbar-fixed-top,
917
+ .navbar-fixed-bottom {
918
+ position: static;
919
+ }
920
+ .navbar-fixed-top {
921
+ margin-bottom: 20px;
922
+ }
923
+ .navbar-fixed-bottom {
924
+ margin-top: 20px;
925
+ }
926
+ .navbar-fixed-top .navbar-inner,
927
+ .navbar-fixed-bottom .navbar-inner {
928
+ padding: 5px;
929
+ }
930
+ .navbar .container {
931
+ width: auto;
932
+ padding: 0;
933
+ }
934
+ .navbar .brand {
935
+ padding-right: 10px;
936
+ padding-left: 10px;
937
+ margin: 0 0 0 -5px;
938
+ }
939
+ .nav-collapse {
940
+ clear: both;
941
+ }
942
+ .nav-collapse .nav {
943
+ float: none;
944
+ margin: 0 0 10px;
945
+ }
946
+ .nav-collapse .nav > li {
947
+ float: none;
948
+ }
949
+ .nav-collapse .nav > li > a {
950
+ margin-bottom: 2px;
951
+ }
952
+ .nav-collapse .nav > .divider-vertical {
953
+ display: none;
954
+ }
955
+ .nav-collapse .nav .nav-header {
956
+ color: #777777;
957
+ text-shadow: none;
958
+ }
959
+ .nav-collapse .nav > li > a,
960
+ .nav-collapse .dropdown-menu a {
961
+ padding: 9px 15px;
962
+ font-weight: bold;
963
+ color: #777777;
964
+ -webkit-border-radius: 3px;
965
+ -moz-border-radius: 3px;
966
+ border-radius: 3px;
967
+ }
968
+ .nav-collapse .btn {
969
+ padding: 4px 10px 4px;
970
+ font-weight: normal;
971
+ -webkit-border-radius: 4px;
972
+ -moz-border-radius: 4px;
973
+ border-radius: 4px;
974
+ }
975
+ .nav-collapse .dropdown-menu li + li a {
976
+ margin-bottom: 2px;
977
+ }
978
+ .nav-collapse .nav > li > a:hover,
979
+ .nav-collapse .dropdown-menu a:hover {
980
+ background-color: #f2f2f2;
981
+ }
982
+ .navbar-inverse .nav-collapse .nav > li > a:hover,
983
+ .navbar-inverse .nav-collapse .dropdown-menu a:hover {
984
+ background-color: #111111;
985
+ }
986
+ .nav-collapse.in .btn-group {
987
+ padding: 0;
988
+ margin-top: 5px;
989
+ }
990
+ .nav-collapse .dropdown-menu {
991
+ position: static;
992
+ top: auto;
993
+ left: auto;
994
+ display: block;
995
+ float: none;
996
+ max-width: none;
997
+ padding: 0;
998
+ margin: 0 15px;
999
+ background-color: transparent;
1000
+ border: none;
1001
+ -webkit-border-radius: 0;
1002
+ -moz-border-radius: 0;
1003
+ border-radius: 0;
1004
+ -webkit-box-shadow: none;
1005
+ -moz-box-shadow: none;
1006
+ box-shadow: none;
1007
+ }
1008
+ .nav-collapse .dropdown-menu:before,
1009
+ .nav-collapse .dropdown-menu:after {
1010
+ display: none;
1011
+ }
1012
+ .nav-collapse .dropdown-menu .divider {
1013
+ display: none;
1014
+ }
1015
+ .nav-collapse .nav > li > .dropdown-menu:before,
1016
+ .nav-collapse .nav > li > .dropdown-menu:after {
1017
+ display: none;
1018
+ }
1019
+ .nav-collapse .navbar-form,
1020
+ .nav-collapse .navbar-search {
1021
+ float: none;
1022
+ padding: 10px 15px;
1023
+ margin: 10px 0;
1024
+ border-top: 1px solid #f2f2f2;
1025
+ border-bottom: 1px solid #f2f2f2;
1026
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
1027
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
1028
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
1029
+ }
1030
+ .navbar-inverse .nav-collapse .navbar-form,
1031
+ .navbar-inverse .nav-collapse .navbar-search {
1032
+ border-top-color: #111111;
1033
+ border-bottom-color: #111111;
1034
+ }
1035
+ .navbar .nav-collapse .nav.pull-right {
1036
+ float: none;
1037
+ margin-left: 0;
1038
+ }
1039
+ .nav-collapse,
1040
+ .nav-collapse.collapse {
1041
+ height: 0;
1042
+ overflow: hidden;
1043
+ }
1044
+ .navbar .btn-navbar {
1045
+ display: block;
1046
+ }
1047
+ .navbar-static .navbar-inner {
1048
+ padding-right: 10px;
1049
+ padding-left: 10px;
1050
+ }
1051
+ }
1052
+
1053
+ @media (min-width: 980px) {
1054
+ .nav-collapse.collapse {
1055
+ height: auto !important;
1056
+ overflow: visible !important;
1057
+ }
1058
+ }