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
@@ -4,6 +4,7 @@
|
|
4
4
|
#
|
5
5
|
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
6
|
#
|
7
|
+
|
7
8
|
require 'fog/core/collection'
|
8
9
|
require 'fog/softlayer/models/compute/server'
|
9
10
|
|
@@ -22,14 +23,17 @@ module Fog
|
|
22
23
|
|
23
24
|
## Get a SoftLayer server.
|
24
25
|
#
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
|
27
|
+
def get(identifier)
|
28
|
+
return nil if identifier.nil? || identifier == ""
|
29
|
+
response = service.get_vm(identifier)
|
30
|
+
bare_metal = false
|
28
31
|
if response.status == 404 # we didn't find it as a VM, look for a BMC server
|
29
|
-
response = service.get_bare_metal_server(
|
30
|
-
|
32
|
+
response = service.get_bare_metal_server(identifier)
|
33
|
+
bare_metal = true
|
31
34
|
end
|
32
35
|
data = response.body
|
36
|
+
data['bare_metal'] = bare_metal
|
33
37
|
new.merge_attributes(data)
|
34
38
|
rescue Excon::Errors::NotFound
|
35
39
|
nil
|
@@ -4,6 +4,7 @@
|
|
4
4
|
#
|
5
5
|
# LICENSE: MIT (http://opensource.org/licenses/MIT)
|
6
6
|
#
|
7
|
+
|
7
8
|
require 'fog/core/model'
|
8
9
|
|
9
10
|
module Fog
|
@@ -29,12 +30,10 @@ module Fog
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def references
|
32
|
-
service.
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
end
|
33
|
+
@servers ||= service.request(:tag, "#{id}", :query => "objectMask=references;references.tagType").body['references'].map do |ref|
|
34
|
+
type = ref['tagType']['keyName']
|
35
|
+
service.servers.get(ref['resourceTableId']) if type == 'GUEST' || type == 'HARDWARE'
|
36
|
+
end.compact
|
38
37
|
end
|
39
38
|
|
40
39
|
def save
|
@@ -0,0 +1,52 @@
|
|
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
|
+
require 'fog/core/model'
|
9
|
+
|
10
|
+
module Fog
|
11
|
+
module Network
|
12
|
+
class Softlayer
|
13
|
+
class Datacenter < Fog::Model
|
14
|
+
identity :id
|
15
|
+
|
16
|
+
attribute :long_name, :aliases => 'longName'
|
17
|
+
attribute :name
|
18
|
+
|
19
|
+
def initialize(attributes)
|
20
|
+
@connection = attributes[:connection]
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def routers
|
25
|
+
requires :id
|
26
|
+
@routers ||= service.get_datacenter_routers(id).body
|
27
|
+
end
|
28
|
+
|
29
|
+
def routable_subnets
|
30
|
+
requires :id
|
31
|
+
@routable_subnets ||= service.request(:location_datacenter, "#{id}/get_bound_subnets").body
|
32
|
+
end
|
33
|
+
|
34
|
+
def save
|
35
|
+
raise "Not possible."
|
36
|
+
end
|
37
|
+
|
38
|
+
def create
|
39
|
+
raise "Not possible."
|
40
|
+
end
|
41
|
+
|
42
|
+
def update
|
43
|
+
raise "Not possible."
|
44
|
+
end
|
45
|
+
|
46
|
+
def destroy
|
47
|
+
raise "Not possible."
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
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
|
+
require 'fog/core/collection'
|
9
|
+
require 'fog/softlayer/models/network/datacenter'
|
10
|
+
|
11
|
+
module Fog
|
12
|
+
module Network
|
13
|
+
class Softlayer
|
14
|
+
class Datacenters < Fog::Collection
|
15
|
+
attribute :filters
|
16
|
+
|
17
|
+
model Fog::Network::Softlayer::Datacenter
|
18
|
+
|
19
|
+
def initialize(attributes)
|
20
|
+
self.filters ||= {}
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def all(filters = filters)
|
25
|
+
self.filters = filters
|
26
|
+
load(service.get_datacenters.body)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(id)
|
30
|
+
data = service.request(:location_datacenter, "#{id}/get_object").body
|
31
|
+
new.merge_attributes(data)
|
32
|
+
rescue Fog::Network::Softlayer::NotFound
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def by_name(name)
|
37
|
+
all.map { |dc| dc if dc.name == name }.compact.first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,67 @@
|
|
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
|
+
require 'fog/core/model'
|
9
|
+
|
10
|
+
module Fog
|
11
|
+
module Network
|
12
|
+
class Softlayer
|
13
|
+
class Ip < Fog::Model
|
14
|
+
identity :id
|
15
|
+
|
16
|
+
attribute :subnet_id, :aliases => 'subnetId'
|
17
|
+
attribute :address, :aliases => 'ipAddress'
|
18
|
+
attribute :broadcast, :aliases => 'isBroadcast'
|
19
|
+
attribute :gateway, :aliases => 'isGateway'
|
20
|
+
attribute :network, :aliases => 'isNetwork'
|
21
|
+
attribute :reserved, :aliases => 'isReserved'
|
22
|
+
attribute :note
|
23
|
+
attribute :assigned_to, :aliases => ['hardware', 'virtualGuest']
|
24
|
+
|
25
|
+
def initialize(attributes)
|
26
|
+
@connection = attributes[:connection]
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def save
|
31
|
+
requires :subnet_id
|
32
|
+
identity ? update : create
|
33
|
+
end
|
34
|
+
|
35
|
+
def create
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def update
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy
|
44
|
+
requires :id
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
def broadcast?
|
49
|
+
attribute[:broadcast]
|
50
|
+
end
|
51
|
+
|
52
|
+
def gateway?
|
53
|
+
attribute[:gateway]
|
54
|
+
end
|
55
|
+
|
56
|
+
def network?
|
57
|
+
attribute[:network]
|
58
|
+
end
|
59
|
+
|
60
|
+
def reserved?
|
61
|
+
attribute[:reserved]
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,39 @@
|
|
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
|
+
require 'fog/core/collection'
|
9
|
+
require 'fog/softlayer/models/network/ip'
|
10
|
+
|
11
|
+
module Fog
|
12
|
+
module Network
|
13
|
+
class Softlayer
|
14
|
+
class Ips < Fog::Collection
|
15
|
+
attribute :filters
|
16
|
+
|
17
|
+
model Fog::Network::Softlayer::Ip
|
18
|
+
|
19
|
+
def initialize(attributes)
|
20
|
+
self.filters ||= {}
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def all(filters = filters)
|
25
|
+
self.filters = filters
|
26
|
+
load(service.list_ips(filters).body)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(id)
|
30
|
+
if ip = service.get_ip_address(id).body
|
31
|
+
new(ip)
|
32
|
+
end
|
33
|
+
rescue Fog::Network::Softlayer::NotFound
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,121 @@
|
|
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
|
+
require 'fog/core/model'
|
9
|
+
|
10
|
+
module Fog
|
11
|
+
module Network
|
12
|
+
class Softlayer
|
13
|
+
class Network < Fog::Model
|
14
|
+
identity :id
|
15
|
+
|
16
|
+
attribute :name
|
17
|
+
attribute :modify_date, :aliases => 'modifyDate'
|
18
|
+
attribute :note
|
19
|
+
attribute :tags, :aliases => 'tagReferences'
|
20
|
+
attribute :type, :squash => :keyName
|
21
|
+
attribute :datacenter
|
22
|
+
attribute :network_space, :aliases => 'networkSpace'
|
23
|
+
attribute :router, :aliases => 'primaryRouter'
|
24
|
+
#attribute :subnets
|
25
|
+
|
26
|
+
def add_tags(tags)
|
27
|
+
requires :id
|
28
|
+
raise ArgumentError, "Tags argument for #{self.class.name}##{__method__} must be Array." unless tags.is_a?(Array)
|
29
|
+
tags.each do |tag|
|
30
|
+
service.tags.new(:resource_id => self.id, :name => tag).save
|
31
|
+
end
|
32
|
+
self.reload
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def datacenter
|
37
|
+
@datacenter ||= attributes[:datacenter] or (service.datacenters.new(attributes[:router]['datacenter']) if attributes[:router] and attributes[:router]['datacenter'])
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete_tags(tags)
|
41
|
+
requires :id
|
42
|
+
raise ArgumentError, "Tags argument for #{self.class.name}##{__method__} must be Array." unless tags.is_a?(Array)
|
43
|
+
tags.each do |tag|
|
44
|
+
service.tags.new(:resource_id => self.id, :name => tag).destroy
|
45
|
+
end
|
46
|
+
self.reload
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def router=(new_data)
|
51
|
+
raise ArgumentError, "Network Router must be a Hash." unless new_data.is_a?(Hash)
|
52
|
+
attributes[:router] = new_data.select { |k,v| ['id', 'hostname', 'datacenter'].include?(k) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def private?
|
56
|
+
requires :network_space
|
57
|
+
network_space == 'PRIVATE'
|
58
|
+
end
|
59
|
+
|
60
|
+
def public?
|
61
|
+
requires :network_space
|
62
|
+
network_space == 'PUBLIC'
|
63
|
+
end
|
64
|
+
|
65
|
+
def save
|
66
|
+
identity ? update : create
|
67
|
+
end
|
68
|
+
|
69
|
+
def subnets
|
70
|
+
requires :id
|
71
|
+
@subnets ||= attributes['subnets'].map do |subnet|
|
72
|
+
service.subnets.get(subnet['id'])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def create
|
77
|
+
requires :datacenter, :router, :network_space
|
78
|
+
response = service.create_network(build_order).body
|
79
|
+
merge_attributes(response)
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def update
|
84
|
+
requires :id
|
85
|
+
merge_attributes(service.update_network(self.id, self.attributes).body)
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def destroy
|
90
|
+
requires :id
|
91
|
+
service.delete_network(self.id)
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
def tags
|
96
|
+
requires :id
|
97
|
+
attributes[:tags].map { |i| i['tag']['name'] } if attributes[:tags]
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def build_order
|
103
|
+
{
|
104
|
+
'complexType' => 'SoftLayer_Container_Product_Order_Network_Vlan',
|
105
|
+
'name' => name,
|
106
|
+
'routerId' =>router['id'],
|
107
|
+
'router' => router['hostname'],
|
108
|
+
'location' => datacenter.id,
|
109
|
+
'quantity' =>1,
|
110
|
+
'packageId' =>0,
|
111
|
+
'prices' =>[
|
112
|
+
{'id' => public? ? service.get_public_vlan_price_code : service.get_private_vlan_price_code },
|
113
|
+
{'id' => service.get_subnet_price_code }
|
114
|
+
]
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
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
|
+
require 'fog/core/collection'
|
9
|
+
require 'fog/softlayer/models/network/network'
|
10
|
+
|
11
|
+
module Fog
|
12
|
+
module Network
|
13
|
+
class Softlayer
|
14
|
+
class Networks < Fog::Collection
|
15
|
+
model Fog::Network::Softlayer::Network
|
16
|
+
|
17
|
+
def all
|
18
|
+
data = service.list_networks.body
|
19
|
+
load(data)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get(id)
|
23
|
+
if network = service.get_network(id).body
|
24
|
+
new(network)
|
25
|
+
end
|
26
|
+
rescue Fog::Network::Softlayer::NotFound
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def tagged_with(tags)
|
31
|
+
raise ArgumentError, "Tags argument for #{self.class.name}##{__method__} must be Array." unless tags.is_a?(Array)
|
32
|
+
ids = service.get_references_by_tag_name(tags.join(',')).body.map do |tag|
|
33
|
+
tag['references'].map do |ref|
|
34
|
+
ref['resourceTableId']
|
35
|
+
end
|
36
|
+
end.flatten.uniq
|
37
|
+
ids.map { |id| get(id) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def by_name(name)
|
41
|
+
all.select { |vlan| vlan.name == name }.first
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,62 @@
|
|
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
|
+
require 'fog/core/model'
|
9
|
+
|
10
|
+
module Fog
|
11
|
+
module Network
|
12
|
+
class Softlayer
|
13
|
+
class Subnet < Fog::Model
|
14
|
+
identity :id
|
15
|
+
|
16
|
+
attribute :name, :aliases => 'note'
|
17
|
+
attribute :network_id, :aliases => 'networkIdentifier'
|
18
|
+
attribute :vlan_id, :aliases => 'networkVlanId'
|
19
|
+
attribute :cidr
|
20
|
+
attribute :ip_version, :aliases => 'version'
|
21
|
+
attribute :type, :aliases => 'subnetType'
|
22
|
+
attribute :gateway_ip, :aliases => 'gateway'
|
23
|
+
attribute :broadcast, :aliases => 'broadcastAddress'
|
24
|
+
attribute :gateway
|
25
|
+
attribute :datacenter, :squash => :name
|
26
|
+
|
27
|
+
def addresses
|
28
|
+
@addresses ||= attributes['ipAddresses'].map do |address|
|
29
|
+
service.ips.get(address['id'])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def save
|
34
|
+
requires :network_id, :cidr, :ip_version
|
35
|
+
identity ? update : create
|
36
|
+
end
|
37
|
+
|
38
|
+
def create
|
39
|
+
requires :network_id, :cidr, :ip_version
|
40
|
+
merge_attributes(service.create_subnet(self.network_id,
|
41
|
+
self.cidr,
|
42
|
+
self.ip_version,
|
43
|
+
self.attributes).body['subnet'])
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def update
|
48
|
+
requires :id, :network_id, :cidr, :ip_version
|
49
|
+
merge_attributes(service.update_subnet(self.id,
|
50
|
+
self.attributes).body['subnet'])
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def destroy
|
55
|
+
requires :id
|
56
|
+
service.delete_subnet(self.id)
|
57
|
+
true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|