fog-softlayer 0.2.1 → 0.3.1
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 +8 -8
- data/.travis.yml +0 -1
- data/CHANGELOG.md +25 -9
- data/CONTRIBUTING.md +13 -25
- data/CONTRIBUTORS.md +1 -1
- data/Rakefile +3 -3
- data/examples/compute.md +114 -3
- data/examples/network.md +285 -0
- data/examples/tags.md +76 -1
- data/fog-softlayer.gemspec +2 -3
- data/lib/fog/softlayer.rb +2 -0
- data/lib/fog/softlayer/compute.rb +16 -73
- data/lib/fog/softlayer/core.rb +105 -1
- data/lib/fog/softlayer/models/compute/flavor.rb +1 -0
- data/lib/fog/softlayer/models/compute/flavors.rb +1 -0
- data/lib/fog/softlayer/models/compute/image.rb +1 -0
- data/lib/fog/softlayer/models/compute/images.rb +1 -0
- data/lib/fog/softlayer/models/compute/server.rb +71 -12
- data/lib/fog/softlayer/models/compute/servers.rb +9 -5
- data/lib/fog/softlayer/models/compute/tag.rb +5 -6
- data/lib/fog/softlayer/models/compute/tags.rb +1 -0
- data/lib/fog/softlayer/models/network/datacenter.rb +52 -0
- data/lib/fog/softlayer/models/network/datacenters.rb +42 -0
- data/lib/fog/softlayer/models/network/ip.rb +67 -0
- data/lib/fog/softlayer/models/network/ips.rb +39 -0
- data/lib/fog/softlayer/models/network/network.rb +121 -0
- data/lib/fog/softlayer/models/network/networks.rb +47 -0
- data/lib/fog/softlayer/models/network/subnet.rb +62 -0
- data/lib/fog/softlayer/models/network/subnets.rb +33 -0
- data/lib/fog/softlayer/models/network/tag.rb +54 -0
- data/lib/fog/softlayer/models/network/tags.rb +40 -0
- data/lib/fog/softlayer/models/storage/directories.rb +7 -0
- data/lib/fog/softlayer/models/storage/directory.rb +7 -0
- data/lib/fog/softlayer/models/storage/file.rb +7 -0
- data/lib/fog/softlayer/models/storage/files.rb +7 -0
- data/lib/fog/softlayer/network.rb +139 -0
- data/lib/fog/softlayer/requests/compute/create_bare_metal_server.rb +1 -1
- data/lib/fog/softlayer/requests/compute/get_vms.rb +1 -1
- data/lib/fog/softlayer/requests/network/create_network.rb +488 -0
- data/lib/fog/softlayer/requests/network/create_network_tags.rb +50 -0
- data/lib/fog/softlayer/requests/network/delete_network.rb +37 -0
- data/lib/fog/softlayer/requests/network/delete_network_tags.rb +46 -0
- data/lib/fog/softlayer/requests/network/get_datacenter_routers.rb +41 -0
- data/lib/fog/softlayer/requests/network/get_datacenters.rb +30 -0
- data/lib/fog/softlayer/requests/network/get_ip_address.rb +28 -0
- data/lib/fog/softlayer/requests/network/get_network.rb +34 -0
- data/lib/fog/softlayer/requests/network/get_network_tags.rb +47 -0
- data/lib/fog/softlayer/requests/network/get_private_vlan_price_code.rb +27 -0
- data/lib/fog/softlayer/requests/network/get_public_vlan_price_code.rb +27 -0
- data/lib/fog/softlayer/requests/network/get_references_by_tag_name.rb +42 -0
- data/lib/fog/softlayer/requests/network/get_subnet.rb +28 -0
- data/lib/fog/softlayer/requests/network/get_subnet_package_id.rb +29 -0
- data/lib/fog/softlayer/requests/network/get_subnet_price_code.rb +30 -0
- data/lib/fog/softlayer/requests/network/list_networks.rb +30 -0
- data/lib/fog/softlayer/requests/network/list_subnets.rb +28 -0
- data/lib/fog/softlayer/storage.rb +7 -0
- data/lib/fog/softlayer/version.rb +2 -1
- data/tests/compute/flavors_helper.rb +1 -0
- data/tests/compute/server_helper.rb +1 -0
- data/tests/compute/servers_helper.rb +1 -0
- data/tests/helper.rb +7 -0
- data/tests/helpers/collection_helper.rb +7 -0
- data/tests/helpers/compute/flavors_helper.rb +7 -0
- data/tests/helpers/compute/server_helper.rb +7 -0
- data/tests/helpers/compute/servers_helper.rb +7 -0
- data/tests/helpers/formats_helper.rb +7 -0
- data/tests/helpers/formats_helper_tests.rb +7 -0
- data/tests/helpers/mock_helper.rb +7 -0
- data/tests/helpers/model_helper.rb +7 -0
- data/tests/helpers/responds_to_helper.rb +7 -0
- data/tests/helpers/schema_validator_tests.rb +7 -0
- data/tests/helpers/succeeds_helper.rb +7 -0
- data/tests/softlayer/compute/helper.rb +1 -0
- data/tests/softlayer/compute/schema.rb +1 -0
- data/tests/softlayer/models/compute/server_tests.rb +31 -4
- data/tests/softlayer/requests/compute/bmc_tests.rb +4 -3
- data/tests/softlayer/requests/compute/tag_tests.rb +1 -1
- data/tests/softlayer/requests/network/network_tests.rb +129 -0
- metadata +35 -25
@@ -0,0 +1,50 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
def create_network_tags(id, tags = [])
|
14
|
+
raise ArgumentError, "Tags argument for #{self.class.name}##{__method__} must be Array." unless tags.is_a?(Array)
|
15
|
+
response = Excon::Response.new
|
16
|
+
response.status = self.get_network(id).status
|
17
|
+
|
18
|
+
if response.status == 200
|
19
|
+
tags.each do |tag|
|
20
|
+
@tags << {
|
21
|
+
'empRecordId' => nil,
|
22
|
+
'id' => Fog::Mock.random_numbers(7),
|
23
|
+
'resourceTableId' => id,
|
24
|
+
'tagId' => tagId = Fog::Mock.random_numbers(5),
|
25
|
+
'tagTypeId' => 1,
|
26
|
+
'usrRecordId' => 123456,
|
27
|
+
'tag' => { 'accountId' => 987654, 'id' => tagId, 'internal' => 0, 'name' => tag },
|
28
|
+
'tagType'=>{'description'=>'Vlan', 'keyName'=>'NETWORK_VLAN'}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
response.body = true
|
32
|
+
else
|
33
|
+
response.body = {
|
34
|
+
"error"=>"Unable to find object with id of '#{id}'.",
|
35
|
+
"code"=>"SoftLayer_Exception_ObjectNotFound"
|
36
|
+
}
|
37
|
+
end
|
38
|
+
response
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Real
|
43
|
+
def create_network_tags(id, tags = [])
|
44
|
+
raise ArgumentError, "Tags argument for #{self.class.name}##{__method__} must be Array." unless tags.is_a?(Array)
|
45
|
+
self.request(:network_vlan, "#{id}/set_tags", :body => tags.join(','), :http_method => :post)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def delete_network(id)
|
15
|
+
response = Excon::Response.new
|
16
|
+
response.status = 200
|
17
|
+
if @networks.reject! { |vlan| vlan['id'] == id }.nil?
|
18
|
+
response.status = 404
|
19
|
+
response.body = "{\"error\":\"Unable to find object with id of '#{id}'.\",\"code\":\"SoftLayer_Exception_ObjectNotFound\"}"
|
20
|
+
else
|
21
|
+
response.body = true
|
22
|
+
end
|
23
|
+
response
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class Real
|
29
|
+
def delete_network(id)
|
30
|
+
billing_id = request(:network_vlan, "#{id}/get_billing_item").body['id']
|
31
|
+
billing_id.nil? and raise "SoftLayer VLAN with ID #{id} cannot be deleted." # will be automatically deleted when hardware using it is deleted.
|
32
|
+
request(:billing_item, "#{billing_id}/cancel_service").body
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def delete_network_tags(id, tags = [])
|
15
|
+
raise ArgumentError, "Tags argument for #{self.class.name}##{__method__} must be Array." unless tags.is_a?(Array)
|
16
|
+
response = Excon::Response.new
|
17
|
+
response.status = self.get_network(id).status
|
18
|
+
|
19
|
+
if response.status == 200
|
20
|
+
@tags = @tags.reject do |tag|
|
21
|
+
tag['resourceTableId'] == id and tags.include?(tag['tag']['name'])
|
22
|
+
end
|
23
|
+
response.body = true
|
24
|
+
else
|
25
|
+
response.body = {
|
26
|
+
"error"=>"Unable to find object with id of '#{id}'.",
|
27
|
+
"code"=>"SoftLayer_Exception_ObjectNotFound"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class Real
|
36
|
+
def delete_network_tags(id, tags = [])
|
37
|
+
raise ArgumentError, "Tags argument for #{self.class.name}##{__method__} must be Array." unless tags.is_a?(Array)
|
38
|
+
subset = self.get_network_tags(id).body['tagReferences'].map do |i|
|
39
|
+
i['tag']['name'] unless tags.include?(i['tag']['name'])
|
40
|
+
end.compact
|
41
|
+
self.create_network_tags(id, subset)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_datacenter_routers(id)
|
15
|
+
response = Excon::Response.new
|
16
|
+
response.status = 200
|
17
|
+
dc = @datacenters.select { |dc| dc['id'] == id }.first
|
18
|
+
if dc.nil?
|
19
|
+
response.status = 404
|
20
|
+
response.body = "{\"error\":\"Unable to find object with id of '#{id}'.\",\"code\":\"SoftLayer_Exception_ObjectNotFound\"}"
|
21
|
+
else
|
22
|
+
response.body = [
|
23
|
+
{ "hostname" => "bcr01a.#{dc['name']}", "id" => Fog::Mock.random_numbers(6).to_i },
|
24
|
+
{ "hostname" => "bcr02a.#{dc['name']}", "id" => Fog::Mock.random_numbers(6).to_i },
|
25
|
+
{ "hostname" => "fcr01a.#{dc['name']}", "id" => Fog::Mock.random_numbers(6).to_i },
|
26
|
+
{ "hostname" => "fcr02a.#{dc['name']}", "id" => Fog::Mock.random_numbers(6).to_i },
|
27
|
+
]
|
28
|
+
end
|
29
|
+
response
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class Real
|
35
|
+
def get_datacenter_routers(id)
|
36
|
+
request(:location_datacenter, "#{id}/get_hardware_routers", :query => 'objectMask=id;hostname')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_datacenters
|
15
|
+
response = Excon::Response.new
|
16
|
+
response.status = 200
|
17
|
+
response.body = @datacenters
|
18
|
+
response
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class Real
|
24
|
+
def get_datacenters
|
25
|
+
request(:location_datacenter, :get_datacenters)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_ip_address(id)
|
15
|
+
# TODO: Implement.
|
16
|
+
raise Fog::Errors::MockNotImplemented
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class Real
|
22
|
+
def get_ip_address(ip_address)
|
23
|
+
self.request(:network_subnet_IpAddress, "#{ip_address}/get_object", :query => 'objectMask=mask[hardware.fullyQualifiedDomainName,hardware.id,virtualGuest.id,virtualGuest.fullyQualifiedDomainName,subnet.id]')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_network(id)
|
15
|
+
response = Excon::Response.new
|
16
|
+
response.status = 200
|
17
|
+
response.body = @networks.select { |vlan| vlan['id'] == id }.first
|
18
|
+
if response.body.nil?
|
19
|
+
response.status = 404
|
20
|
+
response.body = "{\"error\":\"Unable to find object with id of '#{id}'.\",\"code\":\"SoftLayer_Exception_ObjectNotFound\"}"
|
21
|
+
end
|
22
|
+
response
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class Real
|
28
|
+
def get_network(id)
|
29
|
+
self.request(:network_vlan, "#{id}/get_object", :query => 'objectMask=mask[subnets,tagReferences,type,primaryRouter.datacenter,networkSpace]')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_network_tags(id)
|
15
|
+
response = Excon::Response.new
|
16
|
+
|
17
|
+
response.status = self.get_network(id).status
|
18
|
+
|
19
|
+
net = self.get_network(id).body
|
20
|
+
unless net['error']
|
21
|
+
tags = @tags.map do |tag|
|
22
|
+
tag if tag['resourceTableId'] == id
|
23
|
+
end.compact
|
24
|
+
end
|
25
|
+
|
26
|
+
net['tagReferences'] = tags if net.is_a?(Hash)
|
27
|
+
response.body = net
|
28
|
+
|
29
|
+
if response.status == 404
|
30
|
+
response.body = {
|
31
|
+
"error"=>"Unable to find object with id of '#{id}'.",
|
32
|
+
"code"=>"SoftLayer_Exception_ObjectNotFound"
|
33
|
+
}
|
34
|
+
end
|
35
|
+
response
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class Real
|
41
|
+
def get_network_tags(id)
|
42
|
+
self.request(:network_vlan, id, :query => 'objectMask=mask[tagReferences]')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_private_vlan_price_code
|
15
|
+
42
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class Real
|
21
|
+
def get_private_vlan_price_code
|
22
|
+
request(:product_package, '0/get_items').body.map { |item| item['prices'][0]['id'] if item['description'] =~ /vlan/i and item['description'] =~ /private/i }.compact.first
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_public_vlan_price_code
|
15
|
+
42
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class Real
|
21
|
+
def get_public_vlan_price_code
|
22
|
+
request(:product_package, '0/get_items').body.map { |item| item['prices'][0]['id'] if item['description'] =~ /vlan/i and item['description'] =~ /public/i }.compact.first
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_references_by_tag_name(tag_list)
|
15
|
+
response = Excon::Response.new
|
16
|
+
response.status = 200
|
17
|
+
|
18
|
+
response.body = tag_list.split(',').map do |tag|
|
19
|
+
refs = @tags.select { |ref| ref['tag']['name'] == tag }
|
20
|
+
unless refs.empty?
|
21
|
+
{
|
22
|
+
'accountId' => Fog::Softlayer.mock_account_id,
|
23
|
+
'id'=>Fog::Mock.random_numbers(7),
|
24
|
+
'internal' => 0,
|
25
|
+
'name' => tag,
|
26
|
+
'references' => refs
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end.compact
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
class Real
|
36
|
+
def get_references_by_tag_name(tag_list)
|
37
|
+
self.request(:tag, "get_tag_by_tag_name/#{tag_list}", :query => 'objectMask=references')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
|
3
|
+
# © Copyright IBM Corporation 2014.
|
4
|
+
#
|
5
|
+
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
|
+
#
|
7
|
+
|
8
|
+
module Fog
|
9
|
+
module Network
|
10
|
+
class Softlayer
|
11
|
+
|
12
|
+
class Mock
|
13
|
+
|
14
|
+
def get_subnet(id)
|
15
|
+
# TODO: Implement.
|
16
|
+
raise Fog::Errors::MockNotImplemented
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class Real
|
22
|
+
def get_subnet(id)
|
23
|
+
self.request(:network_subnet, "#{id}/get_object", :query => 'objectMask=mask[datacenter,ipAddresses.id,virtualGuests.fullyQualifiedDomainName,virtualGuests.id,hardware.fullyQualifiedDomainName,hardware.id]')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|