vagrant-vcenter 0.1.1 → 0.2.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/Gemfile +4 -0
- data/README.md +19 -2
- data/lib/vagrant-vcenter/action/build_vm.rb +64 -3
- data/lib/vagrant-vcenter/action/power_on.rb +1 -1
- data/lib/vagrant-vcenter/action/read_ssh_info.rb +12 -2
- data/lib/vagrant-vcenter/action.rb +2 -4
- data/lib/vagrant-vcenter/config.rb +87 -0
- data/lib/vagrant-vcenter/version.rb +1 -1
- data/locales/en.yml +8 -6
- metadata +2 -3
- data/lib/vagrant-vcenter/action/sync_folders.rb +0 -135
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: edba3fb939369de58d2a7fa6db6ebbf2313a6c7f
|
4
|
+
data.tar.gz: 5695a7cf151d13558582e1da68bda7c116864e0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1baa1ccf7c60fed8482746d6f3260082b2f72680b4e54973d2c195a54c381f2acd561168da9787e7fb0f2376b972aee8297140f7544eefcad2d9f8307cd1a39
|
7
|
+
data.tar.gz: 96e30c3bd5a0a92b04f58a085c70fda683f37217812371f2cbd7257e9f81274e339420112083d2a4aa93a7d55667b0c30fdcbd43e0060aac2b8c67bc371cecd1
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,30 @@
|
|
1
1
|
[Vagrant](http://www.vagrantup.com) provider for VMware vCenter®
|
2
2
|
=============
|
3
3
|
|
4
|
-
[Version 0.
|
4
|
+
[Version 0.2.0](../../releases/tag/v0.2.0) has been released!
|
5
5
|
-------------
|
6
6
|
|
7
7
|
Please note that this software is still Alpha/Beta quality and is not recommended for production usage.
|
8
8
|
|
9
9
|
Right now a [Precise32](http://vagrant.gosddc.com/boxes/precise32-vcenter.box) is available for use, or you can roll your own as you please, make sure to install VMware tools in it.
|
10
10
|
|
11
|
+
Changes in [version 0.2.0](../../releases/tag/v0.2.0) include:
|
12
|
+
|
13
|
+
New Features
|
14
|
+
|
15
|
+
- Add option to set the actual vm name
|
16
|
+
- Set some options in the vm via linux prep
|
17
|
+
- Static networking
|
18
|
+
- Hostname
|
19
|
+
- Add option to set vmnetwork name and backing
|
20
|
+
- Vagrant now uses builtin ```SyncedFolders``` helper to synchronize folders
|
21
|
+
|
22
|
+
Fixes
|
23
|
+
|
24
|
+
- Fix the read_ssh_info if the vm doesn't have a network yet at first try the later ssh's wont forever fail
|
25
|
+
|
26
|
+
Many thanks to @BarnacleBob for submitting PR #4 with all these new features!
|
27
|
+
|
11
28
|
Changes in [version 0.1.1](../../releases/tag/v0.1.1) include:
|
12
29
|
|
13
30
|
- Support for ```vagrant share``` [Fixes [#2](../../issues/2)]
|
@@ -36,7 +53,7 @@ Configuration
|
|
36
53
|
Here's a sample Multi-VM Vagrantfile:
|
37
54
|
|
38
55
|
```ruby
|
39
|
-
precise32_box_url = 'http://vagrant.
|
56
|
+
precise32_box_url = 'http://vagrant.gosddc.com/boxes/precise32-vcenter.box'
|
40
57
|
|
41
58
|
nodes = [
|
42
59
|
{ hostname: 'web-vm',
|
@@ -93,12 +93,73 @@ module VagrantPlugins
|
|
93
93
|
:location => relocate_spec,
|
94
94
|
:powerOn => false,
|
95
95
|
:template => false)
|
96
|
+
|
97
|
+
if config.vm_network_name or config.num_cpu or config.memory
|
98
|
+
config_spec = RbVmomi::VIM.VirtualMachineConfigSpec
|
99
|
+
config_spec.numCPUs = config.num_cpu if config.num_cpu
|
100
|
+
config_spec.memoryMB = config.memory if config.memory
|
101
|
+
|
102
|
+
if config.vm_network_name
|
103
|
+
# First we must find the specified network
|
104
|
+
network = dc.network.find { |f| f.name == config.vm_network_name } or
|
105
|
+
abort "Could not find network with name #{config.vm_network_name} to join vm to"
|
106
|
+
card = template.config.hardware.device.grep(
|
107
|
+
RbVmomi::VIM::VirtualEthernetCard).first or
|
108
|
+
abort "could not find network card to customize"
|
109
|
+
if config.vm_network_type == "DistributedVirtualSwitchPort"
|
110
|
+
switch_port = RbVmomi::VIM.DistributedVirtualSwitchPortConnection(
|
111
|
+
:switchUuid => network.config.distributedVirtualSwitch.uuid,
|
112
|
+
:portgroupKey => network.key)
|
113
|
+
card.backing = RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo(
|
114
|
+
:port => switch_port)
|
115
|
+
else
|
116
|
+
abort "vm network type of #{config.vm_network_type} is unknown"
|
117
|
+
end
|
118
|
+
dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(:device => card, :operation => "edit")
|
119
|
+
config_spec.deviceChange = [dev_spec]
|
120
|
+
end
|
121
|
+
|
122
|
+
spec.config = config_spec
|
123
|
+
end
|
124
|
+
|
125
|
+
if config.enable_vm_customization or config.enable_vm_customization == 'true'
|
126
|
+
gIPSettings = RbVmomi::VIM.CustomizationGlobalIPSettings(
|
127
|
+
:dnsServerList => config.dns_server_list,
|
128
|
+
:dnsSuffixList => config.dns_suffix_list)
|
129
|
+
|
130
|
+
prep = RbVmomi::VIM.CustomizationLinuxPrep(
|
131
|
+
:domain => env[:machine].name,
|
132
|
+
:hostName => RbVmomi::VIM.CustomizationFixedName(
|
133
|
+
:name => env[:machine].name))
|
134
|
+
|
135
|
+
adapter = RbVmomi::VIM.CustomizationIPSettings(
|
136
|
+
:gateway => [config.gateway],
|
137
|
+
:ip => RbVmomi::VIM.CustomizationFixedIp(
|
138
|
+
:ipAddress => config.ipaddress),
|
139
|
+
:subnetMask => config.netmask)
|
140
|
+
|
141
|
+
nic_map = [RbVmomi::VIM.CustomizationAdapterMapping(
|
142
|
+
:adapter => adapter)]
|
143
|
+
|
144
|
+
cust_spec = RbVmomi::VIM.CustomizationSpec(
|
145
|
+
:globalIPSettings => gIPSettings,
|
146
|
+
:identity => prep,
|
147
|
+
:nicSettingMap => nic_map)
|
148
|
+
|
149
|
+
spec.customization = cust_spec
|
150
|
+
end
|
96
151
|
|
97
152
|
@logger.debug("Spec: #{spec.pretty_inspect}")
|
98
153
|
|
99
|
-
|
100
|
-
|
101
|
-
|
154
|
+
@logger.debug("disable_auto_vm_name: #{config.disable_auto_vm_name}")
|
155
|
+
|
156
|
+
if config.disable_auto_vm_name or config.disable_auto_vm_name == 'true'
|
157
|
+
vm_target = vm_name.to_s
|
158
|
+
else
|
159
|
+
vm_target = "Vagrant-#{Etc.getlogin}-" +
|
160
|
+
"#{vm_name}-#{Socket.gethostname.downcase}-" +
|
161
|
+
"#{SecureRandom.hex(4)}"
|
162
|
+
end
|
102
163
|
|
103
164
|
@logger.debug("VM name: #{vm_target}")
|
104
165
|
|
@@ -27,9 +27,19 @@ module VagrantPlugins
|
|
27
27
|
root_vm_folder = dc.vmFolder
|
28
28
|
vm = root_vm_folder.findByUuid(env[:machine].id)
|
29
29
|
|
30
|
-
|
30
|
+
address = vm.guest.ipAddress
|
31
|
+
if not address or address == ''
|
32
|
+
address = vm.guest_ip
|
33
|
+
end
|
31
34
|
|
32
|
-
|
35
|
+
if not address or address == ''
|
36
|
+
# if we can't find it right away just return nil. it will retry
|
37
|
+
# till the vmware tools supplies the ip address back to vcenter
|
38
|
+
@logger.debug('could not find booted guest ipaddress')
|
39
|
+
return nil
|
40
|
+
end
|
41
|
+
|
42
|
+
{ :host => address, :port => 22 }
|
33
43
|
end
|
34
44
|
end
|
35
45
|
end
|
@@ -14,7 +14,7 @@ module VagrantPlugins
|
|
14
14
|
Vagrant::Action::Builder.new.tap do |b|
|
15
15
|
b.use PowerOn
|
16
16
|
b.use Provision
|
17
|
-
b.use
|
17
|
+
b.use SyncedFolders
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -114,7 +114,7 @@ module VagrantPlugins
|
|
114
114
|
next
|
115
115
|
end
|
116
116
|
b2.use Provision
|
117
|
-
b2.use
|
117
|
+
b2.use SyncedFolders
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|
@@ -224,8 +224,6 @@ module VagrantPlugins
|
|
224
224
|
action_root.join('resume')
|
225
225
|
autoload :Suspend,
|
226
226
|
action_root.join('suspend')
|
227
|
-
autoload :SyncFolders,
|
228
|
-
action_root.join('sync_folders')
|
229
227
|
end
|
230
228
|
end
|
231
229
|
end
|
@@ -58,6 +58,74 @@ module VagrantPlugins
|
|
58
58
|
# @return [Bool]
|
59
59
|
attr_accessor :linked_clones
|
60
60
|
|
61
|
+
# Disable automatic safe vm name generation
|
62
|
+
#
|
63
|
+
# @return [Bool]
|
64
|
+
attr_accessor :disable_auto_vm_name
|
65
|
+
|
66
|
+
# Use prep and customization api in the building
|
67
|
+
# of the vm in vcenter
|
68
|
+
#
|
69
|
+
# Mostly this allows the static ip configuration
|
70
|
+
# of a vm
|
71
|
+
#
|
72
|
+
# @return [Bool]
|
73
|
+
attr_accessor :enable_vm_customization
|
74
|
+
|
75
|
+
# Type of the machine prep to use
|
76
|
+
#
|
77
|
+
# @return [String]
|
78
|
+
attr_accessor :prep_type
|
79
|
+
|
80
|
+
# Dns server list
|
81
|
+
#
|
82
|
+
# @return [Array<String>]
|
83
|
+
attr_accessor :dns_server_list
|
84
|
+
|
85
|
+
# Dns suffix list
|
86
|
+
#
|
87
|
+
# @return [Array<String>]
|
88
|
+
attr_accessor :dns_suffix_list
|
89
|
+
|
90
|
+
# network gateway
|
91
|
+
#
|
92
|
+
# @return [String]
|
93
|
+
attr_accessor :gateway
|
94
|
+
|
95
|
+
# subnet mask
|
96
|
+
#
|
97
|
+
# @return [String]
|
98
|
+
attr_accessor :netmask
|
99
|
+
|
100
|
+
# ip address
|
101
|
+
#
|
102
|
+
# @return [String]
|
103
|
+
attr_accessor :ipaddress
|
104
|
+
|
105
|
+
# vm network name
|
106
|
+
#
|
107
|
+
# @return [String]
|
108
|
+
attr_accessor :vm_network_name
|
109
|
+
|
110
|
+
# vm network type
|
111
|
+
# only supported network type
|
112
|
+
# DistributedVirtualSwitchPort
|
113
|
+
#
|
114
|
+
# @return [String]
|
115
|
+
attr_accessor :vm_network_type
|
116
|
+
|
117
|
+
# num cpu
|
118
|
+
#
|
119
|
+
# @return [Fixnum]
|
120
|
+
attr_accessor :num_cpu
|
121
|
+
|
122
|
+
# memory in MB
|
123
|
+
#
|
124
|
+
# @return [Fixnum]
|
125
|
+
attr_accessor :memory
|
126
|
+
|
127
|
+
|
128
|
+
|
61
129
|
##
|
62
130
|
## vCenter config runtime values
|
63
131
|
##
|
@@ -66,6 +134,14 @@ module VagrantPlugins
|
|
66
134
|
attr_accessor :vcenter_cnx
|
67
135
|
attr_accessor :template_id
|
68
136
|
|
137
|
+
def initialize()
|
138
|
+
@enable_vm_customization = false
|
139
|
+
@prep_type = 'linux'
|
140
|
+
@enable_vm_customization = false
|
141
|
+
@dns_server_list = []
|
142
|
+
@dns_suffix_list = []
|
143
|
+
end
|
144
|
+
|
69
145
|
def validate(machine)
|
70
146
|
errors = _detected_errors
|
71
147
|
|
@@ -85,6 +161,17 @@ module VagrantPlugins
|
|
85
161
|
errors <<
|
86
162
|
I18n.t('vagrant_vcenter.config.network_name') if network_name.nil?
|
87
163
|
|
164
|
+
if enable_vm_customization
|
165
|
+
errors <<
|
166
|
+
I18n.t('vagrant_vcenter.config.no_prep_type') if prep_type != 'linux'
|
167
|
+
errors <<
|
168
|
+
I18n.t('vagrant_vcenter.config.gateway') if gateway.empty?
|
169
|
+
errors <<
|
170
|
+
I18n.t('vagrant_vcenter.config.ipaddress') if ipaddress.empty?
|
171
|
+
errors <<
|
172
|
+
I18n.t('vagrant_vcenter.config.netmask') if netmask.empty?
|
173
|
+
end
|
174
|
+
|
88
175
|
{ 'vCenter Provider' => errors }
|
89
176
|
end
|
90
177
|
end
|
data/locales/en.yml
CHANGED
@@ -9,12 +9,6 @@ en:
|
|
9
9
|
VM is already running
|
10
10
|
vm_halted_cannot_suspend: |-
|
11
11
|
VM is not running or already suspended, cannot suspend it.
|
12
|
-
sync:
|
13
|
-
rsync_not_found_warning: |-
|
14
|
-
Warning! Folder sync disabled because the rsync binary is missing.
|
15
|
-
Make sure rsync is installed and the binary can be found in the PATH.
|
16
|
-
rsync_folder: |-
|
17
|
-
Rsyncing folder: %{hostpath} => %{guestpath}
|
18
12
|
config:
|
19
13
|
hostname: |-
|
20
14
|
Configuration must specify a vCenter hostname
|
@@ -32,6 +26,14 @@ en:
|
|
32
26
|
Configuration must specify a resource pool name
|
33
27
|
resourcepool_name: |-
|
34
28
|
Configuration must specify a resource pool name
|
29
|
+
no_prep_type: |-
|
30
|
+
The only supported prep type is linux. hack away.
|
31
|
+
ipaddress: |-
|
32
|
+
Configuration must specify a ipaddress
|
33
|
+
gateway: |-
|
34
|
+
Configuration must specify a gateway
|
35
|
+
netmask: |-
|
36
|
+
Configuration must specify a netmask
|
35
37
|
states:
|
36
38
|
not_created: |-
|
37
39
|
The environment has not yet been created. Run `vagrant up` to
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-vcenter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabio Rapposelli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: vagrant-rbvmomi
|
@@ -158,7 +158,6 @@ files:
|
|
158
158
|
- lib/vagrant-vcenter/action/read_state.rb
|
159
159
|
- lib/vagrant-vcenter/action/resume.rb
|
160
160
|
- lib/vagrant-vcenter/action/suspend.rb
|
161
|
-
- lib/vagrant-vcenter/action/sync_folders.rb
|
162
161
|
- lib/vagrant-vcenter/cap/public_address.rb
|
163
162
|
- lib/vagrant-vcenter/config.rb
|
164
163
|
- lib/vagrant-vcenter/errors.rb
|
@@ -1,135 +0,0 @@
|
|
1
|
-
# The MIT License (MIT)
|
2
|
-
# Copyright (c) 2013 Mitchell Hashimoto
|
3
|
-
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to
|
6
|
-
# deal in the Software without restriction, including without limitation the
|
7
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
8
|
-
# sell copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
|
11
|
-
# The above copyright notice and this permission notice shall be included in all
|
12
|
-
# copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
19
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
20
|
-
# IN THE SOFTWARE.
|
21
|
-
|
22
|
-
require 'log4r'
|
23
|
-
require 'vagrant/util/subprocess'
|
24
|
-
require 'vagrant/util/scoped_hash_override'
|
25
|
-
require 'vagrant/util/which'
|
26
|
-
|
27
|
-
module VagrantPlugins
|
28
|
-
module VCenter
|
29
|
-
module Action
|
30
|
-
# This class syncs Vagrant folders using RSYNC, this code has been ported
|
31
|
-
# from vagrant-aws (https://github.com/mitchellh/vagrant-aws)
|
32
|
-
class SyncFolders
|
33
|
-
include Vagrant::Util::ScopedHashOverride
|
34
|
-
|
35
|
-
def initialize(app, env)
|
36
|
-
@app = app
|
37
|
-
@logger = Log4r::Logger.new('vagrant_vcenter::action::sync_folders')
|
38
|
-
end
|
39
|
-
|
40
|
-
def call(env)
|
41
|
-
@app.call(env)
|
42
|
-
|
43
|
-
ssh_info = env[:machine].ssh_info
|
44
|
-
|
45
|
-
unless Vagrant::Util::Which.which('rsync')
|
46
|
-
env[:ui].warn(I18n.t('vagrant_vcenter.sync.rsync_not_found_warning',
|
47
|
-
:side => 'host'))
|
48
|
-
return
|
49
|
-
end
|
50
|
-
|
51
|
-
if env[:machine].communicate.execute('which rsync',
|
52
|
-
:error_check => false) != 0
|
53
|
-
env[:ui].warn(I18n.t('vagrant_vcenter.sync.rsync_not_found_warning',
|
54
|
-
:side => 'guest'))
|
55
|
-
return
|
56
|
-
end
|
57
|
-
|
58
|
-
env[:machine].config.vm.synced_folders.each do |id, data|
|
59
|
-
data = scoped_hash_override(data, :vCenter)
|
60
|
-
|
61
|
-
# Ignore disabled shared folders
|
62
|
-
next if data[:disabled]
|
63
|
-
|
64
|
-
hostpath = File.expand_path(data[:hostpath], env[:root_path])
|
65
|
-
guestpath = data[:guestpath]
|
66
|
-
|
67
|
-
# Make sure there is a trailing slash on the host path to
|
68
|
-
# avoid creating an additional directory with rsync
|
69
|
-
hostpath = "#{hostpath}/" if hostpath !~ /\/$/
|
70
|
-
|
71
|
-
# on windows rsync.exe requires cygdrive-style paths
|
72
|
-
if Vagrant::Util::Platform.windows?
|
73
|
-
hostpath = hostpath.gsub(/^(\w):/) { "/cygdrive/\1" }
|
74
|
-
end
|
75
|
-
|
76
|
-
env[:ui].info(I18n.t('vagrant_vcenter.sync.rsync_folder',
|
77
|
-
:hostpath => hostpath,
|
78
|
-
:guestpath => guestpath))
|
79
|
-
|
80
|
-
# Create the host path if it doesn't exist and option flag is set
|
81
|
-
if data[:create]
|
82
|
-
begin
|
83
|
-
FileUtils.mkdir_p(hostpath)
|
84
|
-
rescue => err
|
85
|
-
raise Errors::MkdirError,
|
86
|
-
:hostpath => hostpath,
|
87
|
-
:err => err
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# Create the guest path
|
92
|
-
env[:machine].communicate.sudo("mkdir -p '#{guestpath}'")
|
93
|
-
env[:machine].communicate.sudo(
|
94
|
-
"chown -R #{ssh_info[:username]} '#{guestpath}'")
|
95
|
-
|
96
|
-
# collect rsync excludes specified :rsync_excludes=>['path1',...]
|
97
|
-
# in synced_folder options
|
98
|
-
excludes = ['.vagrant/', 'Vagrantfile',
|
99
|
-
*Array(data[:rsync_excludes])].uniq
|
100
|
-
|
101
|
-
# Rsync over to the guest path using the SSH info
|
102
|
-
command = [
|
103
|
-
'rsync', '--verbose', '--archive', '-z',
|
104
|
-
*excludes.map { |e|['--exclude', e] }.flatten,
|
105
|
-
'-e', "ssh -p #{ssh_info[:port]} -o StrictHostKeyChecking=no " +
|
106
|
-
"#{ssh_key_options(ssh_info)}", hostpath,
|
107
|
-
"#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"]
|
108
|
-
|
109
|
-
# we need to fix permissions when using rsync.exe on windows, see
|
110
|
-
# http://stackoverflow.com/questions/5798807/rsync-permission-
|
111
|
-
# denied-created-directories-have-no-permissions
|
112
|
-
if Vagrant::Util::Platform.windows?
|
113
|
-
command.insert(1, '--chmod', 'ugo=rwX')
|
114
|
-
end
|
115
|
-
|
116
|
-
r = Vagrant::Util::Subprocess.execute(*command)
|
117
|
-
if r.exit_code != 0
|
118
|
-
fail Errors::RsyncError,
|
119
|
-
:guestpath => guestpath,
|
120
|
-
:hostpath => hostpath,
|
121
|
-
:stderr => r.stderr
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
private
|
127
|
-
|
128
|
-
def ssh_key_options(ssh_info)
|
129
|
-
# Ensure that `private_key_path` is an Array (for Vagrant < 1.4)
|
130
|
-
Array(ssh_info[:private_key_path]).map { |path| "-i '#{path}' " }.join
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|