doorkeeper 1.0.0.rc2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -1
- data/lib/doorkeeper/version.rb +1 -1
- data/spec/controllers/applications_controller_spec.rb +4 -4
- data/spec/controllers/authorizations_controller_spec.rb +9 -9
- data/spec/controllers/protected_resources_controller_spec.rb +10 -10
- data/spec/controllers/token_info_controller_spec.rb +4 -4
- data/spec/controllers/tokens_controller_spec.rb +4 -4
- data/spec/lib/config_spec.rb +21 -21
- data/spec/lib/models/expirable_spec.rb +13 -13
- data/spec/lib/models/revocable_spec.rb +5 -5
- data/spec/lib/models/scopes_spec.rb +3 -3
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +5 -5
- data/spec/lib/oauth/authorization_code_request_spec.rb +7 -7
- data/spec/lib/oauth/client/credentials_spec.rb +8 -8
- data/spec/lib/oauth/client/methods_spec.rb +8 -8
- data/spec/lib/oauth/client_credentials/creator_spec.rb +2 -2
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +10 -9
- data/spec/lib/oauth/client_credentials/validation_spec.rb +6 -6
- data/spec/lib/oauth/client_credentials_request_spec.rb +7 -7
- data/spec/lib/oauth/client_spec.rb +8 -8
- data/spec/lib/oauth/code_request_spec.rb +4 -4
- data/spec/lib/oauth/error_response_spec.rb +22 -15
- data/spec/lib/oauth/error_spec.rb +1 -1
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +13 -13
- data/spec/lib/oauth/helpers/unique_token_spec.rb +2 -2
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +13 -13
- data/spec/lib/oauth/invalid_token_response_spec.rb +9 -4
- data/spec/lib/oauth/password_access_token_request_spec.rb +7 -7
- data/spec/lib/oauth/pre_authorization_spec.rb +14 -14
- data/spec/lib/oauth/refresh_token_request_spec.rb +8 -8
- data/spec/lib/oauth/scopes_spec.rb +27 -19
- data/spec/lib/oauth/token_request_spec.rb +4 -4
- data/spec/lib/oauth/token_response_spec.rb +11 -11
- data/spec/lib/oauth/token_spec.rb +9 -9
- data/spec/lib/server_spec.rb +1 -1
- data/spec/models/doorkeeper/access_token_spec.rb +15 -15
- data/spec/models/doorkeeper/application_spec.rb +21 -21
- data/spec/requests/flows/authorization_code_spec.rb +1 -1
- data/spec/requests/flows/client_credentials_spec.rb +1 -1
- data/spec/requests/flows/refresh_token_spec.rb +6 -6
- data/spec/requests/protected_resources/private_api_spec.rb +3 -3
- data/spec/routing/custom_controller_routes_spec.rb +16 -16
- data/spec/routing/default_routes_spec.rb +7 -7
- data/spec/routing/scoped_routes_spec.rb +7 -7
- data/spec/support/helpers/authorization_request_helper.rb +3 -3
- data/spec/support/helpers/model_helper.rb +6 -6
- data/spec/support/helpers/request_spec_helper.rb +9 -9
- data/spec/support/shared/controllers_shared_context.rb +6 -6
- data/spec/support/shared/models_shared_examples.rb +6 -6
- data/spec/validators/redirect_uri_validator_spec.rb +12 -12
- metadata +4 -4
@@ -28,19 +28,19 @@ module Doorkeeper::OAuth
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'returns a code response' do
|
31
|
-
subject.authorize.
|
31
|
+
expect(subject.authorize).to be_a(CodeResponse)
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'does not create token when not authorizable' do
|
35
|
-
pre_auth.
|
35
|
+
allow(pre_auth).to receive(:authorizable?).and_return(false)
|
36
36
|
expect do
|
37
37
|
subject.authorize
|
38
38
|
end.to_not change { Doorkeeper::AccessToken.count }
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'returns a error response' do
|
42
|
-
pre_auth.
|
43
|
-
subject.authorize.
|
42
|
+
allow(pre_auth).to receive(:authorizable?).and_return(false)
|
43
|
+
expect(subject.authorize).to be_a(ErrorResponse)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -7,12 +7,12 @@ module Doorkeeper::OAuth
|
|
7
7
|
|
8
8
|
it 'includes access token response headers' do
|
9
9
|
headers = subject.headers
|
10
|
-
headers.fetch('Cache-Control').
|
11
|
-
headers.fetch('Pragma').
|
10
|
+
expect(headers.fetch('Cache-Control')).to eq('no-store')
|
11
|
+
expect(headers.fetch('Pragma')).to eq('no-cache')
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'status is ok' do
|
15
|
-
subject.status.
|
15
|
+
expect(subject.status).to eq(:ok)
|
16
16
|
end
|
17
17
|
|
18
18
|
describe '.body' do
|
@@ -30,25 +30,25 @@ module Doorkeeper::OAuth
|
|
30
30
|
subject { TokenResponse.new(access_token).body }
|
31
31
|
|
32
32
|
it 'includes :access_token' do
|
33
|
-
subject['access_token'].
|
33
|
+
expect(subject['access_token']).to eq('some-token')
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'includes :token_type' do
|
37
|
-
subject['token_type'].
|
37
|
+
expect(subject['token_type']).to eq('bearer')
|
38
38
|
end
|
39
39
|
|
40
40
|
# expires_in_seconds is returned as `expires_in` in order to match
|
41
41
|
# the OAuth spec (section 4.2.2)
|
42
42
|
it 'includes :expires_in' do
|
43
|
-
subject['expires_in'].
|
43
|
+
expect(subject['expires_in']).to eq('300')
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'includes :scope' do
|
47
|
-
subject['scope'].
|
47
|
+
expect(subject['scope']).to eq('two scopes')
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'includes :refresh_token' do
|
51
|
-
subject['refresh_token'].
|
51
|
+
expect(subject['refresh_token']).to eq('some-refresh-token')
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -66,15 +66,15 @@ module Doorkeeper::OAuth
|
|
66
66
|
subject { TokenResponse.new(access_token).body }
|
67
67
|
|
68
68
|
it 'includes :expires_in' do
|
69
|
-
subject['expires_in'].
|
69
|
+
expect(subject['expires_in']).to be_nil
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'includes :scope' do
|
73
|
-
subject['scope'].
|
73
|
+
expect(subject['scope']).to be_nil
|
74
74
|
end
|
75
75
|
|
76
76
|
it 'includes :refresh_token' do
|
77
|
-
subject['refresh_token'].
|
77
|
+
expect(subject['refresh_token']).to be_nil
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
@@ -18,24 +18,24 @@ module Doorkeeper
|
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'accepts anything that responds to #call' do
|
21
|
-
method.
|
21
|
+
expect(method).to receive(:call).with(request)
|
22
22
|
Token.from_request request, method
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'delegates methods received as symbols to Token class' do
|
26
|
-
Token.
|
26
|
+
expect(Token).to receive(:from_params).with(request)
|
27
27
|
Token.from_request request, :from_params
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'stops at the first credentials found' do
|
31
31
|
not_called_method = double
|
32
|
-
not_called_method.
|
32
|
+
expect(not_called_method).not_to receive(:call)
|
33
33
|
credentials = Token.from_request request, lambda { |r| }, method, not_called_method
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'returns the credential from extractor method' do
|
37
37
|
credentials = Token.from_request request, method
|
38
|
-
credentials.
|
38
|
+
expect(credentials).to eq('token-value')
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -43,7 +43,7 @@ module Doorkeeper
|
|
43
43
|
it 'returns token from access_token parameter' do
|
44
44
|
request = double :parameters => { :access_token => 'some-token' }
|
45
45
|
token = Token.from_access_token_param(request)
|
46
|
-
token.
|
46
|
+
expect(token).to eq("some-token")
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -51,7 +51,7 @@ module Doorkeeper
|
|
51
51
|
it 'returns token from bearer_token parameter' do
|
52
52
|
request = double :parameters => { :bearer_token => 'some-token' }
|
53
53
|
token = Token.from_bearer_param(request)
|
54
|
-
token.
|
54
|
+
expect(token).to eq("some-token")
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -59,13 +59,13 @@ module Doorkeeper
|
|
59
59
|
it 'returns token from authorization bearer' do
|
60
60
|
request = double :authorization => "Bearer SomeToken"
|
61
61
|
token = Token.from_bearer_authorization(request)
|
62
|
-
token.
|
62
|
+
expect(token).to eq("SomeToken")
|
63
63
|
end
|
64
64
|
|
65
65
|
it 'does not return token if authorization is not bearer' do
|
66
66
|
request = double :authorization => "MAC SomeToken"
|
67
67
|
token = Token.from_bearer_authorization(request)
|
68
|
-
token.
|
68
|
+
expect(token).to be_blank
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
@@ -74,7 +74,7 @@ module Doorkeeper
|
|
74
74
|
|
75
75
|
it 'calls the finder if token was found' do
|
76
76
|
token = lambda { |r| 'token' }
|
77
|
-
AccessToken.
|
77
|
+
expect(AccessToken).to receive(:authenticate).with('token')
|
78
78
|
Token.authenticate double, token
|
79
79
|
end
|
80
80
|
end
|
data/spec/lib/server_spec.rb
CHANGED
@@ -21,7 +21,7 @@ describe Doorkeeper::Server do
|
|
21
21
|
|
22
22
|
it 'builds the request with selected strategy' do
|
23
23
|
stub_const 'Doorkeeper::Request::Code', fake_class
|
24
|
-
fake_class.
|
24
|
+
expect(fake_class).to receive(:build).with(subject)
|
25
25
|
subject.authorization_request :code
|
26
26
|
end
|
27
27
|
end
|
@@ -15,19 +15,19 @@ module Doorkeeper
|
|
15
15
|
describe :refresh_token do
|
16
16
|
it 'has empty refresh token if it was not required' do
|
17
17
|
token = FactoryGirl.create :access_token
|
18
|
-
token.refresh_token.
|
18
|
+
expect(token.refresh_token).to be_nil
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'generates a refresh token if it was requested' do
|
22
22
|
token = FactoryGirl.create :access_token, :use_refresh_token => true
|
23
|
-
token.refresh_token.
|
23
|
+
expect(token.refresh_token).not_to be_nil
|
24
24
|
end
|
25
25
|
|
26
26
|
it "is not valid if token exists" do
|
27
27
|
token1 = FactoryGirl.create :access_token, :use_refresh_token => true
|
28
28
|
token2 = FactoryGirl.create :access_token, :use_refresh_token => true
|
29
29
|
token2.send :write_attribute, :refresh_token, token1.refresh_token
|
30
|
-
token2.
|
30
|
+
expect(token2).not_to be_valid
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'expects database to raise an error if refresh tokens are the same' do
|
@@ -59,20 +59,20 @@ module Doorkeeper
|
|
59
59
|
FactoryGirl.create :access_token, default_attributes
|
60
60
|
AccessToken.revoke_all_for application.id, resource_owner
|
61
61
|
AccessToken.all.each do |token|
|
62
|
-
token.
|
62
|
+
expect(token).to be_revoked
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'matches application' do
|
67
67
|
FactoryGirl.create :access_token, default_attributes.merge(:application => FactoryGirl.create(:application))
|
68
68
|
AccessToken.revoke_all_for application.id, resource_owner
|
69
|
-
AccessToken.all.
|
69
|
+
expect(AccessToken.all).not_to be_empty
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'matches resource owner' do
|
73
73
|
FactoryGirl.create :access_token, default_attributes.merge(:resource_owner_id => 90)
|
74
74
|
AccessToken.revoke_all_for application.id, resource_owner
|
75
|
-
AccessToken.all.
|
75
|
+
expect(AccessToken.all).not_to be_empty
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
@@ -87,51 +87,51 @@ module Doorkeeper
|
|
87
87
|
it 'returns only one token' do
|
88
88
|
token = FactoryGirl.create :access_token, default_attributes
|
89
89
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
90
|
-
last_token.
|
90
|
+
expect(last_token).to eq(token)
|
91
91
|
end
|
92
92
|
|
93
93
|
it 'accepts resource owner as object' do
|
94
94
|
resource_owner = double(:to_key => true, :id => 100)
|
95
95
|
token = FactoryGirl.create :access_token, default_attributes
|
96
96
|
last_token = AccessToken.matching_token_for(application, resource_owner, scopes)
|
97
|
-
last_token.
|
97
|
+
expect(last_token).to eq(token)
|
98
98
|
end
|
99
99
|
|
100
100
|
it 'accepts nil as resource owner' do
|
101
101
|
token = FactoryGirl.create :access_token, default_attributes.merge(:resource_owner_id => nil)
|
102
102
|
last_token = AccessToken.matching_token_for(application, nil, scopes)
|
103
|
-
last_token.
|
103
|
+
expect(last_token).to eq(token)
|
104
104
|
end
|
105
105
|
|
106
106
|
it 'excludes revoked tokens' do
|
107
107
|
FactoryGirl.create :access_token, default_attributes.merge(:revoked_at => 1.day.ago)
|
108
108
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
109
|
-
last_token.
|
109
|
+
expect(last_token).to be_nil
|
110
110
|
end
|
111
111
|
|
112
112
|
it 'matches the application' do
|
113
113
|
token = FactoryGirl.create :access_token, default_attributes.merge(:application => FactoryGirl.create(:application))
|
114
114
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
115
|
-
last_token.
|
115
|
+
expect(last_token).to be_nil
|
116
116
|
end
|
117
117
|
|
118
118
|
it 'matches the resource owner' do
|
119
119
|
FactoryGirl.create :access_token, default_attributes.merge(:resource_owner_id => 2)
|
120
120
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
121
|
-
last_token.
|
121
|
+
expect(last_token).to be_nil
|
122
122
|
end
|
123
123
|
|
124
124
|
it 'matches the scopes' do
|
125
125
|
FactoryGirl.create :access_token, default_attributes.merge(:scopes => 'public email')
|
126
126
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
127
|
-
last_token.
|
127
|
+
expect(last_token).to be_nil
|
128
128
|
end
|
129
129
|
|
130
130
|
it 'returns the last created token' do
|
131
131
|
FactoryGirl.create :access_token, default_attributes.merge(:created_at => 1.day.ago)
|
132
132
|
token = FactoryGirl.create :access_token, default_attributes
|
133
133
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
134
|
-
last_token.
|
134
|
+
expect(last_token).to eq(token)
|
135
135
|
end
|
136
136
|
|
137
137
|
it 'returns as_json hash' do
|
@@ -142,7 +142,7 @@ module Doorkeeper
|
|
142
142
|
:expires_in_seconds => token.expires_in_seconds,
|
143
143
|
:application => { :uid => token.application.uid }
|
144
144
|
}
|
145
|
-
token.as_json.
|
145
|
+
expect(token.as_json).to eq token_hash
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
@@ -25,7 +25,7 @@ module Doorkeeper
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'is valid given valid attributes' do
|
28
|
-
new_application.
|
28
|
+
expect(new_application).to be_valid
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -36,50 +36,50 @@ module Doorkeeper
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'is invalid without an owner' do
|
39
|
-
new_application.
|
39
|
+
expect(new_application).not_to be_valid
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'is valid with an owner' do
|
43
43
|
new_application.owner = @owner
|
44
|
-
new_application.
|
44
|
+
expect(new_application).to be_valid
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'is invalid without a name' do
|
50
50
|
new_application.name = nil
|
51
|
-
new_application.
|
51
|
+
expect(new_application).not_to be_valid
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'generates uid on create' do
|
55
|
-
new_application.uid.
|
55
|
+
expect(new_application.uid).to be_nil
|
56
56
|
new_application.save
|
57
|
-
new_application.uid.
|
57
|
+
expect(new_application.uid).not_to be_nil
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'generates uid on create unless one is set' do
|
61
61
|
new_application.uid = uid
|
62
62
|
new_application.save
|
63
|
-
new_application.uid.
|
63
|
+
expect(new_application.uid).to eq(uid)
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'is invalid without uid' do
|
67
67
|
new_application.save
|
68
68
|
new_application.uid = nil
|
69
|
-
new_application.
|
69
|
+
expect(new_application).not_to be_valid
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'is invalid without redirect_uri' do
|
73
73
|
new_application.save
|
74
74
|
new_application.redirect_uri = nil
|
75
|
-
new_application.
|
75
|
+
expect(new_application).not_to be_valid
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'checks uniqueness of uid' do
|
79
79
|
app1 = Factory(:application)
|
80
80
|
app2 = Factory(:application)
|
81
81
|
app2.uid = app1.uid
|
82
|
-
app2.
|
82
|
+
expect(app2).not_to be_valid
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'expects database to throw an error when uids are the same' do
|
@@ -92,21 +92,21 @@ module Doorkeeper
|
|
92
92
|
end
|
93
93
|
|
94
94
|
it 'generate secret on create' do
|
95
|
-
new_application.secret.
|
95
|
+
expect(new_application.secret).to be_nil
|
96
96
|
new_application.save
|
97
|
-
new_application.secret.
|
97
|
+
expect(new_application.secret).not_to be_nil
|
98
98
|
end
|
99
99
|
|
100
100
|
it 'generate secret on create unless one is set' do
|
101
101
|
new_application.secret = secret
|
102
102
|
new_application.save
|
103
|
-
new_application.secret.
|
103
|
+
expect(new_application.secret).to eq(secret)
|
104
104
|
end
|
105
105
|
|
106
106
|
it 'is invalid without secret' do
|
107
107
|
new_application.save
|
108
108
|
new_application.secret = nil
|
109
|
-
new_application.
|
109
|
+
expect(new_application).not_to be_valid
|
110
110
|
end
|
111
111
|
|
112
112
|
describe 'destroy related models on cascade' do
|
@@ -130,31 +130,31 @@ module Doorkeeper
|
|
130
130
|
let(:resource_owner) { double(:resource_owner, :id => 10) }
|
131
131
|
|
132
132
|
it "is empty if the application is not authorized for anyone" do
|
133
|
-
Application.authorized_for(resource_owner).
|
133
|
+
expect(Application.authorized_for(resource_owner)).to be_empty
|
134
134
|
end
|
135
135
|
|
136
136
|
it "returns only application for a specific resource owner" do
|
137
137
|
FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id + 1)
|
138
138
|
token = FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id)
|
139
|
-
Application.authorized_for(resource_owner).
|
139
|
+
expect(Application.authorized_for(resource_owner)).to eq([token.application])
|
140
140
|
end
|
141
141
|
|
142
142
|
it "excludes revoked tokens" do
|
143
143
|
FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id, :revoked_at => 2.days.ago)
|
144
|
-
Application.authorized_for(resource_owner).
|
144
|
+
expect(Application.authorized_for(resource_owner)).to be_empty
|
145
145
|
end
|
146
146
|
|
147
147
|
it "returns all applications that have been authorized" do
|
148
148
|
token1 = FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id)
|
149
149
|
token2 = FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id)
|
150
|
-
Application.authorized_for(resource_owner).
|
150
|
+
expect(Application.authorized_for(resource_owner)).to eq([token1.application, token2.application])
|
151
151
|
end
|
152
152
|
|
153
153
|
it "returns only one application even if it has been authorized twice" do
|
154
154
|
application = FactoryGirl.create(:application)
|
155
155
|
FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id, :application => application)
|
156
156
|
FactoryGirl.create(:access_token, :resource_owner_id => resource_owner.id, :application => application)
|
157
|
-
Application.authorized_for(resource_owner).
|
157
|
+
expect(Application.authorized_for(resource_owner)).to eq([application])
|
158
158
|
end
|
159
159
|
|
160
160
|
it "should fail to mass assign a new application", if: ::Rails::VERSION::MAJOR < 4 do
|
@@ -162,7 +162,7 @@ module Doorkeeper
|
|
162
162
|
:redirect_uri => 'http://somewhere.com/something',
|
163
163
|
:uid => 123,
|
164
164
|
:secret => 'something' }
|
165
|
-
Application.create(mass_assign).uid.
|
165
|
+
expect(Application.create(mass_assign).uid).not_to eq(123)
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
@@ -170,7 +170,7 @@ module Doorkeeper
|
|
170
170
|
it 'finds the application via uid/secret' do
|
171
171
|
app = FactoryGirl.create :application
|
172
172
|
authenticated = Application.authenticate(app.uid, app.secret)
|
173
|
-
authenticated.
|
173
|
+
expect(authenticated).to eq(app)
|
174
174
|
end
|
175
175
|
end
|
176
176
|
end
|
@@ -100,7 +100,7 @@ feature 'Authorization Code Flow' do
|
|
100
100
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
101
101
|
post token_endpoint_url(:code => authorization_code, :client => @client)
|
102
102
|
|
103
|
-
Doorkeeper::AccessToken.count.
|
103
|
+
expect(Doorkeeper::AccessToken.count).to be(2)
|
104
104
|
|
105
105
|
should_have_json 'access_token', Doorkeeper::AccessToken.last.token
|
106
106
|
end
|