dployr 0.0.2 → 0.0.3
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/README.md +25 -19
- data/lib/dployr/cli.rb +13 -16
- data/lib/dployr/commands/base.rb +43 -0
- data/lib/dployr/commands/config.rb +29 -12
- data/lib/dployr/commands/execute.rb +13 -16
- data/lib/dployr/commands/provision_test.rb +14 -18
- data/lib/dployr/commands/ssh.rb +40 -0
- data/lib/dployr/commands/start.rb +17 -18
- data/lib/dployr/commands/stop_destroy.rb +19 -21
- data/lib/dployr/commands/utils.rb +40 -0
- data/lib/dployr/compute/aws.rb +76 -77
- data/lib/dployr/compute/gce.rb +134 -0
- data/lib/dployr/config/file_utils.rb +7 -9
- data/lib/dployr/configuration.rb +3 -1
- data/lib/dployr/init.rb +1 -2
- data/lib/dployr/scripts/default_hooks.rb +2 -9
- data/lib/dployr/scripts/hook.rb +4 -9
- data/lib/dployr/scripts/local_shell.rb +29 -0
- data/lib/dployr/scripts/scp.rb +1 -9
- data/lib/dployr/scripts/shell.rb +11 -23
- data/lib/dployr/scripts/ssh.rb +23 -0
- data/lib/dployr/utils.rb +0 -21
- data/lib/dployr/version.rb +1 -1
- data/lib/dployr.rb +4 -0
- data/spec/commands_util_spec.rb +108 -0
- data/{config → spec/fixtures/config}/Dployrfile.yml +19 -8
- data/spec/utils_spec.rb +0 -68
- metadata +15 -5
- /data/{config → spec/fixtures/config}/hello/hello.sh +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e18de4be7a56b2227ef830bd0159a0fe9e675a9
|
4
|
+
data.tar.gz: b2d9e30ad637839636e952069b43768d8476db1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5151faf23cfdc2b09998a78a78d25aaaf00123b234275fc9a903fc5d72c0b11907142c9b046e49142f3fc9ccf3ba2c0e65abaee599adf53827e0535c2c4f4dc9
|
7
|
+
data.tar.gz: 5fb7a5c245f56633f6759f12d22a5530ce8795b22fdc85a7ae3089de2f0fd6f07e2c82a177688a31abc13d65e634cb9bc5895265e93b4c9a3aeabfec71b8f99c
|
data/README.md
CHANGED
@@ -54,10 +54,10 @@ or a YAML file (adding the `.yml` or `.yaml` extension)
|
|
54
54
|
|
55
55
|
Each configuration level supports the followings members:
|
56
56
|
|
57
|
-
- **attributes** `Object`
|
58
|
-
- **scripts** `Array`
|
57
|
+
- **attributes** `Object` Custom attrbutes to apply to the current template
|
58
|
+
- **scripts** `Array|Object`
|
59
59
|
- **providers** `Object`
|
60
|
-
- **authentication** `Object`
|
60
|
+
- **authentication** `Object` (optional)
|
61
61
|
- **extends** `String|Array` Allows to inherits the current config object from others
|
62
62
|
|
63
63
|
#### Templating
|
@@ -132,11 +132,13 @@ default:
|
|
132
132
|
instance_type: n1-standard-1
|
133
133
|
network: liberty-gce
|
134
134
|
scripts:
|
135
|
-
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
135
|
+
pre-start:
|
136
|
+
-
|
137
|
+
path: ./scripts/routes_allregions.sh
|
138
|
+
start:
|
139
|
+
-
|
140
|
+
args: "%{name}"
|
141
|
+
path: ./scripts/updatedns.sh
|
140
142
|
|
141
143
|
|
142
144
|
custom:
|
@@ -157,12 +159,13 @@ custom:
|
|
157
159
|
attributes:
|
158
160
|
instance_type: m1.large
|
159
161
|
scripts:
|
160
|
-
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
162
|
+
post-start:
|
163
|
+
-
|
164
|
+
args:
|
165
|
+
- "%{name}"
|
166
|
+
- "%{type}"
|
167
|
+
- "%{domain}"
|
168
|
+
path: ./scripts/.sh
|
166
169
|
-
|
167
170
|
args:
|
168
171
|
- "%{hydra}"
|
@@ -182,22 +185,25 @@ Usage: dployr <command> [options]
|
|
182
185
|
|
183
186
|
Commands
|
184
187
|
|
185
|
-
|
188
|
+
start start instances
|
186
189
|
halt stop instances
|
190
|
+
destroy destroy instances
|
187
191
|
status retrieve the instances status
|
188
192
|
test run remote test in instances
|
189
193
|
deploy start, provision and test running instances
|
190
194
|
provision instance provisioning
|
191
|
-
config generate configuration in YAML
|
195
|
+
config generate configuration in YAML from Dployrfile
|
196
|
+
execute run custom stages
|
192
197
|
init create a sample Dployrfile
|
193
198
|
|
194
199
|
Options
|
195
200
|
|
196
|
-
-e, --environment ENV environment to pass to the instances
|
197
201
|
-n, --name NAME template name identifier to load
|
202
|
+
-f, --file PATH custom config file path to load
|
198
203
|
-a, --attributes ATTRS aditional attributes to pass to the configuration in matrix query format
|
199
|
-
-p, --provider
|
200
|
-
-r, --region
|
204
|
+
-p, --provider VALUES provider to use (allow multiple values comma-separated)
|
205
|
+
-r, --region REGION region to use (allow multiple values comma-separated)
|
206
|
+
-v, -V, --version version
|
201
207
|
-h, --help help
|
202
208
|
|
203
209
|
```
|
data/lib/dployr/cli.rb
CHANGED
@@ -19,6 +19,7 @@ opt_parser = OptionParser.new do |opt|
|
|
19
19
|
opt.separator " provision instance provisioning"
|
20
20
|
opt.separator " config generate configuration in YAML from Dployrfile"
|
21
21
|
opt.separator " execute run custom stages"
|
22
|
+
opt.separator " ssh ssh into machine"
|
22
23
|
opt.separator " init create a sample Dployrfile"
|
23
24
|
opt.separator ""
|
24
25
|
opt.separator " Options"
|
@@ -58,35 +59,31 @@ end
|
|
58
59
|
|
59
60
|
opt_parser.parse!
|
60
61
|
|
61
|
-
dployr = Dployr::Init.new @attributes
|
62
|
-
dployr.load_config options[:file]
|
63
|
-
config = dployr.config.get_region(options[:name], options[:provider], options[:region])
|
64
|
-
|
65
62
|
case command
|
66
63
|
when "start"
|
67
|
-
Dployr::Commands::Start.new
|
64
|
+
Dployr::Commands::Start.new options
|
68
65
|
when "halt"
|
69
|
-
Dployr::Commands::
|
66
|
+
Dployr::Commands::StopDestroy.new options, "halt"
|
70
67
|
when "destroy"
|
71
|
-
Dployr::Commands::
|
68
|
+
Dployr::Commands::StopDestroy.new options, "destroy"
|
72
69
|
when "status"
|
73
70
|
puts "Command currently not available"
|
74
71
|
when "provision"
|
75
|
-
Dployr::Commands::
|
72
|
+
Dployr::Commands::ProvisionTest.new options, "provision"
|
76
73
|
when "test"
|
77
|
-
Dployr::Commands::
|
74
|
+
Dployr::Commands::ProvisionTest.new options, "test"
|
78
75
|
when "deploy"
|
79
|
-
Dployr::Commands::Start.new
|
80
|
-
Dployr::Commands::
|
81
|
-
Dployr::Commands::
|
76
|
+
Dployr::Commands::Start.new options
|
77
|
+
Dployr::Commands::ProvisionTest.new options, "provision"
|
78
|
+
Dployr::Commands::ProvisionTest.new options, "test"
|
82
79
|
when "execute"
|
83
|
-
Dployr::Commands::Execute.new
|
80
|
+
Dployr::Commands::Execute.new options, ARGV[1..-1]
|
81
|
+
when "ssh"
|
82
|
+
Dployr::Commands::Ssh.new options
|
84
83
|
when "config"
|
85
|
-
Dployr::Commands::Config.new
|
84
|
+
Dployr::Commands::Config.new options
|
86
85
|
when "init"
|
87
86
|
Dployr::Config::Create.write_file
|
88
|
-
when '-h', '--help', 'help'
|
89
|
-
# help already showed by option
|
90
87
|
else
|
91
88
|
puts opt_parser
|
92
89
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'dployr/init'
|
3
|
+
require 'dployr/commands/utils'
|
4
|
+
|
5
|
+
module Dployr
|
6
|
+
module Commands
|
7
|
+
class Base
|
8
|
+
|
9
|
+
include Dployr::Commands::Utils
|
10
|
+
|
11
|
+
attr_reader :options, :name, :log, :attrs, :dployr
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
@options = options
|
15
|
+
@name = options[:name]
|
16
|
+
@log = Logger.new STDOUT
|
17
|
+
@attrs = parse_attributes @options[:attributes]
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
begin
|
22
|
+
@dployr = Dployr::Init.new @attrs
|
23
|
+
@dployr.load_config @options[:file]
|
24
|
+
rescue Exception => e
|
25
|
+
raise "Cannot load the config: #{e}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_compute_client
|
30
|
+
begin
|
31
|
+
Dployr::Compute.const_get(@provider.to_sym).new @regions
|
32
|
+
rescue Exception => e
|
33
|
+
raise "Provider '#{@provider}' is not supported: #{e}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_region_config(options)
|
38
|
+
@dployr.config.get_region options[:name], options[:provider], options[:region]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,24 +1,41 @@
|
|
1
|
-
require '
|
2
|
-
require 'dployr/utils'
|
3
|
-
require 'dployr/compute/aws'
|
4
|
-
require 'colorize'
|
1
|
+
require 'dployr/commands/base'
|
5
2
|
|
6
3
|
module Dployr
|
7
4
|
module Commands
|
8
|
-
class Config
|
5
|
+
class Config < Base
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(config, options)
|
7
|
+
def initialize(options)
|
8
|
+
super options
|
13
9
|
begin
|
14
|
-
|
15
|
-
|
10
|
+
create
|
11
|
+
render_file
|
16
12
|
rescue Exception => e
|
17
13
|
@log.error e
|
18
|
-
|
14
|
+
exit 1
|
19
15
|
end
|
20
16
|
end
|
21
|
-
|
17
|
+
|
18
|
+
def render_file
|
19
|
+
raise "Dployrfile was not found" if @dployr.file_path.nil?
|
20
|
+
raise "Configuration is missing" unless @dployr.config.exists?
|
21
|
+
begin
|
22
|
+
if @name and options[:provider] and options[:region]
|
23
|
+
config = get_region_config options
|
24
|
+
elsif @name
|
25
|
+
config = @dployr.config.get_config @name, @attrs
|
26
|
+
else
|
27
|
+
config = @dployr.config.get_config_all @attrs
|
28
|
+
end
|
29
|
+
unless config.nil?
|
30
|
+
puts config.to_yaml
|
31
|
+
else
|
32
|
+
@log.info "Missing configuration data"
|
33
|
+
end
|
34
|
+
rescue Exception => e
|
35
|
+
raise "Cannot generate the config: #{e}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
22
39
|
end
|
23
40
|
end
|
24
41
|
end
|
@@ -1,40 +1,37 @@
|
|
1
|
-
require '
|
2
|
-
require 'dployr/utils'
|
1
|
+
require 'dployr/commands/base'
|
3
2
|
require 'dployr/compute/aws'
|
4
|
-
require 'colorize'
|
5
3
|
|
6
4
|
module Dployr
|
7
5
|
module Commands
|
8
|
-
class Execute
|
6
|
+
class Execute < Base
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(config, options, stages)
|
8
|
+
def initialize(options, stages)
|
9
|
+
super options
|
13
10
|
begin
|
14
|
-
|
11
|
+
create
|
12
|
+
config = get_region_config options
|
13
|
+
|
15
14
|
@name = config[:attributes]["name"]
|
16
15
|
@provider = options[:provider].upcase
|
17
16
|
@region = options[:region]
|
18
|
-
@attributes = config[:attributes]
|
19
17
|
|
20
18
|
puts "Connecting to #{@provider}...".yellow
|
21
|
-
@client = Dployr::Compute.const_get(@provider.to_sym).new
|
22
|
-
|
19
|
+
@client = Dployr::Compute.const_get(@provider.to_sym).new @region
|
20
|
+
|
23
21
|
puts "Looking for #{@name} in #{@region}...".yellow
|
24
|
-
@ip = @client.get_ip
|
22
|
+
@ip = @client.get_ip @name
|
25
23
|
if @ip
|
26
24
|
puts "#{@name} found with IP #{@ip}".yellow
|
27
25
|
else
|
28
26
|
raise "#{@name} not found"
|
29
27
|
end
|
30
|
-
|
28
|
+
|
31
29
|
stages.each do |stage|
|
32
30
|
Dployr::Scripts::Hook.new @ip, config, stage
|
33
31
|
end
|
34
|
-
|
35
32
|
rescue Exception => e
|
36
|
-
|
37
|
-
|
33
|
+
self.log.error e
|
34
|
+
exit 1
|
38
35
|
end
|
39
36
|
end
|
40
37
|
|
@@ -1,44 +1,40 @@
|
|
1
|
-
require '
|
2
|
-
require 'dployr/utils'
|
1
|
+
require 'dployr/commands/base'
|
3
2
|
require 'dployr/compute/aws'
|
4
|
-
require 'colorize'
|
5
3
|
|
6
4
|
module Dployr
|
7
5
|
module Commands
|
8
|
-
class
|
6
|
+
class ProvisionTest < Base
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(config, options, action)
|
8
|
+
def initialize(options, action)
|
9
|
+
super options
|
13
10
|
begin
|
14
|
-
|
11
|
+
create
|
12
|
+
config = get_region_config options
|
13
|
+
|
15
14
|
@name = config[:attributes]["name"]
|
16
15
|
@provider = options[:provider].upcase
|
17
16
|
@region = options[:region]
|
18
|
-
@attributes = config[:attributes]
|
19
|
-
@action = action
|
20
17
|
|
21
18
|
puts "Connecting to #{@provider}...".yellow
|
22
|
-
@client = Dployr::Compute.const_get(@provider.to_sym).new
|
23
|
-
|
19
|
+
@client = Dployr::Compute.const_get(@provider.to_sym).new @region
|
20
|
+
|
24
21
|
puts "Looking for #{@name} in #{@region}...".yellow
|
25
|
-
@ip = @client.get_ip
|
22
|
+
@ip = @client.get_ip @name
|
26
23
|
if @ip
|
27
24
|
puts "#{@name} found with IP #{@ip}".yellow
|
28
25
|
else
|
29
26
|
raise "#{@name} not found"
|
30
27
|
end
|
31
|
-
|
32
|
-
Dployr::Scripts::Default_Hooks.new @ip, config,
|
33
|
-
|
28
|
+
|
29
|
+
Dployr::Scripts::Default_Hooks.new @ip, config, action, self
|
34
30
|
rescue Exception => e
|
35
31
|
@log.error e
|
36
|
-
|
32
|
+
exit 1
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
40
36
|
def action
|
41
|
-
|
37
|
+
@ip
|
42
38
|
end
|
43
39
|
end
|
44
40
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'dployr/commands/base'
|
3
|
+
require 'dployr/compute/aws'
|
4
|
+
|
5
|
+
module Dployr
|
6
|
+
module Commands
|
7
|
+
class Ssh < Base
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
super options
|
11
|
+
begin
|
12
|
+
create
|
13
|
+
config = get_region_config options
|
14
|
+
|
15
|
+
@name = config[:attributes]["name"]
|
16
|
+
@provider = options[:provider].upcase
|
17
|
+
@region = options[:region]
|
18
|
+
|
19
|
+
puts "Connecting to #{@provider}...".yellow
|
20
|
+
@client = Dployr::Compute.const_get(@provider.to_sym).new @region
|
21
|
+
|
22
|
+
puts "Looking for #{@name} in #{@region}...".yellow
|
23
|
+
@ip = @client.get_ip @name
|
24
|
+
if @ip
|
25
|
+
puts "#{@name} found with IP #{@ip}".yellow
|
26
|
+
else
|
27
|
+
raise "#{@name} not found"
|
28
|
+
end
|
29
|
+
|
30
|
+
Dployr::Scripts::Ssh.new @ip, config
|
31
|
+
|
32
|
+
rescue Exception => e
|
33
|
+
self.log.error e
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,46 +1,45 @@
|
|
1
|
-
require '
|
2
|
-
require 'dployr/utils'
|
1
|
+
require 'dployr/commands/base'
|
3
2
|
require 'dployr/compute/aws'
|
4
|
-
require '
|
3
|
+
require 'dployr/compute/gce'
|
5
4
|
|
6
5
|
module Dployr
|
7
6
|
module Commands
|
8
|
-
class Start
|
7
|
+
class Start < Base
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(config, options)
|
9
|
+
def initialize(options)
|
10
|
+
super options
|
13
11
|
begin
|
14
|
-
|
12
|
+
create
|
13
|
+
config = get_region_config options
|
14
|
+
|
15
15
|
@name = config[:attributes]["name"]
|
16
16
|
@provider = options[:provider].upcase
|
17
17
|
@region = options[:region]
|
18
18
|
@attributes = config[:attributes]
|
19
19
|
|
20
20
|
puts "Connecting to #{@provider}...".yellow
|
21
|
-
@client = Dployr::Compute.const_get(@provider.to_sym).new
|
22
|
-
|
21
|
+
@client = Dployr::Compute.const_get(@provider.to_sym).new @region
|
22
|
+
|
23
23
|
puts "Looking for #{@name} in #{@region}...".yellow
|
24
|
-
@ip = @client.get_ip
|
25
|
-
|
24
|
+
@ip = @client.get_ip @name
|
25
|
+
|
26
26
|
Dployr::Scripts::Default_Hooks.new @ip, config, "start", self
|
27
|
-
|
28
27
|
rescue Exception => e
|
29
28
|
@log.error e
|
30
|
-
|
29
|
+
exit 1
|
31
30
|
end
|
32
31
|
end
|
33
|
-
|
32
|
+
|
34
33
|
def action
|
35
34
|
if @ip
|
36
35
|
puts "#{@name} found with IP #{@ip}".yellow
|
37
36
|
else
|
38
|
-
@ip = @client.start
|
37
|
+
@ip = @client.start @attributes, @region
|
39
38
|
puts "Startded instance for #{@name} in #{@region} with IP #{@ip} succesfully".yellow
|
40
39
|
end
|
41
|
-
|
40
|
+
@ip
|
42
41
|
end
|
43
|
-
|
42
|
+
|
44
43
|
end
|
45
44
|
end
|
46
45
|
end
|
@@ -1,49 +1,47 @@
|
|
1
|
-
require '
|
2
|
-
require 'dployr/utils'
|
1
|
+
require 'dployr/commands/base'
|
3
2
|
require 'dployr/compute/aws'
|
4
|
-
require 'colorize'
|
5
3
|
|
6
4
|
module Dployr
|
7
5
|
module Commands
|
8
|
-
class
|
6
|
+
class StopDestroy < Base
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(config, options, action)
|
8
|
+
def initialize(options, action)
|
9
|
+
super options
|
13
10
|
begin
|
14
|
-
|
11
|
+
create
|
12
|
+
config = get_region_config options
|
13
|
+
|
15
14
|
@name = config[:attributes]["name"]
|
16
15
|
@provider = options[:provider].upcase
|
17
16
|
@region = options[:region]
|
18
17
|
@attributes = config[:attributes]
|
19
18
|
@action = action
|
20
|
-
|
19
|
+
|
21
20
|
puts "Connecting to #{@provider}...".yellow
|
22
|
-
@client = Dployr::Compute.const_get(@provider.to_sym).new
|
23
|
-
|
21
|
+
@client = Dployr::Compute.const_get(@provider.to_sym).new @region
|
22
|
+
|
24
23
|
puts "Looking for #{@name} in #{@region}...".yellow
|
25
|
-
@ip = @client.get_ip
|
24
|
+
@ip = @client.get_ip @name
|
26
25
|
if @ip
|
27
26
|
puts "#{@name} found with IP #{@ip}".yellow
|
28
27
|
else
|
29
28
|
puts "#{@name} not found".yellow
|
30
29
|
end
|
31
|
-
|
32
|
-
Dployr::Scripts::Default_Hooks.new @ip, config,
|
33
|
-
|
30
|
+
|
31
|
+
Dployr::Scripts::Default_Hooks.new @ip, config, action, self
|
34
32
|
rescue Exception => e
|
35
33
|
@log.error e
|
36
|
-
|
34
|
+
exit 1
|
37
35
|
end
|
38
36
|
end
|
39
|
-
|
40
|
-
def action
|
37
|
+
|
38
|
+
def action
|
41
39
|
puts "#{@action.capitalize}ing #{@name} in #{@region}...".yellow
|
42
|
-
@client.send(@action.to_sym, @name)
|
40
|
+
@client.send(@action.to_sym, @name)
|
43
41
|
puts "#{@name} #{@action}ed sucesfully".yellow
|
44
|
-
|
42
|
+
@ip
|
45
43
|
end
|
46
|
-
|
44
|
+
|
47
45
|
end
|
48
46
|
end
|
49
47
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Dployr
|
2
|
+
module Commands
|
3
|
+
module Utils
|
4
|
+
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def parse_matrix(str)
|
8
|
+
hash = {}
|
9
|
+
str.split(';').each do |val|
|
10
|
+
val = val.split '='
|
11
|
+
hash[val.first.strip] = val.last.strip
|
12
|
+
end if str.is_a? String
|
13
|
+
hash
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_flags(str)
|
17
|
+
hash = {}
|
18
|
+
str.gsub(/\s+/, ' ').strip.split(' ').each_slice(2) do |val|
|
19
|
+
key = val.first
|
20
|
+
if val.first.is_a? String
|
21
|
+
key = key.gsub(/^\-+/, '').strip
|
22
|
+
hash[key] = (val.last or '').strip
|
23
|
+
end
|
24
|
+
end if str.is_a? String
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_attributes(attributes)
|
29
|
+
if attributes.is_a? String
|
30
|
+
if attributes[0] == '-'
|
31
|
+
parse_flags attributes
|
32
|
+
else
|
33
|
+
parse_matrix attributes
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|