restapi_doc 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +11 -0
- data/Gemfile.lock +36 -0
- data/LICENSE +20 -0
- data/README.rdoc +28 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/lib/restapi_doc/config/restapi_doc.yml +2 -0
- data/lib/restapi_doc/config.rb +46 -0
- data/lib/restapi_doc/method_doc.rb +84 -0
- data/lib/restapi_doc/railtie.rb +9 -0
- data/lib/restapi_doc/resource_doc.rb +104 -0
- data/lib/restapi_doc/tasks/restapi_doc_tasks.rake +28 -0
- data/lib/restapi_doc/template/assets/css/bootstrap-responsive.min.css +12 -0
- data/lib/restapi_doc/template/assets/css/bootstrap.less +9 -0
- data/lib/restapi_doc/template/assets/css/bootstrap.min.css +689 -0
- data/lib/restapi_doc/template/assets/css/prettify.css +30 -0
- data/lib/restapi_doc/template/assets/img/glyphicons-halflings-white.png +0 -0
- data/lib/restapi_doc/template/assets/img/glyphicons-halflings.png +0 -0
- data/lib/restapi_doc/template/assets/js/bootstrap.min.js +6 -0
- data/lib/restapi_doc/template/assets/js/jquery.js +4 -0
- data/lib/restapi_doc/template/assets/js/less.min.js +9 -0
- data/lib/restapi_doc/template/assets/js/prettify.js +28 -0
- data/lib/restapi_doc/template/detail.html.haml +107 -0
- data/lib/restapi_doc/template/index.html.haml +57 -0
- data/lib/restapi_doc.rb +99 -0
- data/restapi_doc.gemspec +79 -0
- metadata +141 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.3)
|
5
|
+
git (1.2.5)
|
6
|
+
haml (3.1.4)
|
7
|
+
jeweler (1.8.3)
|
8
|
+
bundler (~> 1.0)
|
9
|
+
git (>= 1.2.5)
|
10
|
+
rake
|
11
|
+
rdoc
|
12
|
+
json (1.6.6)
|
13
|
+
metaclass (0.0.1)
|
14
|
+
mocha (0.11.3)
|
15
|
+
metaclass (~> 0.0.1)
|
16
|
+
rake (0.9.2.2)
|
17
|
+
rdoc (3.12)
|
18
|
+
json (~> 1.4)
|
19
|
+
rspec (2.9.0)
|
20
|
+
rspec-core (~> 2.9.0)
|
21
|
+
rspec-expectations (~> 2.9.0)
|
22
|
+
rspec-mocks (~> 2.9.0)
|
23
|
+
rspec-core (2.9.0)
|
24
|
+
rspec-expectations (2.9.1)
|
25
|
+
diff-lcs (~> 1.1.3)
|
26
|
+
rspec-mocks (2.9.0)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
haml (= 3.1.4)
|
33
|
+
jeweler
|
34
|
+
mocha
|
35
|
+
rake
|
36
|
+
rspec (>= 2.2.0)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Kevin Haight (kevinjhaight@gmail.com)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
= Rest Api Doc
|
2
|
+
|
3
|
+
Rest API doc generates an easy way to create a Twitter style document for your RESTful interface
|
4
|
+
|
5
|
+
Leveraging Twitter Bootstrap to create an easy to read document for your RESTful api.
|
6
|
+
|
7
|
+
== Installing the gem
|
8
|
+
|
9
|
+
gem install restapi_doc
|
10
|
+
|
11
|
+
== Set Up
|
12
|
+
Run the following rake command to setup your environment.
|
13
|
+
|
14
|
+
rake restapi_doc:generate
|
15
|
+
|
16
|
+
This will create a 'restapi_doc' directory in your Rails config directory.
|
17
|
+
In this directory you will now have a "restapi_doc.yml' file with some simple configuration options for your API document.
|
18
|
+
|
19
|
+
|
20
|
+
== Documenting controllers
|
21
|
+
Below is a sample of how to document the controller to generate a document
|
22
|
+
|
23
|
+
|
24
|
+
== Creating Api Document
|
25
|
+
|
26
|
+
rake restapi_doc:generate
|
27
|
+
|
28
|
+
You will now have a 'apidoc' directory located in your Rails 'public' directory
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "restapi_doc"
|
8
|
+
gem.summary = %Q{REST API doc generates an easy way to create a twitter style document for your RESTful interface}
|
9
|
+
gem.description = %Q{REST API doc generates an easy way to create a twitter style document for your RESTful interface.
|
10
|
+
Leveraging Twitter Bootstrap to create an easy to read document for your RESTful api. }
|
11
|
+
gem.email = "kevinjhaight@gmail.com"
|
12
|
+
gem.homepage = "http://github.com/alayho/restapi_doc"
|
13
|
+
gem.authors = ["Kevin Haight"]
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rspec/core/rake_task'
|
21
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
22
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
26
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
27
|
+
spec.rcov = true
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => :spec
|
31
|
+
|
32
|
+
require 'rdoc/task'
|
33
|
+
Rake::RDocTask.new do |rdoc|
|
34
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
35
|
+
rdoc.rdoc_dir = 'rdoc'
|
36
|
+
rdoc.title = "restapi_doc #{version}"
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RestApiDoc
|
3
|
+
module Config
|
4
|
+
def template_dir(f = nil)
|
5
|
+
@template_dir ||= File.join(File.dirname(__FILE__), 'template')
|
6
|
+
form_file_name @template_dir, f
|
7
|
+
end
|
8
|
+
|
9
|
+
def config_template_dir(f = nil)
|
10
|
+
@template_dir ||= File.join(File.dirname(__FILE__), 'config')
|
11
|
+
form_file_name @template_dir, f
|
12
|
+
end
|
13
|
+
|
14
|
+
def asset_dir
|
15
|
+
@asset_dir ||= File.join(File.dirname(__FILE__), 'template/assets')
|
16
|
+
end
|
17
|
+
|
18
|
+
def config_dir(f = nil)
|
19
|
+
@config_dir ||= File.join(::Rails.root.to_s, 'config/restapi_doc')
|
20
|
+
form_file_name @config_dir, f
|
21
|
+
end
|
22
|
+
|
23
|
+
def target_dir(f = nil)
|
24
|
+
@target_dir ||= File.join(::Rails.root.to_s, 'public/apidoc/')
|
25
|
+
form_file_name @target_dir, f
|
26
|
+
end
|
27
|
+
|
28
|
+
def controller_dir(f = nil)
|
29
|
+
@controller_dir ||= File.join(::Rails.root.to_s, 'app/controllers/')
|
30
|
+
form_file_name @controller_dir, f
|
31
|
+
end
|
32
|
+
|
33
|
+
def temp_dir(f = nil)
|
34
|
+
@temp_dir ||= "#{Dir.mktmpdir("apidoc")}/"
|
35
|
+
form_file_name @temp_dir, f
|
36
|
+
end
|
37
|
+
|
38
|
+
def form_file_name(dir, file)
|
39
|
+
case file
|
40
|
+
when NilClass then dir
|
41
|
+
when String then File.join(dir, file)
|
42
|
+
else raise ArgumentError, "Invalid argument #{file}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RestApiDoc
|
3
|
+
class MethodDoc
|
4
|
+
attr_accessor :scope, :method_order, :content, :request, :response, :output, :params, :defname, :response_formats, :requires_authentication, :request_url, :account_password_required, :http_responses
|
5
|
+
|
6
|
+
def initialize(resource_name, type, order)
|
7
|
+
@resource_name = resource_name
|
8
|
+
@scope = type
|
9
|
+
@method_order = order
|
10
|
+
@content = ""
|
11
|
+
@request = ""
|
12
|
+
@response = ""
|
13
|
+
@output = ""
|
14
|
+
@params = []
|
15
|
+
@response_formats = []
|
16
|
+
@http_responses= []
|
17
|
+
@requires_authentication = "No"
|
18
|
+
@account_password_required = "No"
|
19
|
+
@defname = nil
|
20
|
+
@request_url = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def process_line(line, current_scope)
|
24
|
+
new_scope = current_scope
|
25
|
+
case current_scope
|
26
|
+
when :response
|
27
|
+
if line =~ /::response-end::/
|
28
|
+
new_scope = :function
|
29
|
+
else
|
30
|
+
@response << line
|
31
|
+
end
|
32
|
+
when :request
|
33
|
+
if line =~ /::request-end::/
|
34
|
+
new_scope = :function
|
35
|
+
else
|
36
|
+
@request << line
|
37
|
+
end
|
38
|
+
when :output # append output
|
39
|
+
if line =~ /::output-end::/
|
40
|
+
new_scope = :function
|
41
|
+
else
|
42
|
+
@output << line
|
43
|
+
end
|
44
|
+
when :class, :function
|
45
|
+
result = line.scan(/(\w+)\:\:\s*(.+)/)
|
46
|
+
if not result.empty?
|
47
|
+
key, value = result[0]
|
48
|
+
case key
|
49
|
+
when "response", "request"
|
50
|
+
new_scope = key.to_sym
|
51
|
+
when "output"
|
52
|
+
new_scope = key.to_sym
|
53
|
+
when "param"
|
54
|
+
@params << value
|
55
|
+
when "http_response"
|
56
|
+
@http_responses << value
|
57
|
+
when "response_format"
|
58
|
+
@response_formats << value
|
59
|
+
when "requires_authentication"
|
60
|
+
@requires_authentication = value
|
61
|
+
when "request_url"
|
62
|
+
@request_url = value
|
63
|
+
when "account_password_required"
|
64
|
+
@account_password_required = value
|
65
|
+
else # user wants this new shiny variable whose name is the key with value = value
|
66
|
+
instance_variable_set("@#{key}".to_sym, value)
|
67
|
+
define_singleton_method(key.to_sym) { value } # define accessor for the templates to read it
|
68
|
+
end
|
69
|
+
else
|
70
|
+
# add line to block
|
71
|
+
@content << line
|
72
|
+
end
|
73
|
+
else
|
74
|
+
raise ParsingException, "logic error: unknown current scope #{current_scope}"
|
75
|
+
end
|
76
|
+
new_scope
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_binding
|
80
|
+
binding
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative 'method_doc'
|
3
|
+
|
4
|
+
module RestApiDoc
|
5
|
+
class ParsingException < Exception;
|
6
|
+
end
|
7
|
+
class ResourceDoc
|
8
|
+
|
9
|
+
attr_reader :name, :resource_location, :controller_name, :class_block, :function_blocks, :resource_header, :resource_methods, :description
|
10
|
+
|
11
|
+
# Initializes ResourceDoc.
|
12
|
+
def initialize(name, action_methods, controller_location, options = {})
|
13
|
+
@name = name
|
14
|
+
@class_block = nil
|
15
|
+
@function_blocks = []
|
16
|
+
@resource_methods = action_methods
|
17
|
+
@resource_header = ""
|
18
|
+
@standard_methods = options[:standard_methods] || [:put, :post, :get, :delete]
|
19
|
+
@resource_location = resource_location
|
20
|
+
@controller_location = controller_location
|
21
|
+
@description = nil
|
22
|
+
@controller_name = File.basename(controller_location)
|
23
|
+
end
|
24
|
+
|
25
|
+
# parse the controller
|
26
|
+
def parse_apidoc
|
27
|
+
lines = IO.readlines(@controller_location)
|
28
|
+
begin
|
29
|
+
@class_block, @function_blocks = ResourceDoc.parse_controller_doc(@name, lines)
|
30
|
+
rescue ParsingException => ex
|
31
|
+
puts "error #{ex} while parsing #{@controller_location}"
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
if !@class_block.nil?
|
35
|
+
@description = @class_block.content
|
36
|
+
end
|
37
|
+
|
38
|
+
@resource_methods.each do | req_m |
|
39
|
+
req_m << @function_blocks.select{|f| f.defname == req_m[0]}.first
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# This method parses the doc
|
44
|
+
def self.parse_controller_doc(name, lines)
|
45
|
+
current_api_block = nil
|
46
|
+
current_scope = :none
|
47
|
+
in_class = false
|
48
|
+
class_block = nil
|
49
|
+
function_blocks = []
|
50
|
+
order = 1
|
51
|
+
lines.each_with_index do |line, line_no|
|
52
|
+
line.gsub!(/^ *#/, '') # strip the starting '#' on the line
|
53
|
+
case line
|
54
|
+
when /=begin apidoc/
|
55
|
+
# if we get apidoc tag inside class definition, then they are for a method
|
56
|
+
current_scope = !in_class ? :class : :function
|
57
|
+
current_api_block = MethodDoc.new(name, current_scope, order)
|
58
|
+
when /=end/
|
59
|
+
if current_api_block.nil?
|
60
|
+
raise ParsingException, "#{line_no} - No starttag for '=end' found"
|
61
|
+
end
|
62
|
+
when /class/ # keep track of whether a resource or an api is being annotated
|
63
|
+
in_class = true
|
64
|
+
if !current_api_block.nil?
|
65
|
+
case current_scope
|
66
|
+
when :class
|
67
|
+
class_block = current_api_block
|
68
|
+
when :function
|
69
|
+
function_blocks << current_api_block
|
70
|
+
else
|
71
|
+
raise ParsingException, "logic error: unknown current scope #{current_scope}"
|
72
|
+
end
|
73
|
+
|
74
|
+
current_api_block = nil
|
75
|
+
current_scope = :none
|
76
|
+
order += 1
|
77
|
+
end
|
78
|
+
when /def/
|
79
|
+
if !current_api_block.nil?
|
80
|
+
current_api_block.defname = line.gsub('def ', '').strip
|
81
|
+
|
82
|
+
case current_scope
|
83
|
+
when :class
|
84
|
+
class_block = current_api_block
|
85
|
+
when :function
|
86
|
+
function_blocks << current_api_block
|
87
|
+
else
|
88
|
+
raise ParsingException, "logic error: unknown current scope #{current_scope}"
|
89
|
+
end
|
90
|
+
|
91
|
+
current_api_block = nil
|
92
|
+
current_scope = :none
|
93
|
+
order += 1
|
94
|
+
end
|
95
|
+
else
|
96
|
+
if current_api_block # process lines only if they are apidoc comments
|
97
|
+
current_scope = current_api_block.process_line(line, current_scope)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
[class_block, function_blocks]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
include RestApiDoc
|
3
|
+
|
4
|
+
namespace :restapi_doc do
|
5
|
+
|
6
|
+
desc "Generate the config files"
|
7
|
+
task :setup do
|
8
|
+
create_structure
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Generate the api documentation"
|
12
|
+
task :generate do
|
13
|
+
remove_structure
|
14
|
+
resources = get_resources do |controller, controller_url, controller_location|
|
15
|
+
end
|
16
|
+
if !resources.empty?
|
17
|
+
puts "Generating API documentation..."
|
18
|
+
generate_doc(resources)
|
19
|
+
move_document
|
20
|
+
puts "Completed API documentation generation"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Generate the config files"
|
25
|
+
task :clean do
|
26
|
+
remove_structure
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
|
2
|
+
.clearfix:after{clear:both;}
|
3
|
+
.hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;}
|
4
|
+
.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}
|
5
|
+
.hidden{display:none;visibility:hidden;}
|
6
|
+
.visible-phone{display:none;}
|
7
|
+
.visible-tablet{display:none;}
|
8
|
+
.visible-desktop{display:block;}
|
9
|
+
.hidden-phone{display:block;}
|
10
|
+
.hidden-tablet{display:block;}
|
11
|
+
.hidden-desktop{display:none;}
|
12
|
+
@media (max-width:767px){.visible-phone{display:block;} .hidden-phone{display:none;} .hidden-desktop{display:block;} .visible-desktop{display:none;}}@media (min-width:768px) and (max-width:979px){.visible-tablet{display:block;} .hidden-tablet{display:none;} .hidden-desktop{display:block;} .visible-desktop{display:none;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:18px;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .modal{position:absolute;top:10px;left:10px;right:10px;width:auto;margin:0;}.modal.fade.in{top:auto;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top{margin-left:-20px;margin-right:-20px;} .container{width:auto;} .row-fluid{width:100%;} .row{margin-left:0;} .row>[class*="span"],.row-fluid>[class*="span"]{float:none;display:block;width:auto;margin:0;} .thumbnails [class*="span"]{width:auto;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} .input-prepend input[class*="span"],.input-append input[class*="span"]{width:auto;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.762430939%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid > .span12{width:99.999999993%;} .row-fluid > .span11{width:91.436464082%;} .row-fluid > .span10{width:82.87292817100001%;} .row-fluid > .span9{width:74.30939226%;} .row-fluid > .span8{width:65.74585634900001%;} .row-fluid > .span7{width:57.182320438000005%;} .row-fluid > .span6{width:48.618784527%;} .row-fluid > .span5{width:40.055248616%;} .row-fluid > .span4{width:31.491712705%;} .row-fluid > .span3{width:22.928176794%;} .row-fluid > .span2{width:14.364640883%;} .row-fluid > .span1{width:5.801104972%;} input,textarea,.uneditable-input{margin-left:0;} input.span12, textarea.span12, .uneditable-input.span12{width:714px;} input.span11, textarea.span11, .uneditable-input.span11{width:652px;} input.span10, textarea.span10, .uneditable-input.span10{width:590px;} input.span9, textarea.span9, .uneditable-input.span9{width:528px;} input.span8, textarea.span8, .uneditable-input.span8{width:466px;} input.span7, textarea.span7, .uneditable-input.span7{width:404px;} input.span6, textarea.span6, .uneditable-input.span6{width:342px;} input.span5, textarea.span5, .uneditable-input.span5{width:280px;} input.span4, textarea.span4, .uneditable-input.span4{width:218px;} input.span3, textarea.span3, .uneditable-input.span3{width:156px;} input.span2, textarea.span2, .uneditable-input.span2{width:94px;} input.span1, textarea.span1, .uneditable-input.span1{width:32px;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top{position:static;margin-bottom:18px;} .navbar-fixed-top .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .navbar .nav-collapse{clear:left;} .navbar .nav{float:none;margin:0 0 9px;} .navbar .nav>li{float:none;} .navbar .nav>li>a{margin-bottom:2px;} .navbar .nav>.divider-vertical{display:none;} .navbar .nav .nav-header{color:#999999;text-shadow:none;} .navbar .nav>li>a,.navbar .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .navbar .dropdown-menu li+li a{margin-bottom:2px;} .navbar .nav>li>a:hover,.navbar .dropdown-menu a:hover{background-color:#222222;} .navbar .dropdown-menu{position:static;top:auto;left:auto;float:none;display:block;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .navbar .dropdown-menu:before,.navbar .dropdown-menu:after{display:none;} .navbar .dropdown-menu .divider{display:none;} .navbar-form,.navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222222;border-bottom:1px solid #222222;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);} .navbar .nav.pull-right{float:none;margin-left:0;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;} .btn-navbar{display:block;} .nav-collapse{overflow:hidden;height:0;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:30px;} .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.564102564%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid > .span12{width:100%;} .row-fluid > .span11{width:91.45299145300001%;} .row-fluid > .span10{width:82.905982906%;} .row-fluid > .span9{width:74.358974359%;} .row-fluid > .span8{width:65.81196581200001%;} .row-fluid > .span7{width:57.264957265%;} .row-fluid > .span6{width:48.717948718%;} .row-fluid > .span5{width:40.170940171000005%;} .row-fluid > .span4{width:31.623931624%;} .row-fluid > .span3{width:23.076923077%;} .row-fluid > .span2{width:14.529914530000001%;} .row-fluid > .span1{width:5.982905983%;} input,textarea,.uneditable-input{margin-left:0;} input.span12, textarea.span12, .uneditable-input.span12{width:1160px;} input.span11, textarea.span11, .uneditable-input.span11{width:1060px;} input.span10, textarea.span10, .uneditable-input.span10{width:960px;} input.span9, textarea.span9, .uneditable-input.span9{width:860px;} input.span8, textarea.span8, .uneditable-input.span8{width:760px;} input.span7, textarea.span7, .uneditable-input.span7{width:660px;} input.span6, textarea.span6, .uneditable-input.span6{width:560px;} input.span5, textarea.span5, .uneditable-input.span5{width:460px;} input.span4, textarea.span4, .uneditable-input.span4{width:360px;} input.span3, textarea.span3, .uneditable-input.span3{width:260px;} input.span2, textarea.span2, .uneditable-input.span2{width:160px;} input.span1, textarea.span1, .uneditable-input.span1{width:60px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;}}
|