swiss_admin 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +275 -0
  6. data/Rakefile +8 -0
  7. data/bin/swissadmin +8 -0
  8. data/lib/swiss_admin.rb +9 -0
  9. data/lib/swiss_admin/cli.rb +6 -0
  10. data/lib/swiss_admin/cli/cli.rb +19 -0
  11. data/lib/swiss_admin/cli/hardware_cli.rb +19 -0
  12. data/lib/swiss_admin/cli/host_cli.rb +18 -0
  13. data/lib/swiss_admin/cli/network_cli.rb +19 -0
  14. data/lib/swiss_admin/cli/user_cli.rb +25 -0
  15. data/lib/swiss_admin/cli/web_cli.rb +68 -0
  16. data/lib/swiss_admin/hardware.rb +2 -0
  17. data/lib/swiss_admin/hardware/cpus.rb +11 -0
  18. data/lib/swiss_admin/hardware/memory.rb +36 -0
  19. data/lib/swiss_admin/host.rb +1 -0
  20. data/lib/swiss_admin/host/host.rb +15 -0
  21. data/lib/swiss_admin/network.rb +1 -0
  22. data/lib/swiss_admin/network/network.rb +13 -0
  23. data/lib/swiss_admin/user.rb +1 -0
  24. data/lib/swiss_admin/user/user.rb +18 -0
  25. data/lib/swiss_admin/version.rb +3 -0
  26. data/lib/swiss_admin/web/app.rb +60 -0
  27. data/lib/swiss_admin/web/public/css/base.css +269 -0
  28. data/lib/swiss_admin/web/public/css/layout.css +58 -0
  29. data/lib/swiss_admin/web/public/css/skeleton.css +242 -0
  30. data/lib/swiss_admin/web/public/css/tables.css +46 -0
  31. data/lib/swiss_admin/web/public/images/apple-touch-icon-114x114.png +0 -0
  32. data/lib/swiss_admin/web/public/images/apple-touch-icon-72x72.png +0 -0
  33. data/lib/swiss_admin/web/public/images/apple-touch-icon.png +0 -0
  34. data/lib/swiss_admin/web/public/images/favicon.ico +0 -0
  35. data/lib/swiss_admin/web/public/javascript/jquery-2.1.0.min.js +4 -0
  36. data/lib/swiss_admin/web/views/info.erb +60 -0
  37. data/lib/swiss_admin/web/views/layout.erb +25 -0
  38. data/swiss_admin.gemspec +29 -0
  39. data/test/cli/cli_hardware_test.rb +21 -0
  40. data/test/cli/cli_host_test.rb +20 -0
  41. data/test/cli/cli_network_test.rb +17 -0
  42. data/test/cli/cli_user_test.rb +28 -0
  43. data/test/hardware_test.rb +9 -0
  44. data/test/host_test.rb +12 -0
  45. data/test/network_test.rb +14 -0
  46. data/test/test_helper.rb +28 -0
  47. data/test/user_test.rb +17 -0
  48. data/test/web/test_api.rb +70 -0
  49. data/test/web/test_host_info.rb +44 -0
  50. metadata +216 -0
