qtc-sdk 0.2.0 → 0.3.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/.gitignore +18 -18
- data/Changelog.md +14 -6
- data/Gemfile +4 -4
- data/LICENSE.txt +22 -22
- data/README.md +44 -44
- data/Rakefile +1 -1
- data/bin/qtc-cli +13 -13
- data/lib/qtc/cli/commands.rb +15 -15
- data/lib/qtc/cli/common.rb +146 -91
- data/lib/qtc/cli/eds/base.rb +27 -27
- data/lib/qtc/cli/eds/commands.rb +20 -20
- data/lib/qtc/cli/eds/instances.rb +30 -30
- data/lib/qtc/cli/mar/apps.rb +116 -125
- data/lib/qtc/cli/mar/base.rb +60 -60
- data/lib/qtc/cli/mar/commands.rb +221 -199
- data/lib/qtc/cli/mar/debug.rb +87 -86
- data/lib/qtc/cli/mar/domains.rb +35 -38
- data/lib/qtc/cli/mar/env.rb +38 -40
- data/lib/qtc/cli/mar/repository.rb +24 -26
- data/lib/qtc/cli/mar/ssl_certificates.rb +40 -42
- data/lib/qtc/cli/mar/stack.rb +29 -0
- data/lib/qtc/cli/mdb/base.rb +47 -43
- data/lib/qtc/cli/mdb/commands.rb +43 -31
- data/lib/qtc/cli/mdb/instances.rb +79 -60
- data/lib/qtc/cli/platform/clouds.rb +33 -15
- data/lib/qtc/cli/platform/commands.rb +132 -65
- data/lib/qtc/cli/platform/datacenters.rb +23 -21
- data/lib/qtc/cli/platform/ssh_keys.rb +41 -41
- data/lib/qtc/cli/platform/user.rb +25 -25
- data/lib/qtc/cli/platform/vpn.rb +93 -0
- data/lib/qtc/client.rb +170 -170
- data/lib/qtc/eds/client.rb +116 -116
- data/lib/qtc/eds/collection.rb +124 -124
- data/lib/qtc/eds/user_collection.rb +13 -13
- data/lib/qtc/eds/usergroup_collection.rb +41 -41
- data/lib/qtc/errors.rb +13 -11
- data/lib/qtc/version.rb +3 -3
- data/lib/qtc-sdk.rb +1 -1
- data/qtc-sdk.gemspec +28 -28
- data/spec/unit/qtc/client_spec.rb +147 -147
- metadata +20 -19
- data/lib/qtc/mws/client.rb +0 -89
data/lib/qtc/client.rb
CHANGED
@@ -1,170 +1,170 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'httpclient'
|
3
|
-
require_relative 'errors'
|
4
|
-
|
5
|
-
module Qtc
|
6
|
-
class Client
|
7
|
-
|
8
|
-
attr_accessor :default_headers
|
9
|
-
attr_reader :http_client
|
10
|
-
|
11
|
-
# Initialize api client
|
12
|
-
#
|
13
|
-
# @param [String] api_url
|
14
|
-
# @param [Hash] default_headers
|
15
|
-
def initialize(api_url, default_headers = {})
|
16
|
-
@http_client = HTTPClient.new
|
17
|
-
@default_headers = {'Accept' => 'application/json', 'Content-Type' => 'application/json'}.merge(default_headers)
|
18
|
-
@api_url = api_url
|
19
|
-
end
|
20
|
-
|
21
|
-
# Get request
|
22
|
-
#
|
23
|
-
# @param [String] path
|
24
|
-
# @param [Hash,NilClass] params
|
25
|
-
# @return [Hash]
|
26
|
-
def get(path, params = nil, headers = {})
|
27
|
-
response = http_client.get(request_uri(path), params, request_headers(headers))
|
28
|
-
if response.status == 200
|
29
|
-
parse_response(response)
|
30
|
-
else
|
31
|
-
handle_error_response(response)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# Post request
|
36
|
-
#
|
37
|
-
# @param [String] path
|
38
|
-
# @param [Object] obj
|
39
|
-
# @param [Hash] params
|
40
|
-
# @param [Hash] headers
|
41
|
-
# @return [Hash]
|
42
|
-
def post(path, obj, params = {}, headers = {})
|
43
|
-
request_headers = request_headers(headers)
|
44
|
-
request_options = {
|
45
|
-
header: request_headers,
|
46
|
-
body: encode_body(obj, request_headers['Content-Type']),
|
47
|
-
query: params
|
48
|
-
}
|
49
|
-
response = http_client.post(request_uri(path), request_options)
|
50
|
-
if [200, 201].include?(response.status)
|
51
|
-
parse_response(response)
|
52
|
-
else
|
53
|
-
handle_error_response(response)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# Put request
|
58
|
-
#
|
59
|
-
# @param [String] path
|
60
|
-
# @param [Object] obj
|
61
|
-
# @param [Hash] params
|
62
|
-
# @param [Hash] headers
|
63
|
-
# @return [Hash]
|
64
|
-
def put(path, obj, params = {}, headers = {})
|
65
|
-
request_headers = request_headers(headers)
|
66
|
-
request_options = {
|
67
|
-
header: request_headers,
|
68
|
-
body: encode_body(obj, request_headers['Content-Type']),
|
69
|
-
query: params
|
70
|
-
}
|
71
|
-
|
72
|
-
response = http_client.put(request_uri(path), request_options)
|
73
|
-
if [200, 201].include?(response.status)
|
74
|
-
parse_response(response)
|
75
|
-
else
|
76
|
-
handle_error_response(response)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# Delete request
|
81
|
-
#
|
82
|
-
# @param [String] path
|
83
|
-
# @param [Hash,String] body
|
84
|
-
# @param [Hash] params
|
85
|
-
# @param [Hash] headers
|
86
|
-
# @return [Hash]
|
87
|
-
def delete(path, body = nil, params = {}, headers = {})
|
88
|
-
request_headers = request_headers(headers)
|
89
|
-
request_options = {
|
90
|
-
header: request_headers,
|
91
|
-
body: encode_body(body, request_headers['Content-Type']),
|
92
|
-
query: params
|
93
|
-
}
|
94
|
-
response = http_client.delete(request_uri(path), request_options)
|
95
|
-
if response.status == 200
|
96
|
-
parse_response(response)
|
97
|
-
else
|
98
|
-
handle_error_response(response)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
private
|
103
|
-
|
104
|
-
##
|
105
|
-
# Get full request uri
|
106
|
-
#
|
107
|
-
# @param [String] path
|
108
|
-
# @return [String]
|
109
|
-
def request_uri(path)
|
110
|
-
"#{@api_url}#{path}"
|
111
|
-
end
|
112
|
-
|
113
|
-
##
|
114
|
-
# Get request headers
|
115
|
-
#
|
116
|
-
# @param [Hash] headers
|
117
|
-
# @return [Hash]
|
118
|
-
def request_headers(headers = {})
|
119
|
-
@default_headers.merge(headers)
|
120
|
-
end
|
121
|
-
|
122
|
-
##
|
123
|
-
# Encode body based on content type
|
124
|
-
#
|
125
|
-
# @param [Object] body
|
126
|
-
# @param [String] content_type
|
127
|
-
def encode_body(body, content_type)
|
128
|
-
if content_type == 'application/json'
|
129
|
-
dump_json(body)
|
130
|
-
else
|
131
|
-
body
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
##
|
136
|
-
# Parse response
|
137
|
-
#
|
138
|
-
# @param [HTTP::Message]
|
139
|
-
# @return [Object]
|
140
|
-
def parse_response(response)
|
141
|
-
if response.headers['Content-Type'].include?('application/json')
|
142
|
-
parse_json(response.body)
|
143
|
-
else
|
144
|
-
response.body
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
##
|
149
|
-
# Parse json
|
150
|
-
#
|
151
|
-
# @param [String] json
|
152
|
-
# @return [Hash,Object,NilClass]
|
153
|
-
def parse_json(json)
|
154
|
-
JSON.parse(json) rescue nil
|
155
|
-
end
|
156
|
-
|
157
|
-
##
|
158
|
-
# Dump json
|
159
|
-
#
|
160
|
-
# @param [Object] obj
|
161
|
-
# @return [String]
|
162
|
-
def dump_json(obj)
|
163
|
-
JSON.dump(obj)
|
164
|
-
end
|
165
|
-
|
166
|
-
def handle_error_response(response)
|
167
|
-
raise Qtc::Errors::StandardError.new(response.status, response.body)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
1
|
+
require 'json'
|
2
|
+
require 'httpclient'
|
3
|
+
require_relative 'errors'
|
4
|
+
|
5
|
+
module Qtc
|
6
|
+
class Client
|
7
|
+
|
8
|
+
attr_accessor :default_headers
|
9
|
+
attr_reader :http_client
|
10
|
+
|
11
|
+
# Initialize api client
|
12
|
+
#
|
13
|
+
# @param [String] api_url
|
14
|
+
# @param [Hash] default_headers
|
15
|
+
def initialize(api_url, default_headers = {})
|
16
|
+
@http_client = HTTPClient.new
|
17
|
+
@default_headers = {'Accept' => 'application/json', 'Content-Type' => 'application/json'}.merge(default_headers)
|
18
|
+
@api_url = api_url
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get request
|
22
|
+
#
|
23
|
+
# @param [String] path
|
24
|
+
# @param [Hash,NilClass] params
|
25
|
+
# @return [Hash]
|
26
|
+
def get(path, params = nil, headers = {})
|
27
|
+
response = http_client.get(request_uri(path), params, request_headers(headers))
|
28
|
+
if response.status == 200
|
29
|
+
parse_response(response)
|
30
|
+
else
|
31
|
+
handle_error_response(response)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Post request
|
36
|
+
#
|
37
|
+
# @param [String] path
|
38
|
+
# @param [Object] obj
|
39
|
+
# @param [Hash] params
|
40
|
+
# @param [Hash] headers
|
41
|
+
# @return [Hash]
|
42
|
+
def post(path, obj, params = {}, headers = {})
|
43
|
+
request_headers = request_headers(headers)
|
44
|
+
request_options = {
|
45
|
+
header: request_headers,
|
46
|
+
body: encode_body(obj, request_headers['Content-Type']),
|
47
|
+
query: params
|
48
|
+
}
|
49
|
+
response = http_client.post(request_uri(path), request_options)
|
50
|
+
if [200, 201].include?(response.status)
|
51
|
+
parse_response(response)
|
52
|
+
else
|
53
|
+
handle_error_response(response)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Put request
|
58
|
+
#
|
59
|
+
# @param [String] path
|
60
|
+
# @param [Object] obj
|
61
|
+
# @param [Hash] params
|
62
|
+
# @param [Hash] headers
|
63
|
+
# @return [Hash]
|
64
|
+
def put(path, obj, params = {}, headers = {})
|
65
|
+
request_headers = request_headers(headers)
|
66
|
+
request_options = {
|
67
|
+
header: request_headers,
|
68
|
+
body: encode_body(obj, request_headers['Content-Type']),
|
69
|
+
query: params
|
70
|
+
}
|
71
|
+
|
72
|
+
response = http_client.put(request_uri(path), request_options)
|
73
|
+
if [200, 201].include?(response.status)
|
74
|
+
parse_response(response)
|
75
|
+
else
|
76
|
+
handle_error_response(response)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Delete request
|
81
|
+
#
|
82
|
+
# @param [String] path
|
83
|
+
# @param [Hash,String] body
|
84
|
+
# @param [Hash] params
|
85
|
+
# @param [Hash] headers
|
86
|
+
# @return [Hash]
|
87
|
+
def delete(path, body = nil, params = {}, headers = {})
|
88
|
+
request_headers = request_headers(headers)
|
89
|
+
request_options = {
|
90
|
+
header: request_headers,
|
91
|
+
body: encode_body(body, request_headers['Content-Type']),
|
92
|
+
query: params
|
93
|
+
}
|
94
|
+
response = http_client.delete(request_uri(path), request_options)
|
95
|
+
if response.status == 200
|
96
|
+
parse_response(response)
|
97
|
+
else
|
98
|
+
handle_error_response(response)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
##
|
105
|
+
# Get full request uri
|
106
|
+
#
|
107
|
+
# @param [String] path
|
108
|
+
# @return [String]
|
109
|
+
def request_uri(path)
|
110
|
+
"#{@api_url}#{path}"
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Get request headers
|
115
|
+
#
|
116
|
+
# @param [Hash] headers
|
117
|
+
# @return [Hash]
|
118
|
+
def request_headers(headers = {})
|
119
|
+
@default_headers.merge(headers)
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Encode body based on content type
|
124
|
+
#
|
125
|
+
# @param [Object] body
|
126
|
+
# @param [String] content_type
|
127
|
+
def encode_body(body, content_type)
|
128
|
+
if content_type == 'application/json'
|
129
|
+
dump_json(body)
|
130
|
+
else
|
131
|
+
body
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Parse response
|
137
|
+
#
|
138
|
+
# @param [HTTP::Message]
|
139
|
+
# @return [Object]
|
140
|
+
def parse_response(response)
|
141
|
+
if response.headers['Content-Type'].include?('application/json')
|
142
|
+
parse_json(response.body)
|
143
|
+
else
|
144
|
+
response.body
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
##
|
149
|
+
# Parse json
|
150
|
+
#
|
151
|
+
# @param [String] json
|
152
|
+
# @return [Hash,Object,NilClass]
|
153
|
+
def parse_json(json)
|
154
|
+
JSON.parse(json) rescue nil
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# Dump json
|
159
|
+
#
|
160
|
+
# @param [Object] obj
|
161
|
+
# @return [String]
|
162
|
+
def dump_json(obj)
|
163
|
+
JSON.dump(obj)
|
164
|
+
end
|
165
|
+
|
166
|
+
def handle_error_response(response)
|
167
|
+
raise Qtc::Errors::StandardError.new(response.status, response.body)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
data/lib/qtc/eds/client.rb
CHANGED
@@ -1,117 +1,117 @@
|
|
1
|
-
require_relative 'collection'
|
2
|
-
require_relative 'user_collection'
|
3
|
-
require_relative 'usergroup_collection'
|
4
|
-
|
5
|
-
module Qtc
|
6
|
-
module Eds
|
7
|
-
class Client
|
8
|
-
|
9
|
-
DEFAULT_OPTIONS = {
|
10
|
-
api_url: 'https://api.engin.io/v1'
|
11
|
-
}
|
12
|
-
|
13
|
-
##
|
14
|
-
# Initialize
|
15
|
-
#
|
16
|
-
# @param [String] backend_id
|
17
|
-
# @param [Hash] options
|
18
|
-
def initialize(backend_id, options = {})
|
19
|
-
@options = DEFAULT_OPTIONS.merge(options)
|
20
|
-
@backend_id = backend_id
|
21
|
-
headers = {'Enginio-Backend-Id' => @backend_id}
|
22
|
-
@client = Qtc::Client.new(@options[:api_url], headers)
|
23
|
-
end
|
24
|
-
|
25
|
-
##
|
26
|
-
# Get Qtc::Client instance
|
27
|
-
#
|
28
|
-
# @return [Qtc::Client]
|
29
|
-
def http_client
|
30
|
-
@client
|
31
|
-
end
|
32
|
-
|
33
|
-
##
|
34
|
-
# Get collection
|
35
|
-
#
|
36
|
-
# @param [String] name
|
37
|
-
# @return [Qtc::Eds::Collection]
|
38
|
-
def collection(name)
|
39
|
-
Qtc::Eds::Collection.new(@client, "/objects/#{name}")
|
40
|
-
end
|
41
|
-
|
42
|
-
##
|
43
|
-
# Get user collection
|
44
|
-
#
|
45
|
-
# @return [Qtc::Eds::UserCollection]
|
46
|
-
def users
|
47
|
-
Qtc::Eds::UserCollection.new(@client)
|
48
|
-
end
|
49
|
-
|
50
|
-
##
|
51
|
-
# Get usergroup collection
|
52
|
-
#
|
53
|
-
# @return [Qtc::Eds::UsergroupCollection]
|
54
|
-
def usergroups
|
55
|
-
Qtc::Eds::UsergroupCollection.new(@client)
|
56
|
-
end
|
57
|
-
|
58
|
-
def current_user
|
59
|
-
if @client.default_headers['Authorization']
|
60
|
-
@client.get('/user')
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
##
|
65
|
-
# Set access token
|
66
|
-
#
|
67
|
-
# @param [String] access_token
|
68
|
-
def access_token=(access_token)
|
69
|
-
if !access_token.nil?
|
70
|
-
@client.default_headers['Authorization'] = "Bearer #{access_token}"
|
71
|
-
else
|
72
|
-
@client.default_headers.delete('Authorization')
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
##
|
77
|
-
# Call block with given access token
|
78
|
-
#
|
79
|
-
# @param [String] access_token
|
80
|
-
# @param []
|
81
|
-
def with_access_token(access_token, &block)
|
82
|
-
prev_auth = @client.default_headers['Authorization'].dup
|
83
|
-
@client.default_headers['Authorization'] = "Bearer #{access_token}"
|
84
|
-
result = call(&block)
|
85
|
-
@client.default_headers['Authorization'] = prev_auth
|
86
|
-
result
|
87
|
-
ensure
|
88
|
-
@client.default_headers['Authorization'] = prev_auth if prev_auth
|
89
|
-
end
|
90
|
-
|
91
|
-
##
|
92
|
-
# Create user access token
|
93
|
-
#
|
94
|
-
# @param [String] username
|
95
|
-
# @param [String] password
|
96
|
-
def create_user_token(username, password)
|
97
|
-
body = {
|
98
|
-
grant_type: 'password',
|
99
|
-
username: username,
|
100
|
-
password: password
|
101
|
-
}
|
102
|
-
@client.post('/auth/oauth2/token', body, {}, {'Content-Type' => 'application/x-www-form-urlencoded'})
|
103
|
-
end
|
104
|
-
|
105
|
-
##
|
106
|
-
# Revoke user access token
|
107
|
-
#
|
108
|
-
# @param [String] token
|
109
|
-
def revoke_user_token(token)
|
110
|
-
body = {
|
111
|
-
token: token
|
112
|
-
}
|
113
|
-
@client.post('/auth/oauth2/revoke', body, {}, {'Content-Type' => 'application/x-www-form-urlencoded'})
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
1
|
+
require_relative 'collection'
|
2
|
+
require_relative 'user_collection'
|
3
|
+
require_relative 'usergroup_collection'
|
4
|
+
|
5
|
+
module Qtc
|
6
|
+
module Eds
|
7
|
+
class Client
|
8
|
+
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
api_url: 'https://api.engin.io/v1'
|
11
|
+
}
|
12
|
+
|
13
|
+
##
|
14
|
+
# Initialize
|
15
|
+
#
|
16
|
+
# @param [String] backend_id
|
17
|
+
# @param [Hash] options
|
18
|
+
def initialize(backend_id, options = {})
|
19
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
20
|
+
@backend_id = backend_id
|
21
|
+
headers = {'Enginio-Backend-Id' => @backend_id}
|
22
|
+
@client = Qtc::Client.new(@options[:api_url], headers)
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Get Qtc::Client instance
|
27
|
+
#
|
28
|
+
# @return [Qtc::Client]
|
29
|
+
def http_client
|
30
|
+
@client
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Get collection
|
35
|
+
#
|
36
|
+
# @param [String] name
|
37
|
+
# @return [Qtc::Eds::Collection]
|
38
|
+
def collection(name)
|
39
|
+
Qtc::Eds::Collection.new(@client, "/objects/#{name}")
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Get user collection
|
44
|
+
#
|
45
|
+
# @return [Qtc::Eds::UserCollection]
|
46
|
+
def users
|
47
|
+
Qtc::Eds::UserCollection.new(@client)
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Get usergroup collection
|
52
|
+
#
|
53
|
+
# @return [Qtc::Eds::UsergroupCollection]
|
54
|
+
def usergroups
|
55
|
+
Qtc::Eds::UsergroupCollection.new(@client)
|
56
|
+
end
|
57
|
+
|
58
|
+
def current_user
|
59
|
+
if @client.default_headers['Authorization']
|
60
|
+
@client.get('/user')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Set access token
|
66
|
+
#
|
67
|
+
# @param [String] access_token
|
68
|
+
def access_token=(access_token)
|
69
|
+
if !access_token.nil?
|
70
|
+
@client.default_headers['Authorization'] = "Bearer #{access_token}"
|
71
|
+
else
|
72
|
+
@client.default_headers.delete('Authorization')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Call block with given access token
|
78
|
+
#
|
79
|
+
# @param [String] access_token
|
80
|
+
# @param []
|
81
|
+
def with_access_token(access_token, &block)
|
82
|
+
prev_auth = @client.default_headers['Authorization'].dup
|
83
|
+
@client.default_headers['Authorization'] = "Bearer #{access_token}"
|
84
|
+
result = call(&block)
|
85
|
+
@client.default_headers['Authorization'] = prev_auth
|
86
|
+
result
|
87
|
+
ensure
|
88
|
+
@client.default_headers['Authorization'] = prev_auth if prev_auth
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Create user access token
|
93
|
+
#
|
94
|
+
# @param [String] username
|
95
|
+
# @param [String] password
|
96
|
+
def create_user_token(username, password)
|
97
|
+
body = {
|
98
|
+
grant_type: 'password',
|
99
|
+
username: username,
|
100
|
+
password: password
|
101
|
+
}
|
102
|
+
@client.post('/auth/oauth2/token', body, {}, {'Content-Type' => 'application/x-www-form-urlencoded'})
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Revoke user access token
|
107
|
+
#
|
108
|
+
# @param [String] token
|
109
|
+
def revoke_user_token(token)
|
110
|
+
body = {
|
111
|
+
token: token
|
112
|
+
}
|
113
|
+
@client.post('/auth/oauth2/revoke', body, {}, {'Content-Type' => 'application/x-www-form-urlencoded'})
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
117
|
end
|