network-projector 0.0.2 → 0.0.3

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/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
+ }