@@ -0,0 +1,25 @@
1
+ require "thor"
2
+ module SwissAdmin
3
+ module Commands
4
+ class User < Thor
5
+ namespace :user
6
+
7
+ desc "current", "Current user"
8
+ def current
9
+ $stdout.puts SwissAdmin::User.current
10
+ end
11
+
12
+ desc "home", "Current user's home directory"
13
+ def home
14
+ $stdout.puts SwissAdmin::User.home
15
+ end
16
+
17
+ desc "active", "All active users"
18
+ def active
19
+ $stdout.puts SwissAdmin::User.active[:output]
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,68 @@
1
+ require "thor"
2
+ require "swiss_admin/web/app"
3
+ module SwissAdmin
4
+ module Commands
5
+ # @todo move to another module Commands::Helpers??
6
+ def self.app_running? pid
7
+ pid = pid.to_i
8
+ result = begin
9
+ Process.kill(0, pid)
10
+ :running
11
+ rescue Errno::EPERM => e
12
+ e.message
13
+ rescue Errno::ESRCH => e
14
+ :not_running
15
+ rescue
16
+ "Unable to determine status for #{pid} : #{$!}"
17
+ end
18
+ result
19
+ end
20
+
21
+ class Web < Thor
22
+ namespace :web
23
+
24
+ desc "start", "Start web server"
25
+ # must keep global state of pid file..yaml or marshall?
26
+ # at rack start create file with pid file info
27
+ # on stop read from file then do the thing
28
+ #method_option :pid_file, aliases: "-P", desc: "Set path for pid file", default: "/tmp/swissadmin.pid"
29
+ method_option :port, aliases: "-p", desc: "Set port for web companion", default: 8080
30
+ def start
31
+ $stdout.puts "Starting..."
32
+ Rack::Server.start(app: SwissAdmin::HostInfo,
33
+ daemonize: true,
34
+ pid: options[:pid_file],
35
+ Port: options[:port])
36
+ end
37
+
38
+ # @todo need to break out all the file to separate module
39
+ desc "stop", "Stop web server"
40
+ def stop
41
+ begin
42
+ pid = IO.read("/tmp/swissadmin.pid")
43
+ res = Commands.app_running? pid
44
+ if res == :running
45
+ Process.kill("HUP",pid.to_i)
46
+ end
47
+ File.delete("/tmp/swissadmin.pid")
48
+ $stdout.puts "Stopped" || res != :running
49
+ rescue Errno::ENOENT => e
50
+ $stdout.puts e.message
51
+ return 0
52
+ end
53
+ end
54
+
55
+ desc "status", "Get status of the web server"
56
+ def status
57
+ running = false
58
+ if File.exist?("/tmp/swissadmin.pid")
59
+ pid = IO.read("/tmp/swissadmin.pid")
60
+ res = Commands.app_running? pid
61
+ running = true if res == :running
62
+ end
63
+ $stdout.puts (running ? "Running" : "Not Running")
64
+ end
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,2 @@
1
+ require_relative "hardware/memory"
2
+ require_relative "hardware/cpus"
@@ -0,0 +1,11 @@
1
+ module SwissAdmin
2
+ class Hardware
3
+ def self.cpus
4
+ cpus = if File.readable?("/proc/cpuinfo")
5
+ IO.read("/proc/cpuinfo").scan(/^processor/).size
6
+ else
7
+ "unknown"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+
2
+ module SwissAdmin
3
+ class Hardware
4
+ # @example
5
+ # Mem — Displays the current state of physical RAM in the system,
6
+ # including a full breakdown of total, used, free, shared, buffered,
7
+ # and cached memory utilization in bytes.
8
+ # Swap — Displays the total, used, and free amounts of swap space, in bytes.
9
+ # MemTotal — Total amount of physical RAM, in kilobytes.
10
+ # MemFree — The amount of physical RAM, in kilobytes, left unused by the system.
11
+ # MemShared — Unused with 2.4 and higher kernels
12
+ # but left in for compatibility with earlier kernel versions.
13
+ # Buffers — The amount of physical RAM, in kilobytes, used for file buffers.
14
+ # Cached — The amount of physical RAM, in kilobytes, used as cache memory.
15
+ # Active — The total amount of buffer or page cache memory, in kilobytes, that is in active use.
16
+ # Inact_dirty — The total amount of buffer or cache pages, in kilobytes, that might be freeable.
17
+ # Inact_clean — The total amount of buffer or cache pages in kilobytes
18
+ # Inact_target — The net amount of allocations per second, in kilobytes, averaged over one minute.
19
+ # HighTotal and HighFree — The total and free amount of memory,
20
+ # respectively, that is not directly mapped into kernel space.
21
+ # The HighTotal value can vary based on the type of kernel used.
22
+ # LowTotal and LowFree — The total and free amount of memory, respectively,
23
+ # that is directly mapped into kernel space.
24
+ # The LowTotal value can vary based on the type of kernel used.
25
+ # SwapTotal — The total amount of swap available, in kilobytes.
26
+ # SwapFree — The total amount of swap free, in kilobytes.
27
+ def self.memory
28
+ memory = if File.readable?("/proc/meminfo")
29
+ IO.read("/proc/meminfo").scan(/([a-zA-Z]+):\W+(\d+)/)
30
+ else
31
+ "unknown"
32
+ end
33
+ memory.inject({}) { |a,d| a[d[0]] = d[1]; a }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1 @@
1
+ require_relative "host/host"
@@ -0,0 +1,15 @@
1
+ module SwissAdmin
2
+ class Host
3
+ def self.name
4
+ Socket.gethostname
5
+ end
6
+
7
+ def self.loadavg
8
+ loadavg = if File.readable?("/proc/loadavg")
9
+ IO.read("/proc/loadavg")
10
+ else
11
+ "unknown"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ require_relative "network/network"
@@ -0,0 +1,13 @@
1
+ require 'socket'
2
+
3
+ module SwissAdmin
4
+ class Network
5
+ def self.ip_addresses
6
+ Socket.ip_address_list.map { |i| {ip_address: i.ip_address, name: i.getnameinfo} }
7
+ end
8
+
9
+ def self.first_ipv4
10
+ Socket.ip_address_list.detect{|intf| intf.ipv4_private?}.ip_address
11
+ end
12
+ end
13
+ end
@@ -0,0 +1 @@
1
+ require_relative "user/user"
@@ -0,0 +1,18 @@
1
+ require "etc"
2
+ require "shelltastic"
3
+
4
+ module SwissAdmin
5
+ class User
6
+ def self.current
7
+ ENV["USER"] || Etc.getlogin
8
+ end
9
+
10
+ def self.home
11
+ Dir.home(Etc.getlogin)
12
+ end
13
+
14
+ def self.active
15
+ ::ShellTastic::Command.run("w -s -h").first
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module SwissAdmin
2
+ VERSION = "0.6.1"
3
+ end
@@ -0,0 +1,60 @@
1
+ require 'sinatra'
2
+ require "json"
3
+ require_relative "../hardware"
4
+ require_relative "../host"
5
+ require_relative "../network"
6
+
7
+ module SwissAdmin
8
+ class HostInfo < Sinatra::Base
9
+ helpers do
10
+ def generate_json(message)
11
+ JSON.generate(message)
12
+ end
13
+
14
+ def run_plugin(klass, params)
15
+ begin
16
+ generate_json(params[:plugin] => klass.send(params[:plugin]))
17
+ rescue NoMethodError => e
18
+ generate_json(error: "Plugin not implemented correctly or does not exist")
19
+ end
20
+ end
21
+ end
22
+
23
+ get '/test' do
24
+ "hello world"
25
+ end
26
+
27
+ get "/info" do
28
+ @memory = SwissAdmin::Hardware.memory
29
+ @host_name = SwissAdmin::Host.name
30
+ @users = SwissAdmin::User.active
31
+ @load_average = SwissAdmin::Host.loadavg
32
+ @cpus = SwissAdmin::Hardware.cpus
33
+ @ip_addresses = SwissAdmin::Network.ip_addresses
34
+ erb :info
35
+ end
36
+
37
+ #### api
38
+
39
+ ## host
40
+ get "/api/host/:plugin" do
41
+ run_plugin(SwissAdmin::Host, params)
42
+ end
43
+
44
+ ## hardware
45
+ get "/api/hardware/:plugin" do
46
+ run_plugin(SwissAdmin::Hardware, params)
47
+ end
48
+
49
+ ## User
50
+ get "/api/users/:plugin" do
51
+ run_plugin(SwissAdmin::User, params)
52
+ end
53
+
54
+ ## Network
55
+ get "/api/network/:plugin" do
56
+ run_plugin(SwissAdmin::Network, params)
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,269 @@
1
+ /*
2
+ * Skeleton V1.2
3
+ * Copyright 2011, Dave Gamache
4
+ * www.getskeleton.com
5
+ * Free to use under the MIT license.
6
+ * http://www.opensource.org/licenses/mit-license.php
7
+ * 6/20/2012
8
+ */
9
+
10
+
11
+ /* Table of Content
12
+ ==================================================
13
+ #Reset & Basics
14
+ #Basic Styles
15
+ #Site Styles
16
+ #Typography
17
+ #Links
18
+ #Lists
19
+ #Images
20
+ #Buttons
21
+ #Forms
22
+ #Misc */
23
+
24
+
25
+ /* #Reset & Basics (Inspired by E. Meyers)
26
+ ================================================== */
27
+ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
28
+ margin: 0;
29
+ padding: 0;
30
+ border: 0;
31
+ font-size: 100%;
32
+ font: inherit;
33
+ vertical-align: baseline; }
34
+ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
35
+ display: block; }
36
+ body {
37
+ line-height: 1; }
38
+ ol, ul {
39
+ list-style: none; }
40
+ blockquote, q {
41
+ quotes: none; }
42
+ blockquote:before, blockquote:after,
43
+ q:before, q:after {
44
+ content: '';
45
+ content: none; }
46
+ table {
47
+ border-collapse: collapse;
48
+ border-spacing: 0; }
49
+
50
+
51
+ /* #Basic Styles
52
+ ================================================== */
53
+ body {
54
+ background: #fff;
55
+ font: 14px/21px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
56
+ color: #444;
57
+ -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */
58
+ -webkit-text-size-adjust: 100%;
59
+ }
60
+
61
+
62
+ /* #Typography
63
+ ================================================== */
64
+ h1, h2, h3, h4, h5, h6 {
65
+ color: #181818;
66
+ font-family: "Georgia", "Times New Roman", serif;
67
+ font-weight: normal; }
68
+ h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; }
69
+ h1 { font-size: 46px; line-height: 50px; margin-bottom: 14px;}
70
+ h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; }
71
+ h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; }
72
+ h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; }
73
+ h5 { font-size: 17px; line-height: 24px; }
74
+ h6 { font-size: 14px; line-height: 21px; }
75
+ .subheader { color: #777; }
76
+
77
+ p { margin: 0 0 20px 0; }
78
+ p img { margin: 0; }
79
+ p.lead { font-size: 21px; line-height: 27px; color: #777; }
80
+
81
+ em { font-style: italic; }
82
+ strong { font-weight: bold; color: #333; }
83
+ small { font-size: 80%; }
84
+
85
+ /* Blockquotes */
86
+ blockquote, blockquote p { font-size: 17px; line-height: 24px; color: #777; font-style: italic; }
87
+ blockquote { margin: 0 0 20px; padding: 9px 20px 0 19px; border-left: 1px solid #ddd; }
88
+ blockquote cite { display: block; font-size: 12px; color: #555; }
89
+ blockquote cite:before { content: "\2014 \0020"; }
90
+ blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { color: #555; }
91
+
92
+ hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; }
93
+
94
+
95
+ /* #Links
96
+ ================================================== */
97
+ a, a:visited { color: #333; text-decoration: underline; outline: 0; }
98
+ a:hover, a:focus { color: #000; }
99
+ p a, p a:visited { line-height: inherit; }
100
+
101
+
102
+ /* #Lists
103
+ ================================================== */
104
+ ul, ol { margin-bottom: 20px; }
105
+ ul { list-style: none outside; }
106
+ ol { list-style: decimal; }
107
+ ol, ul.square, ul.circle, ul.disc { margin-left: 30px; }
108
+ ul.square { list-style: square outside; }
109
+ ul.circle { list-style: circle outside; }
110
+ ul.disc { list-style: disc outside; }
111
+ ul ul, ul ol,
112
+ ol ol, ol ul { margin: 4px 0 5px 30px; font-size: 90%; }
113
+ ul ul li, ul ol li,
114
+ ol ol li, ol ul li { margin-bottom: 6px; }
115
+ li { line-height: 18px; margin-bottom: 12px; }
116
+ ul.large li { line-height: 21px; }
117
+ li p { line-height: 21px; }
118
+
119
+ /* #Images
120
+ ================================================== */
121
+
122
+ img.scale-with-grid {
123
+ max-width: 100%;
124
+ height: auto; }
125
+
126
+
127
+ /* #Buttons
128
+ ================================================== */
129
+
130
+ .button,
131
+ button,
132
+ input[type="submit"],
133
+ input[type="reset"],
134
+ input[type="button"] {
135
+ background: #eee; /* Old browsers */
136
+ background: #eee -moz-linear-gradient(top, rgba(255,255,255,.2) 0%, rgba(0,0,0,.2) 100%); /* FF3.6+ */
137
+ background: #eee -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.2)), color-stop(100%,rgba(0,0,0,.2))); /* Chrome,Safari4+ */
138
+ background: #eee -webkit-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Chrome10+,Safari5.1+ */
139
+ background: #eee -o-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Opera11.10+ */
140
+ background: #eee -ms-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* IE10+ */
141
+ background: #eee linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* W3C */
142
+ border: 1px solid #aaa;
143
+ border-top: 1px solid #ccc;
144
+ border-left: 1px solid #ccc;
145
+ -moz-border-radius: 3px;
146
+ -webkit-border-radius: 3px;
147
+ border-radius: 3px;
148
+ color: #444;
149
+ display: inline-block;
150
+ font-size: 11px;
151
+ font-weight: bold;
152
+ text-decoration: none;
153
+ text-shadow: 0 1px rgba(255, 255, 255, .75);
154
+ cursor: pointer;
155
+ margin-bottom: 20px;
156
+ line-height: normal;
157
+ padding: 8px 10px;
158
+ font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; }
159
+
160
+ .button:hover,
161
+ button:hover,
162
+ input[type="submit"]:hover,
163
+ input[type="reset"]:hover,
164
+ input[type="button"]:hover {
165
+ color: #222;
166
+ background: #ddd; /* Old browsers */
167
+ background: #ddd -moz-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%); /* FF3.6+ */
168
+ background: #ddd -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.3)), color-stop(100%,rgba(0,0,0,.3))); /* Chrome,Safari4+ */
169
+ background: #ddd -webkit-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Chrome10+,Safari5.1+ */
170
+ background: #ddd -o-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Opera11.10+ */
171
+ background: #ddd -ms-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* IE10+ */
172
+ background: #ddd linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* W3C */
173
+ border: 1px solid #888;
174
+ border-top: 1px solid #aaa;
175
+ border-left: 1px solid #aaa; }
176
+
177
+ .button:active,
178
+ button:active,
179
+ input[type="submit"]:active,
180
+ input[type="reset"]:active,
181
+ input[type="button"]:active {
182
+ border: 1px solid #666;
183
+ background: #ccc; /* Old browsers */
184
+ background: #ccc -moz-linear-gradient(top, rgba(255,255,255,.35) 0%, rgba(10,10,10,.4) 100%); /* FF3.6+ */
185
+ background: #ccc -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.35)), color-stop(100%,rgba(10,10,10,.4))); /* Chrome,Safari4+ */
186
+ background: #ccc -webkit-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Chrome10+,Safari5.1+ */
187
+ background: #ccc -o-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Opera11.10+ */
188
+ background: #ccc -ms-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* IE10+ */
189
+ background: #ccc linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* W3C */ }
190
+
191
+ .button.full-width,
192
+ button.full-width,
193
+ input[type="submit"].full-width,
194
+ input[type="reset"].full-width,
195
+ input[type="button"].full-width {
196
+ width: 100%;
197
+ padding-left: 0 !important;
198
+ padding-right: 0 !important;
199
+ text-align: center; }
200
+
201
+ /* Fix for odd Mozilla border & padding issues */
202
+ button::-moz-focus-inner,
203
+ input::-moz-focus-inner {
204
+ border: 0;
205
+ padding: 0;
206
+ }
207
+
208
+
209
+ /* #Forms
210
+ ================================================== */
211
+
212
+ form {
213
+ margin-bottom: 20px; }
214
+ fieldset {
215
+ margin-bottom: 20px; }
216
+ input[type="text"],
217
+ input[type="password"],
218
+ input[type="email"],
219
+ textarea,
220
+ select {
221
+ border: 1px solid #ccc;
222
+ padding: 6px 4px;
223
+ outline: none;
224
+ -moz-border-radius: 2px;
225
+ -webkit-border-radius: 2px;
226
+ border-radius: 2px;
227
+ font: 13px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
228
+ color: #777;
229
+ margin: 0;
230
+ width: 210px;
231
+ max-width: 100%;
232
+ display: block;
233
+ margin-bottom: 20px;
234
+ background: #fff; }
235
+ select {
236
+ padding: 0; }
237
+ input[type="text"]:focus,
238
+ input[type="password"]:focus,
239
+ input[type="email"]:focus,
240
+ textarea:focus {
241
+ border: 1px solid #aaa;
242
+ color: #444;
243
+ -moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
244
+ -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
245
+ box-shadow: 0 0 3px rgba(0,0,0,.2); }
246
+ textarea {
247
+ min-height: 60px; }
248
+ label,
249
+ legend {
250
+ display: block;
251
+ font-weight: bold;
252
+ font-size: 13px; }
253
+ select {
254
+ width: 220px; }
255
+ input[type="checkbox"] {
256
+ display: inline; }
257
+ label span,
258
+ legend span {
259
+ font-weight: normal;
260
+ font-size: 13px;
261
+ color: #444; }
262
+
263
+ /* #Misc
264
+ ================================================== */
265
+ .remove-bottom { margin-bottom: 0 !important; }
266
+ .half-bottom { margin-bottom: 10px !important; }
267
+ .add-bottom { margin-bottom: 20px !important; }
268
+
269
+