open311 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +49 -0
- data/README.md +11 -45
- data/lib/open311.rb +2 -2
- data/lib/open311/client.rb +2 -2
- data/lib/open311/client/connection.rb +14 -16
- data/lib/open311/client/request.rb +12 -13
- data/lib/open311/client/service.rb +22 -15
- data/lib/open311/configuration.rb +3 -3
- data/lib/open311/response/raise_error.rb +33 -0
- data/lib/open311/version.rb +13 -1
- data/open311.gemspec +22 -27
- metadata +94 -231
- data/.gemtest +0 -0
- data/.gitignore +0 -10
- data/.rspec +0 -3
- data/.travis.yml +0 -12
- data/Gemfile +0 -8
- data/Rakefile +0 -23
- data/lib/faraday/response/raise_error.rb +0 -31
- data/spec/faraday/response_spec.rb +0 -33
- data/spec/fixtures/403.xml +0 -4
- data/spec/fixtures/get_service_request.xml +0 -23
- data/spec/fixtures/post_service_request.xml +0 -10
- data/spec/fixtures/request_id_from_token.xml +0 -7
- data/spec/fixtures/service_definition.xml +0 -23
- data/spec/fixtures/service_requests.xml +0 -41
- data/spec/fixtures/services.xml +0 -30
- data/spec/helper.rb +0 -15
- data/spec/open311_spec.rb +0 -178
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 91e2d7979b5e169e433be4e1cc56b25a2394c1e4
|
4
|
+
data.tar.gz: ec14c1ef94d7094e7ba1dc0a2f419a9a0b34857e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 12650fcbf7c2e86417735ae72a635127bd7194e60cbd644bb0b6936cd9ccfe78e6139202a3b101e8ffb6520425c30eb1468240980b8588afd3dcd094fe9eceb9
|
7
|
+
data.tar.gz: 39008e419f2d23b02fe20602da6eaf89f64caddd6a0e01b45124a209c7de63293e51a63b57f6ea1a7f0d1c2c39a56a33399896e1b70fea37933b3511c03dce95
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
## Contributing
|
2
|
+
In the spirit of [free software][free-sw], **everyone** is encouraged to help improve
|
3
|
+
this project.
|
4
|
+
|
5
|
+
[free-sw]: http://www.fsf.org/licensing/essays/free-sw.html
|
6
|
+
|
7
|
+
Here are some ways *you* can contribute:
|
8
|
+
|
9
|
+
* by using alpha, beta, and prerelease versions
|
10
|
+
* by reporting bugs
|
11
|
+
* by suggesting new features
|
12
|
+
* by writing or editing documentation
|
13
|
+
* by writing specifications
|
14
|
+
* by writing code (**no patch is too small**: fix typos, add comments, clean up
|
15
|
+
inconsistent whitespace)
|
16
|
+
* by refactoring code
|
17
|
+
* by fixing [issues][]
|
18
|
+
* by reviewing patches
|
19
|
+
|
20
|
+
[issues]: https://github.com/codeforamerica/open311/issues
|
21
|
+
|
22
|
+
## Submitting an Issue
|
23
|
+
We use the [GitHub issue tracker][issues] to track bugs and features. Before
|
24
|
+
submitting a bug report or feature request, check to make sure it hasn't
|
25
|
+
already been submitted. When submitting a bug report, please include a [Gist][]
|
26
|
+
that includes a stack trace and any details that may be necessary to reproduce
|
27
|
+
the bug, including your gem version, Ruby version, and operating system.
|
28
|
+
Ideally, a bug report should include a pull request with failing specs.
|
29
|
+
|
30
|
+
[gist]: https://gist.github.com/
|
31
|
+
|
32
|
+
## Submitting a Pull Request
|
33
|
+
1. [Fork the repository.][fork]
|
34
|
+
2. [Create a topic branch.][branch]
|
35
|
+
3. Add specs for your unimplemented feature or bug fix.
|
36
|
+
4. Run `bundle exec rake spec`. If your specs pass, return to step 3.
|
37
|
+
5. Implement your feature or bug fix.
|
38
|
+
6. Run `bundle exec rake`. If your specs fail, return to step 5.
|
39
|
+
7. Run `open coverage/index.html`. If your changes are not completely covered
|
40
|
+
by your tests, return to step 3.
|
41
|
+
8. Add documentation for your feature or bug fix.
|
42
|
+
9. Run `bundle exec rake verify_measurements`. If your changes are not 100%
|
43
|
+
documented, go back to step 8.
|
44
|
+
10. Commit and push your changes.
|
45
|
+
11. [Submit a pull request.][pr]
|
46
|
+
|
47
|
+
[fork]: http://help.github.com/fork-a-repo/
|
48
|
+
[branch]: http://learn.github.com/p/branching.html
|
49
|
+
[pr]: http://help.github.com/send-pull-requests/
|
data/README.md
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
# Open311
|
1
|
+
# Open311 [![Build Status](https://secure.travis-ci.org/codeforamerica/open311.png)][travis]
|
2
2
|
A Ruby wrapper for the Open311 API v2.
|
3
3
|
|
4
|
-
|
4
|
+
[travis]: http://travis-ci.org/codeforamerica/open311
|
5
|
+
|
6
|
+
## Does your project or organization use this gem?
|
5
7
|
Add it to the [apps](https://github.com/codeforamerica/open311/wiki/apps) wiki!
|
6
8
|
|
7
|
-
##
|
9
|
+
## Installation
|
8
10
|
gem install open311
|
9
11
|
|
10
|
-
##
|
12
|
+
## Documentation
|
11
13
|
[http://rdoc.info/gems/open311](http://rdoc.info/gems/open311)
|
12
14
|
|
13
|
-
## <a name="ci">Continuous Integration</a>
|
14
|
-
[![Build Status](https://secure.travis-ci.org/codeforamerica/open311.png)](http://travis-ci.org/codeforamerica/open311)
|
15
15
|
|
16
|
-
##
|
16
|
+
## Usage Examples
|
17
17
|
require 'open311'
|
18
18
|
|
19
19
|
# Certain methods require an API key
|
@@ -52,48 +52,14 @@ Add it to the [apps](https://github.com/codeforamerica/open311/wiki/apps) wiki!
|
|
52
52
|
# Get multiple service requests by ids, comma separated
|
53
53
|
Open311.service_requests({"service_request_id" => "101000119824,101000119823"})
|
54
54
|
|
55
|
-
##
|
56
|
-
In the spirit of [free software](http://www.fsf.org/licensing/essays/free-sw.html), **everyone** is encouraged to help improve this project.
|
57
|
-
|
58
|
-
Here are some ways *you* can contribute:
|
59
|
-
|
60
|
-
* by using alpha, beta, and prerelease versions
|
61
|
-
* by reporting bugs
|
62
|
-
* by suggesting new features
|
63
|
-
* by writing or editing documentation
|
64
|
-
* by writing specifications
|
65
|
-
* by writing code (**no patch is too small**: fix typos, add comments, clean up inconsistent whitespace)
|
66
|
-
* by refactoring code
|
67
|
-
* by resolving [issues](https://github.com/codeforamerica/open311/issues)
|
68
|
-
* by reviewing patches
|
69
|
-
|
70
|
-
## <a name="issues">Submitting an Issue</a>
|
71
|
-
We use the [GitHub issue tracker](https://github.com/codeforamerica/open311/issues) to track bugs and
|
72
|
-
features. Before submitting a bug report or feature request, check to make sure it hasn't already
|
73
|
-
been submitted. You can indicate support for an existing issuse by voting it up. When submitting a
|
74
|
-
bug report, please include a [Gist](https://gist.github.com/) that includes a stack trace and any
|
75
|
-
details that may be necessary to reproduce the bug, including your gem version, Ruby version, and
|
76
|
-
operating system. Ideally, a bug report should include a pull request with failing specs.
|
77
|
-
|
78
|
-
## <a name="pulls">Submitting a Pull Request</a>
|
79
|
-
1. Fork the project.
|
80
|
-
2. Create a topic branch.
|
81
|
-
3. Implement your feature or bug fix.
|
82
|
-
4. Add documentation for your feature or bug fix.
|
83
|
-
5. Run <tt>bundle exec rake doc:yard</tt>. If your changes are not 100% documented, go back to step 4.
|
84
|
-
6. Add specs for your feature or bug fix.
|
85
|
-
7. Run <tt>bundle exec rake spec</tt>. If your changes are not 100% covered, go back to step 6.
|
86
|
-
8. Commit and push your changes.
|
87
|
-
9. Submit a pull request. Please do not include changes to the gemspec, version, or history file. (If you want to create your own version for some reason, please do so in a separate commit.)
|
88
|
-
|
89
|
-
## <a name="rubies">Supported Rubies</a>
|
55
|
+
## Supported Rubies
|
90
56
|
This library aims to support and is [tested
|
91
57
|
against](http://travis-ci.org/codeforamerica/open311) the following Ruby
|
92
58
|
implementations:
|
93
59
|
|
94
|
-
* Ruby 1.8.7
|
95
|
-
* Ruby 1.9.2
|
96
60
|
* Ruby 1.9.3
|
61
|
+
* Ruby 2.0.0
|
62
|
+
* Ruby 2.1
|
97
63
|
* [JRuby](http://www.jruby.org/)
|
98
64
|
* [Rubinius](http://rubini.us/)
|
99
65
|
|
@@ -111,7 +77,7 @@ implementation, you will be personally responsible for providing patches in a
|
|
111
77
|
timely fashion. If critical issues for a particular implementation exist at the
|
112
78
|
time of a major release, support for that Ruby version may be dropped.
|
113
79
|
|
114
|
-
##
|
80
|
+
## Copyright
|
115
81
|
Copyright (c) 2010 Code for America.
|
116
82
|
See [LICENSE](https://github.com/codeforamerica/open311/blob/master/LICENSE.md) for details.
|
117
83
|
|
data/lib/open311.rb
CHANGED
@@ -8,7 +8,7 @@ module Open311
|
|
8
8
|
# Alias for Open311::Client.new
|
9
9
|
#
|
10
10
|
# @return [Open311::Client]
|
11
|
-
def new(options={})
|
11
|
+
def new(options = {})
|
12
12
|
Open311::Client.new(options)
|
13
13
|
end
|
14
14
|
|
@@ -18,7 +18,7 @@ module Open311
|
|
18
18
|
new.send(method, *args, &block)
|
19
19
|
end
|
20
20
|
|
21
|
-
def respond_to?(method, include_private=false)
|
21
|
+
def respond_to?(method, include_private = false)
|
22
22
|
new.respond_to?(method, include_private) || super(method, include_private)
|
23
23
|
end
|
24
24
|
end
|
data/lib/open311/client.rb
CHANGED
@@ -4,9 +4,9 @@ require 'open311/client/service'
|
|
4
4
|
|
5
5
|
module Open311
|
6
6
|
class Client
|
7
|
-
attr_accessor
|
7
|
+
attr_accessor(*Configuration::VALID_OPTIONS_KEYS)
|
8
8
|
|
9
|
-
def initialize(options={})
|
9
|
+
def initialize(options = {})
|
10
10
|
options = Open311.options.merge(options)
|
11
11
|
Configuration::VALID_OPTIONS_KEYS.each do |key|
|
12
12
|
send("#{key}=", options[key])
|
@@ -1,32 +1,30 @@
|
|
1
1
|
require 'faraday_middleware'
|
2
|
-
require '
|
2
|
+
require 'open311/response/raise_error'
|
3
3
|
|
4
4
|
module Open311
|
5
5
|
class Client
|
6
6
|
# @private
|
7
7
|
module Connection
|
8
|
-
|
8
|
+
private
|
9
9
|
|
10
|
-
def
|
11
|
-
|
10
|
+
def options
|
11
|
+
{
|
12
12
|
# :headers => {'Accept' => "*/#{format}", 'User-Agent' => user_agent},
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
13
|
+
proxy: proxy,
|
14
|
+
ssl: {verify: false},
|
15
|
+
url: endpoint,
|
16
16
|
}
|
17
|
+
end
|
17
18
|
|
19
|
+
def connection
|
18
20
|
Faraday.new(options) do |connection|
|
19
21
|
connection.use Faraday::Request::Multipart
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
connection.use Faraday::Response::ParseJson
|
25
|
-
when 'xml'
|
26
|
-
connection.use Faraday::Response::ParseXml
|
27
|
-
end
|
22
|
+
connection.use Faraday::Response::Mashify
|
23
|
+
case format.to_s.downcase
|
24
|
+
when 'json' then connection.use Faraday::Response::ParseJson
|
25
|
+
when 'xml' then connection.use Faraday::Response::ParseXml
|
28
26
|
end
|
29
|
-
connection.use
|
27
|
+
connection.use Open311::Response::RaiseError
|
30
28
|
connection.adapter(adapter)
|
31
29
|
end
|
32
30
|
end
|
@@ -1,26 +1,26 @@
|
|
1
1
|
module Open311
|
2
2
|
class Client
|
3
3
|
module Request
|
4
|
-
def get(path, options={}
|
5
|
-
request(:get, path, options
|
4
|
+
def get(path, options = {})
|
5
|
+
request(:get, path, options)
|
6
6
|
end
|
7
7
|
|
8
|
-
def post(path, options={}
|
9
|
-
request(:post, path, options
|
8
|
+
def post(path, options = {})
|
9
|
+
request(:post, path, options)
|
10
10
|
end
|
11
11
|
|
12
|
-
def put(path, options={}
|
13
|
-
request(:put, path, options
|
12
|
+
def put(path, options = {})
|
13
|
+
request(:put, path, options)
|
14
14
|
end
|
15
15
|
|
16
|
-
def delete(path, options={}
|
17
|
-
request(:delete, path, options
|
16
|
+
def delete(path, options = {})
|
17
|
+
request(:delete, path, options)
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
private
|
21
21
|
|
22
|
-
def request(method, path, options
|
23
|
-
|
22
|
+
def request(method, path, options)
|
23
|
+
connection.send(method) do |request|
|
24
24
|
case method
|
25
25
|
when :get, :delete
|
26
26
|
request.url(formatted_path(path), options)
|
@@ -28,8 +28,7 @@ module Open311
|
|
28
28
|
request.path = formatted_path(path)
|
29
29
|
request.body = options unless options.empty?
|
30
30
|
end
|
31
|
-
end
|
32
|
-
raw ? response : response.body
|
31
|
+
end.body
|
33
32
|
end
|
34
33
|
|
35
34
|
def formatted_path(path)
|
@@ -10,8 +10,8 @@ module Open311
|
|
10
10
|
# @see http://wiki.open311.org/GeoReport_v2#GET_Service_List
|
11
11
|
# @example Provide a list of acceptable 311 service request types and their associated service codes
|
12
12
|
# Open311.service_list
|
13
|
-
def service_list(options={})
|
14
|
-
|
13
|
+
def service_list(options = {})
|
14
|
+
merge_options!(options)
|
15
15
|
response = get('services', options)
|
16
16
|
unpack_if_xml(response) do
|
17
17
|
response['services']['service']
|
@@ -26,8 +26,8 @@ module Open311
|
|
26
26
|
# @see http://wiki.open311.org/GeoReport_v2#GET_Service_Definition
|
27
27
|
# @example define attributes associated with a service code, i.e. 033
|
28
28
|
# Open311.service_definition
|
29
|
-
def service_definition(id, options={})
|
30
|
-
|
29
|
+
def service_definition(id, options = {})
|
30
|
+
merge_options!(options)
|
31
31
|
response = get("services/#{id}", options)
|
32
32
|
unpack_if_xml(response) do
|
33
33
|
response['service_definition']
|
@@ -40,11 +40,13 @@ module Open311
|
|
40
40
|
# @return [Array]
|
41
41
|
# @see http://wiki.open311.org/GeoReport_v2#GET_Service_Requests
|
42
42
|
# Open311.service_requests
|
43
|
-
def service_requests(options={})
|
44
|
-
|
45
|
-
response = get(
|
43
|
+
def service_requests(options = {})
|
44
|
+
merge_options!(options)
|
45
|
+
response = get('requests', options)
|
46
46
|
unpack_if_xml(response) do
|
47
|
-
response.service_requests.
|
47
|
+
return [] unless response.service_requests.respond_to? :request
|
48
|
+
|
49
|
+
response.service_requests.request.map do |_request|
|
48
50
|
response['service_requests']['request']
|
49
51
|
end
|
50
52
|
end
|
@@ -56,9 +58,9 @@ module Open311
|
|
56
58
|
# @return Hash
|
57
59
|
# @see http://wiki.open311.org/GeoReport_v2#POST_Service_Request
|
58
60
|
# Open311.post_service_request
|
59
|
-
def post_service_request(options={})
|
60
|
-
|
61
|
-
response = post(
|
61
|
+
def post_service_request(options = {})
|
62
|
+
merge_options!(options, api_key: api_key)
|
63
|
+
response = post('requests', options)
|
62
64
|
unpack_if_xml(response) do
|
63
65
|
response['service_requests']['request']
|
64
66
|
end
|
@@ -71,8 +73,8 @@ module Open311
|
|
71
73
|
# @return Hash
|
72
74
|
# @see http://wiki.open311.org/GeoReport_v2#GET_Service_Requests
|
73
75
|
# Open311.get_service_request
|
74
|
-
def get_service_request(id, options={})
|
75
|
-
|
76
|
+
def get_service_request(id, options = {})
|
77
|
+
merge_options!(options)
|
76
78
|
response = get("requests/#{id}", options)
|
77
79
|
unpack_if_xml(response) do
|
78
80
|
response['service_requests']['request']
|
@@ -87,14 +89,19 @@ module Open311
|
|
87
89
|
# @see http://wiki.open311.org/GeoReport_v2#GET_request_id_from_a_token
|
88
90
|
# Open311.request_id
|
89
91
|
def request_id_from_token(token_id, options = {})
|
90
|
-
|
92
|
+
merge_options!(options)
|
91
93
|
response = get("tokens/#{token_id}", options)
|
92
94
|
unpack_if_xml(response) do
|
93
95
|
response['service_requests']['request']
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
97
|
-
|
99
|
+
private
|
100
|
+
|
101
|
+
def merge_options!(options, additional_options = {})
|
102
|
+
options.merge!(jurisdiction_id: jurisdiction) if jurisdiction
|
103
|
+
options.merge!(additional_options)
|
104
|
+
end
|
98
105
|
|
99
106
|
def unpack_if_xml(response)
|
100
107
|
if format.to_s.downcase == 'xml'
|
@@ -22,9 +22,9 @@ module Open311
|
|
22
22
|
DEFAULT_FORMAT = :xml
|
23
23
|
DEFAULT_JURISDICTION = nil
|
24
24
|
DEFAULT_PROXY = nil
|
25
|
-
DEFAULT_USER_AGENT = "Open311 Ruby Gem #{Open311::
|
25
|
+
DEFAULT_USER_AGENT = "Open311 Ruby Gem #{Open311::Version}".freeze
|
26
26
|
|
27
|
-
attr_accessor
|
27
|
+
attr_accessor(*VALID_OPTIONS_KEYS)
|
28
28
|
|
29
29
|
def self.extended(base)
|
30
30
|
base.reset
|
@@ -35,7 +35,7 @@ module Open311
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def options
|
38
|
-
VALID_OPTIONS_KEYS.inject({}){|
|
38
|
+
VALID_OPTIONS_KEYS.inject({}) { |a, e| a.merge!(e => send(e)) }
|
39
39
|
end
|
40
40
|
|
41
41
|
def reset
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
module Open311
|
5
|
+
module Response
|
6
|
+
class RaiseError < Faraday::Response::Middleware
|
7
|
+
def on_complete(response) # rubocop:disable AbcSize, CyclomaticComplexity, MethodLength
|
8
|
+
case response[:status].to_i
|
9
|
+
when 400
|
10
|
+
fail Open311::BadRequest.new(error_message(response))
|
11
|
+
when 401
|
12
|
+
fail Open311::Unauthorized.new(error_message(response))
|
13
|
+
when 403
|
14
|
+
fail Open311::Forbidden.new(error_message(response))
|
15
|
+
when 404
|
16
|
+
fail Open311::NotFound.new(error_message(response))
|
17
|
+
when 406
|
18
|
+
fail Open311::NotAcceptable.new(error_message(response))
|
19
|
+
when 500
|
20
|
+
fail Open311::InternalServerError.new(error_message(response))
|
21
|
+
when 502
|
22
|
+
fail Open311::BadGateway.new(error_message(response))
|
23
|
+
when 503
|
24
|
+
fail Open311::ServiceUnavailable.new(error_message(response))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def error_message(response)
|
29
|
+
"#{response[:method].to_s.upcase} #{response[:url]}: #{response[:response_headers]['status']}#{(': ' + response[:body]['error']) if response[:body] && response[:body]['error']}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/open311/version.rb
CHANGED
data/open311.gemspec
CHANGED
@@ -1,32 +1,27 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'open311/version'
|
3
4
|
|
4
|
-
Gem::Specification.new do |
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
gem.description = %q{A Ruby wrapper for the Open311 API v2.}
|
19
|
-
gem.email = ['dan@codeforamerica.org', 'erik@codeforamerica.org']
|
20
|
-
gem.files = `git ls-files`.split("\n")
|
21
|
-
gem.homepage = 'https://github.com/codeforamerica/open311'
|
22
|
-
gem.name = 'open311'
|
23
|
-
gem.post_install_message =<<eos
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.add_dependency 'faraday', '~> 0.7'
|
7
|
+
spec.add_dependency 'faraday_middleware', '~> 0.7'
|
8
|
+
spec.add_dependency 'hashie', '~> 3.3'
|
9
|
+
spec.add_dependency 'multi_json', '~> 1.0'
|
10
|
+
spec.add_dependency 'multi_xml', '~> 0.4'
|
11
|
+
spec.add_development_dependency 'bundler', '~> 1.0'
|
12
|
+
spec.authors = ['Dan Melton', 'Erik Michaels-Ober']
|
13
|
+
spec.description = 'A Ruby wrapper for the Open311 API v2.'
|
14
|
+
spec.email = ['dan@codeforamerica.org', 'erik@codeforamerica.org']
|
15
|
+
spec.files = %w(.yardopts CONTRIBUTING.md LICENSE.md README.md open311.gemspec) + Dir['lib/**/*.rb']
|
16
|
+
spec.homepage = 'https://github.com/codeforamerica/open311'
|
17
|
+
spec.name = 'open311'
|
18
|
+
spec.post_install_message = <<eos
|
24
19
|
Using this gem in your project or organization? Add it to the apps wiki!
|
25
20
|
https://github.com/codeforamerica/open311/wiki/apps
|
26
21
|
eos
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
spec.required_ruby_version = '>= 1.9.3'
|
24
|
+
spec.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
|
25
|
+
spec.summary = spec.description
|
26
|
+
spec.version = Open311::Version
|
32
27
|
end
|