vagrant-parallels 0.0.9 → 0.1.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.
- 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
|