tracking_number 0.10.5 → 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitmodules +3 -0
- data/.travis.yml +15 -7
- data/Gemfile +2 -0
- data/README.md +87 -15
- data/Rakefile +3 -0
- data/lib/checksum_validations.rb +63 -0
- data/lib/tasks/stats.rake +90 -0
- data/lib/tracking_number.rb +79 -8
- data/lib/tracking_number/base.rb +169 -15
- data/lib/tracking_number/info.rb +18 -0
- data/lib/tracking_number/unknown.rb +33 -0
- data/lib/tracking_number/version.rb +1 -1
- data/test/test_helper.rb +10 -2
- data/test/tracking_number_data_test.rb +161 -0
- data/test/tracking_number_test.rb +105 -0
- data/tracking_number.gemspec +3 -2
- metadata +52 -23
- data/VERSION +0 -1
- data/lib/tracking_number/dhl.rb +0 -34
- data/lib/tracking_number/fedex.rb +0 -156
- data/lib/tracking_number/ontrac.rb +0 -34
- data/lib/tracking_number/ups.rb +0 -108
- data/lib/tracking_number/usps.rb +0 -166
- data/test/dhl_tracking_number_test.rb +0 -35
- data/test/fedex_tracking_number_test.rb +0 -75
- data/test/ontrac_tracking_number_test.rb +0 -24
- data/test/ups_tracking_number_test.rb +0 -36
- data/test/usps_tracking_number_test.rb +0 -73
@@ -6,6 +6,9 @@ class TrackingNumberTest < Minitest::Test
|
|
6
6
|
t = TrackingNumber.new("101")
|
7
7
|
assert_equal TrackingNumber::Unknown, t.class
|
8
8
|
assert_equal :unknown, t.carrier
|
9
|
+
assert_equal :unknown, t.courier_code
|
10
|
+
assert_equal "Unknown", t.courier_name
|
11
|
+
|
9
12
|
assert !t.valid?
|
10
13
|
end
|
11
14
|
|
@@ -26,10 +29,112 @@ class TrackingNumberTest < Minitest::Test
|
|
26
29
|
assert_equal 2, s.size
|
27
30
|
end
|
28
31
|
|
32
|
+
should "return two ups tracking numbers when given string with two ups tracking numbers" do
|
33
|
+
s = TrackingNumber.search("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 1Z5R89390357567127 nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute 1Z879E930346834440 dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
|
34
|
+
assert_equal 2, s.size
|
35
|
+
assert_equal [TrackingNumber::UPS, TrackingNumber::UPS], s.collect { |t| t.class }
|
36
|
+
end
|
37
|
+
|
29
38
|
should "return tracking numbers without trailing whitespace" do
|
30
39
|
s = TrackingNumber.search("hello 1Z879E930346834440\nbye")
|
31
40
|
assert_equal 1, s.size
|
32
41
|
assert_equal "1Z879E930346834440", s.first.tracking_number
|
33
42
|
end
|
34
43
|
end
|
44
|
+
|
45
|
+
context "tracking number additional data for ups" do
|
46
|
+
tracking_number = TrackingNumber.new("1Z5R89390357567127")
|
47
|
+
|
48
|
+
should "report correct courier name" do
|
49
|
+
assert_equal "UPS", tracking_number.courier_name
|
50
|
+
end
|
51
|
+
|
52
|
+
should "report correct service" do
|
53
|
+
assert_equal "UPS United States Ground", tracking_number.service_type
|
54
|
+
end
|
55
|
+
|
56
|
+
should "report correct shipper_id" do
|
57
|
+
assert_equal "5R8939", tracking_number.shipper_id
|
58
|
+
end
|
59
|
+
|
60
|
+
should "report correct no destination" do
|
61
|
+
assert_nil tracking_number.destination_zip
|
62
|
+
end
|
63
|
+
|
64
|
+
should "report correct no package info" do
|
65
|
+
assert_nil tracking_number.package_type
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "tracking number additional data for s10" do
|
70
|
+
tracking_number = TrackingNumber.new("RB123456785GB")
|
71
|
+
|
72
|
+
should "report correct courier name" do
|
73
|
+
assert_equal "Royal Mail Group plc", tracking_number.courier_name
|
74
|
+
end
|
75
|
+
|
76
|
+
should "report correct service" do
|
77
|
+
assert_equal "Letter Post Registered", tracking_number.service_type
|
78
|
+
end
|
79
|
+
|
80
|
+
should "report correct shipper_id" do
|
81
|
+
assert_nil tracking_number.shipper_id
|
82
|
+
end
|
83
|
+
|
84
|
+
should "report correct no destination" do
|
85
|
+
assert_nil tracking_number.destination_zip
|
86
|
+
end
|
87
|
+
|
88
|
+
should "report correct no package info" do
|
89
|
+
assert_nil tracking_number.package_type
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "tracking number additional data for USPS 20" do
|
94
|
+
tracking_number = TrackingNumber.new("0307 1790 0005 2348 3741")
|
95
|
+
|
96
|
+
should "report correct courier name" do
|
97
|
+
assert_equal "United States Postal Service", tracking_number.courier_name
|
98
|
+
end
|
99
|
+
|
100
|
+
should "report correct service" do
|
101
|
+
assert_nil tracking_number.service_type
|
102
|
+
end
|
103
|
+
|
104
|
+
should "report correct shipper_id" do
|
105
|
+
assert_nil tracking_number.shipper_id
|
106
|
+
end
|
107
|
+
|
108
|
+
should "report correct no destination" do
|
109
|
+
assert_nil tracking_number.destination_zip
|
110
|
+
end
|
111
|
+
|
112
|
+
should "report correct no package info" do
|
113
|
+
assert_nil tracking_number.package_type
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "tracking number additional data for USPS 34v2" do
|
118
|
+
tracking_number = TrackingNumber.new("4201002334249200190132607600833457")
|
119
|
+
|
120
|
+
should "report correct courier name" do
|
121
|
+
assert_equal "United States Postal Service", tracking_number.courier_name
|
122
|
+
end
|
123
|
+
|
124
|
+
should "report correct service" do
|
125
|
+
assert_nil tracking_number.service_type
|
126
|
+
end
|
127
|
+
|
128
|
+
should "report correct shipper_id" do
|
129
|
+
assert_equal "00190132", tracking_number.shipper_id
|
130
|
+
end
|
131
|
+
|
132
|
+
should "report correct no destination" do
|
133
|
+
assert_equal "10023", tracking_number.destination_zip
|
134
|
+
end
|
135
|
+
|
136
|
+
should "report correct no package info" do
|
137
|
+
assert_nil tracking_number.package_type
|
138
|
+
end
|
139
|
+
end
|
35
140
|
end
|
data/tracking_number.gemspec
CHANGED
@@ -6,10 +6,8 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = %q{tracking_number}
|
7
7
|
s.version = TrackingNumber::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
|
10
9
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
10
|
s.authors = ["Jeff Keen"]
|
12
|
-
s.date = %q{2017-02-21}
|
13
11
|
s.description = %q{This gem identifies valid tracking numbers and the service they're associated with. It can also tell you a little bit about the package purely from the number—there's quite a bit of info tucked away into those numbers, it turns out.}
|
14
12
|
s.email = %q{jeff@keen.me}
|
15
13
|
s.extra_rdoc_files = [
|
@@ -26,7 +24,10 @@ Gem::Specification.new do |s|
|
|
26
24
|
|
27
25
|
s.add_development_dependency('rake', '~> 10.4.2')
|
28
26
|
s.add_development_dependency('shoulda')
|
27
|
+
s.add_development_dependency('minitest-reporters', '~> 1.1')
|
29
28
|
s.add_development_dependency('simplecov')
|
30
29
|
s.add_development_dependency('activemodel', '~> 4.2.5.1')
|
31
30
|
s.add_development_dependency('minitest','~> 5.5')
|
31
|
+
s.add_development_dependency('awesome_print','~> 1.8')
|
32
|
+
s.add_development_dependency('terminal-table')
|
32
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracking_number
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Keen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest-reporters
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: simplecov
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +94,34 @@ dependencies:
|
|
80
94
|
- - "~>"
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '5.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: awesome_print
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.8'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.8'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: terminal-table
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
83
125
|
description: This gem identifies valid tracking numbers and the service they're associated
|
84
126
|
with. It can also tell you a little bit about the package purely from the number—there's
|
85
127
|
quite a bit of info tucked away into those numbers, it turns out.
|
@@ -91,29 +133,24 @@ extra_rdoc_files:
|
|
91
133
|
files:
|
92
134
|
- ".document"
|
93
135
|
- ".gitignore"
|
136
|
+
- ".gitmodules"
|
94
137
|
- ".travis.yml"
|
95
138
|
- Gemfile
|
96
139
|
- LICENSE.txt
|
97
140
|
- README.md
|
98
141
|
- Rakefile
|
99
|
-
-
|
142
|
+
- lib/checksum_validations.rb
|
143
|
+
- lib/tasks/stats.rake
|
100
144
|
- lib/tracking_number.rb
|
101
145
|
- lib/tracking_number/active_model_validator.rb
|
102
146
|
- lib/tracking_number/base.rb
|
103
|
-
- lib/tracking_number/
|
104
|
-
- lib/tracking_number/
|
105
|
-
- lib/tracking_number/ontrac.rb
|
106
|
-
- lib/tracking_number/ups.rb
|
107
|
-
- lib/tracking_number/usps.rb
|
147
|
+
- lib/tracking_number/info.rb
|
148
|
+
- lib/tracking_number/unknown.rb
|
108
149
|
- lib/tracking_number/version.rb
|
109
150
|
- test/active_model_validator_test.rb
|
110
|
-
- test/dhl_tracking_number_test.rb
|
111
|
-
- test/fedex_tracking_number_test.rb
|
112
|
-
- test/ontrac_tracking_number_test.rb
|
113
151
|
- test/test_helper.rb
|
152
|
+
- test/tracking_number_data_test.rb
|
114
153
|
- test/tracking_number_test.rb
|
115
|
-
- test/ups_tracking_number_test.rb
|
116
|
-
- test/usps_tracking_number_test.rb
|
117
154
|
- tracking_number.gemspec
|
118
155
|
homepage: http://github.com/jkeen/tracking_number
|
119
156
|
licenses:
|
@@ -135,16 +172,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
172
|
version: '0'
|
136
173
|
requirements: []
|
137
174
|
rubyforge_project:
|
138
|
-
rubygems_version: 2.
|
175
|
+
rubygems_version: 2.7.4
|
139
176
|
signing_key:
|
140
177
|
specification_version: 4
|
141
178
|
summary: Identifies valid tracking numbers
|
142
|
-
test_files:
|
143
|
-
- test/active_model_validator_test.rb
|
144
|
-
- test/dhl_tracking_number_test.rb
|
145
|
-
- test/fedex_tracking_number_test.rb
|
146
|
-
- test/ontrac_tracking_number_test.rb
|
147
|
-
- test/test_helper.rb
|
148
|
-
- test/tracking_number_test.rb
|
149
|
-
- test/ups_tracking_number_test.rb
|
150
|
-
- test/usps_tracking_number_test.rb
|
179
|
+
test_files: []
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.10.5
|
data/lib/tracking_number/dhl.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
module TrackingNumber
|
2
|
-
class DHL < Base
|
3
|
-
def carrier
|
4
|
-
:dhl
|
5
|
-
end
|
6
|
-
|
7
|
-
def valid_checksum?
|
8
|
-
# standard mod 7 check
|
9
|
-
sequence, check_digit = matches
|
10
|
-
return true if sequence.to_i % 7 == check_digit.to_i
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
#DHL Air (a division of DHL Express) have 11 digit numbers
|
15
|
-
class DHLExpressAir < DHL
|
16
|
-
SEARCH_PATTERN = /(\b([0-9]\s*){11,11}\b)/
|
17
|
-
VERIFY_PATTERN = /^([0-9]{10,10})([0-9])$/
|
18
|
-
|
19
|
-
def matches
|
20
|
-
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
#DHL Express numbers are 10 digits long
|
25
|
-
# http://www.dhl.co.uk/content/dam/downloads/uk/Express/PDFs/developer_centre/dhlis9_shipment_and_piece_ranges_v1.3.pdf
|
26
|
-
class DHLExpress < DHL
|
27
|
-
SEARCH_PATTERN = /(\b([0-9]\s*){10,10}\b)/
|
28
|
-
VERIFY_PATTERN = /^([0-9]{9,9})([0-9])$/
|
29
|
-
|
30
|
-
def matches
|
31
|
-
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,156 +0,0 @@
|
|
1
|
-
module TrackingNumber
|
2
|
-
class FedEx < Base
|
3
|
-
def carrier
|
4
|
-
:fedex
|
5
|
-
end
|
6
|
-
end
|
7
|
-
|
8
|
-
class FedExExpress < FedEx
|
9
|
-
SEARCH_PATTERN = /(\b([0-9]\s*){12,12}\b)/
|
10
|
-
VERIFY_PATTERN = /^([0-9]{11,11})([0-9])$/
|
11
|
-
LENGTH = 12
|
12
|
-
|
13
|
-
def matches
|
14
|
-
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
15
|
-
end
|
16
|
-
|
17
|
-
def valid_checksum?
|
18
|
-
sequence, check_digit = matches
|
19
|
-
total = 0
|
20
|
-
sequence.chars.to_a.zip([3,1,7,3,1,7,3,1,7,3,1]).each do |(a,b)|
|
21
|
-
total += a.to_i * b
|
22
|
-
end
|
23
|
-
return (total % 11 % 10) == check_digit.to_i
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class FedExSmartPost < FedEx
|
28
|
-
SEARCH_PATTERN = /(\b(?:9\s*2\s*)?([0-9]\s*){20}\b)/
|
29
|
-
VERIFY_PATTERN = /^((?:92)?[0-9]{5}[0-9]{14})([0-9])$/
|
30
|
-
|
31
|
-
def matches
|
32
|
-
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
33
|
-
end
|
34
|
-
|
35
|
-
def valid_checksum?
|
36
|
-
# http://stackoverflow.com/questions/15744704/how-to-calculate-a-fedex-smartpost-tracking-number-check-digit
|
37
|
-
|
38
|
-
@tracking_number = "92#{tracking_number}" unless tracking_number =~ /^92/
|
39
|
-
sequence = @tracking_number.chars.map(&:to_i)
|
40
|
-
check_digit = sequence.pop
|
41
|
-
|
42
|
-
total = 0
|
43
|
-
sequence.reverse.each_with_index do |x, i|
|
44
|
-
x *= 3 if i.even?
|
45
|
-
total += x
|
46
|
-
end
|
47
|
-
|
48
|
-
check = total % 10
|
49
|
-
check = (10 - check) unless (check.zero?)
|
50
|
-
|
51
|
-
return true if check == check_digit.to_i
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class FedExGround96 < FedEx
|
56
|
-
SEARCH_PATTERN = /(\b9\s*6\s*([0-9]\s*){20,20}\b)/
|
57
|
-
VERIFY_PATTERN = /^96[0-9]{5,5}([0-9]{14,14})([0-9])$/
|
58
|
-
LENGTH = 22
|
59
|
-
|
60
|
-
def matches
|
61
|
-
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
62
|
-
end
|
63
|
-
|
64
|
-
def decode
|
65
|
-
{:application_id => self.tracking_number.to_s.slice(0...2),
|
66
|
-
:serial_container => self.tracking_number.to_s.slice(2...4),
|
67
|
-
:service_code => self.tracking_number.to_s.slice(4...7),
|
68
|
-
:shipper_id => self.tracking_number.to_s.slice(7...14),
|
69
|
-
:package_identifier => self.tracking_number.to_s.slice(14...21),
|
70
|
-
:check_digit => self.tracking_number.slice(21...22)
|
71
|
-
}
|
72
|
-
end
|
73
|
-
|
74
|
-
def valid_checksum?
|
75
|
-
# 22 numbers
|
76
|
-
# http://fedex.com/us/solutions/ppe/FedEx_Ground_Label_Layout_Specification.pdf
|
77
|
-
# 96 - UCC/EAN Application Identifier
|
78
|
-
|
79
|
-
# [0-9]{2,2} - SCNC
|
80
|
-
# [0-9]{3,3} - Class Of Service
|
81
|
-
# [0-9]{7,7} - RPS Shipper ID (used in calculation)
|
82
|
-
# [0-9]{7,7} - Package Number (used in calculation)
|
83
|
-
# [0-9] - Check Digit
|
84
|
-
sequence, check_digit = matches
|
85
|
-
|
86
|
-
total = 0
|
87
|
-
sequence.chars.to_a.map(&:to_i).reverse.each_with_index do |x, i|
|
88
|
-
x *= 3 if i.even?
|
89
|
-
total += x
|
90
|
-
end
|
91
|
-
|
92
|
-
check = total % 10
|
93
|
-
check = (10 - check) unless (check.zero?)
|
94
|
-
return true if check == check_digit.to_i
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
class FedExGround < FedEx
|
99
|
-
SEARCH_PATTERN = /(\b([0-9]\s*){15,15}\b)/
|
100
|
-
VERIFY_PATTERN = /^([0-9]{15,15})$/
|
101
|
-
LENGTH = 15
|
102
|
-
|
103
|
-
def matches
|
104
|
-
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
105
|
-
end
|
106
|
-
|
107
|
-
def valid_checksum?
|
108
|
-
sequence = tracking_number.chars.to_a.map(&:to_i)
|
109
|
-
check_digit = sequence.pop
|
110
|
-
total = 0
|
111
|
-
sequence.reverse.each_with_index do |x, i|
|
112
|
-
x *= 3 if i.even?
|
113
|
-
total += x
|
114
|
-
end
|
115
|
-
check = total % 10
|
116
|
-
check = (10 - check) unless (check.zero?)
|
117
|
-
return true if check == check_digit.to_i
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
class FedExGround18 < FedEx
|
122
|
-
SEARCH_PATTERN = /(\b([0-9]\s*){18,18}\b)/
|
123
|
-
VERIFY_PATTERN = /^[0-9]{2,2}([0-9]{15,15})([0-9])$/
|
124
|
-
LENGTH = 20
|
125
|
-
|
126
|
-
def matches
|
127
|
-
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
128
|
-
end
|
129
|
-
|
130
|
-
def decode
|
131
|
-
{:application_id => self.tracking_number.to_s.slice(0...2),
|
132
|
-
:serial_container => self.tracking_number.to_s.slice(1...2),
|
133
|
-
:service_code => self.tracking_number.to_s.slice(2...3),
|
134
|
-
:shipper_id => self.tracking_number.to_s.slice(3...10),
|
135
|
-
:package_identifier => self.tracking_number.to_s.slice(10...17),
|
136
|
-
:check_digit => self.tracking_number.slice(17...18)
|
137
|
-
}
|
138
|
-
end
|
139
|
-
|
140
|
-
def valid_checksum?
|
141
|
-
# [0-9]{2,2} - Not used
|
142
|
-
# [0-9]{15, 15} - used for calculation
|
143
|
-
|
144
|
-
sequence = tracking_number.chars.to_a.map(&:to_i)
|
145
|
-
check_digit = sequence.pop
|
146
|
-
total = 0
|
147
|
-
sequence.reverse.each_with_index do |x, i|
|
148
|
-
x *= 3 if i.even?
|
149
|
-
total += x
|
150
|
-
end
|
151
|
-
check = total % 10
|
152
|
-
check = (10 - check) unless (check.zero?)
|
153
|
-
return true if check == check_digit.to_i
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|