solutious-rudy 0.9.1 → 0.9.2

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.
Files changed (84) hide show
  1. data/CHANGES.txt +40 -16
  2. data/README.rdoc +6 -6
  3. data/bin/rudy +66 -10
  4. data/bin/rudy-ec2 +3 -1
  5. data/examples/authorize.rb +15 -0
  6. data/examples/gem-test.rb +11 -5
  7. data/examples/solaris.rb +35 -0
  8. data/examples/windows.rb +101 -0
  9. data/lib/rudy.rb +7 -1
  10. data/lib/rudy/aws.rb +2 -2
  11. data/lib/rudy/aws/ec2.rb +29 -22
  12. data/lib/rudy/aws/ec2/group.rb +1 -1
  13. data/lib/rudy/aws/ec2/image.rb +1 -29
  14. data/lib/rudy/aws/ec2/instance.rb +4 -32
  15. data/lib/rudy/aws/ec2/keypair.rb +1 -6
  16. data/lib/rudy/aws/ec2/snapshot.rb +2 -20
  17. data/lib/rudy/aws/ec2/volume.rb +11 -19
  18. data/lib/rudy/aws/ec2/zone.rb +1 -6
  19. data/lib/rudy/aws/sdb.rb +1 -1
  20. data/lib/rudy/cli/aws/ec2/addresses.rb +4 -10
  21. data/lib/rudy/cli/aws/ec2/groups.rb +0 -1
  22. data/lib/rudy/cli/aws/ec2/images.rb +1 -4
  23. data/lib/rudy/cli/aws/ec2/info.rb +63 -0
  24. data/lib/rudy/cli/aws/ec2/instances.rb +3 -5
  25. data/lib/rudy/cli/aws/ec2/keypairs.rb +3 -5
  26. data/lib/rudy/cli/aws/ec2/snapshots.rb +2 -6
  27. data/lib/rudy/cli/aws/ec2/zones.rb +2 -4
  28. data/lib/rudy/cli/backups.rb +20 -9
  29. data/lib/rudy/cli/base.rb +60 -3
  30. data/lib/rudy/cli/candy.rb +1 -1
  31. data/lib/rudy/cli/disks.rb +65 -7
  32. data/lib/rudy/cli/execbase.rb +0 -2
  33. data/lib/rudy/cli/images.rb +97 -0
  34. data/lib/rudy/cli/info.rb +48 -0
  35. data/lib/rudy/cli/keypairs.rb +43 -0
  36. data/lib/rudy/cli/machines.rb +48 -38
  37. data/lib/rudy/cli/networks.rb +68 -0
  38. data/lib/rudy/cli/routines.rb +3 -10
  39. data/lib/rudy/config/objects.rb +0 -1
  40. data/lib/rudy/disks.rb +4 -0
  41. data/lib/rudy/global.rb +1 -1
  42. data/lib/rudy/huxtable.rb +9 -3
  43. data/lib/rudy/machines.rb +1 -1
  44. data/lib/rudy/metadata.rb +4 -1
  45. data/lib/rudy/metadata/backup.rb +2 -2
  46. data/lib/rudy/metadata/disk.rb +7 -4
  47. data/lib/rudy/metadata/machine.rb +66 -2
  48. data/lib/rudy/routines.rb +2 -1
  49. data/lib/rudy/routines/base.rb +4 -157
  50. data/lib/rudy/routines/handlers/base.rb +6 -3
  51. data/lib/rudy/routines/handlers/disks.rb +127 -42
  52. data/lib/rudy/routines/handlers/group.rb +45 -10
  53. data/lib/rudy/routines/handlers/host.rb +16 -10
  54. data/lib/rudy/routines/handlers/keypair.rb +26 -10
  55. data/lib/rudy/routines/handlers/rye.rb +173 -0
  56. data/lib/rudy/routines/handlers/script.rb +2 -1
  57. data/lib/rudy/routines/passthrough.rb +2 -2
  58. data/lib/rudy/routines/reboot.rb +2 -2
  59. data/lib/rudy/routines/shutdown.rb +2 -2
  60. data/lib/rudy/routines/startup.rb +4 -2
  61. data/rudy.gemspec +15 -8
  62. data/tryouts/10_require_time/10_rudy_tryouts.rb +1 -1
  63. data/tryouts/12_config/20_defaults_tryouts.rb +1 -1
  64. data/tryouts/12_config/40_machines_tryouts.rb +1 -1
  65. data/tryouts/15_huxtable/20_user_tryouts.rb +1 -1
  66. data/tryouts/25_ec2/10_keypairs_tryouts.rb +1 -0
  67. data/tryouts/30_metadata/10_include_tryouts.rb +1 -1
  68. data/tryouts/30_metadata/13_object_tryouts.rb +4 -0
  69. data/tryouts/30_metadata/50_disk_tryouts.rb +4 -2
  70. data/tryouts/30_metadata/51_disk_digest_tryouts.rb +1 -1
  71. data/tryouts/30_metadata/53_disk_list_tryouts.rb +2 -1
  72. data/tryouts/30_metadata/56_disk_volume_tryouts.rb +1 -1
  73. data/tryouts/30_metadata/60_backup_tryouts.rb +4 -2
  74. data/tryouts/30_metadata/63_backup_list_tryouts.rb +1 -1
  75. data/tryouts/30_metadata/64_backup_disk_tryouts.rb +3 -1
  76. data/tryouts/30_metadata/66_backup_snapshot_tryouts.rb +1 -1
  77. data/tryouts/30_metadata/70_machine_tryouts.rb +5 -2
  78. data/tryouts/30_metadata/73_machine_list_tryouts.rb +1 -1
  79. data/tryouts/30_metadata/76_machine_instance_tryouts.rb +15 -3
  80. data/tryouts/30_metadata/77_machines_tryouts.rb +1 -1
  81. data/tryouts/40_routines/10_keypair_handler_tryouts.rb +6 -5
  82. data/tryouts/40_routines/11_group_handler_tryouts.rb +1 -1
  83. metadata +13 -6
  84. data/lib/rudy/cli/status.rb +0 -60
