httparty 0.13.7 → 0.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +18 -0
  3. data/.github/dependabot.yml +6 -0
  4. data/.github/workflows/ci.yml +24 -0
  5. data/.gitignore +3 -0
  6. data/.rubocop_todo.yml +1 -1
  7. data/Changelog.md +624 -0
  8. data/Gemfile +11 -3
  9. data/Guardfile +3 -2
  10. data/README.md +18 -17
  11. data/bin/httparty +3 -1
  12. data/docs/README.md +223 -0
  13. data/examples/README.md +35 -12
  14. data/examples/aaws.rb +7 -3
  15. data/examples/body_stream.rb +14 -0
  16. data/examples/crack.rb +1 -1
  17. data/examples/custom_parsers.rb +5 -1
  18. data/examples/delicious.rb +4 -4
  19. data/examples/headers_and_user_agents.rb +7 -3
  20. data/examples/idn.rb +10 -0
  21. data/examples/logging.rb +4 -4
  22. data/examples/microsoft_graph.rb +52 -0
  23. data/examples/multipart.rb +35 -0
  24. data/examples/party_foul_mode.rb +90 -0
  25. data/examples/peer_cert.rb +9 -0
  26. data/examples/stackexchange.rb +1 -1
  27. data/examples/stream_download.rb +26 -0
  28. data/examples/tripit_sign_in.rb +17 -6
  29. data/examples/twitter.rb +2 -2
  30. data/examples/whoismyrep.rb +1 -1
  31. data/httparty.gemspec +9 -5
  32. data/lib/httparty/connection_adapter.rb +71 -24
  33. data/lib/httparty/cookie_hash.rb +10 -8
  34. data/lib/httparty/decompressor.rb +102 -0
  35. data/lib/httparty/exceptions.rb +42 -5
  36. data/lib/httparty/hash_conversions.rb +30 -8
  37. data/lib/httparty/headers_processor.rb +32 -0
  38. data/lib/httparty/logger/apache_formatter.rb +31 -6
  39. data/lib/httparty/logger/curl_formatter.rb +68 -23
  40. data/lib/httparty/logger/logger.rb +5 -1
  41. data/lib/httparty/logger/logstash_formatter.rb +62 -0
  42. data/lib/httparty/module_inheritable_attributes.rb +9 -9
  43. data/lib/httparty/net_digest_auth.rb +23 -21
  44. data/lib/httparty/parser.rb +28 -14
  45. data/lib/httparty/request/body.rb +125 -0
  46. data/lib/httparty/request/multipart_boundary.rb +13 -0
  47. data/lib/httparty/request/streaming_multipart_body.rb +190 -0
  48. data/lib/httparty/request.rb +224 -122
  49. data/lib/httparty/response/headers.rb +23 -19
  50. data/lib/httparty/response.rb +92 -13
  51. data/lib/httparty/response_fragment.rb +21 -0
  52. data/lib/httparty/text_encoder.rb +72 -0
  53. data/lib/httparty/utils.rb +13 -0
  54. data/lib/httparty/version.rb +3 -1
  55. data/lib/httparty.rb +118 -42
  56. data/script/release +4 -4
  57. data/website/css/common.css +1 -1
  58. metadata +50 -112
  59. data/.simplecov +0 -1
  60. data/.travis.yml +0 -7
  61. data/History +0 -390
  62. data/features/basic_authentication.feature +0 -20
  63. data/features/command_line.feature +0 -95
  64. data/features/deals_with_http_error_codes.feature +0 -26
  65. data/features/digest_authentication.feature +0 -30
  66. data/features/handles_compressed_responses.feature +0 -27
  67. data/features/handles_multiple_formats.feature +0 -57
  68. data/features/steps/env.rb +0 -27
  69. data/features/steps/httparty_response_steps.rb +0 -52
  70. data/features/steps/httparty_steps.rb +0 -43
  71. data/features/steps/mongrel_helper.rb +0 -127
  72. data/features/steps/remote_service_steps.rb +0 -90
  73. data/features/supports_read_timeout_option.feature +0 -13
  74. data/features/supports_redirection.feature +0 -22
  75. data/features/supports_timeout_option.feature +0 -13
  76. data/spec/fixtures/delicious.xml +0 -23
  77. data/spec/fixtures/empty.xml +0 -0
  78. data/spec/fixtures/google.html +0 -3
  79. data/spec/fixtures/ssl/generate.sh +0 -29
  80. data/spec/fixtures/ssl/generated/1fe462c2.0 +0 -16
  81. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  82. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  83. data/spec/fixtures/ssl/generated/ca.key +0 -15
  84. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  85. data/spec/fixtures/ssl/generated/server.crt +0 -13
  86. data/spec/fixtures/ssl/generated/server.key +0 -15
  87. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  88. data/spec/fixtures/twitter.csv +0 -2
  89. data/spec/fixtures/twitter.json +0 -1
  90. data/spec/fixtures/twitter.xml +0 -403
  91. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  92. data/spec/httparty/connection_adapter_spec.rb +0 -468
  93. data/spec/httparty/cookie_hash_spec.rb +0 -83
  94. data/spec/httparty/exception_spec.rb +0 -38
  95. data/spec/httparty/hash_conversions_spec.rb +0 -41
  96. data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
  97. data/spec/httparty/logger/curl_formatter_spec.rb +0 -18
  98. data/spec/httparty/logger/logger_spec.rb +0 -38
  99. data/spec/httparty/net_digest_auth_spec.rb +0 -230
  100. data/spec/httparty/parser_spec.rb +0 -173
  101. data/spec/httparty/request_spec.rb +0 -1073
  102. data/spec/httparty/response_spec.rb +0 -241
  103. data/spec/httparty/ssl_spec.rb +0 -74
  104. data/spec/httparty_spec.rb +0 -850
  105. data/spec/spec_helper.rb +0 -59
  106. data/spec/support/ssl_test_helper.rb +0 -47
  107. data/spec/support/ssl_test_server.rb +0 -80
  108. data/spec/support/stub_response.rb +0 -49
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module HTTParty
6
+ # Allow access to http_response and code by delegation on fragment
7
+ class ResponseFragment < SimpleDelegator
8
+ attr_reader :http_response, :connection
9
+
10
+ def code
11
+ @http_response.code.to_i
12
+ end
13
+
14
+ def initialize(fragment, http_response, connection)
15
+ @fragment = fragment
16
+ @http_response = http_response
17
+ @connection = connection
18
+ super fragment
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ class TextEncoder
5
+ attr_reader :text, :content_type, :assume_utf16_is_big_endian
6
+
7
+ def initialize(text, assume_utf16_is_big_endian: true, content_type: nil)
8
+ @text = +text
9
+ @content_type = content_type
10
+ @assume_utf16_is_big_endian = assume_utf16_is_big_endian
11
+ end
12
+
13
+ def call
14
+ if can_encode?
15
+ encoded_text
16
+ else
17
+ text
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def can_encode?
24
+ ''.respond_to?(:encoding) && charset
25
+ end
26
+
27
+ def encoded_text
28
+ if 'utf-16'.casecmp(charset) == 0
29
+ encode_utf_16
30
+ else
31
+ encode_with_ruby_encoding
32
+ end
33
+ end
34
+
35
+ def encode_utf_16
36
+ if text.bytesize >= 2
37
+ if text.getbyte(0) == 0xFF && text.getbyte(1) == 0xFE
38
+ return text.force_encoding('UTF-16LE')
39
+ elsif text.getbyte(0) == 0xFE && text.getbyte(1) == 0xFF
40
+ return text.force_encoding('UTF-16BE')
41
+ end
42
+ end
43
+
44
+ if assume_utf16_is_big_endian # option
45
+ text.force_encoding('UTF-16BE')
46
+ else
47
+ text.force_encoding('UTF-16LE')
48
+ end
49
+ end
50
+
51
+ def encode_with_ruby_encoding
52
+ # NOTE: This will raise an argument error if the
53
+ # charset does not exist
54
+ encoding = Encoding.find(charset)
55
+ text.force_encoding(encoding.to_s)
56
+ rescue ArgumentError
57
+ text
58
+ end
59
+
60
+ def charset
61
+ return nil if content_type.nil?
62
+
63
+ if (matchdata = content_type.match(/;\s*charset\s*=\s*([^=,;"\s]+)/i))
64
+ return matchdata.captures.first
65
+ end
66
+
67
+ if (matchdata = content_type.match(/;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i))
68
+ return matchdata.captures.first.gsub(/\\(.)/, '\1')
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ module Utils
5
+ def self.stringify_keys(hash)
6
+ return hash.transform_keys(&:to_s) if hash.respond_to?(:transform_keys)
7
+
8
+ hash.each_with_object({}) do |(key, value), new_hash|
9
+ new_hash[key.to_s] = value
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTTParty
2
- VERSION = "0.13.7"
4
+ VERSION = '0.24.2'
3
5
  end
data/lib/httparty.rb CHANGED
@@ -1,12 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
  require 'net/http'
3
- require 'net/https'
4
5
  require 'uri'
5
- require 'zlib'
6
- require 'multi_xml'
7
- require 'json'
8
- require 'csv'
9
- require 'erb'
10
6
 
11
7
  require 'httparty/module_inheritable_attributes'
12
8
  require 'httparty/cookie_hash'
@@ -14,6 +10,11 @@ require 'httparty/net_digest_auth'
14
10
  require 'httparty/version'
15
11
  require 'httparty/connection_adapter'
16
12
  require 'httparty/logger/logger'
13
+ require 'httparty/request/body'
14
+ require 'httparty/response_fragment'
15
+ require 'httparty/decompressor'
16
+ require 'httparty/text_encoder'
17
+ require 'httparty/headers_processor'
17
18
 
18
19
  # @see HTTParty::ClassMethods
19
20
  module HTTParty
@@ -22,8 +23,8 @@ module HTTParty
22
23
  base.send :include, ModuleInheritableAttributes
23
24
  base.send(:mattr_inheritable, :default_options)
24
25
  base.send(:mattr_inheritable, :default_cookies)
25
- base.instance_variable_set("@default_options", {})
26
- base.instance_variable_set("@default_cookies", CookieHash.new)
26
+ base.instance_variable_set(:@default_options, {})
27
+ base.instance_variable_set(:@default_cookies, CookieHash.new)
27
28
  end
28
29
 
29
30
  # == Common Request Options
@@ -37,10 +38,11 @@ module HTTParty
37
38
  # [:+limit+:] Maximum number of redirects to follow. Takes precedences over :+no_follow+.
38
39
  # [:+query+:] Query string, or an object that responds to #to_hash representing it. Normalized according to the same rules as :+body+. If you specify this on a POST, you must use an object which responds to #to_hash. See also HTTParty::ClassMethods.default_params.
39
40
  # [:+timeout+:] Timeout for opening connection and reading data.
40
- # [:+local_host:] Local address to bind to before connecting.
41
- # [:+local_port:] Local port to bind to before connecting.
42
- # [:+body_steam:] Allow streaming to a REST server to specify a body_stream.
43
- # [:+stream_body:] Allow for streaming large files without loading them into memory.
41
+ # [:+local_host+:] Local address to bind to before connecting.
42
+ # [:+local_port+:] Local port to bind to before connecting.
43
+ # [:+body_stream+:] Allow streaming to a REST server to specify a body_stream.
44
+ # [:+stream_body+:] When downloading with a block, avoids accumulating the response in memory. When uploading files, streams the request body to reduce memory usage (opt-in).
45
+ # [:+multipart+:] Force content-type to be multipart
44
46
  #
45
47
  # There are also another set of options with names corresponding to various class methods. The methods in question are those that let you set a class-wide default, and the options override the defaults on a request-by-request basis. Those options are:
46
48
  # * :+base_uri+: see HTTParty::ClassMethods.base_uri.
@@ -60,6 +62,16 @@ module HTTParty
60
62
  # * :+ssl_ca_path+: see HTTParty::ClassMethods.ssl_ca_path.
61
63
 
62
64
  module ClassMethods
65
+ # Turns on or off the foul option.
66
+ #
67
+ # class Foo
68
+ # include HTTParty
69
+ # foul true
70
+ # end
71
+ def foul(bool)
72
+ default_options[:foul] = bool
73
+ end
74
+
63
75
  # Turns on logging
64
76
  #
65
77
  # class Foo
@@ -72,6 +84,16 @@ module HTTParty
72
84
  default_options[:log_format] = format
73
85
  end
74
86
 
87
+ # Raises HTTParty::ResponseError if response's code matches this statuses
88
+ #
89
+ # class Foo
90
+ # include HTTParty
91
+ # raise_on [404, 500, '5[0-9]*']
92
+ # end
93
+ def raise_on(codes = [])
94
+ default_options[:raise_on] = *codes
95
+ end
96
+
75
97
  # Allows setting http proxy information to be used
76
98
  #
77
99
  # class Foo
@@ -118,7 +140,7 @@ module HTTParty
118
140
  end
119
141
 
120
142
  # Do not send rails style query strings.
121
- # Specically, don't use bracket notation when sending an array
143
+ # Specifically, don't use bracket notation when sending an array
122
144
  #
123
145
  # For a query:
124
146
  # get '/', query: {selected_ids: [1,2,3]}
@@ -147,7 +169,7 @@ module HTTParty
147
169
  # default_params api_key: 'secret', another: 'foo'
148
170
  # end
149
171
  def default_params(h = {})
150
- raise ArgumentError, 'Default params must an object which respond to #to_hash' unless h.respond_to?(:to_hash)
172
+ raise ArgumentError, 'Default params must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
151
173
  default_options[:default_params] ||= {}
152
174
  default_options[:default_params].merge!(h)
153
175
  end
@@ -159,9 +181,9 @@ module HTTParty
159
181
  # include HTTParty
160
182
  # default_timeout 10
161
183
  # end
162
- def default_timeout(t)
163
- raise ArgumentError, 'Timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float))
164
- default_options[:timeout] = t
184
+ def default_timeout(value)
185
+ validate_timeout_argument(__method__, value)
186
+ default_options[:timeout] = value
165
187
  end
166
188
 
167
189
  # Allows setting a default open_timeout for all HTTP calls in seconds
@@ -170,9 +192,9 @@ module HTTParty
170
192
  # include HTTParty
171
193
  # open_timeout 10
172
194
  # end
173
- def open_timeout(t)
174
- raise ArgumentError, 'open_timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float))
175
- default_options[:open_timeout] = t
195
+ def open_timeout(value)
196
+ validate_timeout_argument(__method__, value)
197
+ default_options[:open_timeout] = value
176
198
  end
177
199
 
178
200
  # Allows setting a default read_timeout for all HTTP calls in seconds
@@ -181,11 +203,24 @@ module HTTParty
181
203
  # include HTTParty
182
204
  # read_timeout 10
183
205
  # end
184
- def read_timeout(t)
185
- raise ArgumentError, 'read_timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float))
186
- default_options[:read_timeout] = t
206
+ def read_timeout(value)
207
+ validate_timeout_argument(__method__, value)
208
+ default_options[:read_timeout] = value
187
209
  end
188
210
 
211
+ # Allows setting a default write_timeout for all HTTP calls in seconds
212
+ # Supported by Ruby > 2.6.0
213
+ #
214
+ # class Foo
215
+ # include HTTParty
216
+ # write_timeout 10
217
+ # end
218
+ def write_timeout(value)
219
+ validate_timeout_argument(__method__, value)
220
+ default_options[:write_timeout] = value
221
+ end
222
+
223
+
189
224
  # Set an output stream for debugging, defaults to $stderr.
190
225
  # The output stream is passed on to Net::HTTP#set_debug_output.
191
226
  #
@@ -203,14 +238,18 @@ module HTTParty
203
238
  # include HTTParty
204
239
  # headers 'Accept' => 'text/html'
205
240
  # end
206
- def headers(h = {})
207
- raise ArgumentError, 'Headers must an object which responds to #to_hash' unless h.respond_to?(:to_hash)
208
- default_options[:headers] ||= {}
209
- default_options[:headers].merge!(h.to_hash)
241
+ def headers(h = nil)
242
+ if h
243
+ raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
244
+ default_options[:headers] ||= {}
245
+ default_options[:headers].merge!(h.to_hash)
246
+ else
247
+ default_options[:headers] || {}
248
+ end
210
249
  end
211
250
 
212
251
  def cookies(h = {})
213
- raise ArgumentError, 'Cookies must an object which respond to #to_hash' unless h.respond_to?(:to_hash)
252
+ raise ArgumentError, 'Cookies must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
214
253
  default_cookies.add_cookies(h)
215
254
  end
216
255
 
@@ -367,6 +406,22 @@ module HTTParty
367
406
  default_options[:ssl_version] = version
368
407
  end
369
408
 
409
+ # Deactivate automatic decompression of the response body.
410
+ # This will require you to explicitly handle body decompression
411
+ # by inspecting the Content-Encoding response header.
412
+ #
413
+ # Refer to docs/README.md "HTTP Compression" section for
414
+ # further details.
415
+ #
416
+ # @example
417
+ # class Foo
418
+ # include HTTParty
419
+ # skip_decompression
420
+ # end
421
+ def skip_decompression(value = true)
422
+ default_options[:skip_decompression] = !!value
423
+ end
424
+
370
425
  # Allows setting of SSL ciphers to use. This only works in Ruby 1.9+.
371
426
  # You can get a list of valid specific ciphers from OpenSSL::Cipher.ciphers.
372
427
  # You also can specify a cipher suite here, listed here at openssl.org:
@@ -486,7 +541,7 @@ module HTTParty
486
541
  # Foo.post('http://foo.com/resources', body: {bar: 'baz'})
487
542
  #
488
543
  # # Simple post with full url using :query option,
489
- # # which gets set as form data on the request.
544
+ # # which appends the parameters to the URI.
490
545
  # Foo.post('http://foo.com/resources', query: {bar: 'baz'})
491
546
  def post(path, options = {}, &block)
492
547
  perform_request Net::HTTP::Post, path, options, &block
@@ -528,38 +583,54 @@ module HTTParty
528
583
  perform_request Net::HTTP::Options, path, options, &block
529
584
  end
530
585
 
586
+ # Perform a MKCOL request to a path
587
+ def mkcol(path, options = {}, &block)
588
+ perform_request Net::HTTP::Mkcol, path, options, &block
589
+ end
590
+
591
+ def lock(path, options = {}, &block)
592
+ perform_request Net::HTTP::Lock, path, options, &block
593
+ end
594
+
595
+ def unlock(path, options = {}, &block)
596
+ perform_request Net::HTTP::Unlock, path, options, &block
597
+ end
598
+
599
+ def build_request(http_method, path, options = {})
600
+ options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options)
601
+ HeadersProcessor.new(headers, options).call
602
+ process_cookies(options)
603
+ Request.new(http_method, path, options)
604
+ end
605
+
531
606
  attr_reader :default_options
532
607
 
533
608
  private
534
609
 
610
+ def validate_timeout_argument(timeout_type, value)
611
+ raise ArgumentError, "#{ timeout_type } must be an integer or float" unless value && (value.is_a?(Integer) || value.is_a?(Float))
612
+ end
613
+
535
614
  def ensure_method_maintained_across_redirects(options)
536
- unless options.has_key? :maintain_method_across_redirects
615
+ unless options.key?(:maintain_method_across_redirects)
537
616
  options[:maintain_method_across_redirects] = true
538
617
  end
539
618
  end
540
619
 
541
620
  def perform_request(http_method, path, options, &block) #:nodoc:
542
- options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options)
543
- process_headers(options)
544
- process_cookies(options)
545
- Request.new(http_method, path, options).perform(&block)
546
- end
547
-
548
- def process_headers(options)
549
- if options[:headers] && headers.any?
550
- options[:headers] = headers.merge(options[:headers])
551
- end
621
+ build_request(http_method, path, options).perform(&block)
552
622
  end
553
623
 
554
624
  def process_cookies(options) #:nodoc:
555
625
  return unless options[:cookies] || default_cookies.any?
556
626
  options[:headers] ||= headers.dup
557
- options[:headers]["cookie"] = cookies.merge(options.delete(:cookies) || {}).to_cookie_string
627
+ options[:headers]['cookie'] = cookies.merge(options.delete(:cookies) || {}).to_cookie_string
558
628
  end
559
629
 
560
630
  def validate_format
561
631
  if format && parser.respond_to?(:supports_format?) && !parser.supports_format?(format)
562
- raise UnsupportedFormat, "'#{format.inspect}' Must be one of: #{parser.supported_formats.map(&:to_s).sort.join(', ')}"
632
+ supported_format_names = parser.supported_formats.map(&:to_s).sort.join(', ')
633
+ raise UnsupportedFormat, "'#{format.inspect}' Must be one of: #{supported_format_names}"
563
634
  end
564
635
  end
565
636
  end
@@ -614,9 +685,14 @@ module HTTParty
614
685
  def self.options(*args, &block)
615
686
  Basement.options(*args, &block)
616
687
  end
688
+
689
+ def self.build_request(*args, &block)
690
+ Basement.build_request(*args, &block)
691
+ end
617
692
  end
618
693
 
619
694
  require 'httparty/hash_conversions'
695
+ require 'httparty/utils'
620
696
  require 'httparty/exceptions'
621
697
  require 'httparty/parser'
622
698
  require 'httparty/request'
data/script/release CHANGED
@@ -18,9 +18,9 @@ gem_name=httparty
18
18
  rm -rf $gem_name-*.gem
19
19
  gem build -q $gem_name.gemspec
20
20
 
21
- # Make sure we're on the master branch.
22
- (git branch | grep -q '* master') || {
23
- echo "Only release from the master branch."
21
+ # Make sure we're on the main branch.
22
+ (git branch | grep -q '* main') || {
23
+ echo "Only release from the main branch."
24
24
  exit 1
25
25
  }
26
26
 
@@ -39,4 +39,4 @@ git fetch -t origin
39
39
 
40
40
  # Tag it and bag it.
41
41
  gem push $gem_name-*.gem && git tag "$tag" &&
42
- git push origin master && git push origin "$tag"
42
+ git push origin main && git push origin "$tag"
@@ -8,7 +8,7 @@
8
8
  body {font:13px arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}select, input, textarea {font:99% arial,helvetica,clean,sans-serif;}pre, code {font:115% monospace;*font-size:100%;}body * {line-height:1.22em;}
9
9
  body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}/*ol,ul {list-style:none;}*/caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;}
10
10
  /* end of yahoo reset and fonts */
11
-
11
+
12
12
  body {color:#333; background:#4b1a1a; line-height:1.3;}
13
13
  p {margin:0 0 20px;}
14
14
  a {color:#4b1a1a;}