vagrant-parallels 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +9 -4
- data/lib/vagrant-parallels/action.rb +2 -7
- data/lib/vagrant-parallels/action/check_guest_tools.rb +3 -4
- data/lib/vagrant-parallels/action/prepare_nfs_settings.rb +36 -23
- data/lib/vagrant-parallels/driver/prl_ctl.rb +6 -4
- data/lib/vagrant-parallels/errors.rb +4 -0
- data/lib/vagrant-parallels/plugin.rb +7 -2
- data/lib/vagrant-parallels/synced_folder.rb +79 -0
- data/lib/vagrant-parallels/version.rb +1 -1
- data/locales/en.yml +3 -4
- metadata +3 -4
- data/lib/vagrant-parallels/action/prune_nfs_exports.rb +0 -20
- data/lib/vagrant-parallels/action/share_folders.rb +0 -130
data/README.md
CHANGED
@@ -12,18 +12,23 @@ Almost all features are available except for exporting/packaging VM's. This wil
|
|
12
12
|
|
13
13
|
We look forward to hearing from you with any issues or features. Thank you!
|
14
14
|
|
15
|
+
## Installation
|
16
|
+
The latest version of this provider is supporting **only Vagrant 1.4 or higher**.
|
17
|
+
If you are still using Vagrant 1.3.*, please, specify the plugin version '0.0.9':
|
18
|
+
|
19
|
+
- For Vagrant 1.4 or higher execute `vagrant plugin install vagrant-parallels`.
|
20
|
+
- For Vagrant 1.3.x execute `vagrant plugin install vagrant-parallels --plugin-version 0.0.9`.
|
21
|
+
|
15
22
|
## Usage
|
16
|
-
|
23
|
+
After installing, then do a `vagrant up` and specify the `parallels` provider. An example is shown below.
|
17
24
|
|
18
25
|
```
|
19
|
-
$ vagrant plugin install vagrant-parallels
|
20
|
-
...
|
21
26
|
$ vagrant init
|
22
27
|
$ vagrant up --provider=parallels
|
23
28
|
...
|
24
29
|
```
|
25
30
|
|
26
|
-
You need to have a parallels compatible box
|
31
|
+
You need to have a parallels compatible box specified in your `Vagrantfile` before doing a `vagrant up`, please refer to the coming section for instructions.
|
27
32
|
|
28
33
|
### Default Provider
|
29
34
|
|
@@ -12,17 +12,14 @@ module VagrantPlugins
|
|
12
12
|
def self.action_boot
|
13
13
|
Vagrant::Action::Builder.new.tap do |b|
|
14
14
|
b.use CheckAccessible
|
15
|
-
# b.use CleanMachineFolder
|
16
15
|
# b.use ClearForwardedPorts
|
17
16
|
b.use Provision
|
18
17
|
b.use EnvSet, :port_collision_repair => true
|
19
18
|
# b.use PrepareForwardedPortCollisionParams
|
20
19
|
# b.use HandleForwardedPortCollisions
|
21
|
-
b.use
|
22
|
-
b.use
|
20
|
+
b.use SyncedFolderCleanup
|
21
|
+
b.use SyncedFolders
|
23
22
|
b.use PrepareNFSSettings
|
24
|
-
b.use ClearSharedFolders
|
25
|
-
b.use ShareFolders
|
26
23
|
b.use Network
|
27
24
|
b.use ClearNetworkInterfaces
|
28
25
|
# b.use ForwardPorts
|
@@ -295,11 +292,9 @@ module VagrantPlugins
|
|
295
292
|
autoload :Package, File.expand_path("../action/package", __FILE__)
|
296
293
|
autoload :PackageConfigFiles, File.expand_path("../action/package_config_files", __FILE__)
|
297
294
|
autoload :PrepareNFSSettings, File.expand_path("../action/prepare_nfs_settings", __FILE__)
|
298
|
-
autoload :PruneNFSExports, File.expand_path("../action/prune_nfs_exports", __FILE__)
|
299
295
|
autoload :RegisterTemplate, File.expand_path("../action/register_template", __FILE__)
|
300
296
|
autoload :Resume, File.expand_path("../action/resume", __FILE__)
|
301
297
|
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
|
302
|
-
autoload :ShareFolders, File.expand_path("../action/share_folders", __FILE__)
|
303
298
|
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
|
304
299
|
autoload :UnregisterTemplate, File.expand_path("../action/unregister_template", __FILE__)
|
305
300
|
|
@@ -11,12 +11,11 @@ module VagrantPlugins
|
|
11
11
|
if !tools_version
|
12
12
|
env[:ui].warn I18n.t("vagrant.actions.vm.check_guest_tools.not_detected")
|
13
13
|
else
|
14
|
-
env[:machine].provider.driver.
|
15
|
-
|
16
|
-
unless os_version.start_with? tools_version
|
14
|
+
pd_version = env[:machine].provider.driver.version
|
15
|
+
unless pd_version.start_with? tools_version
|
17
16
|
env[:ui].warn(I18n.t("vagrant_parallels.actions.vm.check_guest_tools.version_mismatch",
|
18
17
|
tools_version: tools_version,
|
19
|
-
parallels_version:
|
18
|
+
parallels_version: pd_version))
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
@@ -8,35 +8,48 @@ module VagrantPlugins
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def call(env)
|
11
|
+
@machine = env[:machine]
|
11
12
|
@app.call(env)
|
12
13
|
|
13
|
-
using_nfs
|
14
|
-
|
15
|
-
|
16
|
-
using_nfs = true
|
17
|
-
break
|
18
|
-
end
|
14
|
+
if using_nfs?
|
15
|
+
@logger.info("Using NFS, preparing NFS settings by reading host IP and machine IP")
|
16
|
+
add_nfs_settings_to_env!(env)
|
19
17
|
end
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
# We're using NFS if we have any synced folder with NFS configured. If
|
21
|
+
# we are not using NFS we don't need to do the extra work to
|
22
|
+
# populate these fields in the environment.
|
23
|
+
def using_nfs?
|
24
|
+
@machine.config.vm.synced_folders.any? { |_, opts| opts[:type] == :nfs }
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
# Extracts the proper host and guest IPs for NFS mounts and stores them
|
28
|
+
# in the environment for the SyncedFolder action to use them in
|
29
|
+
# mounting.
|
30
|
+
#
|
31
|
+
# The ! indicates that this method modifies its argument.
|
32
|
+
def add_nfs_settings_to_env!(env)
|
33
|
+
adapter, host_ip = find_host_only_adapter
|
34
|
+
machine_ip = nil
|
35
|
+
machine_ip = read_machine_ip if adapter
|
36
|
+
|
37
|
+
raise Vagrant::Errors::NFSNoHostonlyNetwork if !host_ip || !machine_ip
|
38
|
+
|
39
|
+
env[:nfs_host_ip] = host_ip
|
40
|
+
env[:nfs_machine_ip] = machine_ip
|
28
41
|
end
|
29
42
|
|
30
|
-
#
|
43
|
+
# Finds first host only network adapter and returns its adapter number
|
44
|
+
# and IP address
|
31
45
|
#
|
32
|
-
# @
|
33
|
-
|
34
|
-
|
35
|
-
machine.provider.driver.read_network_interfaces.each do |adapter, opts|
|
46
|
+
# @return [Integer, String] adapter number, ip address of found host-only adapter
|
47
|
+
def find_host_only_adapter
|
48
|
+
@machine.provider.driver.read_network_interfaces.each do |adapter, opts|
|
36
49
|
if opts[:type] == :hostonly
|
37
|
-
machine.provider.driver.read_host_only_interfaces.each do |interface|
|
50
|
+
@machine.provider.driver.read_host_only_interfaces.each do |interface|
|
38
51
|
if interface[:bound_to] == opts[:hostonly]
|
39
|
-
return interface[:ip]
|
52
|
+
return adapter, interface[:ip]
|
40
53
|
end
|
41
54
|
end
|
42
55
|
end
|
@@ -48,17 +61,17 @@ module VagrantPlugins
|
|
48
61
|
# Returns the IP address of the guest by looking at the first
|
49
62
|
# enabled host only network.
|
50
63
|
#
|
51
|
-
# @return [String]
|
52
|
-
def read_machine_ip
|
64
|
+
# @return [String] ip address of adapter in guest
|
65
|
+
def read_machine_ip
|
53
66
|
ips = []
|
54
|
-
machine.config.vm.networks.each do |type, options|
|
67
|
+
@machine.config.vm.networks.each do |type, options|
|
55
68
|
if type == :private_network && options[:ip].is_a?(String)
|
56
69
|
ips << options[:ip]
|
57
70
|
end
|
58
71
|
end
|
59
72
|
|
60
73
|
if ips.empty?
|
61
|
-
|
74
|
+
raise Vagrant::Errors::NFSNoGuestIP
|
62
75
|
end
|
63
76
|
|
64
77
|
ips
|
@@ -411,13 +411,15 @@ module VagrantPlugins
|
|
411
411
|
#
|
412
412
|
# This should raise a VagrantError if things are not ready.
|
413
413
|
def verify!
|
414
|
-
|
415
|
-
execute('--version')
|
414
|
+
version
|
416
415
|
end
|
417
416
|
|
418
417
|
def version
|
419
|
-
|
420
|
-
|
418
|
+
if execute('--version', retryable: true) =~ /prlctl version ([\d\.]+)/
|
419
|
+
$1.downcase
|
420
|
+
else
|
421
|
+
raise VagrantPlugins::Parallels::Errors::ParallelsInstallIncomplete
|
422
|
+
end
|
421
423
|
end
|
422
424
|
|
423
425
|
private
|
@@ -19,6 +19,10 @@ module VagrantPlugins
|
|
19
19
|
error_key(:parallels_kernel_module_not_loaded)
|
20
20
|
end
|
21
21
|
|
22
|
+
class ParallelsInstallIncomplete < VagrantParallelsError
|
23
|
+
error_key(:parallels_install_incomplete)
|
24
|
+
end
|
25
|
+
|
22
26
|
class ParallelsNoRoomForHighLevelNetwork < VagrantParallelsError
|
23
27
|
error_key(:parallels_no_room_for_high_level_network)
|
24
28
|
end
|
@@ -6,8 +6,8 @@ end
|
|
6
6
|
|
7
7
|
# This is a sanity check to make sure no one is attempting to install
|
8
8
|
# this into an early Vagrant version.
|
9
|
-
if Vagrant::VERSION < "1.
|
10
|
-
raise "The Vagrant Parallels plugin is only compatible with Vagrant 1.
|
9
|
+
if Vagrant::VERSION < "1.4.0"
|
10
|
+
raise "The Vagrant Parallels plugin is only compatible with Vagrant 1.4+"
|
11
11
|
end
|
12
12
|
|
13
13
|
module VagrantPlugins
|
@@ -40,6 +40,11 @@ module VagrantPlugins
|
|
40
40
|
GuestLinuxCap::MountParallelsSharedFolder
|
41
41
|
end
|
42
42
|
|
43
|
+
synced_folder(:parallels) do
|
44
|
+
require File.expand_path("../synced_folder", __FILE__)
|
45
|
+
SyncedFolder
|
46
|
+
end
|
47
|
+
|
43
48
|
end
|
44
49
|
|
45
50
|
module Driver
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "vagrant/util/platform"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Parallels
|
5
|
+
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
|
6
|
+
def usable?(machine)
|
7
|
+
# These synced folders only work if the provider if VirtualBox
|
8
|
+
machine.provider_name == :parallels
|
9
|
+
end
|
10
|
+
|
11
|
+
def prepare(machine, folders, _opts)
|
12
|
+
defs = []
|
13
|
+
folders.each do |id, data|
|
14
|
+
hostpath = Vagrant::Util::Platform.cygwin_windows_path(data[:hostpath])
|
15
|
+
|
16
|
+
defs << {
|
17
|
+
# Escape special symbols (Parallels Shared Folders specific)
|
18
|
+
name: id.split('/').delete_if{|i| i.empty?}.join('_'),
|
19
|
+
hostpath: hostpath.to_s,
|
20
|
+
transient: data[:transient],
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
driver(machine).share_folders(defs)
|
25
|
+
end
|
26
|
+
|
27
|
+
def enable(machine, folders, _opts)
|
28
|
+
# short guestpaths first, so we don't step on ourselves
|
29
|
+
folders = folders.sort_by do |id, data|
|
30
|
+
if data[:guestpath]
|
31
|
+
data[:guestpath].length
|
32
|
+
else
|
33
|
+
# A long enough path to just do this at the end.
|
34
|
+
10000
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Go through each folder and mount
|
39
|
+
machine.ui.info(I18n.t("vagrant.actions.vm.share_folders.mounting"))
|
40
|
+
folders.each do |id, data|
|
41
|
+
if data[:guestpath]
|
42
|
+
data[:guestpath] = data[:guestpath]
|
43
|
+
|
44
|
+
# Guest path specified, so mount the folder to specified point
|
45
|
+
machine.ui.info(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
|
46
|
+
:guest_path => data[:guestpath]))
|
47
|
+
|
48
|
+
# Dup the data so we can pass it to the guest API
|
49
|
+
data = data.dup
|
50
|
+
|
51
|
+
# Calculate the owner and group
|
52
|
+
ssh_info = machine.ssh_info
|
53
|
+
data[:owner] ||= ssh_info[:username]
|
54
|
+
data[:group] ||= ssh_info[:username]
|
55
|
+
|
56
|
+
# Mount the actual folder
|
57
|
+
machine.guest.capability(
|
58
|
+
:mount_parallels_shared_folder, id, data[:guestpath], data)
|
59
|
+
else
|
60
|
+
# If no guest path is specified, then automounting is disabled
|
61
|
+
machine.ui.info(I18n.t("vagrant.actions.vm.share_folders.nomount_entry",
|
62
|
+
:host_path => data[:hostpath]))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def cleanup(machine, opts)
|
68
|
+
driver(machine).clear_shared_folders if machine.id && machine.id != ""
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
# This is here so that we can stub it for tests
|
74
|
+
def driver(machine)
|
75
|
+
machine.provider.driver
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/locales/en.yml
CHANGED
@@ -538,10 +538,9 @@ en:
|
|
538
538
|
Parallels Desktop is complaining that the kernel module is not loaded. Please
|
539
539
|
run `prlctl --version` or open the Parallels Desktop GUI to see the error
|
540
540
|
message which should contain instructions on how to fix this error.
|
541
|
-
|
542
|
-
Parallels Desktop is complaining that the installation is incomplete.
|
543
|
-
|
544
|
-
instructions on how to fix this error.
|
541
|
+
parallels_install_incomplete: |-
|
542
|
+
Parallels Desktop is complaining that the installation is incomplete. Try to reinstall Parallels
|
543
|
+
Desktop or contact Parallels support.
|
545
544
|
parallels_no_room_for_high_level_network: |-
|
546
545
|
There is no available slots on the Parallels Desktop VM for the configured
|
547
546
|
high-level network interfaces. "private_network" and "public_network"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-parallels
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -127,11 +127,9 @@ files:
|
|
127
127
|
- lib/vagrant-parallels/action/package.rb
|
128
128
|
- lib/vagrant-parallels/action/package_config_files.rb
|
129
129
|
- lib/vagrant-parallels/action/prepare_nfs_settings.rb
|
130
|
-
- lib/vagrant-parallels/action/prune_nfs_exports.rb
|
131
130
|
- lib/vagrant-parallels/action/register_template.rb
|
132
131
|
- lib/vagrant-parallels/action/resume.rb
|
133
132
|
- lib/vagrant-parallels/action/setup_package_files.rb
|
134
|
-
- lib/vagrant-parallels/action/share_folders.rb
|
135
133
|
- lib/vagrant-parallels/action/suspend.rb
|
136
134
|
- lib/vagrant-parallels/action/unregister_template.rb
|
137
135
|
- lib/vagrant-parallels/action.rb
|
@@ -142,6 +140,7 @@ files:
|
|
142
140
|
- lib/vagrant-parallels/guest_cap/linux/mount_parallels_shared_folder.rb
|
143
141
|
- lib/vagrant-parallels/plugin.rb
|
144
142
|
- lib/vagrant-parallels/provider.rb
|
143
|
+
- lib/vagrant-parallels/synced_folder.rb
|
145
144
|
- lib/vagrant-parallels/version.rb
|
146
145
|
- lib/vagrant-parallels.rb
|
147
146
|
- LICENSE.txt
|
@@ -168,7 +167,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
168
167
|
version: '0'
|
169
168
|
segments:
|
170
169
|
- 0
|
171
|
-
hash:
|
170
|
+
hash: 646482643972557885
|
172
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
172
|
none: false
|
174
173
|
requirements:
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module VagrantPlugins
|
2
|
-
module Parallels
|
3
|
-
module Action
|
4
|
-
class PruneNFSExports
|
5
|
-
def initialize(app, env)
|
6
|
-
@app = app
|
7
|
-
end
|
8
|
-
|
9
|
-
def call(env)
|
10
|
-
if env[:host]
|
11
|
-
vms = env[:machine].provider.driver.read_all_names
|
12
|
-
env[:host].nfs_prune(vms.values)
|
13
|
-
end
|
14
|
-
|
15
|
-
@app.call(env)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,130 +0,0 @@
|
|
1
|
-
require "pathname"
|
2
|
-
|
3
|
-
require "log4r"
|
4
|
-
|
5
|
-
require "vagrant/util/platform"
|
6
|
-
require "vagrant/util/scoped_hash_override"
|
7
|
-
|
8
|
-
module VagrantPlugins
|
9
|
-
module Parallels
|
10
|
-
module Action
|
11
|
-
class ShareFolders
|
12
|
-
include Vagrant::Util::ScopedHashOverride
|
13
|
-
|
14
|
-
def initialize(app, env)
|
15
|
-
@logger = Log4r::Logger.new("vagrant::action::vm::share_folders")
|
16
|
-
@app = app
|
17
|
-
end
|
18
|
-
|
19
|
-
def call(env)
|
20
|
-
@env = env
|
21
|
-
|
22
|
-
prepare_folders
|
23
|
-
create_metadata
|
24
|
-
|
25
|
-
@app.call(env)
|
26
|
-
|
27
|
-
mount_shared_folders
|
28
|
-
end
|
29
|
-
|
30
|
-
# This method returns an actual list of Parallels Desktop
|
31
|
-
# shared folders to create and their proper path.
|
32
|
-
def shared_folders
|
33
|
-
{}.tap do |result|
|
34
|
-
@env[:machine].config.vm.synced_folders.each do |id, data|
|
35
|
-
data = scoped_hash_override(data, :parallels)
|
36
|
-
|
37
|
-
# Ignore NFS shared folders
|
38
|
-
next if data[:nfs]
|
39
|
-
|
40
|
-
# Ignore disabled shared folders
|
41
|
-
next if data[:disabled]
|
42
|
-
|
43
|
-
# This to prevent overwriting the actual shared folders data
|
44
|
-
id = Pathname.new(id).to_s.split('/').drop_while{|i| i.empty?}.join('_')
|
45
|
-
result[id] = data.dup
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# Prepares the shared folders by verifying they exist and creating them
|
51
|
-
# if they don't.
|
52
|
-
def prepare_folders
|
53
|
-
shared_folders.each do |id, options|
|
54
|
-
hostpath = Pathname.new(options[:hostpath]).expand_path(@env[:root_path])
|
55
|
-
|
56
|
-
if !hostpath.directory? && options[:create]
|
57
|
-
# Host path doesn't exist, so let's create it.
|
58
|
-
@logger.debug("Host path doesn't exist, creating: #{hostpath}")
|
59
|
-
|
60
|
-
begin
|
61
|
-
hostpath.mkpath
|
62
|
-
rescue Errno::EACCES
|
63
|
-
raise Vagrant::Errors::SharedFolderCreateFailed,
|
64
|
-
:path => hostpath.to_s
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def create_metadata
|
71
|
-
@env[:ui].info I18n.t("vagrant.actions.vm.share_folders.creating")
|
72
|
-
|
73
|
-
folders = []
|
74
|
-
shared_folders.each do |id, data|
|
75
|
-
hostpath = File.expand_path(data[:hostpath], @env[:root_path])
|
76
|
-
hostpath = Vagrant::Util::Platform.cygwin_windows_path(hostpath)
|
77
|
-
|
78
|
-
folders << {
|
79
|
-
:name => id,
|
80
|
-
:hostpath => hostpath,
|
81
|
-
:transient => data[:transient]
|
82
|
-
}
|
83
|
-
end
|
84
|
-
|
85
|
-
@env[:machine].provider.driver.share_folders(folders)
|
86
|
-
end
|
87
|
-
|
88
|
-
# TODO: Fix this, doesn't execute at the correct time
|
89
|
-
def mount_shared_folders
|
90
|
-
@env[:ui].info I18n.t("vagrant.actions.vm.share_folders.mounting")
|
91
|
-
|
92
|
-
# short guestpaths first, so we don't step on ourselves
|
93
|
-
folders = shared_folders.sort_by do |id, data|
|
94
|
-
if data[:guestpath]
|
95
|
-
data[:guestpath].length
|
96
|
-
else
|
97
|
-
# A long enough path to just do this at the end.
|
98
|
-
10000
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# Go through each folder and mount
|
103
|
-
folders.each do |id, data|
|
104
|
-
if data[:guestpath]
|
105
|
-
# Guest path specified, so mount the folder to specified point
|
106
|
-
@env[:ui].info(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
|
107
|
-
:guest_path => data[:guestpath]))
|
108
|
-
|
109
|
-
# Dup the data so we can pass it to the guest API
|
110
|
-
data = data.dup
|
111
|
-
|
112
|
-
# Calculate the owner and group
|
113
|
-
ssh_info = @env[:machine].ssh_info
|
114
|
-
data[:owner] ||= ssh_info[:username]
|
115
|
-
data[:group] ||= ssh_info[:username]
|
116
|
-
|
117
|
-
# Mount the actual folder
|
118
|
-
@env[:machine].guest.capability(
|
119
|
-
:mount_parallels_shared_folder, id, data[:guestpath], data)
|
120
|
-
else
|
121
|
-
# If no guest path is specified, then automounting is disabled
|
122
|
-
@env[:ui].info(I18n.t("vagrant.actions.vm.share_folders.nomount_entry",
|
123
|
-
:host_path => data[:hostpath]))
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|