httparty 0.16.3 → 0.16.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of httparty might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +6 -5
- data/Changelog.md +6 -0
- data/examples/stream_download.rb +8 -2
- data/lib/httparty.rb +5 -2
- data/lib/httparty/connection_adapter.rb +7 -2
- data/lib/httparty/fragment_with_response.rb +20 -0
- data/lib/httparty/request.rb +2 -1
- data/lib/httparty/request/body.rb +9 -15
- data/lib/httparty/response.rb +9 -0
- data/lib/httparty/version.rb +1 -1
- data/spec/fixtures/example.html +10 -0
- data/spec/fixtures/ssl/generate.sh +1 -1
- data/spec/httparty/fragment_with_response_spec.rb +14 -0
- data/spec/httparty/logger/curl_formatter_spec.rb +1 -1
- data/spec/httparty/request/body_spec.rb +56 -0
- data/spec/httparty/response_spec.rb +9 -0
- data/spec/httparty_spec.rb +18 -12
- data/spec/spec_helper.rb +5 -0
- metadata +7 -4
- data/spec/fixtures/google.html +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8ea06db7242bc4bea719ac28217cb7a03643277
|
4
|
+
data.tar.gz: 3341968702712ab91fc1348f000337afe1bf4047
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfd0717ef9adb117bc7568a35648b0bc295d0f92210696a423c268be80b7ef12d06d84d2d94ed33a24d31367fd03c3fae3cabc6afbc5cc5b0446f15f01feff79
|
7
|
+
data.tar.gz: 853d4aa140b4717e36ae0baeeb6c1ba113567242398abd56a944bcf29543f74e3a0a3430c0f8823b9fe9c00d8a4bdb2c3a3ff53c59cf9263e080ac7002013f4e
|
data/.travis.yml
CHANGED
@@ -2,9 +2,10 @@ language: ruby
|
|
2
2
|
rvm:
|
3
3
|
- 2.0.0
|
4
4
|
- 2.1.10
|
5
|
-
- 2.2.
|
6
|
-
- 2.3.
|
7
|
-
- 2.4.
|
8
|
-
- 2.5.
|
5
|
+
- 2.2.10
|
6
|
+
- 2.3.8
|
7
|
+
- 2.4.5
|
8
|
+
- 2.5.3
|
9
|
+
- 2.6.0
|
9
10
|
bundler_args: --without development
|
10
|
-
before_install: gem install bundler
|
11
|
+
before_install: gem install bundler -v '< 2'
|
data/Changelog.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
|
2
|
+
## 0.16.4
|
3
|
+
* [Add support for Ruby 2.6](https://github.com/jnunemaker/httparty/pull/636)
|
4
|
+
* [Fix a few multipart issues](https://github.com/jnunemaker/httparty/pull/626)
|
5
|
+
* [Improve a memory usage for https requests](https://github.com/jnunemaker/httparty/pull/625)
|
6
|
+
* [Add response code to streamed body](https://github.com/jnunemaker/httparty/pull/588)
|
7
|
+
|
2
8
|
## 0.16.3
|
3
9
|
* [Add Logstash-compatible formatter](https://github.com/jnunemaker/httparty/pull/612)
|
4
10
|
* [Add support for headers specified with symbols](https://github.com/jnunemaker/httparty/pull/622)
|
data/examples/stream_download.rb
CHANGED
@@ -9,8 +9,14 @@ url = "https://cdn.kernel.org/pub/linux/kernel/v4.x/#{filename}"
|
|
9
9
|
|
10
10
|
File.open(filename, "w") do |file|
|
11
11
|
response = HTTParty.get(url, stream_body: true) do |fragment|
|
12
|
-
|
13
|
-
|
12
|
+
if [301, 302].include?(fragment.code)
|
13
|
+
print "skip writing for redirect"
|
14
|
+
elsif fragment.code == 200
|
15
|
+
print "."
|
16
|
+
file.write(fragment)
|
17
|
+
else
|
18
|
+
raise StandardError, "Non-success status code while streaming #{fragment.code}"
|
19
|
+
end
|
14
20
|
end
|
15
21
|
end
|
16
22
|
puts
|
data/lib/httparty.rb
CHANGED
@@ -574,8 +574,11 @@ module HTTParty
|
|
574
574
|
end
|
575
575
|
|
576
576
|
def process_headers(options)
|
577
|
-
if options[:headers]
|
578
|
-
|
577
|
+
if options[:headers]
|
578
|
+
if headers.any?
|
579
|
+
options[:headers] = headers.merge(options[:headers])
|
580
|
+
end
|
581
|
+
|
579
582
|
options[:headers] = Utils.stringify_keys(process_dynamic_headers(options[:headers]))
|
580
583
|
end
|
581
584
|
end
|
@@ -77,6 +77,12 @@ module HTTParty
|
|
77
77
|
new(uri, options).connection
|
78
78
|
end
|
79
79
|
|
80
|
+
def self.default_cert_store
|
81
|
+
@default_cert_store ||= OpenSSL::X509::Store.new.tap do |cert_store|
|
82
|
+
cert_store.set_default_paths
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
80
86
|
attr_reader :uri, :options
|
81
87
|
|
82
88
|
def initialize(uri, options = {})
|
@@ -176,8 +182,7 @@ module HTTParty
|
|
176
182
|
http.cert_store = options[:cert_store]
|
177
183
|
else
|
178
184
|
# Use the default cert store by default, i.e. system ca certs
|
179
|
-
http.cert_store =
|
180
|
-
http.cert_store.set_default_paths
|
185
|
+
http.cert_store = self.class.default_cert_store
|
181
186
|
end
|
182
187
|
else
|
183
188
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module HTTParty
|
4
|
+
# Allow access to http_response and code by delegation on fragment
|
5
|
+
class FragmentWithResponse < SimpleDelegator
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
attr_reader :http_response
|
9
|
+
|
10
|
+
def code
|
11
|
+
@http_response.code.to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(fragment, http_response)
|
15
|
+
@fragment = fragment
|
16
|
+
@http_response = http_response
|
17
|
+
super fragment
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/httparty/request.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'erb'
|
2
2
|
require 'httparty/request/body'
|
3
|
+
require 'httparty/fragment_with_response'
|
3
4
|
|
4
5
|
module HTTParty
|
5
6
|
class Request #:nodoc:
|
@@ -148,7 +149,7 @@ module HTTParty
|
|
148
149
|
|
149
150
|
http_response.read_body do |fragment|
|
150
151
|
chunks << fragment unless options[:stream_body]
|
151
|
-
block.call(fragment)
|
152
|
+
block.call FragmentWithResponse.new(fragment, http_response)
|
152
153
|
end
|
153
154
|
|
154
155
|
chunked_body = chunks.join
|
@@ -22,7 +22,7 @@ module HTTParty
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def multipart?
|
25
|
-
params.respond_to?(:to_hash) && (force_multipart || has_file?(params
|
25
|
+
params.respond_to?(:to_hash) && (force_multipart || has_file?(params))
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
@@ -46,24 +46,18 @@ module HTTParty
|
|
46
46
|
multipart += "--#{boundary}--\r\n"
|
47
47
|
end
|
48
48
|
|
49
|
-
def has_file?(
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
file?(value)
|
57
|
-
end
|
49
|
+
def has_file?(value)
|
50
|
+
if value.respond_to?(:to_hash)
|
51
|
+
value.to_hash.any? { |_, v| has_file?(v) }
|
52
|
+
elsif value.respond_to?(:to_ary)
|
53
|
+
value.to_ary.any? { |v| has_file?(v) }
|
54
|
+
else
|
55
|
+
file?(value)
|
58
56
|
end
|
59
57
|
end
|
60
58
|
|
61
59
|
def file?(object)
|
62
|
-
object.respond_to?(:path) && object.respond_to?(:read)
|
63
|
-
end
|
64
|
-
|
65
|
-
def includes_hash?(object)
|
66
|
-
object.respond_to?(:to_ary) && object.any? { |e| e.respond_to?(:hash) }
|
60
|
+
object.respond_to?(:path) && object.respond_to?(:read)
|
67
61
|
end
|
68
62
|
|
69
63
|
def normalize_query(query)
|
data/lib/httparty/response.rb
CHANGED
@@ -65,6 +65,15 @@ module HTTParty
|
|
65
65
|
alias_method :multiple_choice?, :multiple_choices?
|
66
66
|
end
|
67
67
|
|
68
|
+
# Support old status codes method from pre 2.6.0 era.
|
69
|
+
if ::RUBY_VERSION >= "2.6.0" && ::RUBY_PLATFORM != "java"
|
70
|
+
alias_method :gateway_time_out?, :gateway_timeout?
|
71
|
+
alias_method :request_entity_too_large?, :payload_too_large?
|
72
|
+
alias_method :request_time_out?, :request_timeout?
|
73
|
+
alias_method :request_uri_too_long?, :uri_too_long?
|
74
|
+
alias_method :requested_range_not_satisfiable?, :range_not_satisfiable?
|
75
|
+
end
|
76
|
+
|
68
77
|
def nil?
|
69
78
|
response.nil? || response.body.nil? || response.body.empty?
|
70
79
|
end
|
data/lib/httparty/version.rb
CHANGED
@@ -12,7 +12,7 @@ mkdir generated
|
|
12
12
|
openssl req -batch -subj '/CN=INSECURE Test Certificate Authority' -newkey rsa:1024 -new -x509 -days 999999 -keyout generated/ca.key -nodes -out generated/ca.crt
|
13
13
|
|
14
14
|
# Create symlinks for ssl_ca_path
|
15
|
-
|
15
|
+
openssl generated
|
16
16
|
|
17
17
|
# Generate the server private key and self-signed certificate
|
18
18
|
openssl req -batch -subj '/CN=localhost' -newkey rsa:1024 -new -x509 -days 999999 -keyout generated/server.key -nodes -out generated/selfsigned.crt
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
RSpec.describe HTTParty::FragmentWithResponse do
|
4
|
+
it "access to fragment" do
|
5
|
+
fragment = HTTParty::FragmentWithResponse.new("chunk", nil)
|
6
|
+
expect(fragment).to eq("chunk")
|
7
|
+
end
|
8
|
+
it "has access to delegators" do
|
9
|
+
response = double(code: '200')
|
10
|
+
fragment = HTTParty::FragmentWithResponse.new("chunk", response)
|
11
|
+
expect(fragment.code).to eq(200)
|
12
|
+
expect(fragment.http_response).to eq response
|
13
|
+
end
|
14
|
+
end
|
@@ -110,7 +110,7 @@ RSpec.describe HTTParty::Logger::CurlFormatter do
|
|
110
110
|
|
111
111
|
subject = described_class.new(logger_double, :info)
|
112
112
|
|
113
|
-
stub_http_response_with("
|
113
|
+
stub_http_response_with("example.html")
|
114
114
|
|
115
115
|
response = HTTParty::Request.new.perform
|
116
116
|
subject.format(response.request, response)
|
@@ -106,4 +106,60 @@ RSpec.describe HTTParty::Request::Body do
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
109
|
+
|
110
|
+
describe '#multipart?' do
|
111
|
+
let(:force_multipart) { false }
|
112
|
+
let(:file) { File.open('spec/fixtures/tiny.gif') }
|
113
|
+
|
114
|
+
subject { described_class.new(params, force_multipart: force_multipart).multipart? }
|
115
|
+
|
116
|
+
context 'when params does not respond to to_hash' do
|
117
|
+
let(:params) { 'name=Bob%20Jones' }
|
118
|
+
|
119
|
+
it { is_expected.to be false }
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when params responds to to_hash' do
|
123
|
+
class HashLike
|
124
|
+
def initialize(hash)
|
125
|
+
@hash = hash
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_hash
|
129
|
+
@hash
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class ArrayLike
|
134
|
+
def initialize(ary)
|
135
|
+
@ary = ary
|
136
|
+
end
|
137
|
+
|
138
|
+
def to_ary
|
139
|
+
@ary
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'when force_multipart is true' do
|
144
|
+
let(:params) { { name: 'Bob Jones' } }
|
145
|
+
let(:force_multipart) { true }
|
146
|
+
|
147
|
+
it { is_expected.to be true }
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'when it does not contain a file' do
|
151
|
+
let(:hash_like_param) { HashLike.new(first: 'Bob', last: ArrayLike.new(['Jones'])) }
|
152
|
+
let(:params) { { name: ArrayLike.new([hash_like_param]) } }
|
153
|
+
|
154
|
+
it { is_expected.to eq false }
|
155
|
+
end
|
156
|
+
|
157
|
+
context 'when it contains file' do
|
158
|
+
let(:hash_like_param) { HashLike.new(first: 'Bob', last: 'Jones', file: ArrayLike.new([file])) }
|
159
|
+
let(:params) { { name: ArrayLike.new([hash_like_param]) } }
|
160
|
+
|
161
|
+
it { is_expected.to be true }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
109
165
|
end
|
@@ -282,6 +282,15 @@ RSpec.describe HTTParty::Response do
|
|
282
282
|
SPECIFIC_CODES[:multiple_choices?] = Net::HTTPMultipleChoices
|
283
283
|
end
|
284
284
|
|
285
|
+
# Ruby 2.6, those status codes have been updated.
|
286
|
+
if RUBY_VERSION >= "2.6.0" && ::RUBY_PLATFORM != "java"
|
287
|
+
SPECIFIC_CODES[:gateway_timeout?] = Net::HTTPGatewayTimeout
|
288
|
+
SPECIFIC_CODES[:payload_too_large?] = Net::HTTPPayloadTooLarge
|
289
|
+
SPECIFIC_CODES[:request_timeout?] = Net::HTTPRequestTimeout
|
290
|
+
SPECIFIC_CODES[:uri_too_long?] = Net::HTTPURITooLong
|
291
|
+
SPECIFIC_CODES[:range_not_satisfiable?] = Net::HTTPRangeNotSatisfiable
|
292
|
+
end
|
293
|
+
|
285
294
|
SPECIFIC_CODES.each do |method, klass|
|
286
295
|
it "responds to #{method}" do
|
287
296
|
net_response = response_mock(klass)
|
data/spec/httparty_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
1
3
|
RSpec.describe HTTParty do
|
2
4
|
before(:each) do
|
3
5
|
@klass = Class.new
|
@@ -192,7 +194,7 @@ RSpec.describe HTTParty do
|
|
192
194
|
end
|
193
195
|
|
194
196
|
it 'adds optional cookies to the optional headers' do
|
195
|
-
expect_headers(baz
|
197
|
+
expect_headers('baz' => 'spax', 'cookie' => 'type=snickerdoodle')
|
196
198
|
@klass.get('', cookies: {type: 'snickerdoodle'}, headers: {baz: 'spax'})
|
197
199
|
end
|
198
200
|
end
|
@@ -215,12 +217,14 @@ RSpec.describe HTTParty do
|
|
215
217
|
end
|
216
218
|
|
217
219
|
context 'when headers passed as symbols' do
|
218
|
-
let(:headers) { { 'foo' => 'application/json', 'bar' => 'example' } }
|
219
|
-
|
220
220
|
it 'converts them to string' do
|
221
|
-
|
222
|
-
|
223
|
-
|
221
|
+
expect_headers('foo' => 'application/json', 'bar' => 'example')
|
222
|
+
headers = { foo: 'application/json', bar: 'example' }
|
223
|
+
@klass.post('http://example.com', headers: headers)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'converts default headers to string' do
|
227
|
+
expect_headers('foo' => 'application/json', 'bar' => 'example')
|
224
228
|
|
225
229
|
@klass.headers(foo: 'application/json')
|
226
230
|
@klass.post('http://example.com', headers: { bar: 'example' })
|
@@ -804,8 +808,8 @@ RSpec.describe HTTParty do
|
|
804
808
|
|
805
809
|
describe "#get" do
|
806
810
|
it "should be able to get html" do
|
807
|
-
stub_http_response_with('
|
808
|
-
expect(HTTParty.get('http://www.
|
811
|
+
stub_http_response_with('example.html')
|
812
|
+
expect(HTTParty.get('http://www.example.com').parsed_response).to eq(file_fixture('example.html'))
|
809
813
|
end
|
810
814
|
|
811
815
|
it "should be able to get chunked html" do
|
@@ -827,6 +831,8 @@ RSpec.describe HTTParty do
|
|
827
831
|
expect(
|
828
832
|
HTTParty.get('http://www.google.com', options) do |fragment|
|
829
833
|
expect(chunks).to include(fragment)
|
834
|
+
expect(fragment.code).to eql 200
|
835
|
+
expect(fragment.http_response).to be
|
830
836
|
end.parsed_response
|
831
837
|
).to eq(nil)
|
832
838
|
end
|
@@ -886,16 +892,16 @@ RSpec.describe HTTParty do
|
|
886
892
|
end
|
887
893
|
|
888
894
|
it "should accept http URIs" do
|
889
|
-
stub_http_response_with('
|
895
|
+
stub_http_response_with('example.html')
|
890
896
|
expect do
|
891
|
-
HTTParty.get('http://
|
897
|
+
HTTParty.get('http://example.com')
|
892
898
|
end.not_to raise_error
|
893
899
|
end
|
894
900
|
|
895
901
|
it "should accept https URIs" do
|
896
|
-
stub_http_response_with('
|
902
|
+
stub_http_response_with('example.html')
|
897
903
|
expect do
|
898
|
-
HTTParty.get('https://
|
904
|
+
HTTParty.get('https://example.com')
|
899
905
|
end.not_to raise_error
|
900
906
|
end
|
901
907
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httparty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.16.
|
4
|
+
version: 0.16.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-02-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_xml
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- lib/httparty/connection_adapter.rb
|
103
103
|
- lib/httparty/cookie_hash.rb
|
104
104
|
- lib/httparty/exceptions.rb
|
105
|
+
- lib/httparty/fragment_with_response.rb
|
105
106
|
- lib/httparty/hash_conversions.rb
|
106
107
|
- lib/httparty/logger/apache_formatter.rb
|
107
108
|
- lib/httparty/logger/curl_formatter.rb
|
@@ -120,7 +121,7 @@ files:
|
|
120
121
|
- script/release
|
121
122
|
- spec/fixtures/delicious.xml
|
122
123
|
- spec/fixtures/empty.xml
|
123
|
-
- spec/fixtures/
|
124
|
+
- spec/fixtures/example.html
|
124
125
|
- spec/fixtures/ssl/generate.sh
|
125
126
|
- spec/fixtures/ssl/generated/bogushost.crt
|
126
127
|
- spec/fixtures/ssl/generated/ca.crt
|
@@ -137,6 +138,7 @@ files:
|
|
137
138
|
- spec/httparty/connection_adapter_spec.rb
|
138
139
|
- spec/httparty/cookie_hash_spec.rb
|
139
140
|
- spec/httparty/exception_spec.rb
|
141
|
+
- spec/httparty/fragment_with_response_spec.rb
|
140
142
|
- spec/httparty/hash_conversions_spec.rb
|
141
143
|
- spec/httparty/logger/apache_formatter_spec.rb
|
142
144
|
- spec/httparty/logger/curl_formatter_spec.rb
|
@@ -196,7 +198,7 @@ test_files:
|
|
196
198
|
- features/supports_timeout_option.feature
|
197
199
|
- spec/fixtures/delicious.xml
|
198
200
|
- spec/fixtures/empty.xml
|
199
|
-
- spec/fixtures/
|
201
|
+
- spec/fixtures/example.html
|
200
202
|
- spec/fixtures/ssl/generate.sh
|
201
203
|
- spec/fixtures/ssl/generated/bogushost.crt
|
202
204
|
- spec/fixtures/ssl/generated/ca.crt
|
@@ -213,6 +215,7 @@ test_files:
|
|
213
215
|
- spec/httparty/connection_adapter_spec.rb
|
214
216
|
- spec/httparty/cookie_hash_spec.rb
|
215
217
|
- spec/httparty/exception_spec.rb
|
218
|
+
- spec/httparty/fragment_with_response_spec.rb
|
216
219
|
- spec/httparty/hash_conversions_spec.rb
|
217
220
|
- spec/httparty/logger/apache_formatter_spec.rb
|
218
221
|
- spec/httparty/logger/curl_formatter_spec.rb
|
data/spec/fixtures/google.html
DELETED
@@ -1,3 +0,0 @@
|
|
1
|
-
<html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><style>body,td,a,p,.h{font-family:arial,sans-serif}.h{color:#36c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}#gbar{height:22px;padding-left:2px}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#gbi,#gbs{background:#fff;left:0;position:absolute;top:24px;visibility:hidden;z-index:1000}#gbi{border:1px solid;border-color:#c9d7f1 #36c #36c #a2bae7;z-index:1001}#guser{padding-bottom:7px !important}#gbar,#guser{font-size:13px;padding-top:1px !important}@media all{.gb1,.gb3{height:22px;margin-right:.73em;vertical-align:top}#gbar{float:left}}.gb2{display:block;padding:.2em .5em}a.gb1,a.gb2,a.gb3{color:#00c !important}.gb2,.gb3{text-decoration:none}a.gb2:hover{background:#36c;color:#fff !important}</style><script>window.google={kEI:"Zuk6ScOkLKHCMrrttckF",kEXPI:"17259,19124,19314",kHL:"en"};
|
2
|
-
google.y={};google.x=function(e,g){google.y[e.id]=[e,g];return false};function sf(){document.f.q.focus()}
|
3
|
-
window.gbar={};(function(){var b=window.gbar,f,h;b.qs=function(a){var c=window.encodeURIComponent&&(document.forms[0].q||"").value;if(c)a.href=a.href.replace(/([?&])q=[^&]*|$/,function(i,g){return(g||"&")+"q="+encodeURIComponent(c)})};function j(a,c){a.visibility=h?"hidden":"visible";a.left=c+"px"}b.tg=function(a){a=a||window.event;var c=0,i,g=window.navExtra,d=document.getElementById("gbi"),e=a.target||a.srcElement;a.cancelBubble=true;if(!f){f=document.createElement(Array.every||window.createPopup?"iframe":"div");f.frameBorder="0";f.src="#";d.parentNode.appendChild(f).id="gbs";if(g)for(i in g)d.insertBefore(g[i],d.firstChild).className="gb2";document.onclick=b.close}if(e.className!="gb3")e=e.parentNode;do c+=e.offsetLeft;while(e=e.offsetParent);j(d.style,c);f.style.width=d.offsetWidth+"px";f.style.height=d.offsetHeight+"px";j(f.style,c);h=!h};b.close=function(a){h&&b.tg(a)}})();</script></head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onload="sf();if(document.images)new Image().src='/images/nav_logo3.png'" topmargin=3 marginheight=3><div id=gbar><nobr><b class=gb1>Web</b> <a href="http://images.google.com/imghp?hl=en&tab=wi" onclick=gbar.qs(this) class=gb1>Images</a> <a href="http://maps.google.com/maps?hl=en&tab=wl" onclick=gbar.qs(this) class=gb1>Maps</a> <a href="http://news.google.com/nwshp?hl=en&tab=wn" onclick=gbar.qs(this) class=gb1>News</a> <a href="http://www.google.com/prdhp?hl=en&tab=wf" onclick=gbar.qs(this) class=gb1>Shopping</a> <a href="http://mail.google.com/mail/?hl=en&tab=wm" class=gb1>Gmail</a> <a href="http://www.google.com/intl/en/options/" onclick="this.blur();gbar.tg(event);return !1" class=gb3><u>more</u> <small>▼</small></a><div id=gbi> <a href="http://video.google.com/?hl=en&tab=wv" onclick=gbar.qs(this) class=gb2>Video</a> <a href="http://groups.google.com/grphp?hl=en&tab=wg" onclick=gbar.qs(this) class=gb2>Groups</a> <a href="http://books.google.com/bkshp?hl=en&tab=wp" onclick=gbar.qs(this) class=gb2>Books</a> <a href="http://scholar.google.com/schhp?hl=en&tab=ws" onclick=gbar.qs(this) class=gb2>Scholar</a> <a href="http://finance.google.com/finance?hl=en&tab=we" onclick=gbar.qs(this) class=gb2>Finance</a> <a href="http://blogsearch.google.com/?hl=en&tab=wb" onclick=gbar.qs(this) class=gb2>Blogs</a> <div class=gb2><div class=gbd></div></div> <a href="http://www.youtube.com/?hl=en&tab=w1" onclick=gbar.qs(this) class=gb2>YouTube</a> <a href="http://www.google.com/calendar/render?hl=en&tab=wc" class=gb2>Calendar</a> <a href="http://picasaweb.google.com/home?hl=en&tab=wq" onclick=gbar.qs(this) class=gb2>Photos</a> <a href="http://docs.google.com/?hl=en&tab=wo" class=gb2>Documents</a> <a href="http://www.google.com/reader/view/?hl=en&tab=wy" class=gb2>Reader</a> <a href="http://sites.google.com/?hl=en&tab=w3" class=gb2>Sites</a> <div class=gb2><div class=gbd></div></div> <a href="http://www.google.com/intl/en/options/" class=gb2>even more »</a></div> </nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div><div align=right id=guser style="font-size:84%;padding:0 0 4px" width=100%><nobr><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNFA18XPfgb7dKnXfKz7x7g1GDH1tg">iGoogle</a> | <a href="https://www.google.com/accounts/Login?continue=http://www.google.com/&hl=en">Sign in</a></nobr></div><center><br clear=all id=lgpd><img alt="Google" height=110 src="/intl/en_ALL/images/logo.gif" width=276><br><br><form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top><td width=25%> </td><td align=center nowrap><input name=hl type=hidden value=en><input type=hidden name=ie value="ISO-8859-1"><input autocomplete="off" maxlength=2048 name=q size=55 title="Google Search" value=""><br><input name=btnG type=submit value="Google Search"><input name=btnI type=submit value="I'm Feeling Lucky"></td><td nowrap width=25%><font size=-2> <a href=/advanced_search?hl=en>Advanced Search</a><br> <a href=/preferences?hl=en>Preferences</a><br> <a href=/language_tools?hl=en>Language Tools</a></font></td></tr></table></form><br><br><font size=-1><a href="/intl/en/ads/">Advertising Programs</a> - <a href="/services/">Business Solutions</a> - <a href="/intl/en/about.html">About Google</a></font><p><font size=-2>©2008 - <a href="/intl/en/privacy.html">Privacy</a></font></p></center></body><script>if(google.y)google.y.first=[];window.setTimeout(function(){var xjs=document.createElement('script');xjs.src='/extern_js/f/CgJlbhICdXMgACswCjgMLCswDjgCLCswGDgDLA/8MIofMT_4o8.js';document.getElementsByTagName('head')[0].appendChild(xjs)},0);google.y.first.push(function(){google.ac.i(document.f,document.f.q,'','')})</script></html>
|