data/lib/rudy.rb CHANGED
@@ -42,7 +42,7 @@ module Rudy
42
42
  unless defined?(MAJOR)
43
43
  MAJOR = 0.freeze
44
44
  MINOR = 9.freeze
45
- TINY = 1.freeze
45
+ TINY = 2.freeze
46
46
  end
47
47
  def self.to_s; [MAJOR, MINOR, TINY].join('.'); end
48
48
  def self.to_f; self.to_s.to_f; end
@@ -72,6 +72,12 @@ module Rudy
72
72
  DEFAULT_EC2_HOST = "ec2.amazonaws.com"
73
73
  DEFAULT_EC2_PORT = 443
74
74
 
75
+ DEFAULT_WINDOWS_FS = 'ntfs'
76
+ DEFAULT_LINUX_FS = 'ext3'
77
+
78
+ DEFAULT_WINDOWS_DEVICE = 'xvdf'
79
+ DEFAULT_LINUX_DEVICE = '/dev/sdh'
80
+
75
81
  MAX_INSTANCES = 5.freeze
76
82
 
77
83
  ID_MAP = {
data/lib/rudy/aws.rb CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- require 'EC2' # amazon-ec2 gem
3
+ require 'AWS' # amazon-ec2 gem
4
4
 
5
5
 
6
6
  module Rudy
@@ -27,7 +27,7 @@ module Rudy
27
27
 
28
28
  Rudy::Utils.require_glob(RUDY_LIB, 'rudy', 'aws', '{ec2,s3,sdb}', "*.rb")
29
29
 
30
- class Error < ::EC2::Error; end
30
+ class Error < ::AWS::Error; end
31
31
  end
32
32
 
33
33
  end
data/lib/rudy/aws/ec2.rb CHANGED
@@ -3,6 +3,8 @@ module Rudy; module AWS
3
3
  module EC2
4
4
  # include Rudy::Huxtable
5
5
 
6
+ @@mutex = Mutex.new
7
+
6
8
  def self.connect(access_key=nil, secret_key=nil, region=nil, logger=nil)
7
9
 
8
10
  if region
@@ -15,7 +17,7 @@ module Rudy; module AWS
15
17
  host ||= DEFAULT_EC2_HOST
16
18
  port ||= DEFAULT_EC2_PORT
17
19
 
18
- @@ec2 = ::EC2::Base.new(:port => port, :server=> host, :access_key_id => access_key, :secret_access_key => secret_key)
20
+ @@ec2 = ::AWS::EC2::Base.new(:port => port, :server=> host, :access_key_id => access_key, :secret_access_key => secret_key)
19
21
  @@logger = logger
20
22
  end
21
23
 
@@ -28,31 +30,36 @@ module Rudy; module AWS
28
30
  # Returns the return value from the request is returned untouched
29
31
  # or the default value on error or if the request returned nil.
30
32
  def self.execute_request(default=nil, timeout=nil, &request)
31
- timeout ||= 15
33
+ timeout ||= 30
32
34
  raise "No block provided" unless request
33
35
  response = nil
34
- begin
35
- Timeout::timeout(timeout) do
36
- response = request.call
37
- end
38
- # Raise the EC2 exceptions
39
- rescue ::EC2::Error, ::EC2::InvalidInstanceIDMalformed => ex
40
- raise Rudy::AWS::Error, ex.message
36
+ @@mutex.synchronize {
37
+ begin
38
+
39
+ Timeout::timeout(timeout) do
40
+ response = request.call
41
+ end
41
42
 
42
- # NOTE: The InternalError is returned for non-existent volume IDs.
43
- # It's probably a bug so we're ignoring it -- Dave.
44
- rescue ::EC2::InternalError => ex
45
- raise Rudy::AWS::Error, ex.message
43
+ # Raise the EC2 exceptions
44
+ rescue ::AWS::Error, ::AWS::InvalidInstanceIDMalformed => ex
45
+ raise Rudy::AWS::Error, ex.message
46
+
47
+ # NOTE: The InternalError is returned for non-existent volume IDs.
48
+ # It's probably a bug so we're ignoring it -- Dave.
49
+ rescue ::AWS::InternalError => ex
50
+ raise Rudy::AWS::Error, ex.message
46
51
 
47
- rescue Timeout::Error => ex
48
- STDERR.puts "Timeout (#{timeout}): #{ex.message}!"
49
- rescue SocketError => ex
50
- #STDERR.puts ex.message
51
- #STDERR.puts ex.backtrace
52
- raise SocketError, "Check your Internets!" unless @@global.offline
53
- ensure
54
- response ||= default
55
- end
52
+ rescue Timeout::Error => ex
53
+ STDERR.puts "Timeout (#{timeout}): #{ex.message}!"
54
+ rescue SocketError => ex
55
+ #STDERR.puts ex.message
56
+ #STDERR.puts ex.backtrace
57
+ raise SocketError, "Check your Internets!" unless @@global.offline
58
+ ensure
59
+ response ||= default
60
+ end
61
+ sleep 0.1 # defeat race conditions
62
+ }
56
63
  response
57
64
  end
58
65
 
@@ -171,7 +171,7 @@ module Rudy::AWS
171
171
  def exists?(name)
172
172
  begin
173
173
  g = list([name.to_s])
174
- rescue ::EC2::InvalidGroupNotFound
174
+ rescue ::AWS::InvalidGroupNotFound
175
175
  return false
176
176
  end
177
177
 
@@ -13,37 +13,9 @@ module Rudy::AWS
13
13
  field :visibility
14
14
  field :location
15
15
  field :kind
16
-
17
- def liner_note
18
- info = @location
19
- # Highlight "debian-5" in /dir/debian-5.manifest.xml
20
- #info = info.split(/\//)
21
- #info[-1].gsub!(/(.+?)((\.img)?\.manifest\.xml)/) { |m,n| ($1 || "").bright << $2 }
22
- #info = info.join('/')
23
- "%s %-6s (%s)" % [self.awsid.bright, self.arch, info]
24
- end
25
16
 
26
17
  def to_s(with_title=false)
27
- lines = []
28
- lines << liner_note
29
- #if self.available?
30
- # p = public? ? "public" : "private"
31
- # k, r = @aki || 'aki-unknown', @ari || 'ari-unknown'
32
- # lines << @@sformat % %w{arch owner aki ari visibility} if with_title
33
- # lines << @@sformat % [@arch, @owner, k, r, p]
34
- #end
35
- lines.join($/)
36
- end
37
-
38
- def inspect
39
- lines = []
40
- lines << liner_note
41
- field_names.each do |key|
42
- next unless self.respond_to?(key)
43
- val = self.send(key)
44
- lines << sprintf(" %22s: %s", key, (val.is_a?(Array) ? val.join(', ') : val))
45
- end
46
- lines.join($/)
18
+ [@awsid.bright, @arch, @visibility, @location].join '; '
47
19
  end
48
20
 
49
21
  def available?; @state && @state == "available"; end
@@ -23,38 +23,9 @@ module Rudy::AWS
23
23
  @groups ||= []
24
24
  end
25
25
 
26
- def liner_note
27
- info = self.running? ? self.dns_public : self.state
28
- "%s %-30s" % [self.awsid.bright, info]
29
- end
30
-
31
- def to_s(with_title=false)
32
- lines = []
33
- if @groups
34
- gpstr = [@groups].flatten.compact.join(', ')
35
- gpstr &&= "(#{gpstr})"
36
- else
37
- gpstr = ''
38
- end
39
-
40
- lines << "%s %s" % [liner_note, gpstr]
41
- #if self.running?
42
- # k, g = @keyname || 'no-keypair', self.groups.join(', ')
43
- # lines << @@sformat % %w{zone size ami keyname groups} if with_title
44
- # lines << @@sformat % [@zone, @size, @ami, k, g]
45
- #end
46
- lines.join($/)
47
- end
48
-
49
- def pretty
50
- lines = []
51
- lines << liner_note
52
- field_names.each do |key|
53
- next unless self.respond_to?(key)
54
- val = self.send(key)
55
- lines << sprintf(" %22s: %s", key, (val.is_a?(Array) ? val.join(', ') : val))
56
- end
57
- lines.join($/)
26
+ def to_s(*args)
27
+ groups = [@groups].flatten.compact.join(', ')
28
+ [self.awsid.bright, self.state, self.dns_public, groups].join '; '
58
29
  end
59
30
 
60
31
  def running?; self.state && self.state == 'running'; end
@@ -307,6 +278,7 @@ module Rudy::AWS
307
278
  # +inst_id+ is an instance ID
308
279
  # Returns an Instance object
309
280
  def get(inst_id)
281
+ return nil if inst_id.nil?
310
282
  inst_id = inst_id.awsid if inst_id.is_a?(Rudy::AWS::EC2::Instance)
311
283
  inst = list(:any, inst_id)
312
284
  inst &&= inst.first
@@ -8,13 +8,8 @@ module Rudy::AWS
8
8
  field :fingerprint
9
9
  field :private_key
10
10
 
11
- def liner_note
12
- "%-20s %s" % [self.name.bright, self.fingerprint]
13
- end
14
-
15
11
  def to_s(titles=false)
16
- str = titles ? "%-20s %s#{$/}" % ['name', 'fingerprint'] : ""
17
- str << liner_note
12
+ [@name.bright, @fingerprint].join '; '
18
13
  end
19
14
 
20
15
  def public_key
@@ -3,7 +3,6 @@
3
3
  module Rudy::AWS
4
4
  module EC2
5
5
  class Snapshot < Storable
6
- @@sformat = "%s <- %10s; %s"
7
6
 
8
7
  field :awsid
9
8
  field :progress
@@ -11,25 +10,8 @@ module Rudy::AWS
11
10
  field :volid
12
11
  field :status
13
12
 
14
- def liner_note
15
- t = Time.parse(@created)
16
- info = t.strftime("%Y-%m-%d %H:%M:%S")
17
- "%s (%s)" % [(self.awsid || '').bright, info]
18
- end
19
-
20
13
  def to_s(with_title=false)
21
- @@sformat % [liner_note, @volid, @status]
22
- end
23
-
24
- def pretty
25
- lines = []
26
- lines << liner_note
27
- field_names.each do |key|
28
- next unless self.respond_to?(key)
29
- val = self.send(key)
30
- lines << sprintf(" %22s: %s", key, (val.is_a?(Array) ? val.join(', ') : val))
31
- end
32
- lines.join($/)
14
+ [@awsid.bright, @volid, @created, @status, @progress].join '; '
33
15
  end
34
16
 
35
17
  def completed?
@@ -98,7 +80,7 @@ module Rudy::AWS
98
80
  end
99
81
 
100
82
  def get(snap_id)
101
- list(snap_id).first || nil
83
+ list(snap_id).first rescue nil
102
84
  end
103
85
 
104
86
  def exists?(snap_id)
@@ -20,23 +20,8 @@ module Rudy::AWS
20
20
  @size &&= @size.to_i
21
21
  end
22
22
 
23
- def liner_note
24
- info = attached? ? "attached to #{@instid}" : @status
25
- "%s (%s)" % [(self.awsid || '').bright, info]
26
- end
27
-
28
- def to_s(with_title=false)
29
- line = @@sformat % [liner_note, @zone, @size, @device]
30
- line << " <- %s" % [@snapid] if @snapid
31
- line
32
- end
33
-
34
- def pretty
35
- lines = [liner_note]
36
- field_names.each do |n|
37
- lines << sprintf(" %12s: %s", n, self.send(n)) if self.send(n)
38
- end
39
- lines.join($/)
23
+ def to_s(*args)
24
+ [@awsid.bright, @zone, @size, @created, @instid, @snapid].join '; '
40
25
  end
41
26
 
42
27
  # Alias for status
@@ -155,7 +140,14 @@ module Rudy::AWS
155
140
  volumes = nil if volumes.empty?
156
141
  volumes
157
142
  end
158
-
143
+
144
+ def list_by_instance(instid, &each_vol)
145
+ instid = instid.awsid if instid.is_a? Rudy::AWS::EC2::Instance
146
+ volumes = list(:attached, &each_vol)
147
+ volumes &&= volumes.select { |v| v.instid == instid }
148
+ volumes
149
+ end
150
+
159
151
  def any?(state=nil,vol_id=[])
160
152
  vols = list(state, vol_id)
161
153
  !vols.nil?
@@ -180,7 +172,7 @@ module Rudy::AWS
180
172
  vol_id = Volumes.get_vol_id(vol_id)
181
173
  return false unless vol_id
182
174
  vol = get(vol_id)
183
- (vol && vol.status == state)
175
+ (vol && vol.status == state) ? true : false
184
176
  end
185
177
  end
186
178
 
@@ -8,13 +8,8 @@ module Rudy::AWS
8
8
  field :region
9
9
  field :state
10
10
 
11
- def liner_note
12
- "%-10s %9s %s" % [self.name, self.region, self.state]
13
- end
14
-
15
11
  def to_s(titles=false)
16
- str = titles ? "%-20s %s#{$/}" % ['name', 'region', 'state'] : ""
17
- str << liner_note
12
+ [@name.bright, @region, @state].join '; '
18
13
  end
19
14
 
20
15
  end
data/lib/rudy/aws/sdb.rb CHANGED
@@ -181,7 +181,7 @@ module Rudy
181
181
  # Returns the return value from the request is returned untouched
182
182
  # or the default value on error or if the request returned nil.
183
183
  def execute_request(default=nil, timeout=nil, &request)
184
- timeout ||= 15
184
+ timeout ||= 30
185
185
  raise "No block provided" unless request
186
186
  response = nil
187
187
  begin
@@ -7,7 +7,7 @@ module AWS; module EC2;
7
7
 
8
8
  def addresses_create
9
9
  address = Rudy::AWS::EC2::Addresses.create
10
- puts @@global.verbose > 0 ? address.inspect : address.dump(@@global.format)
10
+ print_stobject address
11
11
  end
12
12
 
13
13
  def addresses_destroy_valid?
@@ -24,7 +24,6 @@ module AWS; module EC2;
24
24
  puts "NOTE: this IP address will become available to other EC2 customers.".bright
25
25
  execute_check(:medium)
26
26
  execute_action { Rudy::AWS::EC2::Addresses.destroy(@argv.ipaddress) }
27
- self.addresses
28
27
  end
29
28
 
30
29
  def associate_addresses_valid?
@@ -58,7 +57,7 @@ module AWS; module EC2;
58
57
  execute_check(:low)
59
58
  execute_action { Rudy::AWS::EC2::Addresses.associate(address, instance.awsid) }
60
59
  address = Rudy::AWS::EC2::Addresses.get(address)
61
- puts @@global.verbose > 0 ? address.inspect : address.dump(@@global.format)
60
+ print_stobject address
62
61
  end
63
62
 
64
63
  def disassociate_addresses_valid?
@@ -76,17 +75,12 @@ module AWS; module EC2;
76
75
  execute_check(:medium)
77
76
  execute_action { Rudy::AWS::EC2::Addresses.disassociate(@argv.ipaddress) }
78
77
  address = Rudy::AWS::EC2::Addresses.get(@argv.ipaddress)
79
- puts @@global.verbose > 0 ? address.inspect : address.dump(@@global.format)
78
+ print_stobject address
80
79
  end
81
80
 
82
81
  def addresses
83
82
  addresses = Rudy::AWS::EC2::Addresses.list || []
84
-
85
- addresses.each do |address|
86
- puts @@global.verbose > 0 ? address.inspect : address.dump(@@global.format)
87
- end
88
-
89
- puts "No Addresses" if addresses.empty?
83
+ print_stobjects addresses
90
84
  end
91
85
 
92
86
 
@@ -33,7 +33,6 @@ module AWS; module EC2;
33
33
  execute_check(:medium)
34
34
  execute_action { Rudy::AWS::EC2::Groups.destroy(@argv.name) }
35
35
  @argv.clear # so groups will print all other groups
36
- groups
37
36
  end
38
37
 
39
38
  def revoke_groups_valid?; modify_group_valid?; end
@@ -21,10 +21,7 @@ module AWS; module EC2;
21
21
  end
22
22
 
23
23
  images = Rudy::AWS::EC2::Images.list(@option.owner, @argv) || []
24
- images.each do |img|
25
- puts @@global.verbose > 0 ? img.inspect : img.dump(@@global.format)
26
- end
27
- puts "No images" if images.empty?
24
+ print_stobjects images
28
25
  end
29
26
 
30
27
  def destroy_images_valid?
@@ -0,0 +1,63 @@
1
+
2
+
3
+ module Rudy; module CLI
4
+ module AWS; module EC2;
5
+
6
+ class Info < Rudy::CLI::CommandBase
7
+
8
+ def info
9
+ process_region @@global.region
10
+ oregions = Rudy::AWS::VALID_REGIONS - [@@global.region.to_sym]
11
+ if @option.all
12
+ oregions.each do |region|
13
+ Rudy::AWS::EC2.connect @@global.accesskey, @@global.secretkey, region
14
+ process_region region
15
+ end
16
+ else
17
+ puts $/, "Other regions: " << oregions.join(', ')
18
+ end
19
+ end
20
+
21
+
22
+ private
23
+ def process_region(region)
24
+ puts " Region: %s %30s".att(:reverse) % [region, '']
25
+ puts " Instances".bright
26
+ istatus = @option.all ? :any : :running
27
+ (Rudy::AWS::EC2::Instances.list(istatus) || []).collect do |inst|
28
+ #puts " %s (%s): %s; %s; %s" % [inst.awsid, inst.state, inst.dns_public || '[no dns]', inst.size, inst.created]
29
+ puts " #{inst.to_s.noatt}"
30
+ end
31
+
32
+ puts " Volumes".bright
33
+ (Rudy::AWS::EC2::Volumes.list || []).collect do |vol|
34
+ puts " %s (%s): %sGB; %s" % [vol.awsid, vol.instid || vol.status, vol.size, vol.created]
35
+ end
36
+
37
+ puts " Snapshots".bright
38
+ (Rudy::AWS::EC2::Snapshots.list || []).collect do |snap|
39
+ puts " %s: %s; %s" % [snap.awsid, snap.volid, snap.created]
40
+ end
41
+
42
+ puts " Addresses".bright
43
+ (Rudy::AWS::EC2::Addresses.list || []).collect do |o|
44
+ puts " %s (%s)" % [o.ipaddress, o.instid || 'available']
45
+ end
46
+
47
+ puts " Groups".bright
48
+ puts (Rudy::AWS::EC2::Groups.list || []).collect { |o| " #{o.name}" }
49
+
50
+ puts " Keypairs".bright
51
+ puts (Rudy::AWS::EC2::Keypairs.list || []).collect { |o| " #{o.name}" }
52
+
53
+ puts " Images".bright
54
+ (Rudy::AWS::EC2::Images.list('self') || []).collect do |o|
55
+ puts " %s: %s; %s; %s" % [o.awsid, o.location, o.arch, o.visibility]
56
+ end
57
+ puts
58
+ end
59
+
60
+ end
61
+
62
+ end; end
63
+ end; end