easypost 3.0.0 → 3.2.0
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 +4 -4
- data/.github/workflows/ci.yml +22 -0
- data/CHANGELOG +40 -0
- data/README.md +2 -1
- data/VERSION +1 -1
- data/easypost.gemspec +24 -20
- data/lib/easypost.rb +108 -118
- data/lib/easypost/address.rb +47 -47
- data/lib/easypost/batch.rb +34 -38
- data/lib/easypost/carrier_account.rb +4 -6
- data/lib/easypost/customs_info.rb +3 -2
- data/lib/easypost/customs_item.rb +3 -2
- data/lib/easypost/error.rb +25 -33
- data/lib/easypost/event.rb +3 -6
- data/lib/easypost/insurance.rb +1 -3
- data/lib/easypost/item.rb +4 -8
- data/lib/easypost/object.rb +111 -113
- data/lib/easypost/order.rb +20 -18
- data/lib/easypost/parcel.rb +1 -3
- data/lib/easypost/pickup.rb +19 -18
- data/lib/easypost/pickup_rate.rb +1 -3
- data/lib/easypost/postage_label.rb +1 -3
- data/lib/easypost/print_job.rb +1 -5
- data/lib/easypost/printer.rb +18 -22
- data/lib/easypost/rate.rb +1 -3
- data/lib/easypost/refund.rb +1 -3
- data/lib/easypost/report.rb +22 -24
- data/lib/easypost/resource.rb +58 -60
- data/lib/easypost/scan_form.rb +4 -6
- data/lib/easypost/shipment.rb +84 -92
- data/lib/easypost/tracker.rb +10 -12
- data/lib/easypost/user.rb +33 -37
- data/lib/easypost/util.rb +99 -136
- data/lib/easypost/webhook.rb +22 -21
- metadata +33 -60
- data/circle.yml +0 -3
- data/spec/address_spec.rb +0 -81
- data/spec/batch_spec.rb +0 -48
- data/spec/carrier_account_spec.rb +0 -121
- data/spec/insurance_spec.rb +0 -69
- data/spec/item_spec.rb +0 -105
- data/spec/order_spec.rb +0 -58
- data/spec/pickup_spec.rb +0 -83
- data/spec/report_spec.rb +0 -59
- data/spec/scan_form_spec.rb +0 -46
- data/spec/shipment_spec.rb +0 -144
- data/spec/spec_helper.rb +0 -10
- data/spec/support/constant.rb +0 -106
- data/spec/tracker_spec.rb +0 -94
- data/spec/user_spec.rb +0 -88
- data/spec/webhook_spec.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77a7386297f189954ea974f3704cd7b61317f680
|
4
|
+
data.tar.gz: 3f2f2a129f9413f73910743c64a9d1b957998814
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73d59ca7ab531ee6bd6b5bae9d5d8cb862501ba1e3a41d3a218c3853f9a7c96dc69fb5c0a67a94fd068c123f76037aaa8bd64ab0ddff01fe80e446aac254100c
|
7
|
+
data.tar.gz: 77174452488594f5b154548a784c9e294aa66e3a54b1267d1d3a7076475ed41fa6027db1af2a4b2b0b869588853982770e0d43bd797755fe68ed5bbd5f124487
|
@@ -0,0 +1,22 @@
|
|
1
|
+
name: 'CI'
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request: ~
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
run-tests:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
strategy:
|
12
|
+
matrix:
|
13
|
+
rubyversion: ['2.4', '2.5', '2.6', '2.7', '3.0']
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
- name: set up ruby
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: ${{ matrix.rubyversion }}
|
20
|
+
bundler-cache: true
|
21
|
+
- name: run tests
|
22
|
+
run: bundle exec rspec
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,43 @@
|
|
1
|
+
=== 3.2.0 2021-01-14
|
2
|
+
|
3
|
+
* Replace Travis CI with Github Actions
|
4
|
+
* Add Ruby 3.0 to supported platforms (#110; thanks @maxwell)
|
5
|
+
|
6
|
+
=== 3.1.5 2020-12-16
|
7
|
+
|
8
|
+
* Fix attribute lookup when manually constructing objects (#105; thanks @drewtempelmeyer)
|
9
|
+
* Flatten class names and clean up some other style issues
|
10
|
+
* Fix `EasyPost::Address.create_and_verify`, broken since 3.1.0 (#108; thanks @rajbirverma)
|
11
|
+
|
12
|
+
=== 3.1.4 2020-09-29
|
13
|
+
|
14
|
+
* Don't modify params passed into Address#create (#78; thanks @TheRusskiy)
|
15
|
+
* Don't modify `carriers` and `services` parameters to `Shipment.lowest_rate` (#71 / #103, thanks @vladvinnikov and @jurisgalang)
|
16
|
+
* When constructing an easypost object, convert the key to a string (#102; thanks @Geesu)
|
17
|
+
* Expose the raw HTTP response as `#http_body` on `EasyPost::Error` objects (#101; thanks @Geesu)
|
18
|
+
|
19
|
+
=== 3.1.3 2020-06-26
|
20
|
+
|
21
|
+
* Fix bug causing Authorization header to be included in User-Agent header. All users must upgrade.
|
22
|
+
|
23
|
+
=== 3.1.2 2020-06-24
|
24
|
+
|
25
|
+
* Bad gem push. New version required.
|
26
|
+
|
27
|
+
=== 3.1.1 2020-06-23
|
28
|
+
|
29
|
+
* Fix bug where EasyPost.http_config was invalid when not explicitly initialized.
|
30
|
+
|
31
|
+
=== 3.1.0 2020-06-23
|
32
|
+
|
33
|
+
* Add Shipment Invoice and Refund Report
|
34
|
+
* Remove dependencies on `RestClient` and `MultiJson`
|
35
|
+
* Remove some deprecated endpoints
|
36
|
+
|
37
|
+
=== 3.0.1 2018-05-17
|
38
|
+
|
39
|
+
* Enforce TLS certificate validity by default
|
40
|
+
|
1
41
|
=== 3.0.0 2018-02-09
|
2
42
|
|
3
43
|
* Require use of ruby ~> 2.0 and TLSv1.2
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# EasyPost Ruby Client Library
|
2
2
|
|
3
|
-
[
|
3
|
+
[](https://github.com/EasyPost/easypost-ruby/actions?query=workflow%3ACI)
|
4
|
+
[](https://badge.fury.io/rb/easypost)
|
4
5
|
|
5
6
|
|
6
7
|
EasyPost is a simple shipping API. You can sign up for an account at https://easypost.com
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.2.0
|
data/easypost.gemspec
CHANGED
@@ -1,27 +1,31 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
5
|
+
require "easypost/version"
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.
|
10
|
-
spec.
|
11
|
-
spec.
|
12
|
-
spec.
|
13
|
-
spec.
|
14
|
-
spec.
|
8
|
+
spec.name = "easypost"
|
9
|
+
spec.version = EasyPost::VERSION
|
10
|
+
spec.licenses = ["MIT"]
|
11
|
+
spec.date = Time.now.strftime("%Y-%m-%d")
|
12
|
+
spec.summary = "EasyPost Ruby Client Library"
|
13
|
+
spec.description = "Client library for accessing the EasyPost shipping API via Ruby."
|
14
|
+
spec.authors = ["Jake Epstein", "Andrew Tribone", "James Brown"]
|
15
|
+
spec.email = "support@easypost.com"
|
16
|
+
spec.homepage = "https://www.easypost.com/docs"
|
15
17
|
|
16
|
-
spec.files
|
17
|
-
|
18
|
-
|
19
|
-
spec.
|
20
|
-
spec.
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{^(test|spec|features)/})
|
20
|
+
end
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
spec.required_ruby_version = ">= 2.2"
|
21
25
|
|
22
|
-
spec.
|
23
|
-
spec.
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
26
|
+
spec.add_development_dependency "pry", "~> 0.13"
|
27
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.9"
|
29
|
+
spec.add_development_dependency "webmock", "~> 3.8"
|
30
|
+
spec.add_development_dependency "vcr", "~> 5.1"
|
27
31
|
end
|
data/lib/easypost.rb
CHANGED
@@ -1,157 +1,147 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require 'rest_client'
|
5
|
-
require 'multi_json'
|
1
|
+
require "base64"
|
2
|
+
require "cgi"
|
3
|
+
require "net/http"
|
6
4
|
|
7
5
|
# Resources
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
25
|
-
require
|
26
|
-
require
|
27
|
-
require
|
28
|
-
require
|
29
|
-
require
|
30
|
-
require
|
31
|
-
require
|
32
|
-
require
|
33
|
-
require
|
34
|
-
require
|
35
|
-
|
36
|
-
require
|
6
|
+
require "easypost/version"
|
7
|
+
require "easypost/util"
|
8
|
+
require "easypost/object"
|
9
|
+
require "easypost/resource"
|
10
|
+
require "easypost/address"
|
11
|
+
require "easypost/parcel"
|
12
|
+
require "easypost/customs_item"
|
13
|
+
require "easypost/customs_info"
|
14
|
+
require "easypost/shipment"
|
15
|
+
require "easypost/rate"
|
16
|
+
require "easypost/postage_label"
|
17
|
+
require "easypost/scan_form"
|
18
|
+
require "easypost/refund"
|
19
|
+
require "easypost/insurance"
|
20
|
+
require "easypost/event"
|
21
|
+
require "easypost/batch"
|
22
|
+
require "easypost/tracker"
|
23
|
+
require "easypost/item"
|
24
|
+
require "easypost/order"
|
25
|
+
require "easypost/pickup"
|
26
|
+
require "easypost/pickup_rate"
|
27
|
+
require "easypost/printer"
|
28
|
+
require "easypost/print_job"
|
29
|
+
require "easypost/carrier_account"
|
30
|
+
require "easypost/user"
|
31
|
+
require "easypost/report"
|
32
|
+
require "easypost/webhook"
|
33
|
+
|
34
|
+
require "easypost/error"
|
37
35
|
|
38
36
|
module EasyPost
|
39
|
-
|
40
|
-
|
41
|
-
@@api_version = nil
|
42
|
-
@@open_timeout = 30
|
43
|
-
@@timeout = 60
|
44
|
-
|
45
|
-
def self.api_url(url='')
|
46
|
-
@@api_base + url
|
47
|
-
end
|
37
|
+
@api_key = nil
|
38
|
+
@api_base = "https://api.easypost.com"
|
48
39
|
|
49
40
|
def self.api_key=(api_key)
|
50
|
-
|
41
|
+
@api_key = api_key
|
51
42
|
end
|
52
43
|
|
53
44
|
def self.api_key
|
54
|
-
|
45
|
+
@api_key
|
55
46
|
end
|
56
47
|
|
57
48
|
def self.api_base=(api_base)
|
58
|
-
|
49
|
+
@api_base = api_base
|
59
50
|
end
|
60
51
|
|
61
52
|
def self.api_base
|
62
|
-
|
53
|
+
@api_base
|
63
54
|
end
|
64
55
|
|
65
|
-
def self.
|
66
|
-
|
67
|
-
|
56
|
+
def self.reset_http_config
|
57
|
+
@http_config = {
|
58
|
+
timeout: 60,
|
59
|
+
open_timeout: 30,
|
60
|
+
verify_ssl: OpenSSL::SSL::VERIFY_PEER,
|
61
|
+
}
|
62
|
+
|
63
|
+
ruby_version = Gem::Version.new(RUBY_VERSION)
|
64
|
+
if ruby_version >= Gem::Version.new("2.5.0")
|
65
|
+
@http_config[:min_version] = OpenSSL::SSL::TLS1_2_VERSION
|
66
|
+
else
|
67
|
+
@http_config[:ssl_version] = :TLSv1_2
|
68
|
+
end
|
68
69
|
|
69
|
-
|
70
|
-
@@api_version
|
70
|
+
@http_config
|
71
71
|
end
|
72
72
|
|
73
73
|
def self.http_config
|
74
|
-
|
75
|
-
timeout: 60,
|
76
|
-
open_timeout: 30,
|
77
|
-
verify_ssl: false,
|
78
|
-
ssl_version: :TLSv1_2,
|
79
|
-
}
|
74
|
+
@http_config ||= reset_http_config
|
80
75
|
end
|
81
76
|
|
82
77
|
def self.http_config=(http_config_params)
|
83
|
-
|
78
|
+
http_config.merge!(http_config_params)
|
84
79
|
end
|
85
80
|
|
86
|
-
def self.
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
81
|
+
def self.make_client(uri)
|
82
|
+
client = if http_config[:proxy]
|
83
|
+
proxy_uri = URI(http_config[:proxy])
|
84
|
+
Net::HTTP.new(
|
85
|
+
uri.host,
|
86
|
+
uri.port,
|
87
|
+
proxy_uri.host,
|
88
|
+
proxy_uri.port,
|
89
|
+
proxy_uri.user,
|
90
|
+
proxy_uri.password
|
91
|
+
)
|
92
|
+
else
|
93
|
+
Net::HTTP.new(uri.host, uri.port)
|
94
|
+
end
|
95
|
+
client.use_ssl = true
|
96
|
+
|
97
|
+
http_config.each do |name, value|
|
98
|
+
# Discrepancies between RestClient and Net::HTTP.
|
99
|
+
if name == :verify_ssl
|
100
|
+
name = :verify_mode
|
101
|
+
elsif name == :timeout
|
102
|
+
name = :read_timeout
|
103
|
+
end
|
91
104
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
when :get, :head, :delete
|
96
|
-
# Make params into GET parameters
|
97
|
-
if params && params.count > 0
|
98
|
-
query_string = Util.flatten_params(params).collect{|key, value| "#{key}=#{Util.url_encode(value)}"}.join('&')
|
99
|
-
url += "#{URI.parse(url).query ? '&' : '?'}#{query_string}"
|
105
|
+
# Handled in the creation of the client.
|
106
|
+
if name == :proxy
|
107
|
+
next
|
100
108
|
end
|
101
|
-
|
102
|
-
|
103
|
-
payload = Util.flatten_params(params).collect{|(key, value)| "#{key}=#{Util.url_encode(value)}"}.join('&')
|
109
|
+
|
110
|
+
client.send("#{name}=", value)
|
104
111
|
end
|
105
112
|
|
106
|
-
|
107
|
-
|
108
|
-
:authorization => "Bearer #{api_key}",
|
109
|
-
:content_type => 'application/x-www-form-urlencoded'
|
110
|
-
}.merge(headers)
|
111
|
-
|
112
|
-
opts = http_config.merge(
|
113
|
-
{
|
114
|
-
:method => method,
|
115
|
-
:url => url,
|
116
|
-
:headers => headers,
|
117
|
-
:payload => payload
|
118
|
-
}
|
119
|
-
)
|
113
|
+
client
|
114
|
+
end
|
120
115
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
rescue MultiJson::DecodeError
|
128
|
-
raise Error.new("Invalid response from API, unable to decode.", response_code, response_body)
|
129
|
-
end
|
130
|
-
begin
|
131
|
-
raise NoMethodError if response_json[:error][:message] == nil
|
132
|
-
raise Error.new(response_json[:error][:message], response_code, response_body, response_json)
|
133
|
-
rescue NoMethodError, TypeError
|
134
|
-
raise Error.new(response_json[:error], response_code, response_body, response_json)
|
135
|
-
end
|
136
|
-
else
|
137
|
-
raise Error.new(e.message)
|
138
|
-
end
|
139
|
-
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
140
|
-
raise Error.new(e.message)
|
116
|
+
def self.make_request(method, path, api_key=nil, body=nil)
|
117
|
+
client = make_client(URI(@api_base))
|
118
|
+
|
119
|
+
request = Net::HTTP.const_get(method.capitalize).new(path)
|
120
|
+
if body
|
121
|
+
request.body = JSON.dump(EasyPost::Util.objects_to_ids(body))
|
141
122
|
end
|
142
123
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
124
|
+
request["Content-Type"] = "application/json"
|
125
|
+
request["User-Agent"] = "EasyPost/v2 RubyClient/#{VERSION} Ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
126
|
+
if api_key = api_key || @api_key
|
127
|
+
request["Authorization"] = "Basic #{Base64.strict_encode64("#{api_key}:")}"
|
147
128
|
end
|
148
129
|
|
149
|
-
|
150
|
-
end
|
130
|
+
response = client.request(request)
|
151
131
|
|
152
|
-
|
132
|
+
if (400..599).include? response.code.to_i
|
133
|
+
error = JSON.parse(response.body)["error"]
|
134
|
+
raise EasyPost::Error.new(error["message"], response.code.to_i, error["code"], error["errors"], response.body)
|
135
|
+
end
|
153
136
|
|
154
|
-
|
155
|
-
|
137
|
+
if response["Content-Type"].include? "application/json"
|
138
|
+
JSON.parse(response.body)
|
139
|
+
else
|
140
|
+
response.body
|
141
|
+
end
|
142
|
+
rescue JSON::ParserError
|
143
|
+
raise RuntimeError.new(
|
144
|
+
"Invalid response object from API, unable to decode.\n#{response.body}"
|
145
|
+
)
|
156
146
|
end
|
157
147
|
end
|
data/lib/easypost/address.rb
CHANGED
@@ -1,58 +1,58 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
attr_accessor :message # Backwards compatibility
|
4
|
-
|
5
|
-
def self.create(params={}, api_key=nil)
|
6
|
-
url = self.url
|
7
|
-
|
8
|
-
if params[:verify] || params[:verify_strict]
|
9
|
-
verify = params.delete(:verify) || []
|
10
|
-
verify_strict = params.delete(:verify_strict) || []
|
11
|
-
|
12
|
-
url += "?"
|
13
|
-
verify.each do |verification|
|
14
|
-
url += "verify[]=#{verification}&"
|
15
|
-
end
|
16
|
-
verify_strict.each do |verification|
|
17
|
-
url += "verify_strict[]=#{verification}&"
|
18
|
-
end
|
19
|
-
end
|
1
|
+
class EasyPost::Address < EasyPost::Resource
|
2
|
+
attr_accessor :message # Backwards compatibility
|
20
3
|
|
21
|
-
|
22
|
-
|
23
|
-
|
4
|
+
def self.create(params={}, api_key=nil)
|
5
|
+
url = self.url
|
6
|
+
|
7
|
+
address = params.reject { |k,_| k == :verify || k == :verify_strict }
|
8
|
+
|
9
|
+
if params[:verify] || params[:verify_strict]
|
10
|
+
verify = params[:verify] || []
|
11
|
+
verify_strict = params[:verify_strict] || []
|
24
12
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if response.has_key?(:address)
|
32
|
-
if response.has_key?(:message)
|
33
|
-
response[:address][:message] = response[:message]
|
34
|
-
end
|
35
|
-
verified_address = EasyPost::Util::convert_to_easypost_object(response[:address], api_key)
|
36
|
-
return verified_address
|
37
|
-
else
|
38
|
-
raise Error.new("Unable to verify address.")
|
13
|
+
url += "?"
|
14
|
+
verify.each do |verification|
|
15
|
+
url += "verify[]=#{verification}&"
|
16
|
+
end
|
17
|
+
verify_strict.each do |verification|
|
18
|
+
url += "verify_strict[]=#{verification}&"
|
39
19
|
end
|
40
20
|
end
|
41
21
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
rescue
|
46
|
-
raise Error.new("Unable to verify address.")
|
47
|
-
end
|
22
|
+
response = EasyPost.make_request(:post, url, api_key, {address: address})
|
23
|
+
return EasyPost::Util.convert_to_easypost_object(response, api_key)
|
24
|
+
end
|
48
25
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
26
|
+
def self.create_and_verify(params={}, carrier=nil, api_key=nil)
|
27
|
+
wrapped_params = {}
|
28
|
+
wrapped_params[self.class_name().to_sym] = params
|
29
|
+
wrapped_params[:carrier] = carrier
|
30
|
+
response = EasyPost.make_request(:post, url + '/create_and_verify', api_key, wrapped_params)
|
31
|
+
|
32
|
+
if response.has_key?("address")
|
33
|
+
if response.has_key?("message")
|
34
|
+
response["address"]["message"] = response["message"]
|
53
35
|
end
|
36
|
+
verified_address = EasyPost::Util::convert_to_easypost_object(response["address"], api_key)
|
37
|
+
return verified_address
|
38
|
+
else
|
39
|
+
raise EasyPost::Error.new("Unable to verify address.")
|
40
|
+
end
|
41
|
+
end
|
54
42
|
|
55
|
-
|
43
|
+
def verify(params={}, carrier=nil)
|
44
|
+
begin
|
45
|
+
response = EasyPost.make_request(:get, url + '/verify?carrier=' + String(carrier), @api_key, params)
|
46
|
+
rescue
|
47
|
+
raise EasyPost::Error.new("Unable to verify address.")
|
56
48
|
end
|
49
|
+
|
50
|
+
if response.has_key?("address")
|
51
|
+
return EasyPost::Util::convert_to_easypost_object(response["address"], api_key)
|
52
|
+
else
|
53
|
+
raise EasyPost::Error.new("Unable to verify address.")
|
54
|
+
end
|
55
|
+
|
56
|
+
return self
|
57
57
|
end
|
58
58
|
end
|