httplog 0.2.4 → 0.2.5
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.
- checksums.yaml +15 -0
- data/README.md +8 -0
- data/lib/httplog/adapters/ethon.rb +10 -3
- data/lib/httplog/adapters/excon.rb +21 -8
- data/lib/httplog/adapters/httpclient.rb +18 -10
- data/lib/httplog/adapters/net_http.rb +6 -3
- data/lib/httplog/adapters/patron.rb +13 -7
- data/lib/httplog/http_log.rb +24 -11
- data/lib/httplog/version.rb +1 -1
- metadata +19 -27
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MzdhNzViMDJmOTIxNmQ2NWQ2YmM3NjU2MmE2NDI3NGQ1MTVjNzdmYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OWU5NjJjZTY1OTRmYjNlZDNmZWVmZWVmMGJlNGZlNjYzMGQxYzM4OQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NWJjNTFmYzk4YTM2ZjIxMjg0ZTM4NjQyZDJlY2NmZWFlMGIyZDZiODE5YTVk
|
10
|
+
ZTk1Njc4NWIxYjczMzgwNDBiOTM5ZTBiNTVmZTdhM2NkNDNhMmVhYzQ4NmI1
|
11
|
+
YjBlMGVhNjQ4ZmZkNjI0N2Q5MTQxY2MzODY3NTdhZWI5OThlNmE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MWIxNTdiNzMyNGQ5YWIxOGNhMjg2ZGZmMzIyOTlmYWU2MTA2ODE2YTU0Yzlh
|
14
|
+
MWQ3MTQ4NmQ5OTlkZjdlNTIyNWQ4MGNlMzY5MWM5Y2U5ZTJlNzk4ZmYyNDZi
|
15
|
+
NGRiZGRmYzY4ZTk3NTg0Y2QxZDRlMWQwMWU5ODQxNzcyYTJiZWY=
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
## httplog
|
2
2
|
|
3
|
+
[](http://badge.fury.io/rb/httplog)
|
4
|
+
|
3
5
|
Log outgoing HTTP requests made from your application.
|
4
6
|
See the [blog post](http://trusche.github.com/blog/2011/09/29/logging-outgoing-http-requests/)
|
5
7
|
for more details.
|
@@ -50,6 +52,11 @@ You can override the following default options:
|
|
50
52
|
HttpLog.options[:log_benchmark] = true
|
51
53
|
HttpLog.options[:compact_log] = false # setting this to true will make all "log_*" options redundant
|
52
54
|
|
55
|
+
# only log requests made to specified hosts (URLs)
|
56
|
+
HttpLog.options[:url_whitelist_pattern] = /.*/
|
57
|
+
# overrides whitelist
|
58
|
+
HttpLog.options[:url_blacklist_pattern] = nil
|
59
|
+
|
53
60
|
So if you want to use this in a Rails app:
|
54
61
|
|
55
62
|
# config/initializers/httplog.rb
|
@@ -124,3 +131,4 @@ Thanks to these fine folks for contributing pull requests:
|
|
124
131
|
* [Eric Cohen](https://github.com/eirc)
|
125
132
|
* [Nikos Dimitrakopoulos](https://github.com/nikosd)
|
126
133
|
* [Marcos Hack](https://github.com/marcoshack)
|
134
|
+
* [Andrew Hammond](https://github.com/andrhamm)
|
@@ -2,12 +2,17 @@ if defined?(Ethon)
|
|
2
2
|
module Ethon
|
3
3
|
class Easy
|
4
4
|
|
5
|
+
attr_accessor :action_name
|
6
|
+
|
5
7
|
module Http
|
6
8
|
alias_method :orig_http_request, :http_request
|
7
9
|
def http_request(url, action_name, options = {})
|
8
|
-
|
9
|
-
HttpLog.
|
10
|
-
|
10
|
+
@action_name = action_name # remember this for compact logging
|
11
|
+
if HttpLog.url_approved?(url)
|
12
|
+
HttpLog.log_request(action_name, url)
|
13
|
+
HttpLog.log_headers(options[:headers])
|
14
|
+
HttpLog.log_data(options[:body]) if action_name == :post
|
15
|
+
end
|
11
16
|
|
12
17
|
orig_http_request(url, action_name, options)
|
13
18
|
end
|
@@ -16,6 +21,8 @@ if defined?(Ethon)
|
|
16
21
|
module Operations
|
17
22
|
alias_method :orig_perform, :perform
|
18
23
|
def perform
|
24
|
+
return orig_perform unless HttpLog.url_approved?(url)
|
25
|
+
|
19
26
|
response_code = nil
|
20
27
|
bm = Benchmark.realtime do
|
21
28
|
reponse_code = orig_perform
|
@@ -19,25 +19,38 @@ if defined?(Excon)
|
|
19
19
|
|
20
20
|
alias_method :orig_request, :request
|
21
21
|
def request(params, &block)
|
22
|
-
|
22
|
+
result = nil
|
23
23
|
bm = Benchmark.realtime do
|
24
|
-
|
24
|
+
result = orig_request(params, &block)
|
25
25
|
end
|
26
|
-
|
27
|
-
|
28
|
-
datum
|
26
|
+
|
27
|
+
datum = @data.merge(params)
|
28
|
+
datum[:headers] = @data[:headers].merge(datum[:headers] || {})
|
29
|
+
url = _httplog_url(datum)
|
30
|
+
|
31
|
+
if HttpLog.url_approved?(url)
|
32
|
+
HttpLog.log_compact(datum[:method], url, datum[:status] || result.status, bm)
|
33
|
+
HttpLog.log_benchmark(bm)
|
34
|
+
end
|
35
|
+
result
|
29
36
|
end
|
30
37
|
|
31
38
|
alias_method :orig_request_call, :request_call
|
32
39
|
def request_call(datum)
|
33
|
-
|
34
|
-
|
35
|
-
HttpLog.
|
40
|
+
url = _httplog_url(datum)
|
41
|
+
|
42
|
+
if HttpLog.url_approved?(url)
|
43
|
+
HttpLog.log_request(datum[:method], _httplog_url(datum))
|
44
|
+
HttpLog.log_headers(datum[:headers])
|
45
|
+
HttpLog.log_data(datum[:body]) if datum[:method] == :post
|
46
|
+
end
|
36
47
|
orig_request_call(datum)
|
37
48
|
end
|
38
49
|
|
39
50
|
alias_method :orig_response, :response
|
40
51
|
def response(datum={})
|
52
|
+
return orig_response(datum) unless HttpLog.url_approved?(_httplog_url(datum))
|
53
|
+
|
41
54
|
bm = Benchmark.realtime do
|
42
55
|
datum = orig_response(datum)
|
43
56
|
end
|
@@ -4,9 +4,13 @@ if defined?(::HTTPClient)
|
|
4
4
|
alias_method :orig_do_get_block, :do_get_block
|
5
5
|
|
6
6
|
def do_get_block(req, proxy, conn, &block)
|
7
|
-
HttpLog.
|
8
|
-
|
9
|
-
|
7
|
+
log_enabled = HttpLog.url_approved?(req.header.request_uri)
|
8
|
+
|
9
|
+
if log_enabled
|
10
|
+
HttpLog.log_request(req.header.request_method, req.header.request_uri)
|
11
|
+
HttpLog.log_headers(req.headers)
|
12
|
+
HttpLog.log_data(req.body) if req.header.request_method == "POST"
|
13
|
+
end
|
10
14
|
|
11
15
|
retryable_response = nil
|
12
16
|
bm = Benchmark.realtime do
|
@@ -17,12 +21,14 @@ if defined?(::HTTPClient)
|
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
if log_enabled
|
25
|
+
res = conn.pop
|
26
|
+
HttpLog.log_compact(req.header.request_method, req.header.request_uri, res.status_code, bm)
|
27
|
+
HttpLog.log_status(res.status_code)
|
28
|
+
HttpLog.log_benchmark(bm)
|
29
|
+
HttpLog.log_body(res.body)
|
30
|
+
conn.push(res)
|
31
|
+
end
|
26
32
|
|
27
33
|
raise retryable_response if retryable_response != nil
|
28
34
|
end
|
@@ -30,7 +36,9 @@ if defined?(::HTTPClient)
|
|
30
36
|
class Session
|
31
37
|
alias_method :orig_create_socket, :create_socket
|
32
38
|
def create_socket(site)
|
33
|
-
HttpLog.
|
39
|
+
if HttpLog.url_approved?("#{site.host}:#{site.port}")
|
40
|
+
HttpLog.log_connection(site.host, site.port)
|
41
|
+
end
|
34
42
|
orig_create_socket(site)
|
35
43
|
end
|
36
44
|
end
|
@@ -7,7 +7,9 @@ module Net
|
|
7
7
|
|
8
8
|
url = "http://#{@address}:#{@port}#{req.path}"
|
9
9
|
|
10
|
-
|
10
|
+
log_enabled = HttpLog.url_approved?(url)
|
11
|
+
|
12
|
+
if log_enabled && started?
|
11
13
|
HttpLog.log_request(req.method, url)
|
12
14
|
HttpLog.log_headers(req.each_header.collect)
|
13
15
|
# A bit convoluted becase post_form uses form_data= to assign the data, so
|
@@ -19,7 +21,7 @@ module Net
|
|
19
21
|
@response = orig_request(req, body, &block)
|
20
22
|
end
|
21
23
|
|
22
|
-
if started?
|
24
|
+
if log_enabled && started?
|
23
25
|
HttpLog.log_compact(req.method, url, @response.code, bm)
|
24
26
|
HttpLog.log_status(@response.code)
|
25
27
|
HttpLog.log_benchmark(bm)
|
@@ -31,7 +33,8 @@ module Net
|
|
31
33
|
end
|
32
34
|
|
33
35
|
def connect
|
34
|
-
HttpLog.log_connection(@address, @port)
|
36
|
+
HttpLog.log_connection(@address, @port) if !started? && HttpLog.url_approved?("#{@address}:#{@port}")
|
37
|
+
|
35
38
|
orig_connect
|
36
39
|
end
|
37
40
|
end
|
@@ -3,18 +3,24 @@ if defined?(Patron)
|
|
3
3
|
class Session
|
4
4
|
alias_method :orig_request, :request
|
5
5
|
def request(action_name, url, headers, options = {})
|
6
|
-
HttpLog.
|
7
|
-
|
8
|
-
|
6
|
+
log_enabled = HttpLog.url_approved?(url)
|
7
|
+
|
8
|
+
if log_enabled
|
9
|
+
HttpLog.log_request(action_name, url)
|
10
|
+
HttpLog.log_headers(headers)
|
11
|
+
HttpLog.log_data(options[:data]) if action_name == :post
|
12
|
+
end
|
9
13
|
|
10
14
|
bm = Benchmark.realtime do
|
11
15
|
@response = orig_request(action_name, url, headers, options)
|
12
16
|
end
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
if log_enabled
|
19
|
+
HttpLog.log_compact(action_name, url, @response.status, bm)
|
20
|
+
HttpLog.log_status(@response.status)
|
21
|
+
HttpLog.log_benchmark(bm)
|
22
|
+
HttpLog.log_body(@response.body)
|
23
|
+
end
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
data/lib/httplog/http_log.rb
CHANGED
@@ -5,18 +5,22 @@ require "benchmark"
|
|
5
5
|
module HttpLog
|
6
6
|
DEFAULT_LOGGER = Logger.new($stdout)
|
7
7
|
DEFAULT_OPTIONS = {
|
8
|
-
:logger
|
9
|
-
:severity
|
10
|
-
:log_connect
|
11
|
-
:log_request
|
12
|
-
:log_headers
|
13
|
-
:log_data
|
14
|
-
:log_status
|
15
|
-
:log_response
|
16
|
-
:log_benchmark
|
17
|
-
:compact_log
|
8
|
+
:logger => DEFAULT_LOGGER,
|
9
|
+
:severity => Logger::Severity::DEBUG,
|
10
|
+
:log_connect => true,
|
11
|
+
:log_request => true,
|
12
|
+
:log_headers => false,
|
13
|
+
:log_data => true,
|
14
|
+
:log_status => true,
|
15
|
+
:log_response => true,
|
16
|
+
:log_benchmark => true,
|
17
|
+
:compact_log => false,
|
18
|
+
:url_whitelist_pattern => /.*/,
|
19
|
+
:url_blacklist_pattern => nil
|
18
20
|
}
|
19
21
|
|
22
|
+
LOG_PREFIX = "[httplog] ".freeze
|
23
|
+
|
20
24
|
class << self
|
21
25
|
def options
|
22
26
|
@@options ||= DEFAULT_OPTIONS.clone
|
@@ -26,8 +30,16 @@ module HttpLog
|
|
26
30
|
@@options = DEFAULT_OPTIONS.clone
|
27
31
|
end
|
28
32
|
|
33
|
+
def url_approved?(url)
|
34
|
+
unless @@options[:url_blacklist_pattern].nil?
|
35
|
+
return false if url.to_s.match(@@options[:url_blacklist_pattern])
|
36
|
+
end
|
37
|
+
|
38
|
+
url.to_s.match(@@options[:url_whitelist_pattern])
|
39
|
+
end
|
40
|
+
|
29
41
|
def log(msg)
|
30
|
-
@@options[:logger].add(@@options[:severity]) {
|
42
|
+
@@options[:logger].add(@@options[:severity]) { LOG_PREFIX + msg }
|
31
43
|
end
|
32
44
|
|
33
45
|
def log_connection(host, port = nil)
|
@@ -81,6 +93,7 @@ module HttpLog
|
|
81
93
|
|
82
94
|
def log_compact(method, uri, status, seconds)
|
83
95
|
return unless options[:compact_log]
|
96
|
+
status = Rack::Utils.status_code(status) unless status == /\d{3}/
|
84
97
|
log("#{method.to_s.upcase} #{uri} completed with status code #{status} in #{seconds} seconds")
|
85
98
|
end
|
86
99
|
end
|
data/lib/httplog/version.rb
CHANGED
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httplog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.5
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Thilo Rusche
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-02-01 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rspec
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rack
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: thin
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: httpclient
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ! '>='
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ! '>='
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,7 +69,6 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: httparty
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ! '>='
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ! '>='
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -94,7 +83,6 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: faraday
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - ! '>='
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,7 +90,6 @@ dependencies:
|
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - ! '>='
|
108
95
|
- !ruby/object:Gem::Version
|
@@ -110,7 +97,6 @@ dependencies:
|
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: excon
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
101
|
- - ! '>='
|
116
102
|
- !ruby/object:Gem::Version
|
@@ -118,7 +104,6 @@ dependencies:
|
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
108
|
- - ! '>='
|
124
109
|
- !ruby/object:Gem::Version
|
@@ -126,7 +111,6 @@ dependencies:
|
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: typhoeus
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
115
|
- - ! '>='
|
132
116
|
- !ruby/object:Gem::Version
|
@@ -134,7 +118,6 @@ dependencies:
|
|
134
118
|
type: :development
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
122
|
- - ! '>='
|
140
123
|
- !ruby/object:Gem::Version
|
@@ -142,7 +125,6 @@ dependencies:
|
|
142
125
|
- !ruby/object:Gem::Dependency
|
143
126
|
name: ethon
|
144
127
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
128
|
requirements:
|
147
129
|
- - ! '>='
|
148
130
|
- !ruby/object:Gem::Version
|
@@ -150,7 +132,6 @@ dependencies:
|
|
150
132
|
type: :development
|
151
133
|
prerelease: false
|
152
134
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
135
|
requirements:
|
155
136
|
- - ! '>='
|
156
137
|
- !ruby/object:Gem::Version
|
@@ -158,7 +139,6 @@ dependencies:
|
|
158
139
|
- !ruby/object:Gem::Dependency
|
159
140
|
name: patron
|
160
141
|
requirement: !ruby/object:Gem::Requirement
|
161
|
-
none: false
|
162
142
|
requirements:
|
163
143
|
- - ! '>='
|
164
144
|
- !ruby/object:Gem::Version
|
@@ -166,7 +146,20 @@ dependencies:
|
|
166
146
|
type: :development
|
167
147
|
prerelease: false
|
168
148
|
version_requirements: !ruby/object:Gem::Requirement
|
169
|
-
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: simplecov
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
170
163
|
requirements:
|
171
164
|
- - ! '>='
|
172
165
|
- !ruby/object:Gem::Version
|
@@ -192,27 +185,26 @@ files:
|
|
192
185
|
- README.md
|
193
186
|
homepage: http://github.com/trusche/httplog
|
194
187
|
licenses: []
|
188
|
+
metadata: {}
|
195
189
|
post_install_message:
|
196
190
|
rdoc_options: []
|
197
191
|
require_paths:
|
198
192
|
- lib
|
199
193
|
required_ruby_version: !ruby/object:Gem::Requirement
|
200
|
-
none: false
|
201
194
|
requirements:
|
202
195
|
- - ! '>='
|
203
196
|
- !ruby/object:Gem::Version
|
204
197
|
version: '0'
|
205
198
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
206
|
-
none: false
|
207
199
|
requirements:
|
208
200
|
- - ! '>='
|
209
201
|
- !ruby/object:Gem::Version
|
210
202
|
version: '0'
|
211
203
|
requirements: []
|
212
204
|
rubyforge_project:
|
213
|
-
rubygems_version: 1.
|
205
|
+
rubygems_version: 2.1.11
|
214
206
|
signing_key:
|
215
|
-
specification_version:
|
207
|
+
specification_version: 4
|
216
208
|
summary: Logs outgoing HTTP requests.
|
217
209
|
test_files: []
|
218
210
|
has_rdoc:
|