rack-protection 1.5.5 → 2.1.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/Gemfile +13 -0
- data/License +4 -1
- data/README.md +41 -13
- data/Rakefile +29 -5
- data/lib/rack/protection.rb +41 -24
- data/lib/rack/protection/authenticity_token.rb +181 -9
- data/lib/rack/protection/base.rb +3 -22
- data/lib/rack/protection/content_security_policy.rb +79 -0
- data/lib/rack/protection/cookie_tossing.rb +75 -0
- data/lib/rack/protection/escaped_params.rb +2 -0
- data/lib/rack/protection/form_token.rb +1 -1
- data/lib/rack/protection/http_origin.rb +17 -2
- data/lib/rack/protection/json_csrf.rb +26 -4
- data/lib/rack/protection/path_traversal.rb +4 -12
- data/lib/rack/protection/referrer_policy.rb +25 -0
- data/lib/rack/protection/remote_token.rb +1 -1
- data/lib/rack/protection/session_hijacking.rb +1 -1
- data/lib/rack/protection/strict_transport.rb +39 -0
- data/lib/rack/protection/version.rb +1 -12
- data/lib/rack/protection/xss_header.rb +1 -1
- data/rack-protection.gemspec +26 -104
- metadata +21 -82
- data/spec/authenticity_token_spec.rb +0 -48
- data/spec/base_spec.rb +0 -40
- data/spec/escaped_params_spec.rb +0 -43
- data/spec/form_token_spec.rb +0 -33
- data/spec/frame_options_spec.rb +0 -39
- data/spec/http_origin_spec.rb +0 -38
- data/spec/ip_spoofing_spec.rb +0 -35
- data/spec/json_csrf_spec.rb +0 -58
- data/spec/path_traversal_spec.rb +0 -41
- data/spec/protection_spec.rb +0 -105
- data/spec/remote_referrer_spec.rb +0 -31
- data/spec/remote_token_spec.rb +0 -42
- data/spec/session_hijacking_spec.rb +0 -55
- data/spec/spec_helper.rb +0 -163
- data/spec/xss_header_spec.rb +0 -56
@@ -4,7 +4,7 @@ module Rack
|
|
4
4
|
module Protection
|
5
5
|
##
|
6
6
|
# Prevented attack:: Non-permanent XSS
|
7
|
-
# Supported browsers:: Internet Explorer 8 and
|
7
|
+
# Supported browsers:: Internet Explorer 8+ and Chrome
|
8
8
|
# More infos:: http://blogs.msdn.com/b/ie/archive/2008/07/01/ie8-security-part-iv-the-xss-filter.aspx
|
9
9
|
#
|
10
10
|
# Sets X-XSS-Protection header to tell the browser to block attacks.
|
data/rack-protection.gemspec
CHANGED
@@ -1,118 +1,40 @@
|
|
1
|
-
|
1
|
+
version = File.read(File.expand_path("../../VERSION", __FILE__)).strip
|
2
|
+
|
2
3
|
Gem::Specification.new do |s|
|
3
4
|
# general infos
|
4
5
|
s.name = "rack-protection"
|
5
|
-
s.version =
|
6
|
-
s.description = "
|
7
|
-
s.homepage = "http://
|
6
|
+
s.version = version
|
7
|
+
s.description = "Protect against typical web attacks, works with all Rack apps, including Rails."
|
8
|
+
s.homepage = "http://sinatrarb.com/protection/"
|
8
9
|
s.summary = s.description
|
9
10
|
s.license = 'MIT'
|
10
|
-
|
11
|
-
|
12
|
-
s.
|
13
|
-
"Konstantin Haase",
|
14
|
-
"Alex Rodionov",
|
15
|
-
"Patrick Ellis",
|
16
|
-
"Jason Staten",
|
17
|
-
"ITO Nobuaki",
|
18
|
-
"Jeff Welling",
|
19
|
-
"Matteo Centenaro",
|
20
|
-
"Egor Homakov",
|
21
|
-
"Florian Gilcher",
|
22
|
-
"Fojas",
|
23
|
-
"Igor Bochkariov",
|
24
|
-
"Mael Clerambault",
|
25
|
-
"Martin Mauch",
|
26
|
-
"Renne Nissinen",
|
27
|
-
"SAKAI, Kazuaki",
|
28
|
-
"Stanislav Savulchik",
|
29
|
-
"Steve Agalloco",
|
30
|
-
"TOBY",
|
31
|
-
"Thais Camilo and Konstantin Haase",
|
32
|
-
"Vipul A M",
|
33
|
-
"Akzhan Abdulin",
|
34
|
-
"brookemckim",
|
35
|
-
"Bj\u{f8}rge N\u{e6}ss",
|
36
|
-
"Chris Heald",
|
37
|
-
"Chris Mytton",
|
38
|
-
"Corey Ward",
|
39
|
-
"Dario Cravero",
|
40
|
-
"David Kellum"
|
41
|
-
]
|
42
|
-
|
43
|
-
# generated from git shortlog -sne
|
44
|
-
s.email = [
|
45
|
-
"konstantin.mailinglists@googlemail.com",
|
46
|
-
"p0deje@gmail.com",
|
47
|
-
"jstaten07@gmail.com",
|
48
|
-
"patrick@soundcloud.com",
|
49
|
-
"jeff.welling@gmail.com",
|
50
|
-
"bugant@gmail.com",
|
51
|
-
"daydream.trippers@gmail.com",
|
52
|
-
"florian.gilcher@asquera.de",
|
53
|
-
"developer@fojasaur.us",
|
54
|
-
"ujifgc@gmail.com",
|
55
|
-
"mael@clerambault.fr",
|
56
|
-
"martin.mauch@gmail.com",
|
57
|
-
"rennex@iki.fi",
|
58
|
-
"kaz.july.7@gmail.com",
|
59
|
-
"s.savulchik@gmail.com",
|
60
|
-
"steve.agalloco@gmail.com",
|
61
|
-
"toby.net.info.mail+git@gmail.com",
|
62
|
-
"dev+narwen+rkh@rkh.im",
|
63
|
-
"vipulnsward@gmail.com",
|
64
|
-
"akzhan.abdulin@gmail.com",
|
65
|
-
"brooke@digitalocean.com",
|
66
|
-
"bjoerge@bengler.no",
|
67
|
-
"cheald@gmail.com",
|
68
|
-
"self@hecticjeff.net",
|
69
|
-
"coreyward@me.com",
|
70
|
-
"dario@uxtemple.com",
|
71
|
-
"dek-oss@gravitext.com",
|
72
|
-
"homakov@gmail.com"
|
73
|
-
]
|
74
|
-
|
75
|
-
# generated from git ls-files
|
76
|
-
s.files = [
|
11
|
+
s.authors = ["https://github.com/sinatra/sinatra/graphs/contributors"]
|
12
|
+
s.email = "sinatrarb@googlegroups.com"
|
13
|
+
s.files = Dir["lib/**/*.rb"] + [
|
77
14
|
"License",
|
78
15
|
"README.md",
|
79
16
|
"Rakefile",
|
80
|
-
"
|
81
|
-
"
|
82
|
-
"lib/rack/protection/authenticity_token.rb",
|
83
|
-
"lib/rack/protection/base.rb",
|
84
|
-
"lib/rack/protection/escaped_params.rb",
|
85
|
-
"lib/rack/protection/form_token.rb",
|
86
|
-
"lib/rack/protection/frame_options.rb",
|
87
|
-
"lib/rack/protection/http_origin.rb",
|
88
|
-
"lib/rack/protection/ip_spoofing.rb",
|
89
|
-
"lib/rack/protection/json_csrf.rb",
|
90
|
-
"lib/rack/protection/path_traversal.rb",
|
91
|
-
"lib/rack/protection/remote_referrer.rb",
|
92
|
-
"lib/rack/protection/remote_token.rb",
|
93
|
-
"lib/rack/protection/session_hijacking.rb",
|
94
|
-
"lib/rack/protection/version.rb",
|
95
|
-
"lib/rack/protection/xss_header.rb",
|
96
|
-
"rack-protection.gemspec",
|
97
|
-
"spec/authenticity_token_spec.rb",
|
98
|
-
"spec/base_spec.rb",
|
99
|
-
"spec/escaped_params_spec.rb",
|
100
|
-
"spec/form_token_spec.rb",
|
101
|
-
"spec/frame_options_spec.rb",
|
102
|
-
"spec/http_origin_spec.rb",
|
103
|
-
"spec/ip_spoofing_spec.rb",
|
104
|
-
"spec/json_csrf_spec.rb",
|
105
|
-
"spec/path_traversal_spec.rb",
|
106
|
-
"spec/protection_spec.rb",
|
107
|
-
"spec/remote_referrer_spec.rb",
|
108
|
-
"spec/remote_token_spec.rb",
|
109
|
-
"spec/session_hijacking_spec.rb",
|
110
|
-
"spec/spec_helper.rb",
|
111
|
-
"spec/xss_header_spec.rb"
|
17
|
+
"Gemfile",
|
18
|
+
"rack-protection.gemspec"
|
112
19
|
]
|
113
20
|
|
21
|
+
if s.respond_to?(:metadata)
|
22
|
+
s.metadata = {
|
23
|
+
'source_code_uri' => 'https://github.com/sinatra/sinatra/tree/master/rack-protection',
|
24
|
+
'homepage_uri' => 'http://sinatrarb.com/protection/',
|
25
|
+
'documentation_uri' => 'https://www.rubydoc.info/gems/rack-protection'
|
26
|
+
}
|
27
|
+
else
|
28
|
+
raise <<-EOF
|
29
|
+
RubyGems 2.0 or newer is required to protect against public gem pushes. You can update your rubygems version by running:
|
30
|
+
gem install rubygems-update
|
31
|
+
update_rubygems:
|
32
|
+
gem update --system
|
33
|
+
EOF
|
34
|
+
end
|
35
|
+
|
114
36
|
# dependencies
|
115
37
|
s.add_dependency "rack"
|
116
38
|
s.add_development_dependency "rack-test"
|
117
|
-
s.add_development_dependency "rspec", "~>
|
39
|
+
s.add_development_dependency "rspec", "~> 3.6"
|
118
40
|
end
|
metadata
CHANGED
@@ -1,41 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-protection
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
- Alex Rodionov
|
9
|
-
- Patrick Ellis
|
10
|
-
- Jason Staten
|
11
|
-
- ITO Nobuaki
|
12
|
-
- Jeff Welling
|
13
|
-
- Matteo Centenaro
|
14
|
-
- Egor Homakov
|
15
|
-
- Florian Gilcher
|
16
|
-
- Fojas
|
17
|
-
- Igor Bochkariov
|
18
|
-
- Mael Clerambault
|
19
|
-
- Martin Mauch
|
20
|
-
- Renne Nissinen
|
21
|
-
- SAKAI, Kazuaki
|
22
|
-
- Stanislav Savulchik
|
23
|
-
- Steve Agalloco
|
24
|
-
- TOBY
|
25
|
-
- Thais Camilo and Konstantin Haase
|
26
|
-
- Vipul A M
|
27
|
-
- Akzhan Abdulin
|
28
|
-
- brookemckim
|
29
|
-
- Bjørge Næss
|
30
|
-
- Chris Heald
|
31
|
-
- Chris Mytton
|
32
|
-
- Corey Ward
|
33
|
-
- Dario Cravero
|
34
|
-
- David Kellum
|
7
|
+
- https://github.com/sinatra/sinatra/graphs/contributors
|
35
8
|
autorequire:
|
36
9
|
bindir: bin
|
37
10
|
cert_chain: []
|
38
|
-
date:
|
11
|
+
date: 2020-09-04 00:00:00.000000000 Z
|
39
12
|
dependencies:
|
40
13
|
- !ruby/object:Gem::Dependency
|
41
14
|
name: rack
|
@@ -71,48 +44,22 @@ dependencies:
|
|
71
44
|
requirements:
|
72
45
|
- - "~>"
|
73
46
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
47
|
+
version: '3.6'
|
75
48
|
type: :development
|
76
49
|
prerelease: false
|
77
50
|
version_requirements: !ruby/object:Gem::Requirement
|
78
51
|
requirements:
|
79
52
|
- - "~>"
|
80
53
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
82
|
-
description:
|
83
|
-
|
84
|
-
|
85
|
-
- p0deje@gmail.com
|
86
|
-
- jstaten07@gmail.com
|
87
|
-
- patrick@soundcloud.com
|
88
|
-
- jeff.welling@gmail.com
|
89
|
-
- bugant@gmail.com
|
90
|
-
- daydream.trippers@gmail.com
|
91
|
-
- florian.gilcher@asquera.de
|
92
|
-
- developer@fojasaur.us
|
93
|
-
- ujifgc@gmail.com
|
94
|
-
- mael@clerambault.fr
|
95
|
-
- martin.mauch@gmail.com
|
96
|
-
- rennex@iki.fi
|
97
|
-
- kaz.july.7@gmail.com
|
98
|
-
- s.savulchik@gmail.com
|
99
|
-
- steve.agalloco@gmail.com
|
100
|
-
- toby.net.info.mail+git@gmail.com
|
101
|
-
- dev+narwen+rkh@rkh.im
|
102
|
-
- vipulnsward@gmail.com
|
103
|
-
- akzhan.abdulin@gmail.com
|
104
|
-
- brooke@digitalocean.com
|
105
|
-
- bjoerge@bengler.no
|
106
|
-
- cheald@gmail.com
|
107
|
-
- self@hecticjeff.net
|
108
|
-
- coreyward@me.com
|
109
|
-
- dario@uxtemple.com
|
110
|
-
- dek-oss@gravitext.com
|
111
|
-
- homakov@gmail.com
|
54
|
+
version: '3.6'
|
55
|
+
description: Protect against typical web attacks, works with all Rack apps, including
|
56
|
+
Rails.
|
57
|
+
email: sinatrarb@googlegroups.com
|
112
58
|
executables: []
|
113
59
|
extensions: []
|
114
60
|
extra_rdoc_files: []
|
115
61
|
files:
|
62
|
+
- Gemfile
|
116
63
|
- License
|
117
64
|
- README.md
|
118
65
|
- Rakefile
|
@@ -120,6 +67,8 @@ files:
|
|
120
67
|
- lib/rack/protection.rb
|
121
68
|
- lib/rack/protection/authenticity_token.rb
|
122
69
|
- lib/rack/protection/base.rb
|
70
|
+
- lib/rack/protection/content_security_policy.rb
|
71
|
+
- lib/rack/protection/cookie_tossing.rb
|
123
72
|
- lib/rack/protection/escaped_params.rb
|
124
73
|
- lib/rack/protection/form_token.rb
|
125
74
|
- lib/rack/protection/frame_options.rb
|
@@ -127,31 +76,21 @@ files:
|
|
127
76
|
- lib/rack/protection/ip_spoofing.rb
|
128
77
|
- lib/rack/protection/json_csrf.rb
|
129
78
|
- lib/rack/protection/path_traversal.rb
|
79
|
+
- lib/rack/protection/referrer_policy.rb
|
130
80
|
- lib/rack/protection/remote_referrer.rb
|
131
81
|
- lib/rack/protection/remote_token.rb
|
132
82
|
- lib/rack/protection/session_hijacking.rb
|
83
|
+
- lib/rack/protection/strict_transport.rb
|
133
84
|
- lib/rack/protection/version.rb
|
134
85
|
- lib/rack/protection/xss_header.rb
|
135
86
|
- rack-protection.gemspec
|
136
|
-
|
137
|
-
- spec/base_spec.rb
|
138
|
-
- spec/escaped_params_spec.rb
|
139
|
-
- spec/form_token_spec.rb
|
140
|
-
- spec/frame_options_spec.rb
|
141
|
-
- spec/http_origin_spec.rb
|
142
|
-
- spec/ip_spoofing_spec.rb
|
143
|
-
- spec/json_csrf_spec.rb
|
144
|
-
- spec/path_traversal_spec.rb
|
145
|
-
- spec/protection_spec.rb
|
146
|
-
- spec/remote_referrer_spec.rb
|
147
|
-
- spec/remote_token_spec.rb
|
148
|
-
- spec/session_hijacking_spec.rb
|
149
|
-
- spec/spec_helper.rb
|
150
|
-
- spec/xss_header_spec.rb
|
151
|
-
homepage: http://github.com/rkh/rack-protection
|
87
|
+
homepage: http://sinatrarb.com/protection/
|
152
88
|
licenses:
|
153
89
|
- MIT
|
154
|
-
metadata:
|
90
|
+
metadata:
|
91
|
+
source_code_uri: https://github.com/sinatra/sinatra/tree/master/rack-protection
|
92
|
+
homepage_uri: http://sinatrarb.com/protection/
|
93
|
+
documentation_uri: https://www.rubydoc.info/gems/rack-protection
|
155
94
|
post_install_message:
|
156
95
|
rdoc_options: []
|
157
96
|
require_paths:
|
@@ -167,9 +106,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
106
|
- !ruby/object:Gem::Version
|
168
107
|
version: '0'
|
169
108
|
requirements: []
|
170
|
-
|
171
|
-
rubygems_version: 2.7.3
|
109
|
+
rubygems_version: 3.1.2
|
172
110
|
signing_key:
|
173
111
|
specification_version: 4
|
174
|
-
summary:
|
112
|
+
summary: Protect against typical web attacks, works with all Rack apps, including
|
113
|
+
Rails.
|
175
114
|
test_files: []
|
@@ -1,48 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper.rb', __FILE__)
|
2
|
-
|
3
|
-
describe Rack::Protection::AuthenticityToken do
|
4
|
-
it_behaves_like "any rack application"
|
5
|
-
|
6
|
-
it "denies post requests without any token" do
|
7
|
-
post('/').should_not be_ok
|
8
|
-
end
|
9
|
-
|
10
|
-
it "accepts post requests with correct X-CSRF-Token header" do
|
11
|
-
post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "a")
|
12
|
-
last_response.should be_ok
|
13
|
-
end
|
14
|
-
|
15
|
-
it "denies post requests with wrong X-CSRF-Token header" do
|
16
|
-
post('/', {}, 'rack.session' => {:csrf => "a"}, 'HTTP_X_CSRF_TOKEN' => "b")
|
17
|
-
last_response.should_not be_ok
|
18
|
-
end
|
19
|
-
|
20
|
-
it "accepts post form requests with correct authenticity_token field" do
|
21
|
-
post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"})
|
22
|
-
last_response.should be_ok
|
23
|
-
end
|
24
|
-
|
25
|
-
it "denies post form requests with wrong authenticity_token field" do
|
26
|
-
post('/', {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"})
|
27
|
-
last_response.should_not be_ok
|
28
|
-
end
|
29
|
-
|
30
|
-
it "prevents ajax requests without a valid token" do
|
31
|
-
post('/', {}, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest").should_not be_ok
|
32
|
-
end
|
33
|
-
|
34
|
-
it "allows for a custom authenticity token param" do
|
35
|
-
mock_app do
|
36
|
-
use Rack::Protection::AuthenticityToken, :authenticity_param => 'csrf_param'
|
37
|
-
run proc { |e| [200, {'Content-Type' => 'text/plain'}, ['hi']] }
|
38
|
-
end
|
39
|
-
|
40
|
-
post('/', {"csrf_param" => "a"}, 'rack.session' => {:csrf => "a"})
|
41
|
-
last_response.should be_ok
|
42
|
-
end
|
43
|
-
|
44
|
-
it "sets a new csrf token for the session in env, even after a 'safe' request" do
|
45
|
-
get('/', {}, {})
|
46
|
-
env['rack.session'][:csrf].should_not be_nil
|
47
|
-
end
|
48
|
-
end
|
data/spec/base_spec.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper.rb', __FILE__)
|
2
|
-
|
3
|
-
describe Rack::Protection::Base do
|
4
|
-
|
5
|
-
subject { described_class.new(lambda {}) }
|
6
|
-
|
7
|
-
describe "#random_string" do
|
8
|
-
it "outputs a string of 32 characters" do
|
9
|
-
subject.random_string.length.should == 32
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
describe "#referrer" do
|
14
|
-
it "Reads referrer from Referer header" do
|
15
|
-
env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "http://bar.com/valid"}
|
16
|
-
subject.referrer(env).should == "bar.com"
|
17
|
-
end
|
18
|
-
|
19
|
-
it "Reads referrer from Host header when Referer header is relative" do
|
20
|
-
env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "/valid"}
|
21
|
-
subject.referrer(env).should == "foo.com"
|
22
|
-
end
|
23
|
-
|
24
|
-
it "Reads referrer from Host header when Referer header is missing" do
|
25
|
-
env = {"HTTP_HOST" => "foo.com"}
|
26
|
-
subject.referrer(env).should == "foo.com"
|
27
|
-
end
|
28
|
-
|
29
|
-
it "Returns nil when Referer header is missing and allow_empty_referrer is false" do
|
30
|
-
env = {"HTTP_HOST" => "foo.com"}
|
31
|
-
subject.options[:allow_empty_referrer] = false
|
32
|
-
subject.referrer(env).should be_nil
|
33
|
-
end
|
34
|
-
|
35
|
-
it "Returns nil when Referer header is invalid" do
|
36
|
-
env = {"HTTP_HOST" => "foo.com", "HTTP_REFERER" => "http://bar.com/bad|uri"}
|
37
|
-
subject.referrer(env).should be_nil
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
data/spec/escaped_params_spec.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper.rb', __FILE__)
|
2
|
-
|
3
|
-
describe Rack::Protection::EscapedParams do
|
4
|
-
it_behaves_like "any rack application"
|
5
|
-
|
6
|
-
context 'escaping' do
|
7
|
-
it 'escapes html entities' do
|
8
|
-
mock_app do |env|
|
9
|
-
request = Rack::Request.new(env)
|
10
|
-
[200, {'Content-Type' => 'text/plain'}, [request.params['foo']]]
|
11
|
-
end
|
12
|
-
get '/', :foo => "<bar>"
|
13
|
-
body.should == '<bar>'
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'leaves normal params untouched' do
|
17
|
-
mock_app do |env|
|
18
|
-
request = Rack::Request.new(env)
|
19
|
-
[200, {'Content-Type' => 'text/plain'}, [request.params['foo']]]
|
20
|
-
end
|
21
|
-
get '/', :foo => "bar"
|
22
|
-
body.should == 'bar'
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'copes with nested arrays' do
|
26
|
-
mock_app do |env|
|
27
|
-
request = Rack::Request.new(env)
|
28
|
-
[200, {'Content-Type' => 'text/plain'}, [request.params['foo']['bar']]]
|
29
|
-
end
|
30
|
-
get '/', :foo => {:bar => "<bar>"}
|
31
|
-
body.should == '<bar>'
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'leaves cache-breaker params untouched' do
|
35
|
-
mock_app do |env|
|
36
|
-
[200, {'Content-Type' => 'text/plain'}, ['hi']]
|
37
|
-
end
|
38
|
-
|
39
|
-
get '/?95df8d9bf5237ad08df3115ee74dcb10'
|
40
|
-
body.should == 'hi'
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|